diff --git a/.github/workflows/auto-build.yml b/.github/workflows/auto-build.yml index 56359568c..9db870f6f 100644 --- a/.github/workflows/auto-build.yml +++ b/.github/workflows/auto-build.yml @@ -38,18 +38,24 @@ jobs: { label: "windows-x64", os: "blacksmith-2vcpu-windows-2025", + native_target: "x86_64-pc-windows-msvc", + native_platform_key: "win32-x64", builder_args: "--win nsis portable --x64", artifact_paths: "opennow-stable/dist-release/*-x64.exe\n", }, { label: "windows-arm64", os: "blacksmith-2vcpu-windows-2025", + native_target: "aarch64-pc-windows-msvc", + native_platform_key: "win32-arm64", builder_args: "--win nsis portable --arm64", artifact_paths: "opennow-stable/dist-release/*-arm64.exe\n", }, { label: "macos-x64", os: "blacksmith-6vcpu-macos-15", + native_target: "x86_64-apple-darwin", + native_platform_key: "darwin-x64", builder_args: "--mac dmg zip --x64", artifact_paths: "opennow-stable/dist-release/*.dmg\n" + @@ -58,6 +64,8 @@ jobs: { label: "macos-arm64", os: "blacksmith-6vcpu-macos-15", + native_target: "aarch64-apple-darwin", + native_platform_key: "darwin-arm64", builder_args: "--mac dmg zip --arm64", artifact_paths: "opennow-stable/dist-release/*.dmg\n" + @@ -66,6 +74,8 @@ jobs: { label: "linux-x64", os: "blacksmith-2vcpu-ubuntu-2404", + native_target: "x86_64-unknown-linux-gnu", + native_platform_key: "linux-x64", builder_args: "--linux AppImage deb --x64", artifact_paths: "opennow-stable/dist-release/*-x86_64.AppImage\n" + @@ -74,6 +84,8 @@ jobs: { label: "linux-arm64", os: "blacksmith-2vcpu-ubuntu-2404-arm", + native_target: "aarch64-unknown-linux-gnu", + native_platform_key: "linux-arm64", builder_args: "--linux AppImage deb --arm64", artifact_paths: "opennow-stable/dist-release/*-arm64.AppImage\n" + @@ -87,7 +99,11 @@ jobs: const isDevValidationPullRequest = isPullRequest && baseRef === "dev"; const include = isDevValidationPullRequest ? builds.filter(({ label }) => - label === "windows-x64" || label === "linux-x64" || label === "linux-arm64") + label === "windows-x64" + || label === "macos-x64" + || label === "macos-arm64" + || label === "linux-x64" + || label === "linux-arm64") : builds; fs.appendFileSync(process.env.GITHUB_OUTPUT, `matrix=${JSON.stringify({ include })}\n`); @@ -121,30 +137,73 @@ jobs: cache-dependency-path: opennow-stable/package-lock.json - name: Setup Rust - if: runner.os == 'Linux' uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.native_target }} - - name: Install Linux native streamer dependencies + - name: Install Linux native streamer build dependencies if: runner.os == 'Linux' - env: - DEBIAN_FRONTEND: noninteractive run: | sudo apt-get update - sudo apt-get install -y --no-install-recommends \ - build-essential \ - pkg-config \ + sudo apt-get install -y \ + cmake \ + libasound2-dev \ + libdrm-dev \ + libpulse-dev \ + libva-dev \ libx11-dev \ - libglib2.0-dev \ - libgstreamer1.0-dev \ - libgstreamer-plugins-base1.0-dev \ - libgstreamer-plugins-bad1.0-dev \ - gstreamer1.0-libav \ - gstreamer1.0-plugins-base \ - gstreamer1.0-plugins-good \ - gstreamer1.0-plugins-bad \ - gstreamer1.0-nice \ - gstreamer1.0-gl \ - gstreamer1.0-x + libxcursor-dev \ + libxext-dev \ + libxfixes-dev \ + libxi-dev \ + libxrandr-dev \ + libxrender-dev \ + libxss-dev \ + make \ + nasm \ + pkg-config + + - name: Install Linux ARM64 cross compiler + if: matrix.label == 'linux-arm64' + run: sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu + + - name: Install Windows ARM64 compiler + if: matrix.native_target == 'aarch64-pc-windows-msvc' + shell: pwsh + run: | + $ErrorActionPreference = "Stop" + $installerRoot = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer" + $installPath = & "$installerRoot\vswhere.exe" -latest -products * -property installationPath + if (-not $installPath) { + throw "Visual Studio Build Tools installation was not found." + } + $compiler = Get-ChildItem "$installPath\VC\Tools\MSVC\*\bin\Hostx64\arm64\cl.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 + if (-not $compiler) { + $arguments = "modify --installPath `"$installPath`" --quiet --norestart --add Microsoft.VisualStudio.Component.VC.Tools.ARM64" + $install = Start-Process "$installerRoot\vs_installer.exe" -ArgumentList $arguments -Wait -PassThru + if ($install.ExitCode -notin 0, 3010) { + throw "Visual Studio ARM64 compiler installation failed with exit code $($install.ExitCode)." + } + $compiler = Get-ChildItem "$installPath\VC\Tools\MSVC\*\bin\Hostx64\arm64\cl.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 + } + if (-not $compiler) { + throw "Visual Studio ARM64 compiler is unavailable after installation." + } + Write-Host "Using Windows ARM64 compiler: $($compiler.FullName)" + + - name: Setup Windows ARM64 build tools + if: matrix.native_target == 'aarch64-pc-windows-msvc' + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: amd64_arm64 + + - name: Pin CMake for bundled SDL2 + if: runner.os == 'macOS' + shell: bash + run: | + python3 -m venv "$RUNNER_TEMP/cmake-venv" + "$RUNNER_TEMP/cmake-venv/bin/pip" install --disable-pip-version-check cmake==3.31.6 + echo "$RUNNER_TEMP/cmake-venv/bin" >> "$GITHUB_PATH" - name: Install dependencies run: npm ci @@ -165,10 +224,14 @@ jobs: id: build run: npm run build - - name: Test and build Linux native streamer - if: runner.os == 'Linux' + - name: Test and build native streamer v2 + env: + OPENNOW_NATIVE_STREAMER_TARGET: ${{ matrix.native_target }} + OPENNOW_NATIVE_STREAMER_PLATFORM_KEY: ${{ matrix.native_platform_key }} run: | - cargo test --manifest-path ../native/opennow-streamer/Cargo.toml --features gstreamer + cargo fmt --manifest-path ../native/opennow-streamer/Cargo.toml --all -- --check + cargo clippy --manifest-path ../native/opennow-streamer/Cargo.toml --workspace --all-targets -- -D warnings + cargo test --manifest-path ../native/opennow-streamer/Cargo.toml --workspace npm run native:build - name: CI summary diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 430de07c5..ea1e0f5ab 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,14 +36,27 @@ jobs: prerelease: ${{ steps.release.outputs.prerelease }} make_latest: ${{ steps.release.outputs.make_latest }} release_tag: ${{ steps.release.outputs.release_tag }} - source_ref: ${{ steps.release.outputs.source_ref }} release_type: ${{ steps.release.outputs.release_type }} release_name: ${{ steps.release.outputs.release_name }} previous_tag: ${{ steps.release.outputs.previous_tag }} steps: + - name: Validate manual release source + if: github.event_name == 'workflow_dispatch' + shell: bash + env: + REF_NAME: ${{ github.ref_name }} + REF_TYPE: ${{ github.ref_type }} + run: | + if [[ "$REF_TYPE" != "branch" || "$REF_NAME" != "dev" ]]; then + echo "Manual releases must be dispatched from the dev branch." >&2 + exit 1 + fi + - name: Checkout uses: actions/checkout@v4 + with: + ref: ${{ github.event_name == 'workflow_dispatch' && 'refs/heads/dev' || github.sha }} - name: Setup Node.js uses: actions/setup-node@v4 @@ -127,10 +140,8 @@ jobs: if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then release_tag="v${version}" - source_ref="$REF_NAME" else release_tag="$raw" - source_ref="$REF_NAME" fi release_pages="$(gh api --paginate --slurp "repos/${GITHUB_REPOSITORY}/releases?per_page=100")" @@ -167,7 +178,6 @@ jobs: echo "prerelease=$prerelease" echo "make_latest=$make_latest" echo "release_tag=$release_tag" - echo "source_ref=$source_ref" echo "release_type=$release_type" echo "release_name=$release_name" echo "previous_tag=$previous_tag" @@ -186,7 +196,7 @@ jobs: - name: Checkout source uses: actions/checkout@v4 with: - ref: ${{ needs.preflight.outputs.source_ref }} + ref: ${{ github.event_name == 'workflow_dispatch' && 'refs/heads/dev' || github.sha }} fetch-depth: 0 token: ${{ secrets.RELEASE_PUSH_TOKEN || secrets.GITHUB_TOKEN }} @@ -197,7 +207,6 @@ jobs: EVENT_NAME: ${{ github.event_name }} REF_TYPE: ${{ github.ref_type }} RELEASE_VERSION: ${{ needs.preflight.outputs.version }} - SOURCE_REF: ${{ needs.preflight.outputs.source_ref }} RELEASE_TYPE: ${{ needs.preflight.outputs.release_type }} run: | if [[ "$RELEASE_TYPE" == "nightly" ]]; then @@ -225,7 +234,7 @@ jobs: echo "No version bump changes to commit." else git commit -m "chore(release): prepare v${RELEASE_VERSION}" - git push origin HEAD:"$SOURCE_REF" + git push origin HEAD:dev fi echo "release_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" @@ -243,8 +252,7 @@ jobs: os: blacksmith-4vcpu-windows-2025 builder_args: "--win nsis portable --x64" native_build: "true" - bundle_gstreamer: "1" - native_target: "" + native_target: "x86_64-pc-windows-msvc" native_platform_key: "win32-x64" artifact_paths: | opennow-stable/dist-release/*-x64.exe @@ -253,9 +261,8 @@ jobs: - label: windows-arm64 os: blacksmith-4vcpu-windows-2025 builder_args: "--win nsis portable --arm64" - native_build: "false" - bundle_gstreamer: "0" - native_target: "" + native_build: "true" + native_target: "aarch64-pc-windows-msvc" native_platform_key: "win32-arm64" artifact_paths: | opennow-stable/dist-release/*-arm64.exe @@ -263,7 +270,6 @@ jobs: os: blacksmith-6vcpu-macos-15 builder_args: "--mac dmg zip --x64" native_build: "true" - bundle_gstreamer: "1" native_target: "x86_64-apple-darwin" native_platform_key: "darwin-x64" arch: x64 @@ -275,7 +281,6 @@ jobs: os: blacksmith-6vcpu-macos-15 builder_args: "--mac dmg zip --arm64" native_build: "true" - bundle_gstreamer: "1" native_target: "aarch64-apple-darwin" native_platform_key: "darwin-arm64" arch: arm64 @@ -287,8 +292,7 @@ jobs: os: blacksmith-4vcpu-ubuntu-2404 builder_args: "--linux AppImage deb --x64" native_build: "true" - bundle_gstreamer: "0" - native_target: "" + native_target: "x86_64-unknown-linux-gnu" native_platform_key: "linux-x64" artifact_paths: | opennow-stable/dist-release/*-x86_64.AppImage @@ -298,8 +302,7 @@ jobs: os: blacksmith-4vcpu-ubuntu-2404-arm builder_args: "--linux AppImage deb --arm64" native_build: "true" - bundle_gstreamer: "0" - native_target: "" + native_target: "aarch64-unknown-linux-gnu" native_platform_key: "linux-arm64" artifact_paths: | opennow-stable/dist-release/*-arm64.AppImage @@ -316,8 +319,6 @@ jobs: ELECTRON_BUILDER_CACHE: ${{ github.workspace }}/.cache/electron-builder npm_config_audit: "false" npm_config_fund: "false" - GSTREAMER_VERSION: "1.28.2" - GSTREAMER_WINDOWS_VERSION: "1.28.3" CARGO_NET_RETRY: "10" CARGO_HTTP_MULTIPLEXING: "false" CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse @@ -329,7 +330,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: - ref: ${{ needs.prepare-source.outputs.release_sha }} + ref: ${{ github.event_name == 'workflow_dispatch' && 'refs/heads/dev' || github.sha }} - name: Setup Node.js uses: actions/setup-node@v4 @@ -342,6 +343,70 @@ jobs: if: matrix.native_build == 'true' uses: dtolnay/rust-toolchain@stable + - name: Install Linux native streamer build dependencies + if: matrix.native_build == 'true' && runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y \ + cmake \ + libasound2-dev \ + libdrm-dev \ + libpulse-dev \ + libva-dev \ + libx11-dev \ + libxcursor-dev \ + libxext-dev \ + libxfixes-dev \ + libxi-dev \ + libxrandr-dev \ + libxrender-dev \ + libxss-dev \ + make \ + nasm \ + pkg-config + + - name: Install Linux ARM64 cross compiler + if: matrix.native_build == 'true' && matrix.label == 'linux-arm64' + run: sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu + + - name: Install Windows ARM64 compiler + if: matrix.native_target == 'aarch64-pc-windows-msvc' + shell: pwsh + run: | + $ErrorActionPreference = "Stop" + $installerRoot = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer" + $installPath = & "$installerRoot\vswhere.exe" -latest -products * -property installationPath + if (-not $installPath) { + throw "Visual Studio Build Tools installation was not found." + } + $compiler = Get-ChildItem "$installPath\VC\Tools\MSVC\*\bin\Hostx64\arm64\cl.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 + if (-not $compiler) { + $arguments = "modify --installPath `"$installPath`" --quiet --norestart --add Microsoft.VisualStudio.Component.VC.Tools.ARM64" + $install = Start-Process "$installerRoot\vs_installer.exe" -ArgumentList $arguments -Wait -PassThru + if ($install.ExitCode -notin 0, 3010) { + throw "Visual Studio ARM64 compiler installation failed with exit code $($install.ExitCode)." + } + $compiler = Get-ChildItem "$installPath\VC\Tools\MSVC\*\bin\Hostx64\arm64\cl.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 + } + if (-not $compiler) { + throw "Visual Studio ARM64 compiler is unavailable after installation." + } + Write-Host "Using Windows ARM64 compiler: $($compiler.FullName)" + + - name: Setup Windows ARM64 build tools + if: matrix.native_target == 'aarch64-pc-windows-msvc' + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: amd64_arm64 + + - name: Pin CMake for bundled SDL2 + if: matrix.native_build == 'true' && runner.os == 'macOS' + shell: bash + run: | + python3 -m venv "$RUNNER_TEMP/cmake-venv" + "$RUNNER_TEMP/cmake-venv/bin/pip" install --disable-pip-version-check cmake==3.31.6 + echo "$RUNNER_TEMP/cmake-venv/bin" >> "$GITHUB_PATH" + - name: Install Rust target if: matrix.native_build == 'true' && matrix.native_target != '' run: rustup target add ${{ matrix.native_target }} @@ -368,225 +433,6 @@ jobs: restore-keys: | ${{ runner.os }}-electron- - - name: Install Linux build/runtime packages - if: runner.os == 'Linux' - env: - DEBIAN_FRONTEND: noninteractive - run: | - sudo apt-get update - sudo apt-get install -y --no-install-recommends \ - fakeroot \ - rpm \ - build-essential \ - pkg-config \ - libx11-dev \ - libglib2.0-dev \ - libgstreamer1.0-dev \ - libgstreamer-plugins-base1.0-dev \ - libgstreamer-plugins-bad1.0-dev \ - gstreamer1.0-alsa \ - gstreamer1.0-libav \ - gstreamer1.0-plugins-base \ - gstreamer1.0-plugins-good \ - gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-ugly \ - gstreamer1.0-nice \ - gstreamer1.0-vaapi \ - gstreamer1.0-gl \ - gstreamer1.0-x \ - libva2 \ - libva-drm2 \ - libvulkan1 \ - mesa-vulkan-drivers - - - name: Cache macOS GStreamer packages - if: matrix.native_build == 'true' && runner.os == 'macOS' - uses: actions/cache@v4 - with: - path: ${{ github.workspace }}/.cache/gstreamer-macos - key: gstreamer-macos-${{ env.GSTREAMER_VERSION }} - - - name: Install macOS GStreamer build/runtime packages - if: matrix.native_build == 'true' && runner.os == 'macOS' - run: | - primary_base="https://gstreamer.freedesktop.org/data/pkg/macos/${GSTREAMER_VERSION}" - mirror_base="https://gstreamer.freedesktop.org/pkg/macos/${GSTREAMER_VERSION}" - cache_dir="${GITHUB_WORKSPACE}/.cache/gstreamer-macos/${GSTREAMER_VERSION}" - mkdir -p "$cache_dir" - runtime="$cache_dir/gstreamer-1.0-${GSTREAMER_VERSION}-universal.pkg" - devel="$cache_dir/gstreamer-1.0-devel-${GSTREAMER_VERSION}-universal.pkg" - download_pkg() { - local name="$1" - local destination="$2" - local partial="${destination}.part" - if [ -s "$destination" ]; then - return 0 - fi - rm -f "$partial" - if ! curl --fail --location --retry 8 --retry-all-errors --retry-delay 5 --connect-timeout 30 --continue-at - --output "$partial" "$primary_base/$name"; then - curl --fail --location --retry 8 --retry-all-errors --retry-delay 5 --connect-timeout 30 --continue-at - --output "$partial" "$mirror_base/$name" - fi - test -s "$partial" - mv "$partial" "$destination" - } - download_pkg "gstreamer-1.0-${GSTREAMER_VERSION}-universal.pkg" "$runtime" - download_pkg "gstreamer-1.0-devel-${GSTREAMER_VERSION}-universal.pkg" "$devel" - test -s "$runtime" - test -s "$devel" - sudo installer -pkg "$runtime" -target / - sudo installer -pkg "$devel" -target / - root="/Library/Frameworks/GStreamer.framework/Versions/1.0" - echo "GSTREAMER_1_0_ROOT_MACOS=$root" >> "$GITHUB_ENV" - echo "$root/bin" >> "$GITHUB_PATH" - echo "PKG_CONFIG_PATH=$root/lib/pkgconfig:$PKG_CONFIG_PATH" >> "$GITHUB_ENV" - - - name: Cache Windows GStreamer SDK - if: matrix.native_build == 'true' && runner.os == 'Windows' - uses: actions/cache@v4 - with: - path: | - C:\gstreamer - ${{ github.workspace }}\.cache\gstreamer-windows - key: gstreamer-windows-${{ env.GSTREAMER_WINDOWS_VERSION }} - - - name: Install Windows GStreamer SDK - if: matrix.native_build == 'true' && runner.os == 'Windows' - shell: pwsh - run: | - $installRoot = "C:\gstreamer\1.0\msvc_x86_64" - $roots = @( - $installRoot, - "C:\Program Files\gstreamer\1.0\msvc_x86_64" - ) - $searchBases = @("C:\gstreamer", "C:\Program Files\gstreamer") - $script:gstreamerPcPaths = @() - $script:lastInstallerExitCode = $null - function Test-GStreamerRoot([string] $candidate) { - return [bool]($candidate -and - (Test-Path (Join-Path $candidate "lib\pkgconfig\gstreamer-1.0.pc")) -and - ((Test-Path (Join-Path $candidate "bin\pkg-config.exe")) -or (Test-Path (Join-Path $candidate "bin\pkgconf.exe")))) - } - function Find-GStreamerRoot { - $script:gstreamerPcPaths = @() - foreach ($candidate in $roots) { - if (Test-GStreamerRoot $candidate) { return $candidate } - } - foreach ($base in $searchBases) { - if (-not (Test-Path $base)) { continue } - $pcFiles = @(Get-ChildItem -Path $base -Filter "gstreamer-1.0.pc" -Recurse -ErrorAction SilentlyContinue | Where-Object { $_.FullName -like "*\lib\pkgconfig\gstreamer-1.0.pc" }) - foreach ($pc in $pcFiles) { - $script:gstreamerPcPaths += $pc.FullName - $root = Split-Path -Parent (Split-Path -Parent (Split-Path -Parent $pc.FullName)) - if (Test-GStreamerRoot $root) { return $root } - } - } - return $null - } - function Get-GStreamerInstaller([string] $fileName, [string] $downloadDir, [string[]] $urlBases) { - New-Item -ItemType Directory -Force -Path $downloadDir | Out-Null - $output = Join-Path $downloadDir $fileName - $partial = "$output.part" - if ((Test-Path $output) -and ((Get-Item $output).Length -gt 0)) { - Write-Host "Using cached GStreamer MSI: $output" - return $output - } - foreach ($base in $urlBases) { - $url = "$base/$fileName" - Write-Host "Downloading GStreamer MSI from $url" - if ((Test-Path $partial) -and ((Get-Item $partial).Length -eq 0)) { Remove-Item -Force $partial } - $process = Start-Process -FilePath "curl.exe" -ArgumentList @( - "--fail", - "--location", - "--retry", "8", - "--retry-all-errors", - "--retry-delay", "5", - "--connect-timeout", "30", - "--continue-at", "-", - "--output", $partial, - $url - ) -Wait -PassThru -NoNewWindow - if ($process.ExitCode -eq 0 -and (Test-Path $partial) -and ((Get-Item $partial).Length -gt 0)) { - Move-Item -Force $partial $output - return $output - } - Write-Host "GStreamer MSI download failed from $url with curl exit code $($process.ExitCode)." - if ((Test-Path $partial) -and ((Get-Item $partial).Length -eq 0)) { Remove-Item -Force $partial } - } - if (Test-Path $partial) { - Write-Host "Removing incomplete GStreamer MSI download: $partial" - Remove-Item -Force $partial - } - return $null - } - function Install-GStreamerSdk([string] $version) { - $urlBases = @( - "https://gstreamer.freedesktop.org/data/pkg/windows/$version/msvc", - "https://gstreamer.freedesktop.org/pkg/windows/$version/msvc" - ) - $downloadDir = Join-Path $env:GITHUB_WORKSPACE ".cache\gstreamer-windows\$version" - $installer = Get-GStreamerInstaller "gstreamer-1.0-msvc-x86_64-$version.exe" $downloadDir $urlBases - if (-not $installer) { return $false } - $install = Start-Process -FilePath $installer -ArgumentList @( - "/VERYSILENT", - "/SUPPRESSMSGBOXES", - "/NORESTART", - "/TYPE=devel", - "/DIR=$installRoot" - ) -Wait -PassThru -NoNewWindow - $script:lastInstallerExitCode = $install.ExitCode - if ($install.ExitCode -ne 0) { return $false } - return [bool](Find-GStreamerRoot) - } - $root = Find-GStreamerRoot - if ($root) { - Write-Host "Using cached GStreamer Windows SDK: $root" - } elseif (-not (Install-GStreamerSdk $env:GSTREAMER_WINDOWS_VERSION)) { - [void](Find-GStreamerRoot) - Write-Host "GStreamer explicit roots searched: $($roots -join ', ')" - Write-Host "GStreamer recursive search bases: $($searchBases -join ', ')" - Write-Host "Discovered gstreamer-1.0.pc paths: $(if ($script:gstreamerPcPaths.Count) { $script:gstreamerPcPaths -join ', ' } else { 'none' })" - Write-Error "Failed to install/discover GStreamer Windows SDK version $env:GSTREAMER_WINDOWS_VERSION. Installer exit code: $script:lastInstallerExitCode." - exit 1 - } - $root = Find-GStreamerRoot - Write-Host "GStreamer explicit roots searched: $($roots -join ', ')" - Write-Host "GStreamer recursive search bases: $($searchBases -join ', ')" - Write-Host "Discovered gstreamer-1.0.pc paths: $(if ($script:gstreamerPcPaths.Count) { $script:gstreamerPcPaths -join ', ' } else { 'none' })" - if (-not $root) { - Write-Error "GStreamer SDK root not found. Checked: $($roots -join ', '). Expected lib\pkgconfig\gstreamer-1.0.pc and bin\pkg-config.exe or bin\pkgconf.exe." - exit 1 - } - $gstInspect = Join-Path $root "bin\gst-inspect-1.0.exe" - if (-not (Test-Path $gstInspect)) { - Write-Error "gst-inspect-1.0.exe not found in $root\bin after GStreamer install." - exit 1 - } - $h264Decoders = @("avdec_h264", "d3d11h264dec", "d3d12h264dec") - $availableH264Decoders = @() - foreach ($decoder in $h264Decoders) { - $inspect = Start-Process -FilePath $gstInspect -ArgumentList @($decoder) -Wait -PassThru -NoNewWindow - if ($inspect.ExitCode -eq 0) { - $availableH264Decoders += $decoder - Write-Host "GStreamer decoder available: $decoder" - } else { - Write-Host "GStreamer decoder unavailable: $decoder" - } - } - if ($availableH264Decoders.Count -eq 0) { - Write-Error "GStreamer Windows SDK installed, but no H.264 decoder plugins were found among: $($h264Decoders -join ', ')" - exit 1 - } - # Official Cerbero Windows packages disable gstvulkan. OpenNOW injects a - # vendored Vulkan plugin into the private runtime after bundling. - Write-Host "Skipping base-SDK Vulkan element checks; Vulkan is injected into the private OpenNOW runtime bundle." - "GSTREAMER_1_0_ROOT_MSVC_X86_64=$root" | Out-File -FilePath $env:GITHUB_ENV -Append - "$root\bin" | Out-File -FilePath $env:GITHUB_PATH -Append - - - name: Build patched Windows GStreamer D3D11 plugin - if: matrix.native_build == 'true' && runner.os == 'Windows' - shell: pwsh - run: ./scripts/build-patched-gstreamer-d3d11.ps1 -GStreamerRoot "$env:GSTREAMER_1_0_ROOT_MSVC_X86_64" -Version "$env:GSTREAMER_WINDOWS_VERSION" - - name: Install FPM for arm64 deb builds if: matrix.label == 'linux-arm64' run: sudo apt-get install -y ruby ruby-dev build-essential && sudo gem install fpm @@ -621,8 +467,6 @@ jobs: - name: Build native streamer if: matrix.native_build == 'true' env: - OPENNOW_NATIVE_STREAMER_FEATURES: gstreamer - OPENNOW_BUNDLE_GSTREAMER_RUNTIME: ${{ matrix.bundle_gstreamer }} OPENNOW_NATIVE_STREAMER_TARGET: ${{ matrix.native_target }} OPENNOW_NATIVE_STREAMER_PLATFORM_KEY: ${{ matrix.native_platform_key }} run: npm run native:build @@ -777,24 +621,10 @@ jobs: contents: write steps: - - name: Resolve release branch - id: branch - shell: bash - env: - REF_TYPE: ${{ github.ref_type }} - REF_NAME: ${{ github.ref_name }} - run: | - if [[ "$REF_TYPE" == "branch" ]]; then - branch="$REF_NAME" - else - branch="main" - fi - echo "branch=$branch" >> "$GITHUB_OUTPUT" - - name: Checkout release branch uses: actions/checkout@v4 with: - ref: ${{ steps.branch.outputs.branch }} + ref: ${{ github.event_name == 'workflow_dispatch' && 'refs/heads/dev' || 'refs/heads/main' }} fetch-depth: 0 token: ${{ secrets.RELEASE_PUSH_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 4c8d3cf47..c8bf58b5a 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,4 @@ result vendor/ !native/opennow-streamer/vendor/ !native/opennow-streamer/vendor/** +native/opennow-streamer/vendor/**/.cargo-ok diff --git a/THIRD_PARTY_NOTICES b/THIRD_PARTY_NOTICES new file mode 100644 index 000000000..00b2999f5 --- /dev/null +++ b/THIRD_PARTY_NOTICES @@ -0,0 +1,30 @@ +macforce-now +============ + +OpenNOW's NVST transport, control, input, audio, and interoperability tests +include code and behavior specifications adapted from macforce-now pull request +66 at commit 439c0adb3a4bc875d4601581879f27a406cfe0a6: + +https://github.com/anderson-oki/macforce-now + +MIT License + +Copyright (c) 2026 OpenCloud + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/locales/en.json b/locales/en.json index 8208f4318..90064318d 100644 --- a/locales/en.json +++ b/locales/en.json @@ -541,8 +541,8 @@ "advancedTiming": "Decode {{decode}}ms · Render {{render}}ms · JitterBuf {{jitterBuffer}}ms · Jitter {{jitter}}ms", "advancedInputQueue": "Input queue {{buffered}}KB · peak {{peak}}KB · drops {{drops}} · sched {{scheduling}}ms · residual {{residual}}px", "advancedMouseFlush": "Mouse flush {{interval}}ms · {{rate}}/s · PR {{partiallyReliable}}", - "advancedGstreamerEnabled": "GStreamer enabled · {{state}}", - "advancedGstreamerDisabled": "GStreamer disabled · Chromium WebRTC", + "advancedNativeEnabled": "Native streamer enabled · {{state}}", + "advancedNativeDisabled": "Native streamer disabled · Chromium WebRTC", "advancedIceCandidate": "ICE {{transport}} candidate", "advancedShaderActive": "Shader FX active (WebGL post-processing)", "advancedDecoderRecovery": "Decoder recovery {{state}} · attempts {{attempts}} · action {{action}}", @@ -1032,11 +1032,11 @@ "nativeStreamer": { "title": "Native Streamer", "runtime": "Runtime", - "runtimeDescription": "Enable the experimental streamer and inspect its local GStreamer readiness.", + "runtimeDescription": "Enable the experimental streamer and inspect its local native runtime readiness.", "videoOutput": "Video Output", "videoOutputDescription": "Hardware capability, rendering backend, frame pacing, and window mode.", "nativeStreaming": "Native Streaming", - "nativeStreamingHint": "Native streaming is experimental and may have platform-specific bugs, glitches, or fallbacks to Chromium/WebRTC. Enable it only if you are comfortable testing the GStreamer-based desktop streamer for new sessions.", + "nativeStreamingHint": "Native streaming is experimental and may have platform-specific bugs, glitches, or fallbacks to Chromium/WebRTC. Enable it only if you are comfortable testing the self-contained desktop streamer for new sessions.", "enablePromptKicker": "Experimental", "enablePromptTitle": "Enable Native Streamer?", "enablePromptBody": "The native streamer is still experimental. Internal mode keeps video inside the OpenNOW window; external floating mode is available as a fallback in settings.", @@ -1052,13 +1052,12 @@ "showNativeStreamerStatsHint": "Display the native streamer's own diagnostics overlay during native sessions.", "streamerStatus": "Streamer Status", "checkNativeStreamer": "Check native streamer", - "gstreamerReady": "GStreamer Ready", + "nativeRuntimeReady": "Native Runtime Ready", "notReady": "Not Ready", - "statusDefaultHint": "OpenNOW will check the bundled GStreamer streamer when this tab opens.", - "gstreamerRuntime": "GStreamer Runtime", - "bundledPathDetected": "Bundled path detected", + "statusDefaultHint": "OpenNOW will check the bundled native streamer when this tab opens.", + "nativeRuntime": "Native Runtime", + "nativeExecutablePath": "Native executable path", "runtimeDefaultHint": "Packaged Windows/macOS builds auto-detect a bundled runtime next to the native streamer. Linux uses distro packages.", - "linuxRuntimeHint": "Linux AppImage/private GStreamer bundling is intentionally not used by default because VAAPI/V4L2/Vulkan plugins must match the host distro and GPU driver stack. .deb packages declare Debian/Ubuntu dependencies automatically.", "videoPath": "Video Path", "thisPc": "This PC", "supportedVideoBackends": "Backend Compatibility", @@ -1072,13 +1071,13 @@ "noRenderer": "No renderer", "systemMemory": "System memory", "noCodecsAvailable": "No compatible codecs were detected for this backend.", - "probingBackends": "Probing the installed GPU drivers and GStreamer plugins…", + "probingBackends": "Probing installed native video backends…", "activePath": "Active path", "capabilityProbeHint": "Refresh the streamer status to probe the video backends supported by this PC.", - "backendUnavailableOnPc": "This backend is not supported by the installed GPU drivers and GStreamer plugins.", + "backendUnavailableOnPc": "This backend is not supported by the installed native runtime and GPU drivers.", "codecSupportUnknown": "Codec support unknown", "memoryPathUnknown": "Memory path unknown", - "videoPathDefaultHint": "OpenNOW will show the active hardware decode path after GStreamer is detected.", + "videoPathDefaultHint": "OpenNOW will show the active hardware decode path after the native runtime is detected.", "directxBackend": "Video Backend", "directxBackendHint": "Applies to the next native streamer process. Unsupported choices are disabled from the live capability probe. Auto selects the best compatible path.", "framePacing": "Frame Pacing", @@ -1088,12 +1087,12 @@ "renderMode": "Render Mode", "renderModeInternal": "Internal (One Window)", "renderModeExternal": "External (Floating)", - "renderModeHint": "Internal (default) embeds native video in the OpenNOW window. External keeps the floating GStreamer window for testing/fallback. Change applies to the next native streamer process.", + "renderModeHint": "Internal (default) embeds native video in the OpenNOW window. External uses the native presenter's own window for testing. The change applies to the next native streamer process.", "renderModeInternalOnlyHint": "This platform uses Internal (one window) only. Keyboard, mouse, and controller input stay in Electron and are forwarded over IPC. External floating mode is Windows-only.", "transportMode": "Transport Mode", "transportModeWebrtc": "WebRTC (Default)", "transportModeNvst": "NVST (Experimental)", - "transportModeHint": "WebRTC is the supported path. NVST (experimental) uses classic RTSPS + UDP video (Moonlight-hypothesis scaffold) while keyboard/mouse/controller stay on WebRTC SCTP datachannels. First live sessions may need SRTP/pcap validation.", + "transportModeHint": "WebRTC uses Chromium for media. NVST sends H.264 video through the native UDP/SRTP decoder while audio and input continue over WebRTC. Select NVST to test native hardware video decoding.", "transportModeWindowsOnlyHint": "NVST transport is Windows-only for now. This platform always uses WebRTC." }, "thanks": { diff --git a/native/gstreamer-patches/0001-d3d11-enable-tearing-vrr.patch b/native/gstreamer-patches/0001-d3d11-enable-tearing-vrr.patch deleted file mode 100644 index 1bfce4f65..000000000 --- a/native/gstreamer-patches/0001-d3d11-enable-tearing-vrr.patch +++ /dev/null @@ -1,55 +0,0 @@ ---- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_win32.cpp -+++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_win32.cpp -@@ -1155,9 +1155,36 @@ - DXGI_SWAP_CHAIN_DESC desc = { 0, }; - IDXGISwapChain *new_swapchain = NULL; - GstD3D11Device *device = window->device; -+ HRESULT hr; - - self->have_swapchain1 = FALSE; - -+ const gchar *allow_tearing_env = g_getenv ("OPENNOW_NATIVE_D3D_ALLOW_TEARING"); -+ if (allow_tearing_env && -+ (!g_ascii_strcasecmp (allow_tearing_env, "1") || -+ !g_ascii_strcasecmp (allow_tearing_env, "true") || -+ !g_ascii_strcasecmp (allow_tearing_env, "on") || -+ !g_ascii_strcasecmp (allow_tearing_env, "yes"))) { -+ IDXGIFactory1 *factory = -+ gst_d3d11_device_get_dxgi_factory_handle (device); -+ ComPtr < IDXGIFactory5 > factory5; -+ BOOL allow_tearing = FALSE; -+ -+ hr = factory->QueryInterface (IID_PPV_ARGS (&factory5)); -+ if (SUCCEEDED (hr)) { -+ hr = factory5->CheckFeatureSupport (DXGI_FEATURE_PRESENT_ALLOW_TEARING, -+ &allow_tearing, sizeof (allow_tearing)); -+ } -+ -+ if (SUCCEEDED (hr) && allow_tearing) { -+ swapchain_flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; -+ GST_INFO_OBJECT (self, "DXGI tearing/VRR presentation enabled"); -+ } else { -+ GST_WARNING_OBJECT (self, -+ "DXGI tearing/VRR presentation requested but unsupported"); -+ } -+ } -+ - { - DXGI_SWAP_CHAIN_DESC1 desc1 = { 0, }; - desc1.Width = 0; -@@ -1309,6 +1336,15 @@ - return GST_D3D11_WINDOW_FLOW_CLOSED; - } - -+ DXGI_SWAP_CHAIN_DESC swapchain_desc = { 0, }; -+ BOOL exclusive_fullscreen = FALSE; -+ if (SUCCEEDED (window->swap_chain->GetDesc (&swapchain_desc)) && -+ (swapchain_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) && -+ (FAILED (window->swap_chain->GetFullscreenState ( -+ &exclusive_fullscreen, nullptr)) || !exclusive_fullscreen)) { -+ present_flags |= DXGI_PRESENT_ALLOW_TEARING; -+ } -+ - if (self->have_swapchain1) { - IDXGISwapChain1 *swap_chain1 = (IDXGISwapChain1 *) window->swap_chain; - DXGI_PRESENT_PARAMETERS present_params = { 0, }; diff --git a/native/opennow-streamer/Cargo.lock b/native/opennow-streamer/Cargo.lock index 83236c1bd..aa66a2b10 100644 --- a/native/opennow-streamer/Cargo.lock +++ b/native/opennow-streamer/Cargo.lock @@ -3,825 +3,1845 @@ version = 4 [[package]] -name = "aho-corasick" -version = "1.1.4" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] -name = "android_system_properties" -version = "0.1.5" +name = "aead" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ - "libc", + "crypto-common", + "generic-array", ] [[package]] -name = "anyhow" -version = "1.0.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" - -[[package]] -name = "atomic_refcell" -version = "0.1.14" +name = "aes" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e4227379beff4205943696e6c3e0cd809bacdf3f0edd6e3dd153e2269571a4" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] [[package]] -name = "autocfg" -version = "1.5.0" +name = "aes-gcm" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] [[package]] -name = "base64" -version = "0.22.1" +name = "aho-corasick" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] [[package]] -name = "bitflags" -version = "2.11.1" +name = "anyhow" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] -name = "bitstream-io" -version = "4.10.0" +name = "apple-cryptokit-rs" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eff00be299a18769011411c9def0d827e8f2d7bf0c3dbf53633147a8867fd1f" +checksum = "508eed99695e0ddc94adb8dda623477e76bb8b5dcc9f59a01b43ce646f715343" dependencies = [ - "no_std_io2", + "serde", + "serde_json", ] [[package]] -name = "bumpalo" -version = "3.20.3" +name = "arrayvec" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" [[package]] -name = "byte-slice-cast" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" - -[[package]] -name = "bytes" -version = "1.12.1" +name = "ash" +version = "0.38.0+1.3.281" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" +dependencies = [ + "libloading", +] [[package]] -name = "cc" -version = "1.4.0" +name = "ash-window" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" +checksum = "52bca67b61cb81e5553babde81b8211f713cb6db79766f80168f3e5f40ea6c82" dependencies = [ - "find-msvc-tools", - "shlex", + "ash", + "raw-window-handle", + "raw-window-metal", ] [[package]] -name = "cfg-expr" -version = "0.20.7" +name = "asn1-rs" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6b04e07d8080154ed4ac03546d9a2b303cc2fe1901ba0b35b301516e289368" +checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" dependencies = [ - "smallvec", - "target-lexicon", + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom 7.1.3", + "num-traits", + "rusticata-macros", + "thiserror 2.0.18", + "time", ] [[package]] -name = "cfg-if" -version = "1.0.4" +name = "asn1-rs-derive" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] [[package]] -name = "chacha20" -version = "0.10.1" +name = "asn1-rs-impl" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ - "cfg-if", - "cpufeatures", - "rand_core", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] -name = "chrono" -version = "0.4.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +name = "audiopus_sys" +version = "0.2.2" dependencies = [ - "iana-time-zone", - "num-traits", - "windows-link", + "cmake", + "log", + "pkg-config", ] [[package]] -name = "core-foundation-sys" -version = "0.8.7" +name = "autocfg" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] -name = "cpufeatures" -version = "0.3.0" +name = "aws-lc-rs" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +checksum = "ce2b2dcc879c3bae0d371e77c99f2238400ef24ec001394befa67b6e543add9e" dependencies = [ - "libc", + "aws-lc-sys", + "untrusted", + "zeroize", ] [[package]] -name = "deranged" -version = "0.5.8" +name = "aws-lc-sys" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +checksum = "f09fae7be8bb3174e05c6afdb34199e6dc0c7c04ba9fa237b1967adfbde27483" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", + "pkg-config", +] [[package]] -name = "either" -version = "1.15.0" +name = "base16ct" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] -name = "equivalent" -version = "1.0.2" +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "find-msvc-tools" -version = "0.1.9" +name = "base64ct" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] -name = "futures" -version = "0.3.32" +name = "bindgen" +version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", + "bitflags 2.13.1", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex 1.3.0", + "syn 2.0.117", ] [[package]] -name = "futures-channel" -version = "0.3.32" +name = "bindgen" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "futures-core", - "futures-sink", + "bitflags 2.13.1", + "cexpr", + "clang-sys", + "itertools", + "proc-macro2", + "quote", + "regex", + "rustc-hash 2.1.3", + "shlex 1.3.0", + "syn 2.0.117", ] [[package]] -name = "futures-core" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" - -[[package]] -name = "futures-executor" -version = "0.3.32" +name = "bit-vec" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" dependencies = [ - "futures-core", - "futures-task", - "futures-util", + "serde", ] [[package]] -name = "futures-io" -version = "0.3.33" +name = "bitflags" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "futures-macro" -version = "0.3.32" +name = "bitflags" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" [[package]] -name = "futures-sink" -version = "0.3.33" +name = "block" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] -name = "futures-task" -version = "0.3.32" +name = "block-buffer" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] [[package]] -name = "futures-util" -version = "0.3.32" +name = "block2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "slab", + "objc2", ] [[package]] -name = "getrandom" -version = "0.4.3" +name = "bytemuck" +version = "1.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" dependencies = [ - "cfg-if", - "libc", - "r-efi", - "rand_core", + "bytemuck_derive", ] [[package]] -name = "gio" -version = "0.22.8" +name = "bytemuck_derive" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b3e1f669909c326b9413bde5a742097b8c90a7d78f45326db13668984769ded" +checksum = "fc0e56a716f1e132ff6bf4bdac1c944a3fcdc1cae65f70a4a2a1ac3b401d2d1f" dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "gio-sys", - "glib", - "libc", - "pin-project-lite", - "smallvec", + "proc-macro2", + "quote", + "syn 3.0.3", ] [[package]] -name = "gio-sys" -version = "0.22.0" +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64729ba2772c080448f9f966dba8f4456beeb100d8c28a865ef8a0f2ef4987e1" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", - "windows-sys", -] +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "glib" -version = "0.22.5" +name = "byteorder-lite" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b7df55594e0e787d1560e23f7e12d7360d0b22e7b7c228ec2488b9e59b1b6b" -dependencies = [ - "bitflags", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "futures-util", - "gio-sys", - "glib-macros", - "glib-sys", - "gobject-sys", - "libc", - "memchr", - "smallvec", -] +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] -name = "glib-macros" -version = "0.22.2" +name = "bytes" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda575994e3689b1bc12f89c3df621ead46ff292623b76b4710a3a5b79be54bb" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] -name = "glib-sys" -version = "0.22.3" +name = "cc" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1eb23a616a3dbc7fc15bbd26f58756ff0b04c8a894df3f0680cd21011db6a642" +checksum = "509591b7bcd67f4ef775afad7662703b4935daaa6ec0e5605cfb1090b32a2b6d" dependencies = [ + "find-msvc-tools", + "jobserver", "libc", - "system-deps", + "shlex 2.0.1", ] [[package]] -name = "gobject-sys" -version = "0.22.0" +name = "ccm" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18eda93f09d3778f38255b231b17ef67195013a592c91624a4daf8bead875565" +checksum = "9ae3c82e4355234767756212c570e29833699ab63e6ffd161887314cc5b43847" dependencies = [ - "glib-sys", - "libc", - "system-deps", + "aead", + "cipher", + "ctr", + "subtle", ] [[package]] -name = "gst-plugin-rtp" -version = "0.15.3" +name = "cexpr" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94a8636a5d8ab4d590e66c4cd103beac097d4c1f053f5723e47f141f5af67d0e" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "anyhow", - "atomic_refcell", - "bitstream-io", - "byte-slice-cast", - "chrono", - "futures", - "gio", - "glib", - "gst-plugin-version-helper", - "gstreamer", - "gstreamer-audio", - "gstreamer-base", - "gstreamer-net", - "gstreamer-rtp", - "gstreamer-video", - "hex", - "log", - "rand", - "rtcp-types", - "rtp-types", - "slab", - "smallvec", - "thiserror 2.0.18", - "time", - "tokio", - "tokio-util", + "nom 7.1.3", ] [[package]] -name = "gst-plugin-version-helper" -version = "0.8.4" +name = "cfg-if" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94668bc2592732b8c2b653668ae41211d45988fb61264888b9c2d545d4bd826d" -dependencies = [ - "chrono", - "toml_edit", -] +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] -name = "gstreamer" -version = "0.25.3" +name = "cfg_aliases" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4527e1b9bae8d29ce137bde5b8eec8ae8f78f13ad00fc6e70cbe227d6ad027" -dependencies = [ - "cfg-if", - "futures-channel", - "futures-core", - "futures-util", - "glib", - "gstreamer-sys", - "itertools", - "kstring", - "libc", - "muldiv", - "num-integer", - "num-rational", - "option-operations", - "pastey", - "pin-project-lite", - "smallvec", - "thiserror 2.0.18", -] +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] -name = "gstreamer-audio" -version = "0.25.3" +name = "chacha20" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f97532c3e21287a6e94563a328cce89367324acf8a4489291b40ede2e39163a0" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", - "glib", - "gstreamer", - "gstreamer-audio-sys", - "gstreamer-base", - "libc", - "smallvec", + "cipher", + "cpufeatures", ] [[package]] -name = "gstreamer-audio-sys" -version = "0.25.3" +name = "chacha20poly1305" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2abfb81a073c5c8fb115a3639f47b6430f669ee9fa29123bb0116c9ef59d7d16" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ - "glib-sys", - "gobject-sys", - "gstreamer-base-sys", - "gstreamer-sys", - "libc", - "system-deps", + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", ] [[package]] -name = "gstreamer-base" -version = "0.25.0" +name = "cipher" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08353a8a382be9a49b15fb9c46b3abd6f8a6e6439e1eaedc87d08f1abdcfad1" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "atomic_refcell", - "cfg-if", - "glib", - "gstreamer", - "gstreamer-base-sys", - "libc", + "crypto-common", + "inout", + "zeroize", ] [[package]] -name = "gstreamer-base-sys" -version = "0.25.0" +name = "clang-sys" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6569606feeb89cfcf95a6476a64a0f0aec83fadcef0e91c24e576f7851ceac3a" +checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a" dependencies = [ - "glib-sys", - "gobject-sys", - "gstreamer-sys", + "glob", "libc", - "system-deps", + "libloading", ] [[package]] -name = "gstreamer-net" -version = "0.25.0" +name = "cmake" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abcad04d471a4f2c859ef1287f22581b07064e357cc89dfa415ffc99b2a3193d" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" dependencies = [ - "gio", - "glib", - "gstreamer", - "gstreamer-net-sys", + "cc", ] [[package]] -name = "gstreamer-net-sys" +name = "cocoa" version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcefb342a98ffca0b106bc9fea13d5df15879e1613b4dc652a6ec1960c32584c" +checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" dependencies = [ - "gio-sys", - "glib-sys", - "gstreamer-sys", + "bitflags 1.3.2", + "block", + "cocoa-foundation", + "core-foundation 0.9.4", + "core-graphics", + "foreign-types", "libc", - "system-deps", + "objc", ] [[package]] -name = "gstreamer-rtp" -version = "0.25.0" +name = "cocoa-foundation" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea01e76ad8fd2e688a4f8a166060c9f9ba13dd6355ad7e22dbb793325d14411" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" dependencies = [ - "glib", - "gstreamer", - "gstreamer-rtp-sys", + "bitflags 1.3.2", + "block", + "core-foundation 0.9.4", + "core-graphics-types", "libc", + "objc", ] [[package]] -name = "gstreamer-rtp-sys" -version = "0.25.0" +name = "combine" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adf8df32469d863ce4375a978233a40efec206c5256bf0c14ee42bb745d8a793" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ - "glib-sys", - "gstreamer-base-sys", - "gstreamer-sys", - "libc", - "system-deps", + "bytes", + "memchr", ] [[package]] -name = "gstreamer-sdp" -version = "0.25.2" +name = "const-oid" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63c5dba39f65d0ed2cadcaa277fc905c30c9c7db37e024ad3bed7b0492042ad" -dependencies = [ - "glib", - "gstreamer", - "gstreamer-sdp-sys", -] +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] -name = "gstreamer-sdp-sys" -version = "0.25.0" +name = "core-foundation" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20f0eb41ecfbacbf6a29d9457e6de0f59e2638f47fbdb6a6c1bcfb720c2b9ee" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ - "glib-sys", - "gstreamer-sys", + "core-foundation-sys", "libc", - "system-deps", ] [[package]] -name = "gstreamer-sys" -version = "0.25.0" +name = "core-foundation" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85d09343b4c23d64b3ef35f1f644598860cc9a4617e7ccded141de97cd528608" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ - "cfg-if", - "glib-sys", - "gobject-sys", + "core-foundation-sys", "libc", - "system-deps", ] [[package]] -name = "gstreamer-video" -version = "0.25.2" +name = "core-foundation-sys" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf728cb21499561ea0d6ce584e550bf2b98b279cc7741067ee42f41f98b486e" -dependencies = [ - "cfg-if", - "futures-channel", - "glib", - "gstreamer", - "gstreamer-base", - "gstreamer-video-sys", - "libc", - "thiserror 2.0.18", -] +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] -name = "gstreamer-video-sys" -version = "0.25.0" +name = "core-graphics" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f82631a5063057c10583a57ba0fbce689e67122cfdb5eddbeaa43eb812e75" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ - "glib-sys", - "gobject-sys", - "gstreamer-base-sys", - "gstreamer-sys", + "bitflags 1.3.2", + "core-foundation 0.9.4", + "core-graphics-types", + "foreign-types", "libc", - "system-deps", ] [[package]] -name = "gstreamer-webrtc" -version = "0.25.2" +name = "core-graphics-types" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eb47b71d463547b50ec8d0c69e175cb3f5cfc28f55c4cfd6735c9d368202a74" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ - "glib", - "gstreamer", - "gstreamer-sdp", - "gstreamer-webrtc-sys", + "bitflags 1.3.2", + "core-foundation 0.9.4", "libc", ] [[package]] -name = "gstreamer-webrtc-sys" -version = "0.25.0" +name = "cpufeatures" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "405721d1f15bbda47a46f9645077859215a947cdd6af6c7f18e4f4d0cbe63bd7" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ - "glib-sys", - "gstreamer-sdp-sys", - "gstreamer-sys", "libc", - "system-deps", ] [[package]] -name = "hashbrown" -version = "0.17.0" +name = "crc" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] [[package]] -name = "heck" -version = "0.5.0" +name = "crc-catalog" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" [[package]] -name = "hex" -version = "0.4.3" +name = "crc32fast" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] [[package]] -name = "iana-time-zone" -version = "0.1.65" +name = "cros-codecs-extended" +version = "0.0.5-extended.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +checksum = "a5130a93260541c9418be3a57af40916c662e16d02f25727d8f7ad0738ebde1f" dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", + "anyhow", + "byteorder", + "crc32fast", + "cros-libva-extended", + "drm", + "drm-fourcc", "log", - "wasm-bindgen", - "windows-core", + "nix", + "thiserror 1.0.69", + "zerocopy", ] [[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" +name = "cros-libva-extended" +version = "0.0.13-extended.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +checksum = "a734fee2508191b121a756bd5eb35caf0aa096e7f20b7b6020e689a75edd92e5" dependencies = [ - "cc", + "bindgen 0.70.1", + "bitflags 2.13.1", + "log", + "pkg-config", + "regex", + "thiserror 1.0.69", ] [[package]] -name = "indexmap" -version = "2.14.0" +name = "crypto-bigint" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "equivalent", - "hashbrown", + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", ] [[package]] -name = "itertools" -version = "0.15.0" +name = "crypto-common" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ - "either", + "generic-array", + "rand_core 0.6.4", + "typenum", ] [[package]] -name = "itoa" -version = "1.0.18" +name = "ctr" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] [[package]] -name = "js-sys" -version = "0.3.103" +name = "curve25519-dalek" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", - "futures-util", - "wasm-bindgen", + "cpufeatures", + "curve25519-dalek-derive", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", ] [[package]] -name = "kstring" -version = "2.0.2" +name = "curve25519-dalek-derive" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558bf9508a558512042d3095138b1f7b8fe90c5467d94f9f1da28b3731c5dbd1" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ - "static_assertions", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] -name = "libc" -version = "0.2.186" +name = "data-encoding" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" [[package]] -name = "log" -version = "0.4.33" +name = "der" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "der_derive", + "flagset", + "pem-rfc7468", + "zeroize", +] [[package]] -name = "memchr" -version = "2.8.0" +name = "der-parser" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom 7.1.3", + "num-bigint", + "num-traits", + "rusticata-macros", +] [[package]] -name = "muldiv" -version = "1.0.1" +name = "der_derive" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956787520e75e9bd233246045d19f42fb73242759cc57fba9611d940ae96d4b0" +checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] [[package]] -name = "no_std_io2" -version = "0.9.4" +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dimpl" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6aa42b0c64c3e5311a2afad224b32db1ee129d21c63daaaf8ea747b846cdbc" +dependencies = [ + "aes", + "aes-gcm", + "arrayvec", + "aws-lc-rs", + "ccm", + "chacha20", + "chacha20poly1305", + "der", + "ecdsa", + "generic-array", + "hkdf", + "hmac", + "log", + "nom 8.0.0", + "once_cell", + "p256", + "p384", + "pkcs8", + "rand", + "rand_core 0.6.4", + "rcgen", + "sec1", + "sha2", + "signature", + "spki", + "subtle", + "time", + "x25519-dalek", + "x509-cert", +] + +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.13.1", + "objc2", +] + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "drm" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98888c4bbd601524c11a7ed63f814b8825f420514f78e96f752c437ae9cbb5d1" +dependencies = [ + "bitflags 2.13.1", + "bytemuck", + "drm-ffi", + "drm-fourcc", + "rustix", +] + +[[package]] +name = "drm-ffi" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97c98727e48b7ccb4f4aea8cfe881e5b07f702d17b7875991881b41af7278d53" +dependencies = [ + "drm-sys", + "rustix", +] + +[[package]] +name = "drm-fourcc" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" + +[[package]] +name = "drm-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd39dde40b6e196c2e8763f23d119ddb1a8714534bf7d77fa97a65b0feda3986" +dependencies = [ + "libc", + "linux-raw-sys 0.6.5", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "either" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "ffmpeg-next" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6380599799e175191eb7ffe82c97f36a2a90a36cbc54c738a903e5287d7f516a" +dependencies = [ + "bitflags 2.13.1", + "ffmpeg-sys-next", + "libc", +] + +[[package]] +name = "ffmpeg-sys-next" +version = "9.0.0" +dependencies = [ + "bindgen 0.72.1", + "cc", + "libc", + "num_cpus", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "find-msvc-tools" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" + +[[package]] +name = "flagset" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "moxcms", + "num-traits", + "png", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "is" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08f9118d003d441f79c1070e84d0a2a89f35721ca8ae0cd5e1f9026dc4a2517" +dependencies = [ + "crc", + "serde", + "str0m-proto", + "subtle", + "tracing", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7" + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "nasm-rs" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "706bf8a5e8c8ddb99128c3291d31bd21f4bcde17f0f4c20ec678d85c74faa149" +dependencies = [ + "log", +] + +[[package]] +name = "nix" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +dependencies = [ + "bitflags 2.13.1", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-integer" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" +dependencies = [ + "bitflags 2.13.1", + "block2", + "libc", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-core-text", + "objc2-core-video", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-audio-toolbox" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6948501a91121d6399b79abaa33a8aa4ea7857fe019f341b8c23ad6e81b79b08" +dependencies = [ + "bitflags 2.13.1", + "block2", + "dispatch2", + "libc", + "objc2", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" +dependencies = [ + "bitflags 2.13.1", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-audio" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1eebcea8b0dbff5f7c8504f3107c68fc061a3eb44932051c8cf8a68d969c3b2" +dependencies = [ + "dispatch2", + "objc2", + "objc2-core-audio-types", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-core-audio-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a89f2ec274a0cf4a32642b2991e8b351a404d290da87bb6a9a9d8632490bd1c" +dependencies = [ + "bitflags 2.13.1", + "objc2", +] + +[[package]] +name = "objc2-core-data" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" +dependencies = [ + "bitflags 2.13.1", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.13.1", + "block2", + "dispatch2", + "libc", + "objc2", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags 2.13.1", + "dispatch2", + "objc2", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-core-image" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-media" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ec576860167a15dd9fce7fbee7512beb4e31f532159d3482d1f9c6caedf31d" +dependencies = [ + "bitflags 2.13.1", + "block2", + "dispatch2", + "objc2", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", + "objc2-core-video", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.13.1", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", +] + +[[package]] +name = "objc2-core-video" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" +dependencies = [ + "bitflags 2.13.1", + "block2", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-io-surface", + "objc2-metal", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.13.1", + "block2", + "libc", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags 2.13.1", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794" +dependencies = [ + "bitflags 2.13.1", + "block2", + "dispatch2", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags 2.13.1", + "block2", + "libc", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-video", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-video-toolbox" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05bf9a3c14831a7d9641b0d81d87dd913ee238a012b2fde27db5a84b56f5df3e" +dependencies = [ + "bitflags 2.13.1", + "block2", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-media", + "objc2-core-video", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openh264" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc9071a0b5f9c501ddd01066c2600d922cc799dc450a52975222bcda7755a08" +dependencies = [ + "openh264-sys2", + "wide", +] + +[[package]] +name = "openh264-sys2" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ada29a4cadc13d4d326737af87c13e224210d7d99fe47594e9f3f9b0102fd70" +dependencies = [ + "cc", + "nasm-rs", + "walkdir", +] + +[[package]] +name = "opennow-streamer" +version = "0.2.0" +dependencies = [ + "opennow-streamer-core", + "opennow-streamer-platform", + "opennow-streamer-protocol", + "serde_json", + "tracing-subscriber", +] + +[[package]] +name = "opennow-streamer-core" +version = "0.2.0" +dependencies = [ + "base64", + "opennow-streamer-platform", + "opennow-streamer-protocol", + "opennow-streamer-transport", + "serde_json", + "str0m", +] + +[[package]] +name = "opennow-streamer-platform" +version = "0.2.0" +dependencies = [ + "audiopus_sys", + "base64", + "image", + "libc", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "openh264", + "opennow-streamer-platform-linux", + "opennow-streamer-platform-macos", + "opennow-streamer-platform-windows", + "opennow-streamer-protocol", + "opus", + "raw-window-handle", + "sdl2", + "windows-sys 0.61.2", + "x11-dl", +] + +[[package]] +name = "opennow-streamer-platform-linux" +version = "0.2.0" +dependencies = [ + "ash", + "ash-window", + "cros-codecs-extended", + "ffmpeg-next", + "ffmpeg-sys-next", + "libc", + "libloading", + "raw-window-handle", + "static_assertions", + "thiserror 2.0.18", +] + +[[package]] +name = "opennow-streamer-platform-macos" +version = "0.2.0" +dependencies = [ + "libc", + "objc2", + "objc2-app-kit", + "objc2-audio-toolbox", + "objc2-core-audio-types", + "objc2-core-foundation", + "objc2-core-media", + "objc2-core-video", + "objc2-foundation", + "objc2-metal", + "objc2-quartz-core", + "objc2-video-toolbox", + "opus", + "thiserror 2.0.18", +] + +[[package]] +name = "opennow-streamer-platform-windows" +version = "0.2.0" +dependencies = [ + "windows", +] + +[[package]] +name = "opennow-streamer-protocol" +version = "0.2.0" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "opennow-streamer-transport" +version = "0.2.0" +dependencies = [ + "aes", + "crc32fast", + "ctr", + "getrandom 0.3.4", + "ghash", + "hmac", + "opennow-streamer-protocol", + "serde_json", + "sha1", + "socket2", + "str0m", + "subtle", + "thiserror 2.0.18", +] + +[[package]] +name = "opus" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418abd1b6d34fbf6cae440dc874771b0525a604428704c76e48b29a5e67b8003" +checksum = "4d3809943dff6fbad5f0484449ea26bdb9cb7d8efdf26ed50d3c7f227f69eb5c" dependencies = [ - "memchr", + "audiopus_sys", ] [[package]] -name = "num-conv" -version = "0.2.2" +name = "p256" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] [[package]] -name = "num-integer" -version = "0.1.46" +name = "p384" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" dependencies = [ - "num-traits", + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", ] [[package]] -name = "num-rational" -version = "0.4.2" +name = "pem-rfc7468" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" dependencies = [ - "num-integer", - "num-traits", + "base64ct", ] [[package]] -name = "num-traits" -version = "0.2.19" +name = "pin-project-lite" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "autocfg", + "der", + "spki", ] [[package]] -name = "once_cell" -version = "1.21.4" +name = "pkg-config" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" [[package]] -name = "opennow-streamer" -version = "0.1.0" +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "base64", - "gst-plugin-rtp", - "gstreamer", - "gstreamer-sdp", - "gstreamer-video", - "gstreamer-webrtc", - "regex", - "serde", - "serde_json", + "bitflags 2.13.1", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", ] [[package]] -name = "option-operations" -version = "0.6.1" +name = "poly1305" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aca39cf52b03268400c16eeb9b56382ea3c3353409309b63f5c8f0b1faf42754" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ - "pastey", + "cpufeatures", + "opaque-debug", + "universal-hash", ] [[package]] -name = "pastey" -version = "0.2.2" +name = "polyval" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5a797f0e07bdf071d15742978fc3128ec6c22891c31a3a931513263904c982a" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] [[package]] -name = "pin-project-lite" -version = "0.2.17" +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] -name = "pkg-config" -version = "0.3.33" +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] [[package]] -name = "powerfmt" -version = "0.2.0" +name = "primeorder" +version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] [[package]] name = "proc-macro2" @@ -832,6 +1852,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "pxfm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" + [[package]] name = "quote" version = "1.0.45" @@ -841,6 +1867,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "r-efi" version = "6.0.0" @@ -849,26 +1881,78 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.10.2" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ - "chacha20", - "getrandom", - "rand_core", + "rand_chacha", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", ] [[package]] name = "rand_core" -version = "0.10.1" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "raw-window-metal" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e8caa82e31bb98fee12fa8f051c94a6aa36b07cddb03f0d4fc558988360ff1" +dependencies = [ + "cocoa", + "core-graphics", + "objc", + "raw-window-handle", +] + +[[package]] +name = "rcgen" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" +checksum = "091e7a8e7d86e6feb87a27ce8e2cba29d49eff9507afeebefab7eeb2ca667fb4" +dependencies = [ + "aws-lc-rs", + "rustls-pki-types", + "time", + "x509-parser", + "yasna", +] [[package]] name = "regex" -version = "1.12.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -878,9 +1962,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ "aho-corasick", "memchr", @@ -889,110 +1973,404 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom 7.1.3", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.13.1", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "zeroize", +] + +[[package]] +name = "safe_arch" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42c6efa15875e6ecb39ca61fb0b0c1a40b84fac5a5ffe71eef7d1000c8eb3f5f" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "sctp-proto" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f895c3c33ae20283f9129bd09db2ca69138798b372ef2b98bd2946d23ea4819b" +dependencies = [ + "bytes", + "crc", + "log", + "rand", + "rustc-hash 2.1.3", + "slab", + "thiserror 2.0.18", +] + +[[package]] +name = "sdl2" +version = "0.38.0" +source = "git+https://github.com/Rust-SDL2/rust-sdl2.git?rev=adeb978d921a1440da07fddd6651da9f567ed21b#adeb978d921a1440da07fddd6651da9f567ed21b" +dependencies = [ + "bitflags 2.13.1", + "lazy_static", + "libc", + "raw-window-handle", + "sdl2-sys", +] + +[[package]] +name = "sdl2-sys" +version = "0.38.0" +source = "git+https://github.com/Rust-SDL2/rust-sdl2.git?rev=adeb978d921a1440da07fddd6651da9f567ed21b#adeb978d921a1440da07fddd6651da9f567ed21b" +dependencies = [ + "cfg-if", + "cmake", + "libc", + "version-compare", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.13.1", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha1" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "shlex" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] -name = "rtcp-types" -version = "0.3.0" +name = "signature" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c081c846edea632bb47332fada9d4ac2fdf54d84beaf547fc947b58489e5f619" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "thiserror 2.0.18", + "digest", + "rand_core 0.6.4", ] [[package]] -name = "rtp-types" -version = "0.1.2" +name = "simd-adler32" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb90df8268abfe08452ef2dae9e867a54edfdaa71b3127ef47d8b031f77ac73" -dependencies = [ - "smallvec", - "thiserror 1.0.69", -] +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" [[package]] -name = "rustversion" -version = "1.0.23" +name = "slab" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] -name = "serde" -version = "1.0.228" +name = "smallvec" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] -name = "serde_core" -version = "1.0.228" +name = "socket2" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ - "serde_derive", + "libc", + "windows-sys 0.52.0", ] [[package]] -name = "serde_derive" -version = "1.0.228" +name = "spki" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ - "proc-macro2", - "quote", - "syn", + "base64ct", + "der", ] [[package]] -name = "serde_json" -version = "1.0.150" +name = "static_assertions" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "str0m" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "840d11fdd44459d71bc7b3dd6796f55e9ac86c8e3fa8678098a8642f5701c5ff" dependencies = [ - "itoa", - "memchr", + "arrayvec", + "base64ct", + "combine", + "dimpl", + "fastrand", + "is", + "sctp-proto", "serde", - "serde_core", - "zmij", + "str0m-apple-crypto", + "str0m-proto", + "str0m-rust-crypto", + "str0m-wincrypto", + "subtle", + "time", + "tracing", ] [[package]] -name = "serde_spanned" -version = "1.1.1" +name = "str0m-apple-crypto" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +checksum = "9f0fe88675a99679ce154c87ee356eb133af5ade7657fb5fe2db97689b4c41eb" dependencies = [ - "serde_core", + "apple-cryptokit-rs", + "cc", + "core-foundation 0.10.1", + "der", + "dimpl", + "pkcs8", + "sec1", + "security-framework", + "spki", + "str0m-proto", + "subtle", + "time", + "x509-cert", ] [[package]] -name = "shlex" -version = "2.0.1" +name = "str0m-proto" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" +checksum = "e8f3d99f2cf6c76a502e45feb896ea71e54787ede8744bcdb215acfbfcb905dd" +dependencies = [ + "base64ct", + "dimpl", + "fastrand", + "serde", + "subtle", + "time", +] [[package]] -name = "slab" -version = "0.4.12" +name = "str0m-rust-crypto" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" +checksum = "947c2417bf43e47504911f92f47c22b6125a57d162e1661f1c77b78ebb3aa9d3" +dependencies = [ + "aes", + "aes-gcm", + "ctr", + "dimpl", + "hmac", + "p256", + "sha1", + "sha2", + "str0m-proto", + "time", +] [[package]] -name = "smallvec" -version = "1.15.1" +name = "str0m-wincrypto" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "2816a81106af3dfdc321b37da5148238759c900fda9e7f8c11ebe77f1b7a2b73" +dependencies = [ + "dimpl", + "str0m-proto", + "tracing", + "windows", +] [[package]] -name = "static_assertions" -version = "1.1.0" +name = "subtle" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -1006,23 +2384,26 @@ dependencies = [ ] [[package]] -name = "system-deps" -version = "7.0.8" +name = "syn" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396a35feb67335377e0251fcbc1092fc85c484bd4e3a7a54319399da127796e7" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" dependencies = [ - "cfg-expr", - "heck", - "pkg-config", - "toml", - "version-compare", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] -name = "target-lexicon" -version = "0.13.3" +name = "synstructure" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] [[package]] name = "thiserror" @@ -1050,7 +2431,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1061,7 +2442,16 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", +] + +[[package]] +name = "thread_local" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" +dependencies = [ + "cfg-if", ] [[package]] @@ -1075,6 +2465,7 @@ dependencies = [ "powerfmt", "serde_core", "time-core", + "time-macros", ] [[package]] @@ -1084,77 +2475,81 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] -name = "tokio" -version = "1.53.1" +name = "time-macros" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" dependencies = [ - "pin-project-lite", + "num-conv", + "time-core", ] [[package]] -name = "tokio-util" -version = "0.7.19" +name = "tracing" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ - "bytes", - "futures-core", - "futures-sink", "pin-project-lite", - "tokio", + "tracing-attributes", + "tracing-core", ] [[package]] -name = "toml" -version = "1.1.2+spec-1.1.0" +name = "tracing-attributes" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ - "indexmap", - "serde_core", - "serde_spanned", - "toml_datetime", - "toml_parser", - "toml_writer", - "winnow", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] -name = "toml_datetime" -version = "1.1.1+spec-1.1.0" +name = "tracing-core" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ - "serde_core", + "once_cell", + "valuable", ] [[package]] -name = "toml_edit" -version = "0.25.13+spec-1.1.0" +name = "tracing-log" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "indexmap", - "toml_datetime", - "toml_parser", - "winnow", + "log", + "once_cell", + "tracing-core", ] [[package]] -name = "toml_parser" -version = "1.1.2+spec-1.1.0" +name = "tracing-subscriber" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ - "winnow", + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] -name = "toml_writer" -version = "1.1.1+spec-1.1.0" +name = "typenum" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "unicode-ident" @@ -1162,55 +2557,109 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version-compare" -version = "0.2.1" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" [[package]] -name = "wasm-bindgen" -version = "0.2.126" +name = "version_check" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", + "same-file", + "winapi-util", ] [[package]] -name = "wasm-bindgen-macro" -version = "0.2.126" +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ - "quote", - "wasm-bindgen-macro-support", + "wit-bindgen", ] [[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.126" +name = "wide" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +checksum = "de2aaf408e58689c2096682331b1f42bb2d9f2ed6b11560407d023cd0a6c634e" dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", + "bytemuck", + "safe_arch", ] [[package]] -name = "wasm-bindgen-shared" -version = "0.2.126" +name = "winapi-util" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "unicode-ident", + "windows-sys 0.61.2", +] + +[[package]] +name = "windows" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ + "windows-core", ] [[package]] @@ -1226,6 +2675,17 @@ dependencies = [ "windows-strings", ] +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", +] + [[package]] name = "windows-implement" version = "0.60.2" @@ -1234,7 +2694,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1245,7 +2705,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1254,6 +2714,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core", + "windows-link", +] + [[package]] name = "windows-result" version = "0.4.1" @@ -1272,6 +2742,24 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.61.2" @@ -1282,12 +2770,184 @@ dependencies = [ ] [[package]] -name = "winnow" -version = "1.0.2" +name = "windows-targets" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "memchr", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core 0.6.4", + "serde", + "zeroize", +] + +[[package]] +name = "x509-cert" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94" +dependencies = [ + "const-oid", + "der", + "spki", +] + +[[package]] +name = "x509-parser" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" +dependencies = [ + "asn1-rs", + "aws-lc-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom 7.1.3", + "oid-registry", + "rusticata-macros", + "thiserror 2.0.18", + "time", +] + +[[package]] +name = "yasna" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" +dependencies = [ + "bit-vec", + "time", +] + +[[package]] +name = "zerocopy" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] diff --git a/native/opennow-streamer/Cargo.toml b/native/opennow-streamer/Cargo.toml index 229d7e2d8..3eeca254c 100644 --- a/native/opennow-streamer/Cargo.toml +++ b/native/opennow-streamer/Cargo.toml @@ -1,29 +1,55 @@ -[package] -name = "opennow-streamer" -version = "0.1.0" -edition = "2021" -license = "MIT" - -[features] -default = [] -gstreamer = [ - "dep:gstreamer", - "dep:gstreamer-sdp", - "dep:gstreamer-video", - "dep:gstreamer-webrtc", - "dep:gst-plugin-rtp", - "gstreamer-webrtc/v1_22", +[workspace] +members = [ + "crates/opennow-streamer", + "crates/opennow-streamer-core", + "crates/opennow-streamer-platform", + "crates/opennow-streamer-platform-linux", + "crates/opennow-streamer-platform-macos", + "crates/opennow-streamer-platform-windows", + "crates/opennow-streamer-protocol", + "crates/opennow-streamer-transport", ] +default-members = ["crates/opennow-streamer"] +resolver = "2" -[dependencies] +[workspace.package] +version = "0.2.0" +edition = "2024" +license = "MIT" +rust-version = "1.85" + +[workspace.dependencies] +aes = "0.8" +aes-gcm = "0.10" +audiopus_sys = { version = "0.2.2", features = ["static"] } base64 = "0.22" -gstreamer = { version = "0.25.1", optional = true } -gstreamer-sdp = { version = "0.25.0", optional = true } -gstreamer-video = { version = "0.25.0", optional = true } -gstreamer-webrtc = { version = "0.25.0", optional = true } -regex = "1" +ctr = "0.9" +crc32fast = "1" +getrandom = "0.3" +ghash = "0.5" +hmac = "0.12" +image = { version = "0.25", default-features = false, features = ["bmp", "ico", "png"] } +openh264 = { version = "0.9.8", default-features = false, features = ["source"] } +opus = "0.3.1" +# Pin rust-sdl2 after its bundled SDL2 update. SDL 2.26.4 from the crates.io +# release does not compile against current PipeWire headers with modern GCC. +sdl2 = { git = "https://github.com/Rust-SDL2/rust-sdl2.git", rev = "adeb978d921a1440da07fddd6651da9f567ed21b", default-features = false, features = ["bundled", "raw-window-handle", "static-link", "unsafe_textures"] } serde = { version = "1", features = ["derive"] } serde_json = "1" +sha1 = "0.10" +socket2 = { version = "0.5", features = ["all"] } +str0m = { version = "0.23", default-features = false } +subtle = "2" +thiserror = "2" + +[profile.release] +lto = "thin" +codegen-units = 1 +strip = true -[target.'cfg(target_os = "linux")'.dependencies] -gst-plugin-rtp = { version = "0.15.3", optional = true } +[patch.crates-io] +# Always compile the vendored Opus sources for the distributable streamer. +audiopus_sys = { path = "vendor/audiopus-sys" } +# Upstream does not expose an NVDEC-only bundled build. This patch keeps CUDA +# and nvcuvid as driver-loaded interfaces without requiring the CUDA toolkit. +ffmpeg-sys-next = { path = "vendor/ffmpeg-sys-next" } diff --git a/native/opennow-streamer/README.md b/native/opennow-streamer/README.md index 43b66eb74..d64e44fa8 100644 --- a/native/opennow-streamer/README.md +++ b/native/opennow-streamer/README.md @@ -1,14 +1,54 @@ -# OpenNOW Native Streamer +# OpenNOW Native Streamer v2 -This crate contains OpenNOW's native Rust streaming infrastructure. +This workspace is the clean replacement for the former GStreamer-based native streamer. -> [!NOTE] -> Native streamer / native streaming is experimental. Issues can be platform-specific and users may see fallback to Chromium/WebRTC; report problems on [GitHub Issues](https://github.com/OpenCloudGaming/OpenNOW/issues) or [Discord](https://discord.gg/8EJYaJcNfD). +The workspace owns the local process protocol, lifecycle state machine, standards-based WebRTC transport, and media output path. OpenH264, Opus, SDL, and the Linux FFmpeg codec stack are compiled into the executable; GStreamer and external codec processes are not used. -Canonical native streamer, WebRTC, GStreamer, packaging, and development documentation lives at [opennow.zortos.me](https://opennow.zortos.me). This README is intentionally only a pointer so repository docs do not drift from the site. +The executable retains the versioned JSON-lines process contract used by OpenNOW while the app shell is migrated away from Electron. It does not load or redistribute NVIDIA client libraries. -## Linux runtime requirements +## Crates -Linux native video is embedded into the Electron window through an X11 child surface and `GstVideoOverlay`. OpenNOW defaults its Linux Electron shell to X11, which also works on Wayland desktops through XWayland. An explicit pure-Wayland launch is rejected with a diagnostic instead of starting an unmanaged GStreamer window that can remain invisible behind Electron. +- `opennow-streamer-protocol`: versioned local IPC DTOs. +- `opennow-streamer-core`: session lifecycle and command routing. +- `opennow-streamer-transport`: ICE, DTLS-SRTP, RTP/RTCP, and SCTP data channels. +- `opennow-streamer-platform`: bounded media queues, OpenH264/Opus decode, SDL audio/video output, and platform-native Electron surface ownership. +- `opennow-streamer-platform-windows`: Media Foundation H.264 hardware decode, D3D11 NV12 presentation, and WASAPI PCM output for Windows x64 and ARM64. +- `opennow-streamer`: process entry point. -The distro GStreamer runtime must provide WebRTC, the selected codec parser/depayloader, a compatible X11 video sink, and at least one decoder. Hardware decode is preferred, but unavailable hardware plugins fall back to the native GStreamer software decoder. If a hardware decoder starts but produces no frames while audio and RTP remain active, OpenNOW reconnects the same native session once with software decoding. +## Checks + +```sh +cargo test --manifest-path native/opennow-streamer/Cargo.toml +cargo build --manifest-path native/opennow-streamer/Cargo.toml --release +``` + +The Electron app's build wrapper also checks protocol-version parity, copies the executable into the platform package directory, and runs a JSON-lines `hello`/`stop` process smoke test: + +```sh +npm --prefix opennow-stable run native:build +``` + +## Platform integration + +The SDL presentation window is created hidden on the process main thread. Windows supports Media Foundation over either native D3D11 or a D3D12-backed D3D11-on-12 device and uses WASAPI for audio; it creates a non-activating, input-transparent Electron child HWND and falls back to OpenH264/SDL after startup or unrecoverable device loss. `OPENNOW_NATIVE_VIDEO_BACKEND=software` forces the software path, while `d3d12` and `d3d11` select the corresponding Windows graphics path. Auto prefers D3D12 when its complete decode, presentation, and audio probe succeeds. Renderer surface rectangles are already physical pixels and are never scaled again by `deviceScaleFactor`. Linux/X11 reparents the SDL window into Electron. Linux/Wayland uses a separate compositor-managed SDL window because Wayland intentionally has no portable foreign child-window embedding API; that window owns native keyboard, mouse, relative-pointer, and cursor handling, and F11 toggles compositor fullscreen. macOS keeps the output as a non-activating, mouse-ignoring child `NSWindow` and converts renderer-relative surface rectangles through the Electron `NSView`. The executable runs `MainThreadHost` on its real main thread; stdin, WebRTC, and codec work run on named workers. This is required by AppKit and is checked with `pthread_main_np()` on macOS. + +The app and native child select the same Linux window system. `OPENNOW_NATIVE_WINDOW_SYSTEM=x11|wayland` records that launch contract and `SDL_VIDEODRIVER` selects the matching SDL backend. On a native Wayland session the stream opens in its own resizable window; on X11 it remains embedded in the Electron stream rectangle. Linux decode supports H.264, HEVC/H.265, and AV1 through Vulkan Video, CUDA/NVDEC, or FFmpeg software decode; native VA-API and V4L2 provide additional H.264 paths. Vulkan presentation is preferred, with SDL NV12 presentation as an independent fallback so decoder acceleration remains active if the Vulkan window path fails. + +Linux production builds statically include FFmpeg, its H.264/HEVC/AV1 decoders, Opus, OpenH264, SDL, and their C/C++ support runtimes. They do not require system FFmpeg, GStreamer, Opus, SDL, VA-API, X11, Wayland, or Vulkan-loader libraries. Only the Linux base ABI and the selected display/audio/GPU driver interfaces remain system responsibilities. Building the bundled stack requires a C/C++ toolchain, CMake, Make, NASM, pkg-config, and Git. Native VA-API remains opt-in with `OPENNOW_NATIVE_LINUX_VAAPI=1` because it would add a host `libva` runtime dependency. `OPENNOW_NATIVE_VIDEO_BACKEND=auto|vulkan|cuda|nvdec|vaapi|v4l2|ffmpeg|software` controls decoder selection; `auto` prefers CUDA/NVDEC on NVIDIA, then Vulkan Video, VA-API, V4L2, and bundled FFmpeg software. + +## macOS validation + +Run the checks natively on each architecture rather than treating a Linux cross-check as macOS proof: + +```sh +rustup target add aarch64-apple-darwin x86_64-apple-darwin +OPENNOW_NATIVE_STREAMER_TARGET="$(rustc -vV | sed -n 's/^host: //p')" \ +OPENNOW_NATIVE_STREAMER_PLATFORM_KEY="darwin-$(uname -m | sed 's/arm64/arm64/;s/x86_64/x64/')" \ +npm --prefix opennow-stable run native:build +``` + +The CI package matrix runs this build on both Apple Silicon and Intel macOS runners before producing the DMG and ZIP. Release validation must additionally inspect the app bundle, verify its signature, launch the packaged child executable, and confirm fallback behavior on real hardware. + +## Runtime validation + +Unit tests synthesize and decode video and Opus frames, verify drop-oldest queue behavior, and exercise pause/stop lifecycle. Linux hardware validation generates H.264, HEVC, and AV1 keyframes and decodes each through Vulkan Video and CUDA/NVDEC. Release validation must additionally run an authorized live session on Windows, Linux/X11, Linux/Wayland, Intel macOS, and Apple Silicon to validate WebRTC interoperability, A/V timing, Electron child-surface stacking or Wayland top-level behavior, native relative input, and device-specific audio output. diff --git a/native/opennow-streamer/bin/concrt140.dll b/native/opennow-streamer/bin/concrt140.dll deleted file mode 100644 index 830dfaeaf..000000000 Binary files a/native/opennow-streamer/bin/concrt140.dll and /dev/null differ diff --git a/native/opennow-streamer/bin/gio-2.0-0.dll b/native/opennow-streamer/bin/gio-2.0-0.dll deleted file mode 100644 index 56235522e..000000000 Binary files a/native/opennow-streamer/bin/gio-2.0-0.dll and /dev/null differ diff --git a/native/opennow-streamer/bin/glib-2.0-0.dll b/native/opennow-streamer/bin/glib-2.0-0.dll deleted file mode 100644 index a9e79cd53..000000000 Binary files a/native/opennow-streamer/bin/glib-2.0-0.dll and /dev/null differ diff --git a/native/opennow-streamer/bin/gmodule-2.0-0.dll b/native/opennow-streamer/bin/gmodule-2.0-0.dll deleted file mode 100644 index f9712b7cd..000000000 Binary files a/native/opennow-streamer/bin/gmodule-2.0-0.dll and /dev/null differ diff --git a/native/opennow-streamer/bin/gobject-2.0-0.dll b/native/opennow-streamer/bin/gobject-2.0-0.dll deleted file mode 100644 index 33f81a469..000000000 Binary files a/native/opennow-streamer/bin/gobject-2.0-0.dll and /dev/null differ diff --git a/native/opennow-streamer/bin/gstreamer-1.0-0.dll b/native/opennow-streamer/bin/gstreamer-1.0-0.dll deleted file mode 100644 index 66afb1858..000000000 Binary files a/native/opennow-streamer/bin/gstreamer-1.0-0.dll and /dev/null differ diff --git a/native/opennow-streamer/bin/gthread-2.0-0.dll b/native/opennow-streamer/bin/gthread-2.0-0.dll deleted file mode 100644 index e13a20a88..000000000 Binary files a/native/opennow-streamer/bin/gthread-2.0-0.dll and /dev/null differ diff --git a/native/opennow-streamer/bin/intl-8.dll b/native/opennow-streamer/bin/intl-8.dll deleted file mode 100644 index d37f3a60f..000000000 Binary files a/native/opennow-streamer/bin/intl-8.dll and /dev/null differ diff --git a/native/opennow-streamer/bin/msvcp140.dll b/native/opennow-streamer/bin/msvcp140.dll deleted file mode 100644 index 5153fb087..000000000 Binary files a/native/opennow-streamer/bin/msvcp140.dll and /dev/null differ diff --git a/native/opennow-streamer/bin/msvcp140_1.dll b/native/opennow-streamer/bin/msvcp140_1.dll deleted file mode 100644 index fe6169ee5..000000000 Binary files a/native/opennow-streamer/bin/msvcp140_1.dll and /dev/null differ diff --git a/native/opennow-streamer/bin/msvcp140_2.dll b/native/opennow-streamer/bin/msvcp140_2.dll deleted file mode 100644 index 967be8237..000000000 Binary files a/native/opennow-streamer/bin/msvcp140_2.dll and /dev/null differ diff --git a/native/opennow-streamer/bin/msvcp140_atomic_wait.dll b/native/opennow-streamer/bin/msvcp140_atomic_wait.dll deleted file mode 100644 index 01f8e9a36..000000000 Binary files a/native/opennow-streamer/bin/msvcp140_atomic_wait.dll and /dev/null differ diff --git a/native/opennow-streamer/bin/msvcp140_codecvt_ids.dll b/native/opennow-streamer/bin/msvcp140_codecvt_ids.dll deleted file mode 100644 index 63214b8a8..000000000 Binary files a/native/opennow-streamer/bin/msvcp140_codecvt_ids.dll and /dev/null differ diff --git a/native/opennow-streamer/bin/orc-0.4-0.dll b/native/opennow-streamer/bin/orc-0.4-0.dll deleted file mode 100644 index 5270f9f69..000000000 Binary files a/native/opennow-streamer/bin/orc-0.4-0.dll and /dev/null differ diff --git a/native/opennow-streamer/bin/pcre2-8-0.dll b/native/opennow-streamer/bin/pcre2-8-0.dll deleted file mode 100644 index 092953e23..000000000 Binary files a/native/opennow-streamer/bin/pcre2-8-0.dll and /dev/null differ diff --git a/native/opennow-streamer/bin/vcruntime140.dll b/native/opennow-streamer/bin/vcruntime140.dll deleted file mode 100644 index c2f509d20..000000000 Binary files a/native/opennow-streamer/bin/vcruntime140.dll and /dev/null differ diff --git a/native/opennow-streamer/bin/vcruntime140_1.dll b/native/opennow-streamer/bin/vcruntime140_1.dll deleted file mode 100644 index 64cd24630..000000000 Binary files a/native/opennow-streamer/bin/vcruntime140_1.dll and /dev/null differ diff --git a/native/opennow-streamer/crates/opennow-streamer-core/Cargo.toml b/native/opennow-streamer/crates/opennow-streamer-core/Cargo.toml new file mode 100644 index 000000000..359127c2f --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-core/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "opennow-streamer-core" +version.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true + +[dependencies] +base64.workspace = true +opennow-streamer-platform = { path = "../opennow-streamer-platform" } +opennow-streamer-protocol = { path = "../opennow-streamer-protocol" } +opennow-streamer-transport = { path = "../opennow-streamer-transport" } +serde_json.workspace = true + +[dev-dependencies] +str0m.workspace = true diff --git a/native/opennow-streamer/crates/opennow-streamer-core/src/lib.rs b/native/opennow-streamer/crates/opennow-streamer-core/src/lib.rs new file mode 100644 index 000000000..868a2bb85 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-core/src/lib.rs @@ -0,0 +1,2859 @@ +use std::collections::HashMap; +use std::net::UdpSocket; +use std::sync::mpsc::{Receiver, Sender}; +use std::sync::{Arc, Mutex, MutexGuard}; +use std::thread::{self, JoinHandle}; +use std::time::{Duration, Instant}; + +use base64::Engine as _; +use base64::engine::general_purpose::STANDARD as BASE64; +use opennow_streamer_platform::{ + CapturedInput, CapturedInputQueue, EncodedFrame, MediaCodec, MediaControl, MediaFeedback, + MediaRuntime, MediaSession, MediaSink, MediaStreamConfig, MediaVideoCodec, PushOutcome, + supports_audio_decode, supports_audio_output, video_backends, +}; +use opennow_streamer_protocol::{ + Capabilities, Command, PROTOCOL_VERSION, SessionContext, error, event, response, +}; +use opennow_streamer_transport::{ + NvstDropReason, NvstReceiveEvent, NvstReceiverState, NvstRecovery, NvstUdpReceiverControl, + NvstUdpReceiverSession, PreferredVideoTransport, ReservedNvstBundle, SharedNvstFeedback, + TransportControl, TransportEvent, TransportSession, negotiate, reserve_nvst_mjolnir_udp_socket, + select_preferred_video_transport, spawn_nvst_mjolnir_receiver, + spawn_nvst_udp_receiver_with_socket, +}; +use serde_json::{Value, json}; + +pub use opennow_streamer_transport::{EncodedMediaFrame, MediaConsumer}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum State { + Idle, + Prepared, + Negotiating, + Connected, +} + +const ENCODED_MEDIA_QUEUE_CAPACITY: usize = 8; +const NVST_RECOVERY_ATTEMPT_LIMIT: usize = 1; +const NATIVE_INPUT_POLL_INTERVAL: Duration = Duration::from_micros(250); + +trait NvstSessionResources { + fn request_keyframe(&self); + fn acknowledge_video_frame(&self, bytes: u32); + fn send_captured_input(&self, bytes: Vec) -> Result<(), String>; + fn apply_cursor(&self, bytes: Vec); + fn recover(&self) -> Result<(), String>; + fn stop(&self); +} + +struct ActiveNvstResources { + bundle: NvstUdpReceiverControl, + mjolnir: Option, + feedback: SharedNvstFeedback, + media: Option, +} + +impl NvstSessionResources for ActiveNvstResources { + fn request_keyframe(&self) { + self.feedback.request_keyframe(); + } + + fn acknowledge_video_frame(&self, bytes: u32) { + self.feedback.publish_accepted_frame(bytes, Instant::now()); + } + + fn send_captured_input(&self, bytes: Vec) -> Result<(), String> { + self.bundle + .queue_input(bytes, false) + .map_err(|error| error.to_string()) + } + + fn apply_cursor(&self, bytes: Vec) { + if let Some(media) = self.media.as_ref() { + media.update_cursor(bytes); + } + } + + fn recover(&self) -> Result<(), String> { + self.bundle + .recover() + .map_err(|error| format!("bundle recovery failed: {error}"))?; + if let Some(mjolnir) = self.mjolnir.as_ref() { + mjolnir + .recover() + .map_err(|error| format!("Mjolnir recovery failed: {error}"))?; + } + Ok(()) + } + + fn stop(&self) { + let _ = self.bundle.stop(); + if let Some(mjolnir) = self.mjolnir.as_ref() { + let _ = mjolnir.stop(); + } + if let Some(media) = self.media.as_ref() { + media.stop(); + } + } +} + +pub struct Engine { + lifecycle: Arc>, + transport: Option, + nvst_transport: Option, + nvst_mjolnir_transport: Option, + reserved_nvst_bundle: Option, + nvst_hole_punch_socket: Option, + events: Sender, + media_consumer: Option, + media_runtime: Option, + media_session: Option, + media_worker: Option>, + media_feedback: Option>, + feedback_worker: Option>, +} + +#[derive(Debug)] +struct Lifecycle { + state: State, + context: Option, + generation: u64, +} + +impl Engine { + pub fn new(events: Sender) -> Self { + Self { + lifecycle: Arc::new(Mutex::new(Lifecycle { + state: State::Idle, + context: None, + generation: 0, + })), + transport: None, + nvst_transport: None, + nvst_mjolnir_transport: None, + reserved_nvst_bundle: None, + nvst_hole_punch_socket: None, + events, + media_consumer: None, + media_runtime: None, + media_session: None, + media_worker: None, + media_feedback: None, + feedback_worker: None, + } + } + + pub fn with_media_consumer(events: Sender, media_consumer: MediaConsumer) -> Self { + Self { + lifecycle: Arc::new(Mutex::new(Lifecycle { + state: State::Idle, + context: None, + generation: 0, + })), + transport: None, + nvst_transport: None, + nvst_mjolnir_transport: None, + reserved_nvst_bundle: None, + nvst_hole_punch_socket: None, + events, + media_consumer: Some(media_consumer), + media_runtime: None, + media_session: None, + media_worker: None, + media_feedback: None, + feedback_worker: None, + } + } + + pub fn with_media_runtime(events: Sender, media_runtime: MediaRuntime) -> Self { + Self { + lifecycle: Arc::new(Mutex::new(Lifecycle { + state: State::Idle, + context: None, + generation: 0, + })), + transport: None, + nvst_transport: None, + nvst_mjolnir_transport: None, + reserved_nvst_bundle: None, + nvst_hole_punch_socket: None, + events, + media_consumer: None, + media_runtime: Some(media_runtime), + media_session: None, + media_worker: None, + media_feedback: None, + feedback_worker: None, + } + } + + pub fn handle(&mut self, command: Command) -> (Vec, bool) { + let id = command.id.clone(); + let result = match command.kind.as_str() { + "hello" => self.hello(&command), + "nvst-bind" => self.nvst_bind(command), + "nvst-unbind" => self.nvst_unbind(command), + "nvst-send" => self.nvst_send(command), + "start" => self.start(command), + "offer" => self.offer(command), + "remote-ice" => self.remote_ice(command), + "input" => self.input(command), + "input-paused" => self.set_paused(command), + "surface" => self.update_surface(command), + "bitrate" | "update-shortcuts" => Err(error( + Some(&id), + "unsupported-command", + format!( + "Native streamer v2 cannot apply the {} command", + command.kind + ), + )), + "stop" => { + self.stop(command.reason.as_deref().unwrap_or("stopped")); + Ok(vec![response(id, "ok")]) + } + other => Err(error( + Some(&id), + "unknown-command", + format!("Unknown command: {other}"), + )), + }; + + match result { + Ok(values) => (values, true), + Err(value) => (vec![value], true), + } + } + + fn hello(&self, command: &Command) -> Result, Value> { + if command.protocol_version != Some(PROTOCOL_VERSION) { + return Err(error( + Some(&command.id), + "protocol-version-mismatch", + format!("Native streamer v2 requires protocol {PROTOCOL_VERSION}"), + )); + } + let backends = video_backends(); + let media_ready = self.media_runtime.is_some(); + let video_ready = media_ready && backends.iter().any(|backend| backend.available); + let capabilities = Capabilities { + protocol_version: PROTOCOL_VERSION, + backend: "native", + fallback_reason: (!media_ready) + .then_some("Native streamer v2 requires an in-process decoded media runtime"), + supports_offer_answer: media_ready, + supports_remote_ice: media_ready, + supports_local_ice: media_ready, + supports_input: media_ready, + supports_video_decode: video_ready, + supports_video_present: video_ready, + supports_audio_decode: media_ready && supports_audio_decode(), + supports_audio_output: media_ready && supports_audio_output(), + video_backends: backends, + }; + Ok(vec![json!({ + "id": command.id, + "type": "ready", + "capabilities": capabilities, + })]) + } + + fn nvst_bind(&mut self, command: Command) -> Result, Value> { + if self.reserved_nvst_bundle.is_none() { + let bundle = ReservedNvstBundle::reserve().map_err(|bind_error| { + error( + Some(&command.id), + "nvst-bind-failed", + format!("failed to reserve NVST UDP socket: {bind_error}"), + ) + })?; + eprintln!( + "NVST reserved video UDP socket on {} (Mjolnir on {})", + bundle + .local_addr() + .map(|addr| addr.to_string()) + .unwrap_or_else(|_| "unknown".to_owned()), + bundle + .mjolnir_local_addr() + .map(|addr| addr.to_string()) + .unwrap_or_else(|_| "unknown".to_owned()), + ); + self.reserved_nvst_bundle = Some(bundle); + } + let bundle = self.reserved_nvst_bundle.as_mut().ok_or_else(|| { + error( + Some(&command.id), + "nvst-bind-failed", + "reserved NVST UDP socket has no local port", + ) + })?; + let local_addr = bundle.local_addr().map_err(|_| { + error( + Some(&command.id), + "nvst-bind-failed", + "reserved NVST UDP socket has no local port", + ) + })?; + let mjolnir_addr = bundle.mjolnir_local_addr().map_err(|_| { + error( + Some(&command.id), + "nvst-bind-failed", + "reserved NVST Mjolnir UDP socket has no local port", + ) + })?; + let port = local_addr.port(); + let local_address = bundle.advertised_local_address(); + let identity = bundle.identity(); + Ok(vec![json!({ + "id": command.id, + "type": "nvst-bound", + "port": port, + "mjolnirPort": mjolnir_addr.port(), + "localAddress": local_address, + "iceUsernameFragment": identity.ice_username_fragment, + "icePassword": identity.ice_password, + "dtlsFingerprint": identity.dtls_fingerprint, + })]) + } + + fn nvst_send(&mut self, command: Command) -> Result, Value> { + let host = command.host.ok_or_else(|| { + error( + Some(&command.id), + "nvst-send-failed", + "nvst-send requires host", + ) + })?; + let port = command.port.ok_or_else(|| { + error( + Some(&command.id), + "nvst-send-failed", + "nvst-send requires port", + ) + })?; + let payload = BASE64 + .decode(command.payload_base64.unwrap_or_default()) + .map_err(|decode_error| { + error( + Some(&command.id), + "nvst-send-failed", + format!("nvst-send payload is not valid base64: {decode_error}"), + ) + })?; + let send_result = if let Some(bundle) = self.reserved_nvst_bundle.as_ref() { + bundle.send_to(&payload, host.as_str(), port) + } else if let Some(socket) = self.nvst_hole_punch_socket.as_ref() { + socket.send_to(&payload, (host.as_str(), port)) + } else { + return Err(error( + Some(&command.id), + "nvst-send-failed", + "NVST UDP socket has not been reserved", + )); + }; + send_result.map_err(|send_error| { + error( + Some(&command.id), + "nvst-send-failed", + format!("failed to send NVST UDP datagram: {send_error}"), + ) + })?; + Ok(vec![response(command.id, "ok")]) + } + + fn nvst_unbind(&mut self, command: Command) -> Result, Value> { + let lifecycle = lock_lifecycle(&self.lifecycle); + if lifecycle.state != State::Idle + || self.nvst_transport.is_some() + || self.nvst_mjolnir_transport.is_some() + { + return Err(error( + Some(&command.id), + "nvst-unbind-in-use", + "Cannot release an NVST UDP reservation after session start", + )); + } + drop(lifecycle); + self.reserved_nvst_bundle = None; + self.nvst_hole_punch_socket = None; + Ok(vec![response(command.id, "ok")]) + } + + fn start(&mut self, command: Command) -> Result, Value> { + let context = parse_context(command.context, &command.id)?; + validate_context(&context, &command.id)?; + { + let lifecycle = lock_lifecycle(&self.lifecycle); + if lifecycle.state != State::Idle { + return Err(invalid_state(&command.id, "start", lifecycle.state, "Idle")); + } + } + let transport_context = serde_json::to_value(&context).map_err(|context_error| { + error( + Some(&command.id), + "invalid-context", + format!("Session context is not serializable: {context_error}"), + ) + })?; + let explicit_nvst = transport_context + .pointer("/settings/transportMode") + .and_then(Value::as_str) + .is_some_and(|mode| mode.eq_ignore_ascii_case("nvst")) + || transport_context.get("nvstVideo").is_some() + || transport_context.get("nvstTransport").is_some(); + let (nvst_config, fallback_note) = + match select_preferred_video_transport(&transport_context) { + PreferredVideoTransport::Nvst(config) => (Some(*config), None), + PreferredVideoTransport::WebRtcFallback(reason) if explicit_nvst => { + return Err(error( + Some(&command.id), + "invalid-nvst-handoff", + format!("Explicit NVST transport is invalid: {reason:?}"), + )); + } + PreferredVideoTransport::WebRtcFallback(reason) => ( + None, + Some(format!( + "NVST unavailable; using WebRTC fallback: {reason:?}" + )), + ), + }; + if self.media_runtime.is_some() + && nvst_config.is_none() + && context + .settings + .get("codec") + .and_then(Value::as_str) + .is_some_and(|codec| !codec.eq_ignore_ascii_case("h264")) + { + return Err(error( + Some(&command.id), + "unsupported-video-codec", + "Native streamer v2 was built with H.264 decode only", + )); + } + let nvst_bundle_available = nvst_config + .as_ref() + .is_some_and(|config| config.remote_dtls_fingerprint().is_some()); + let nvst_audio_negotiated = nvst_config + .as_ref() + .is_some_and(|config| config.audio_track().is_some()); + + if let Some(transport) = self.transport.take() { + transport.stop(); + } + if let Some(transport) = self.nvst_transport.take() { + transport.stop(); + } + if let Some(transport) = self.nvst_mjolnir_transport.take() { + transport.stop(); + } + self.stop_media_resources(); + if let Some(runtime) = self.media_runtime.clone() { + let (feedback_sender, feedback_receiver) = std::sync::mpsc::channel(); + let stream_config = media_stream_config(&context); + let session = runtime + .start(feedback_sender, stream_config) + .map_err(|message| error(Some(&command.id), "media-output-unavailable", message))?; + let sink = session.sink(); + let (media_consumer, media_receiver) = + std::sync::mpsc::sync_channel(ENCODED_MEDIA_QUEUE_CAPACITY); + let output = self.events.clone(); + let media_worker = match thread::Builder::new() + .name("opennow-media-consumer".to_owned()) + .spawn(move || consume_encoded_media(&output, media_receiver, sink)) + { + Ok(worker) => worker, + Err(spawn_error) => { + session.stop(); + return Err(error( + Some(&command.id), + "media-worker-failed", + spawn_error.to_string(), + )); + } + }; + self.media_consumer = Some(media_consumer); + self.media_session = Some(session); + self.media_worker = Some(media_worker); + self.media_feedback = Some(feedback_receiver); + } + + let mut nvst_events = None; + let mut nvst_resources = None; + if let Some(config) = nvst_config { + let Some(media_consumer) = self.media_consumer.clone() else { + self.stop_media_resources(); + return Err(error( + Some(&command.id), + "media-consumer-unavailable", + "NVST video requires an in-process encoded media consumer", + )); + }; + let (event_sender, event_receiver) = std::sync::mpsc::channel(); + let (reserved_socket, reserved_rtc, reserved_mjolnir) = + match self.reserved_nvst_bundle.take() { + Some(bundle) => { + self.nvst_hole_punch_socket = bundle.try_clone_socket().ok(); + let (socket, rtc, mjolnir_socket) = bundle.into_parts(); + (Some(socket), Some(rtc), Some(mjolnir_socket)) + } + None => (None, None, None), + }; + let mjolnir_udp_port = config.mjolnir_udp_port(); + let feedback = config.feedback(); + let transport = match spawn_nvst_udp_receiver_with_socket( + config.clone(), + media_consumer.clone(), + event_sender.clone(), + reserved_socket, + reserved_rtc, + ) { + Ok(transport) => transport, + Err(transport_error) => { + drop(media_consumer); + self.stop_media_resources(); + return Err(error( + Some(&command.id), + "nvst-start-failed", + transport_error.to_string(), + )); + } + }; + let bundle_control = transport.control(); + self.nvst_transport = Some(transport); + let mut mjolnir_control = None; + if let Some(expected_port) = mjolnir_udp_port { + // Official two-socket model: video RTP/SRTP arrives on the + // dedicated NATT-only Mjolnir socket, not on the ICE/DTLS bundle. + let mjolnir_socket = match reserved_mjolnir { + Some(socket) => { + let actual_port = socket.local_addr().map(|addr| addr.port()).unwrap_or(0); + if actual_port != expected_port { + eprintln!( + "NVST Mjolnir socket port mismatch: reserved {actual_port}, handoff expects {expected_port}; NATT keepalive determines routing" + ); + } + socket + } + None => { + eprintln!( + "NVST Mjolnir reservation missing at start; binding a fresh video UDP socket" + ); + reserve_nvst_mjolnir_udp_socket().map_err(|bind_error| { + if let Some(transport) = self.nvst_transport.take() { + transport.stop(); + } + self.stop_media_resources(); + error( + Some(&command.id), + "nvst-start-failed", + format!("failed to reserve NVST Mjolnir UDP socket: {bind_error}"), + ) + })? + } + }; + let mjolnir = spawn_nvst_mjolnir_receiver( + mjolnir_socket, + config, + media_consumer, + event_sender, + ) + .map_err(|mjolnir_error| { + if let Some(transport) = self.nvst_transport.take() { + transport.stop(); + } + self.stop_media_resources(); + error( + Some(&command.id), + "nvst-start-failed", + mjolnir_error.to_string(), + ) + })?; + mjolnir_control = Some(mjolnir.control()); + self.nvst_mjolnir_transport = Some(mjolnir); + } + nvst_resources = Some(ActiveNvstResources { + bundle: bundle_control, + mjolnir: mjolnir_control, + feedback, + media: self.media_session.as_ref().map(MediaSession::control), + }); + nvst_events = Some(event_receiver); + } else { + self.reserved_nvst_bundle = None; + self.nvst_hole_punch_socket = None; + } + + let generation = { + let mut lifecycle = lock_lifecycle(&self.lifecycle); + lifecycle.generation = lifecycle.generation.wrapping_add(1); + lifecycle.context = Some(context); + lifecycle.state = if nvst_events.is_some() { + State::Connected + } else { + State::Prepared + }; + lifecycle.generation + }; + if let Some(nvst_events) = nvst_events { + let output = self.events.clone(); + let lifecycle = self.lifecycle.clone(); + let media_feedback = self.media_feedback.take(); + let captured_input = self + .media_session + .as_ref() + .map(MediaSession::captured_input); + let nvst_resources = nvst_resources.expect("NVST events require active resources"); + self.feedback_worker = thread::Builder::new() + .name("opennow-nvst-events".to_owned()) + .spawn(move || { + forward_nvst_session_events( + &output, + &lifecycle, + generation, + nvst_events, + media_feedback, + captured_input, + nvst_resources, + ); + }) + .ok(); + if self.feedback_worker.is_none() { + if let Some(transport) = self.nvst_transport.take() { + transport.stop(); + } + if let Some(transport) = self.nvst_mjolnir_transport.take() { + transport.stop(); + } + self.stop_media_resources(); + let mut lifecycle = lock_lifecycle(&self.lifecycle); + if lifecycle.generation == generation { + lifecycle.context = None; + lifecycle.state = State::Idle; + } + return Err(error( + Some(&command.id), + "media-worker-failed", + "Failed to start NVST lifecycle worker", + )); + } + } + let _ = self.events.send(event( + "status", + json!({ + "status": "ready", + "message": if self.nvst_transport.is_some() { + "NVST authenticated H.264 receive path initialized" + } else if self.media_runtime.is_some() { + "H.264 video and Opus audio media path initialized" + } else { + "Native WebRTC session prepared" + } + }), + )); + if let Some(note) = fallback_note { + let _ = self + .events + .send(event("log", json!({ "level": "debug", "message": note }))); + } + let mut start_response = response(command.id, "ok"); + let using_nvst = self.nvst_transport.is_some(); + start_response["transport"] = + Value::String(if using_nvst { "nvst" } else { "webrtc" }.to_owned()); + start_response["capabilities"] = if using_nvst { + json!({ + "supportsOfferAnswer": false, + "supportsRemoteIce": false, + "supportsLocalIce": false, + "supportsInput": nvst_bundle_available, + "supportsAudioDecode": nvst_audio_negotiated && supports_audio_decode(), + "supportsAudioOutput": nvst_audio_negotiated && supports_audio_output(), + }) + } else { + json!({ + "supportsOfferAnswer": self.media_runtime.is_some(), + "supportsRemoteIce": self.media_runtime.is_some(), + "supportsLocalIce": self.media_runtime.is_some(), + "supportsInput": self.media_runtime.is_some(), + "supportsAudioDecode": self.media_runtime.is_some() && supports_audio_decode(), + "supportsAudioOutput": self.media_runtime.is_some() && supports_audio_output(), + }) + }; + Ok(vec![start_response]) + } + + fn offer(&mut self, command: Command) -> Result, Value> { + if self.nvst_transport.is_some() { + return Err(error( + Some(&command.id), + "nvst-video-active", + "NVST video is active; do not negotiate a WebRTC media offer for this session", + )); + } + let offer_sdp = command.sdp.as_deref().ok_or_else(|| { + error( + Some(&command.id), + "missing-sdp", + "Offer command does not include SDP", + ) + })?; + let offered_context = command + .context + .map(|context| parse_context(Some(context), &command.id)) + .transpose()?; + if let Some(context) = &offered_context { + validate_context(context, &command.id)?; + } + let (context, generation) = { + let mut lifecycle = lock_lifecycle(&self.lifecycle); + if lifecycle.state == State::Idle { + return Err(error( + Some(&command.id), + "not-started", + "Start must be sent before offer", + )); + } + if lifecycle.state != State::Prepared { + return Err(invalid_state( + &command.id, + "offer", + lifecycle.state, + "Prepared", + )); + } + let Some(stored_context) = lifecycle.context.as_ref() else { + lifecycle.state = State::Idle; + return Err(error( + Some(&command.id), + "invalid-state", + "Prepared lifecycle is missing its session context", + )); + }; + let stored_session_id = stored_context.session.session_id.clone(); + if let Some(context) = offered_context { + if context.session.session_id != stored_session_id { + return Err(error( + Some(&command.id), + "session-mismatch", + "Offer context does not match the prepared session", + )); + } + lifecycle.context = Some(context); + } + let Some(context) = lifecycle.context.clone() else { + lifecycle.state = State::Idle; + return Err(error( + Some(&command.id), + "invalid-state", + "Prepared lifecycle is missing its session context", + )); + }; + lifecycle.state = State::Negotiating; + (context, lifecycle.generation) + }; + let Some(media_consumer) = self.media_consumer.clone() else { + let mut lifecycle = lock_lifecycle(&self.lifecycle); + if lifecycle.generation == generation && lifecycle.state == State::Negotiating { + lifecycle.state = State::Prepared; + } + return Err(error( + Some(&command.id), + "media-consumer-unavailable", + "No in-process encoded media consumer is configured", + )); + }; + let threshold = partial_reliable_threshold(offer_sdp).unwrap_or(300); + let (transport_events, receiver) = std::sync::mpsc::channel(); + let negotiated = negotiate( + offer_sdp, + &context.session, + threshold, + transport_events, + media_consumer, + ) + .map_err(|transport_error| { + let mut lifecycle = lock_lifecycle(&self.lifecycle); + if lifecycle.generation == generation && lifecycle.state == State::Negotiating { + lifecycle.state = State::Prepared; + } + error( + Some(&command.id), + transport_error.code(), + transport_error.to_string(), + ) + })?; + let output = self.events.clone(); + let lifecycle = self.lifecycle.clone(); + let transport_control = negotiated.session.control(); + let media_feedback = self.media_feedback.take(); + let feedback_worker = thread::Builder::new() + .name("opennow-media-events".to_owned()) + .spawn(move || { + forward_session_events( + &output, + &lifecycle, + generation, + receiver, + media_feedback, + transport_control, + ); + }); + self.feedback_worker = Some(match feedback_worker { + Ok(worker) => worker, + Err(spawn_error) => { + negotiated.session.stop(); + let mut lifecycle = lock_lifecycle(&self.lifecycle); + if lifecycle.generation == generation && lifecycle.state == State::Negotiating { + lifecycle.state = State::Prepared; + } + drop(lifecycle); + self.stop_media_resources(); + return Err(error( + Some(&command.id), + "media-worker-failed", + spawn_error.to_string(), + )); + } + }); + self.transport = Some(negotiated.session); + let _ = self.events.send(event( + "local-ice", + json!({ "candidate": negotiated.local_candidate }), + )); + Ok(vec![json!({ + "id": command.id, + "type": "answer", + "answer": { "sdp": negotiated.answer_sdp }, + })]) + } + + fn remote_ice(&self, command: Command) -> Result, Value> { + if self.nvst_transport.is_some() { + return Err(error( + Some(&command.id), + "nvst-remote-ice-unsupported", + "NVST owns its negotiated ICE bundle and does not accept remote-ice commands", + )); + } + let state = lock_lifecycle(&self.lifecycle).state; + if !matches!(state, State::Negotiating | State::Connected) { + return Err(invalid_state( + &command.id, + "remote-ice", + state, + "Negotiating or Connected", + )); + } + let transport = self.transport.as_ref().ok_or_else(|| { + error( + Some(&command.id), + "transport-not-ready", + "No active WebRTC transport", + ) + })?; + let candidate = command.candidate.as_ref().ok_or_else(|| { + error( + Some(&command.id), + "missing-candidate", + "Remote ICE command is empty", + ) + })?; + transport + .add_remote_candidate(candidate) + .map_err(|transport_error| { + error( + Some(&command.id), + transport_error.code(), + transport_error.to_string(), + ) + })?; + Ok(vec![response(command.id, "ok")]) + } + + fn input(&self, command: Command) -> Result, Value> { + let state = lock_lifecycle(&self.lifecycle).state; + if state != State::Connected { + return Err(invalid_state( + &command.id, + "input", + state, + "Connected with an initialized input channel", + )); + } + let input = command + .input + .as_ref() + .ok_or_else(|| error(Some(&command.id), "missing-input", "Input command is empty"))?; + let bytes = BASE64 + .decode(&input.payload_base64) + .map_err(|decode_error| { + error(Some(&command.id), "invalid-input", decode_error.to_string()) + })?; + let send_result = if let Some(transport) = self.nvst_transport.as_ref() { + transport.send_input(bytes, input.partially_reliable) + } else if let Some(transport) = self.transport.as_ref() { + transport.send_input(bytes, input.partially_reliable) + } else { + return Err(error( + Some(&command.id), + "transport-not-ready", + "No active media transport", + )); + }; + send_result.map_err(|transport_error| { + error( + Some(&command.id), + transport_error.code(), + transport_error.to_string(), + ) + })?; + Ok(vec![response(command.id, "ok")]) + } + + fn set_paused(&self, command: Command) -> Result, Value> { + let Some(runtime) = self.media_runtime.as_ref() else { + return Err(error( + Some(&command.id), + "unsupported-command", + "Native streamer has no media runtime for input-paused", + )); + }; + let paused = command.paused.ok_or_else(|| { + error( + Some(&command.id), + "missing-paused", + "Pause command does not include paused state", + ) + })?; + runtime + .set_paused(paused) + .map_err(|message| error(Some(&command.id), "media-host-unavailable", message))?; + if let Some(media) = self.media_session.as_ref() { + media.set_paused(paused); + } + if let Some(transport) = self.nvst_transport.as_ref() { + let result = if paused { + transport.pause() + } else { + transport.resume() + }; + result.map_err(|transport_error| { + error( + Some(&command.id), + "nvst-control-failed", + transport_error.to_string(), + ) + })?; + } + if let Some(transport) = self.nvst_mjolnir_transport.as_ref() { + let result = if paused { + transport.pause() + } else { + transport.resume() + }; + result.map_err(|transport_error| { + error( + Some(&command.id), + "nvst-control-failed", + transport_error.to_string(), + ) + })?; + } + Ok(vec![response(command.id, "ok")]) + } + + fn update_surface(&self, command: Command) -> Result, Value> { + let Some(runtime) = self.media_runtime.as_ref() else { + return Err(error( + Some(&command.id), + "unsupported-command", + "Native streamer has no media runtime for surface", + )); + }; + let surface = command.surface.ok_or_else(|| { + error( + Some(&command.id), + "missing-surface", + "Surface command does not include a render surface", + ) + })?; + runtime + .update_surface(surface) + .map_err(|message| error(Some(&command.id), "media-host-unavailable", message))?; + Ok(vec![response(command.id, "ok")]) + } + + fn stop(&mut self, reason: &str) { + let was_active = { + let mut lifecycle = lock_lifecycle(&self.lifecycle); + let was_active = lifecycle.state != State::Idle; + lifecycle.generation = lifecycle.generation.wrapping_add(1); + lifecycle.context = None; + lifecycle.state = State::Idle; + was_active + }; + if let Some(transport) = self.transport.take() { + transport.stop(); + } + if let Some(transport) = self.nvst_transport.take() { + transport.stop(); + } + if let Some(transport) = self.nvst_mjolnir_transport.take() { + transport.stop(); + } + self.reserved_nvst_bundle = None; + self.nvst_hole_punch_socket = None; + self.stop_media_resources(); + if was_active { + let _ = self.events.send(event( + "status", + json!({ "status": "stopped", "message": reason }), + )); + } + } + + fn stop_media_resources(&mut self) { + if self.media_runtime.is_some() { + self.media_consumer = None; + if let Some(session) = self.media_session.take() { + session.stop(); + } + if let Some(worker) = self.media_worker.take() { + let _ = worker.join(); + } + self.media_feedback = None; + } + if let Some(worker) = self.feedback_worker.take() { + let _ = worker.join(); + } + } +} + +impl Drop for Engine { + fn drop(&mut self) { + self.stop("process closed"); + } +} + +fn partial_reliable_threshold(sdp: &str) -> Option { + sdp.lines().find_map(|line| { + line.trim() + .strip_prefix("a=ri.partialReliableThresholdMs:") + .and_then(|value| value.trim().parse().ok()) + }) +} + +fn parse_context(context: Option, id: &str) -> Result { + let context = context.ok_or_else(|| { + error( + Some(id), + "missing-context", + "Command requires session context", + ) + })?; + serde_json::from_value(context).map_err(|context_error| { + error( + Some(id), + "invalid-context", + format!("Invalid session context: {context_error}"), + ) + }) +} + +fn validate_context(context: &SessionContext, id: &str) -> Result<(), Value> { + if context.session.session_id.trim().is_empty() { + return Err(error( + Some(id), + "invalid-context", + "Session context requires a non-empty sessionId", + )); + } + if context.session.server_ip.trim().is_empty() { + return Err(error( + Some(id), + "invalid-context", + "Session context requires a non-empty serverIp endpoint", + )); + } + if !context.settings.is_object() || !context.shortcuts.is_object() { + return Err(error( + Some(id), + "invalid-context", + "Session context settings and shortcuts must be objects", + )); + } + if context + .session + .ice_servers + .iter() + .any(|server| server.urls.is_empty() || server.urls.iter().any(|url| url.trim().is_empty())) + { + return Err(error( + Some(id), + "invalid-context", + "Every ICE server requires at least one non-empty URL", + )); + } + if let Some(endpoint) = &context.session.media_connection_info { + if endpoint.ip.trim().is_empty() || endpoint.port == 0 || endpoint.port > u16::MAX.into() { + return Err(error( + Some(id), + "invalid-context", + "mediaConnectionInfo requires a hostname and a port in 1..=65535", + )); + } + } + if context + .session + .connection_info + .as_ref() + .is_some_and(|connections| { + connections.iter().any(|connection| { + connection.port == 0 + || connection.port > u16::MAX.into() + || connection + .ip + .as_ref() + .is_some_and(|ip| ip.trim().is_empty()) + }) + }) + { + return Err(error( + Some(id), + "invalid-context", + "connectionInfo requires ports in 1..=65535 and non-empty hostnames when present", + )); + } + serde_json::to_value(context).map_err(|context_error| { + error( + Some(id), + "invalid-context", + format!("Session context is not serializable: {context_error}"), + ) + })?; + Ok(()) +} + +fn invalid_state(id: &str, command: &str, state: State, required: &str) -> Value { + error( + Some(id), + "invalid-state", + format!("Cannot apply {command} while lifecycle is {state:?}; required state: {required}"), + ) +} + +fn lock_lifecycle(lifecycle: &Mutex) -> MutexGuard<'_, Lifecycle> { + lifecycle + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()) +} + +fn forward_transport_event( + output: &Sender, + lifecycle: &Mutex, + generation: u64, + transport_event: TransportEvent, +) { + { + let mut lifecycle = lock_lifecycle(lifecycle); + if lifecycle.generation != generation { + return; + } + match &transport_event { + TransportEvent::Connected => lifecycle.state = State::Connected, + TransportEvent::Disconnected(_) => { + lifecycle.context = None; + lifecycle.state = State::Idle; + } + _ => {} + } + } + let value = match transport_event { + TransportEvent::Connected => event( + "status", + json!({ "status": "streaming", "message": "ICE, DTLS-SRTP, and RTP connected" }), + ), + TransportEvent::Disconnected(message) => { + event("status", json!({ "status": "stopped", "message": message })) + } + TransportEvent::InputReady(protocol_version) => event( + "input-ready", + json!({ "protocolVersion": protocol_version }), + ), + TransportEvent::InputUnavailable(reason) => { + event("input-unavailable", json!({ "reason": reason })) + } + TransportEvent::Log(message) => { + event("log", json!({ "level": "warn", "message": message })) + } + }; + let _ = output.send(value); +} + +fn forward_nvst_session_events( + output: &Sender, + lifecycle: &Mutex, + generation: u64, + nvst_events: Receiver, + media_feedback: Option>, + captured_input: Option>, + resources: R, +) { + let mut feedback_state = NvstMediaFeedbackState { + drop_reports: HashMap::new(), + recovery_attempts: 0, + input_origin: Instant::now(), + input_available: false, + }; + loop { + if let Some(feedback) = media_feedback.as_ref() { + while let Ok(feedback) = feedback.try_recv() { + forward_nvst_media_feedback( + output, + lifecycle, + generation, + &resources, + feedback, + &mut feedback_state, + ); + } + } + if let Some(captured_input) = captured_input.as_ref() { + if !feedback_state.input_available { + captured_input.clear(); + } else if captured_input.take_overflowed() { + let _ = emit_nvst_terminal( + output, + lifecycle, + generation, + &resources, + "native-input-capture-overflow", + "Native input capture queue overflowed; stopping to prevent stuck input" + .to_owned(), + ); + return; + } else { + // Preserve high-polling-rate RawInput/SDL samples rather than + // turning several reports into one uneven movement burst. + for _ in 0..32 { + let Some(input) = captured_input.take() else { + break; + }; + if let Err(error) = + forward_nvst_captured_input(&resources, input, &feedback_state) + { + let _ = emit_nvst_terminal( + output, + lifecycle, + generation, + &resources, + "native-input-capture-failed", + format!("Native window input capture failed: {error}"), + ); + return; + } + } + } + } + match nvst_events.recv_timeout(NATIVE_INPUT_POLL_INTERVAL) { + Ok(nvst_event) => { + match &nvst_event { + NvstReceiveEvent::InputReady(_) => feedback_state.input_available = true, + NvstReceiveEvent::InputUnavailable(_) => { + feedback_state.input_available = false; + } + _ => {} + } + let terminal = forward_nvst_event( + output, + lifecycle, + generation, + &resources, + &mut feedback_state.recovery_attempts, + nvst_event, + ); + if terminal { + return; + } + } + Err(std::sync::mpsc::RecvTimeoutError::Timeout) => {} + Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => { + let _ = emit_nvst_terminal( + output, + lifecycle, + generation, + &resources, + "nvst-event-channel-closed", + "NVST receiver event channel closed unexpectedly".to_owned(), + ); + return; + } + } + } +} + +fn forward_nvst_event( + output: &Sender, + lifecycle: &Mutex, + generation: u64, + resources: &R, + recovery_attempts: &mut usize, + nvst_event: NvstReceiveEvent, +) -> bool { + if lock_lifecycle(lifecycle).generation != generation { + return true; + } + + match nvst_event { + NvstReceiveEvent::RecoveryNeeded(NvstRecovery::PacketGap { + first_missing_index, + last_missing_index, + }) => { + // Packet loss is expected on the UDP media leg. The reorder buffer + // has already skipped the unrecoverable range and reset the frame + // assembler, so request a clean decoder reference without spending + // the terminal transport-recovery budget. Several gaps can arrive + // before the requested keyframe reaches us at high bitrates. + resources.request_keyframe(); + let _ = output.send(event( + "log", + json!({ + "level": "warn", + "message": format!( + "Recovering NVST packet gap with a fresh keyframe: {first_missing_index}..={last_missing_index}" + ) + }), + )); + false + } + NvstReceiveEvent::RecoveryNeeded(recovery) => attempt_nvst_recovery( + output, + lifecycle, + generation, + resources, + recovery_attempts, + format!("{recovery:?}"), + ), + NvstReceiveEvent::Lifecycle(NvstReceiverState::RecoveryRequired) => attempt_nvst_recovery( + output, + lifecycle, + generation, + resources, + recovery_attempts, + "authenticated media timeout".to_owned(), + ), + NvstReceiveEvent::Lifecycle(NvstReceiverState::Stopped) => emit_nvst_terminal( + output, + lifecycle, + generation, + resources, + "nvst-transport-stopped", + "NVST receiver stopped unexpectedly".to_owned(), + ), + NvstReceiveEvent::Dropped(NvstDropReason::MediaConsumerBackpressured) => { + // A bounded decode queue protects latency. A momentary full queue + // means this access unit is stale, not that the network session is + // dead. Keep receiving and ask for a clean decoder reference. + resources.request_keyframe(); + let _ = output.send(event( + "log", + json!({ + "level": "warn", + "message": "Dropped a backpressured NVST video frame and requested a fresh keyframe" + }), + )); + false + } + NvstReceiveEvent::Dropped(NvstDropReason::MediaConsumerClosed) => emit_nvst_terminal( + output, + lifecycle, + generation, + resources, + "media-consumer-closed", + "NVST receiver stopped because the decoded media path closed".to_owned(), + ), + NvstReceiveEvent::Lifecycle(NvstReceiverState::Running) => { + lock_lifecycle(lifecycle).state = State::Connected; + let _ = output.send(event( + "status", + json!({ "status": "streaming", "message": "NVST SRTP video receiver is running" }), + )); + false + } + NvstReceiveEvent::Lifecycle(NvstReceiverState::Paused) => { + let _ = output.send(event( + "status", + json!({ "status": "paused", "message": "NVST SRTP video receiver is paused" }), + )); + false + } + NvstReceiveEvent::TransportReady(phase) => { + let _ = output.send(event("nvst-transport-ready", json!({ "phase": phase }))); + false + } + NvstReceiveEvent::InputReady(protocol_version) => { + let _ = output.send(event( + "input-ready", + json!({ "protocolVersion": protocol_version }), + )); + false + } + NvstReceiveEvent::InputUnavailable(reason) => { + let _ = output.send(event("input-unavailable", json!({ "reason": reason }))); + false + } + NvstReceiveEvent::Cursor(bytes) => { + resources.apply_cursor(bytes); + false + } + NvstReceiveEvent::Dropped( + NvstDropReason::AwaitingStartOfFrame + | NvstDropReason::StaleRtpPacket { .. } + | NvstDropReason::DuplicateRtpPacket { .. }, + ) => { + // These are expected while a packet-gap recovery waits for the + // requested keyframe. Logging every following datagram can flood + // stdout and steal time from the receive/decode threads. + false + } + NvstReceiveEvent::Dropped(reason) => { + let _ = output.send(event( + "log", + json!({ "level": "debug", "message": format!("Dropped NVST datagram: {reason:?}") }), + )); + false + } + NvstReceiveEvent::Frame(_) => false, + } +} + +fn attempt_nvst_recovery( + output: &Sender, + lifecycle: &Mutex, + generation: u64, + resources: &R, + recovery_attempts: &mut usize, + reason: String, +) -> bool { + if *recovery_attempts >= NVST_RECOVERY_ATTEMPT_LIMIT { + return emit_nvst_terminal( + output, + lifecycle, + generation, + resources, + "nvst-recovery-exhausted", + format!("NVST recovery failed after one attempt: {reason}"), + ); + } + + *recovery_attempts += 1; + resources.request_keyframe(); + if let Err(recovery_error) = resources.recover() { + return emit_nvst_terminal( + output, + lifecycle, + generation, + resources, + "nvst-recovery-failed", + format!("NVST recovery could not be started: {recovery_error}"), + ); + } + let _ = output.send(event( + "log", + json!({ + "level": "warn", + "message": format!("Attempting bounded NVST recovery with a fresh keyframe: {reason}") + }), + )); + false +} + +fn emit_nvst_terminal( + output: &Sender, + lifecycle: &Mutex, + generation: u64, + resources: &R, + code: &str, + message: String, +) -> bool { + { + let mut lifecycle = lock_lifecycle(lifecycle); + if lifecycle.generation != generation { + return true; + } + lifecycle.context = None; + lifecycle.state = State::Idle; + } + resources.stop(); + let _ = output.send(event("error", json!({ "code": code, "message": &message }))); + let _ = output.send(event( + "status", + json!({ "status": "stopped", "message": message }), + )); + true +} + +struct NvstMediaFeedbackState { + drop_reports: HashMap<&'static str, QueueDropReport>, + recovery_attempts: usize, + input_origin: Instant, + input_available: bool, +} + +fn forward_nvst_media_feedback( + output: &Sender, + lifecycle: &Mutex, + generation: u64, + resources: &R, + feedback: MediaFeedback, + state: &mut NvstMediaFeedbackState, +) { + if lock_lifecycle(lifecycle).generation != generation { + return; + } + match feedback { + MediaFeedback::VideoFrameAccepted { + bytes, keyframe, .. + } => { + resources.acknowledge_video_frame(bytes); + if keyframe { + state.recovery_attempts = 0; + } + } + MediaFeedback::PlaybackStarted { backend } => { + let _ = output.send(event( + "status", + json!({ + "status": "streaming", + "message": format!("{backend} presented the first NVST video frame") + }), + )); + } + MediaFeedback::BackendFallback { from, to, reason } => { + let _ = output.send(event( + "log", + json!({ + "level": "warn", + "message": format!("{from} startup failed; using {to}: {reason}") + }), + )); + } + MediaFeedback::RequestKeyframe { reason, .. } => { + resources.request_keyframe(); + let _ = output.send(event( + "log", + json!({ + "level": "info", + "message": format!("Requested an NVST video keyframe: {reason}") + }), + )); + } + MediaFeedback::DecoderError { codec, message } => { + let _ = output.send(event( + "error", + json!({ + "code": "media-decode-error", + "message": format!("{codec} decoder error: {message}") + }), + )); + } + MediaFeedback::OutputError { message } => { + let _ = output.send(event( + "error", + json!({ "code": "media-output-error", "message": message }), + )); + } + MediaFeedback::DeviceLost { + subsystem, + recovered, + message, + } => { + let _ = output.send(event( + "log", + json!({ + "level": if recovered { "info" } else { "warn" }, + "message": message.unwrap_or_else(|| format!( + "{subsystem} device {}", + if recovered { "recovered" } else { "was lost" } + )) + }), + )); + } + MediaFeedback::QueueDropped { media, count } => { + if let Some(dropped) = record_queue_drop(&mut state.drop_reports, media, count) { + let _ = output.send(event( + "log", + json!({ + "level": "debug", + "message": format!("Low-latency {media} queues dropped {dropped} stale samples/frames") + }), + )); + } + } + } +} + +fn forward_nvst_captured_input( + resources: &R, + input: CapturedInput, + state: &NvstMediaFeedbackState, +) -> Result<(), String> { + let timestamp_us = u64::try_from(state.input_origin.elapsed().as_micros()).unwrap_or(u64::MAX); + resources.send_captured_input(captured_input_packet(input, timestamp_us)) +} + +fn captured_input_packet(input: CapturedInput, timestamp_us: u64) -> Vec { + match input { + CapturedInput::Key { + virtual_key, + modifiers, + pressed, + } => { + let mut packet = Vec::with_capacity(18); + packet.extend_from_slice(&(if pressed { 3_u32 } else { 4_u32 }).to_le_bytes()); + packet.extend_from_slice(&virtual_key.to_be_bytes()); + packet.extend_from_slice(&modifiers.to_be_bytes()); + packet.extend_from_slice(&0_u16.to_be_bytes()); + packet.extend_from_slice(×tamp_us.to_be_bytes()); + packet + } + CapturedInput::MouseMove { delta_x, delta_y } => { + let mut packet = Vec::with_capacity(22); + packet.extend_from_slice(&7_u32.to_le_bytes()); + packet.extend_from_slice(&delta_x.to_be_bytes()); + packet.extend_from_slice(&delta_y.to_be_bytes()); + packet.extend_from_slice(&[0; 6]); + packet.extend_from_slice(×tamp_us.to_be_bytes()); + packet + } + CapturedInput::MouseAbsolute { + x, + y, + width, + height, + } => { + let mut packet = Vec::with_capacity(26); + packet.extend_from_slice(&5_u32.to_le_bytes()); + packet.extend_from_slice(&x.to_be_bytes()); + packet.extend_from_slice(&y.to_be_bytes()); + packet.extend_from_slice(&0_u16.to_be_bytes()); + packet.extend_from_slice(&width.to_be_bytes()); + packet.extend_from_slice(&height.to_be_bytes()); + packet.extend_from_slice(&0_u32.to_be_bytes()); + packet.extend_from_slice(×tamp_us.to_be_bytes()); + packet + } + CapturedInput::MouseButton { button, pressed } => { + let mut packet = Vec::with_capacity(18); + packet.extend_from_slice(&(if pressed { 8_u32 } else { 9_u32 }).to_le_bytes()); + packet.extend_from_slice(&[button, 0]); + packet.extend_from_slice(&[0; 4]); + packet.extend_from_slice(×tamp_us.to_be_bytes()); + packet + } + CapturedInput::MouseWheel { delta } => { + let mut packet = Vec::with_capacity(22); + packet.extend_from_slice(&10_u32.to_le_bytes()); + packet.extend_from_slice(&0_i16.to_be_bytes()); + packet.extend_from_slice(&delta.to_be_bytes()); + packet.extend_from_slice(&[0; 6]); + packet.extend_from_slice(×tamp_us.to_be_bytes()); + packet + } + } +} + +fn media_stream_config(context: &SessionContext) -> MediaStreamConfig { + let codec_name = context + .session + .extra + .get("negotiatedStreamProfile") + .and_then(|profile| profile.get("codec")) + .and_then(Value::as_str) + .or_else(|| context.settings.get("codec").and_then(Value::as_str)) + .unwrap_or("H264"); + let codec = match codec_name.trim().to_ascii_uppercase().as_str() { + "H265" | "HEVC" => MediaVideoCodec::H265, + "AV1" => MediaVideoCodec::Av1, + _ => MediaVideoCodec::H264, + }; + let resolution = context + .session + .extra + .get("negotiatedStreamProfile") + .and_then(|profile| profile.get("resolution")) + .and_then(Value::as_str) + .or_else(|| context.settings.get("resolution").and_then(Value::as_str)) + .and_then(|value| { + let lowercase = value.to_ascii_lowercase(); + let (width, height) = lowercase.split_once('x')?; + Some((width.parse::().ok()?, height.parse::().ok()?)) + }) + .filter(|(width, height)| (48..=4096).contains(width) && (48..=2304).contains(height)) + .unwrap_or((1920, 1080)); + let fps = context + .session + .extra + .get("negotiatedStreamProfile") + .and_then(|profile| profile.get("fps")) + .or_else(|| context.settings.get("fps")) + .and_then(Value::as_u64) + .and_then(|value| u32::try_from(value).ok()) + .unwrap_or(60) + .clamp(1, 240); + let bitrate_mbps = context + .settings + .get("maxBitrateMbps") + .and_then(Value::as_u64) + .and_then(|value| u32::try_from(value).ok()) + .unwrap_or(10); + let cloud_gsync = context + .settings + .get("enableCloudGsync") + .and_then(Value::as_bool) + .unwrap_or(false); + MediaStreamConfig { + codec, + width: resolution.0, + height: resolution.1, + fps, + bitrate_bps: bitrate_mbps.saturating_mul(1_000_000).max(1), + cloud_gsync, + } +} + +fn consume_encoded_media( + output: &Sender, + receiver: Receiver, + sink: MediaSink, +) { + while let Ok(frame) = receiver.recv() { + let codec = if frame.codec.eq_ignore_ascii_case("h264") { + MediaCodec::H264 + } else if frame.codec.eq_ignore_ascii_case("h265") + || frame.codec.eq_ignore_ascii_case("hevc") + { + MediaCodec::H265 + } else if frame.codec.eq_ignore_ascii_case("av1") { + MediaCodec::Av1 + } else if frame.codec.eq_ignore_ascii_case("opus") { + MediaCodec::Opus { + channels: frame.channels.unwrap_or(2).clamp(1, 2), + } + } else { + MediaCodec::Unsupported(frame.codec) + }; + match sink.push(EncodedFrame { + mid: frame.mid, + codec, + data: frame.payload, + timestamp: frame.rtp_timestamp, + clock_rate_hz: frame.clock_rate_hz, + keyframe: frame.keyframe, + contiguous: frame.contiguous, + }) { + PushOutcome::Unsupported => { + let _ = output.send(event( + "log", + json!({ + "level": "warn", + "message": "Dropping a frame for a codec not built into native streamer v2" + }), + )); + } + PushOutcome::Closed => break, + PushOutcome::Queued | PushOutcome::DroppedOldest | PushOutcome::Paused => {} + } + } +} + +fn forward_session_events( + output: &Sender, + lifecycle: &Mutex, + generation: u64, + transport_events: Receiver, + media_feedback: Option>, + transport: TransportControl, +) { + let mut drop_reports = HashMap::new(); + loop { + if let Some(feedback) = media_feedback.as_ref() { + while let Ok(feedback) = feedback.try_recv() { + forward_media_feedback( + output, + lifecycle, + generation, + &transport, + feedback, + &mut drop_reports, + ); + } + } + match transport_events.recv_timeout(Duration::from_millis(5)) { + Ok(transport_event) => { + let disconnected = matches!(transport_event, TransportEvent::Disconnected(_)); + forward_transport_event(output, lifecycle, generation, transport_event); + if disconnected { + break; + } + } + Err(std::sync::mpsc::RecvTimeoutError::Timeout) => {} + Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => break, + } + } +} + +fn forward_media_feedback( + output: &Sender, + lifecycle: &Mutex, + generation: u64, + transport: &TransportControl, + feedback: MediaFeedback, + drop_reports: &mut HashMap<&'static str, QueueDropReport>, +) { + if lock_lifecycle(lifecycle).generation != generation { + return; + } + match feedback { + MediaFeedback::VideoFrameAccepted { .. } => {} + MediaFeedback::PlaybackStarted { backend } => { + let _ = output.send(event( + "status", + json!({ + "status": "streaming", + "message": format!("{backend} presented the first video frame") + }), + )); + } + MediaFeedback::BackendFallback { from, to, reason } => { + let _ = output.send(event( + "log", + json!({ + "level": "warn", + "message": format!("{from} startup failed; using {to}: {reason}") + }), + )); + } + MediaFeedback::RequestKeyframe { mid, reason } => { + let request_result = transport.request_keyframe(mid); + let _ = output.send(event( + "log", + json!({ + "level": if request_result.is_ok() { "info" } else { "warn" }, + "message": format!("Requested a video keyframe: {reason}") + }), + )); + } + MediaFeedback::DecoderError { codec, message } => { + let _ = output.send(event( + "error", + json!({ + "code": "media-decode-error", + "message": format!("{codec} decoder error: {message}") + }), + )); + } + MediaFeedback::OutputError { message } => { + let _ = output.send(event( + "error", + json!({ "code": "media-output-error", "message": message }), + )); + } + MediaFeedback::DeviceLost { + subsystem, + recovered, + message, + } => { + let _ = output.send(event( + "log", + json!({ + "level": if recovered { "info" } else { "warn" }, + "message": message.unwrap_or_else(|| format!( + "{subsystem} device {}", + if recovered { "recovered" } else { "was lost" } + )) + }), + )); + } + MediaFeedback::QueueDropped { media, count } => { + if let Some(dropped) = record_queue_drop(drop_reports, media, count) { + let _ = output.send(event( + "log", + json!({ + "level": "debug", + "message": format!( + "Low-latency {media} queues dropped {dropped} stale samples/frames" + ) + }), + )); + } + } + } +} + +struct QueueDropReport { + dropped: usize, + started: Instant, +} + +fn record_queue_drop( + reports: &mut HashMap<&'static str, QueueDropReport>, + media: &'static str, + count: usize, +) -> Option { + let report = reports.entry(media).or_insert_with(|| QueueDropReport { + dropped: 0, + started: Instant::now(), + }); + report.dropped = report.dropped.saturating_add(count); + if report.started.elapsed() < Duration::from_secs(1) { + return None; + } + let dropped = std::mem::take(&mut report.dropped); + report.started = Instant::now(); + Some(dropped) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::net::UdpSocket; + use std::sync::atomic::{AtomicUsize, Ordering}; + use std::time::Instant; + use str0m::media::{Direction, MediaKind}; + use str0m::{Candidate, RtcConfig}; + + fn command(value: Value) -> Command { + serde_json::from_value(value).expect("command") + } + + fn synthetic_context(session_id: &str, ice_servers: Value) -> Value { + json!({ + "session": { + "sessionId": session_id, + "serverIp": "127-0-0-1.synthetic.invalid", + "iceServers": ice_servers, + "mediaConnectionInfo": { + "ip": "127-0-0-1.media.synthetic.invalid", + "port": 18_784, + "usage": 17 + }, + "syntheticExtension": "preserved" + }, + "settings": { "codec": "H264", "fps": 60 }, + "shortcuts": { "stopStream": "Ctrl+Shift+Q" }, + "syntheticContextExtension": true + }) + } + + fn synthetic_offer() -> String { + opennow_streamer_transport::install_crypto(); + let mut offerer = RtcConfig::new().build(Instant::now()); + offerer.add_local_candidate( + Candidate::host("127.0.0.1:49152".parse().expect("candidate address"), "udp") + .expect("local candidate"), + ); + let mut change = offerer.sdp_api(); + change.add_media(MediaKind::Video, Direction::SendOnly, None, None, None); + let (offer, _pending) = change.apply().expect("synthetic offer"); + offer.to_sdp_string() + } + + fn lifecycle_state(engine: &Engine) -> State { + lock_lifecycle(&engine.lifecycle).state + } + + fn unused_udp_port() -> u16 { + let socket = UdpSocket::bind("127.0.0.1:0").expect("ephemeral UDP port"); + let port = socket.local_addr().expect("socket address").port(); + drop(socket); + port + } + + #[derive(Default)] + struct TestNvstResources { + keyframe_requests: AtomicUsize, + acknowledged_frames: AtomicUsize, + recoveries: AtomicUsize, + stops: AtomicUsize, + captured_inputs: Mutex>>, + } + + impl NvstSessionResources for TestNvstResources { + fn request_keyframe(&self) { + self.keyframe_requests.fetch_add(1, Ordering::Relaxed); + } + + fn acknowledge_video_frame(&self, _bytes: u32) { + self.acknowledged_frames.fetch_add(1, Ordering::Relaxed); + } + + fn send_captured_input(&self, bytes: Vec) -> Result<(), String> { + self.captured_inputs + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner) + .push(bytes); + Ok(()) + } + + fn apply_cursor(&self, _bytes: Vec) {} + + fn recover(&self) -> Result<(), String> { + self.recoveries.fetch_add(1, Ordering::Relaxed); + Ok(()) + } + + fn stop(&self) { + self.stops.fetch_add(1, Ordering::Relaxed); + } + } + + fn connected_lifecycle() -> Mutex { + Mutex::new(Lifecycle { + state: State::Connected, + context: Some( + serde_json::from_value(synthetic_context("nvst-recovery", json!([]))) + .expect("session context"), + ), + generation: 7, + }) + } + + #[test] + fn decoder_keyframe_feedback_routes_to_nvst_pli_handle() { + let (sender, receiver) = std::sync::mpsc::channel(); + let lifecycle = connected_lifecycle(); + let resources = TestNvstResources::default(); + let mut state = NvstMediaFeedbackState { + drop_reports: HashMap::new(), + recovery_attempts: 0, + input_origin: Instant::now(), + input_available: true, + }; + + forward_nvst_media_feedback( + &sender, + &lifecycle, + 7, + &resources, + MediaFeedback::RequestKeyframe { + mid: "nvst-video-0".to_owned(), + reason: "decoder reference loss".to_owned(), + }, + &mut state, + ); + + assert_eq!(resources.keyframe_requests.load(Ordering::Relaxed), 1); + let message = receiver.recv().expect("keyframe log"); + assert_eq!(message["type"], "log"); + assert!( + message["message"] + .as_str() + .is_some_and(|message| message.contains("decoder reference loss")) + ); + } + + #[test] + fn accepted_video_keyframe_routes_pacing_feedback_and_resets_recovery_budget() { + let (sender, _receiver) = std::sync::mpsc::channel(); + let lifecycle = connected_lifecycle(); + let resources = TestNvstResources::default(); + let mut state = NvstMediaFeedbackState { + drop_reports: HashMap::new(), + recovery_attempts: 1, + input_origin: Instant::now(), + input_available: true, + }; + + forward_nvst_media_feedback( + &sender, + &lifecycle, + 7, + &resources, + MediaFeedback::VideoFrameAccepted { + timestamp: 90_000, + bytes: 1_024, + keyframe: true, + }, + &mut state, + ); + + assert_eq!(resources.acknowledged_frames.load(Ordering::Relaxed), 1); + assert_eq!(state.recovery_attempts, 0); + } + + #[test] + fn captured_sdl_input_routes_through_the_nvst_input_codec_packet_shape() { + let resources = TestNvstResources::default(); + let state = NvstMediaFeedbackState { + drop_reports: HashMap::new(), + recovery_attempts: 0, + input_origin: Instant::now(), + input_available: true, + }; + + assert!( + forward_nvst_captured_input( + &resources, + CapturedInput::Key { + virtual_key: 0x57, + modifiers: 0x01, + pressed: true, + }, + &state, + ) + .is_ok() + ); + assert!( + forward_nvst_captured_input( + &resources, + CapturedInput::MouseMove { + delta_x: -12, + delta_y: 34, + }, + &state, + ) + .is_ok() + ); + assert!( + forward_nvst_captured_input( + &resources, + CapturedInput::MouseAbsolute { + x: 321, + y: 180, + width: 1280, + height: 720, + }, + &state, + ) + .is_ok() + ); + + let inputs = resources + .captured_inputs + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner); + assert_eq!(inputs.len(), 3); + assert_eq!(u32::from_le_bytes(inputs[0][0..4].try_into().unwrap()), 3); + assert_eq!( + u16::from_be_bytes(inputs[0][4..6].try_into().unwrap()), + 0x57 + ); + assert_eq!( + u16::from_be_bytes(inputs[0][6..8].try_into().unwrap()), + 0x01 + ); + assert_eq!(inputs[0].len(), 18); + assert_eq!(u32::from_le_bytes(inputs[1][0..4].try_into().unwrap()), 7); + assert_eq!(i16::from_be_bytes(inputs[1][4..6].try_into().unwrap()), -12); + assert_eq!(i16::from_be_bytes(inputs[1][6..8].try_into().unwrap()), 34); + assert_eq!(inputs[1].len(), 22); + assert_eq!(u32::from_le_bytes(inputs[2][0..4].try_into().unwrap()), 5); + assert_eq!(u16::from_be_bytes(inputs[2][4..6].try_into().unwrap()), 321); + assert_eq!(u16::from_be_bytes(inputs[2][6..8].try_into().unwrap()), 180); + assert_eq!( + u16::from_be_bytes(inputs[2][10..12].try_into().unwrap()), + 1280 + ); + assert_eq!( + u16::from_be_bytes(inputs[2][12..14].try_into().unwrap()), + 720 + ); + assert_eq!(inputs[2].len(), 26); + } + + #[test] + fn queue_drop_reports_do_not_mix_audio_samples_with_video_frames() { + let expired = Instant::now() - Duration::from_secs(2); + let mut reports = HashMap::from([ + ( + "audio-output", + QueueDropReport { + dropped: 0, + started: expired, + }, + ), + ( + "linux-present", + QueueDropReport { + dropped: 0, + started: expired, + }, + ), + ]); + + assert_eq!( + record_queue_drop(&mut reports, "audio-output", 96_000), + Some(96_000) + ); + assert_eq!( + record_queue_drop(&mut reports, "linux-present", 47), + Some(47) + ); + } + + #[test] + fn nvst_recovery_is_attempted_once_with_pli() { + let (sender, receiver) = std::sync::mpsc::channel(); + let lifecycle = connected_lifecycle(); + let resources = TestNvstResources::default(); + let mut recovery_attempts = 0; + + let terminal = forward_nvst_event( + &sender, + &lifecycle, + 7, + &resources, + &mut recovery_attempts, + NvstReceiveEvent::RecoveryNeeded(opennow_streamer_transport::NvstRecovery::Timeout { + idle_for: Duration::from_secs(2), + }), + ); + + assert!(!terminal); + assert_eq!(recovery_attempts, 1); + assert_eq!(resources.recoveries.load(Ordering::Relaxed), 1); + assert_eq!(resources.keyframe_requests.load(Ordering::Relaxed), 1); + assert_eq!(resources.stops.load(Ordering::Relaxed), 0); + assert_eq!(lock_lifecycle(&lifecycle).state, State::Connected); + assert!( + receiver + .try_iter() + .all(|message| message["type"] != "error") + ); + } + + #[test] + fn repeated_packet_gaps_request_keyframes_without_stopping_the_session() { + let (sender, receiver) = std::sync::mpsc::channel(); + let lifecycle = connected_lifecycle(); + let resources = TestNvstResources::default(); + let mut recovery_attempts = 0; + + for first_missing_index in [100, 200] { + assert!(!forward_nvst_event( + &sender, + &lifecycle, + 7, + &resources, + &mut recovery_attempts, + NvstReceiveEvent::RecoveryNeeded(NvstRecovery::PacketGap { + first_missing_index, + last_missing_index: first_missing_index + 31, + }), + )); + } + + assert_eq!(recovery_attempts, 0); + assert_eq!(resources.recoveries.load(Ordering::Relaxed), 0); + assert_eq!(resources.keyframe_requests.load(Ordering::Relaxed), 2); + assert_eq!(resources.stops.load(Ordering::Relaxed), 0); + assert_eq!(lock_lifecycle(&lifecycle).state, State::Connected); + assert!( + receiver + .try_iter() + .all(|message| message["type"] != "error") + ); + } + + #[test] + fn transient_media_backpressure_requests_keyframe_without_stopping_session() { + let (sender, receiver) = std::sync::mpsc::channel(); + let lifecycle = connected_lifecycle(); + let resources = TestNvstResources::default(); + let mut recovery_attempts = 0; + + assert!(!forward_nvst_event( + &sender, + &lifecycle, + 7, + &resources, + &mut recovery_attempts, + NvstReceiveEvent::Dropped(NvstDropReason::MediaConsumerBackpressured), + )); + + assert_eq!(recovery_attempts, 0); + assert_eq!(resources.keyframe_requests.load(Ordering::Relaxed), 1); + assert_eq!(resources.stops.load(Ordering::Relaxed), 0); + assert_eq!(lock_lifecycle(&lifecycle).state, State::Connected); + assert!( + receiver + .try_iter() + .all(|message| message["type"] != "error" && message["type"] != "status") + ); + } + + #[test] + fn exhausted_nvst_recovery_stops_every_leg_and_emits_terminal_status() { + let (sender, receiver) = std::sync::mpsc::channel(); + let lifecycle = connected_lifecycle(); + let resources = TestNvstResources::default(); + let mut recovery_attempts = 0; + let recovery = || { + NvstReceiveEvent::RecoveryNeeded(opennow_streamer_transport::NvstRecovery::Timeout { + idle_for: Duration::from_secs(2), + }) + }; + + assert!(!forward_nvst_event( + &sender, + &lifecycle, + 7, + &resources, + &mut recovery_attempts, + recovery(), + )); + assert!(forward_nvst_event( + &sender, + &lifecycle, + 7, + &resources, + &mut recovery_attempts, + recovery(), + )); + + assert_eq!(resources.recoveries.load(Ordering::Relaxed), 1); + assert_eq!(resources.keyframe_requests.load(Ordering::Relaxed), 1); + assert_eq!(resources.stops.load(Ordering::Relaxed), 1); + let lifecycle = lock_lifecycle(&lifecycle); + assert_eq!(lifecycle.state, State::Idle); + assert!(lifecycle.context.is_none()); + drop(lifecycle); + let events = receiver.try_iter().collect::>(); + assert!(events.iter().any(|message| { + message["type"] == "error" && message["code"] == "nvst-recovery-exhausted" + })); + assert!( + events + .iter() + .any(|message| { message["type"] == "status" && message["status"] == "stopped" }) + ); + } + + #[test] + fn assembled_keyframe_does_not_reset_recovery_episode_budget() { + let (sender, _receiver) = std::sync::mpsc::channel(); + let lifecycle = connected_lifecycle(); + let resources = TestNvstResources::default(); + let mut recovery_attempts = 1; + + assert!(!forward_nvst_event( + &sender, + &lifecycle, + 7, + &resources, + &mut recovery_attempts, + NvstReceiveEvent::Frame(opennow_streamer_transport::EncodedVideoAccessUnit { + codec: opennow_streamer_transport::NvstVideoCodec::H264, + timestamp: 1, + frame_index: 1, + first_stream_packet_index: 1, + keyframe: true, + contiguous: true, + bytes: vec![0, 0, 0, 1, 0x65], + }), + )); + assert_eq!(recovery_attempts, 1); + } + + #[test] + fn hello_reports_honest_transport_only_capabilities() { + let (sender, _receiver) = std::sync::mpsc::channel(); + let mut engine = Engine::new(sender); + let command = command(json!({ + "id": "hello", + "type": "hello", + "protocolVersion": PROTOCOL_VERSION, + })); + let (responses, _) = engine.handle(command); + assert_eq!(responses[0]["type"], "ready"); + assert_eq!(responses[0]["capabilities"]["supportsOfferAnswer"], false); + assert_eq!(responses[0]["capabilities"]["supportsVideoPresent"], false); + } + + #[test] + fn extracts_partial_reliable_threshold() { + assert_eq!( + partial_reliable_threshold("v=0\r\na=ri.partialReliableThresholdMs:250\r\n"), + Some(250), + ); + } + + #[test] + fn derives_bounded_windows_media_configuration_from_stream_settings() { + let mut value = synthetic_context("media-config", json!([])); + value["settings"] = json!({ + "codec": "H264", + "resolution": "2560x1440", + "fps": 120, + "maxBitrateMbps": 75, + "enableCloudGsync": true + }); + let context: SessionContext = serde_json::from_value(value).expect("context"); + + assert_eq!( + media_stream_config(&context), + MediaStreamConfig { + codec: MediaVideoCodec::H264, + width: 2560, + height: 1440, + fps: 120, + bitrate_bps: 75_000_000, + cloud_gsync: true, + } + ); + + let fallback: SessionContext = + serde_json::from_value(synthetic_context("fallback-config", json!([]))) + .expect("context"); + assert_eq!(media_stream_config(&fallback), MediaStreamConfig::default()); + + let mut high_fps = synthetic_context("high-fps-config", json!([])); + high_fps["settings"] = json!({ + "codec": "H264", + "resolution": "1920x1080", + "fps": 360, + "maxBitrateMbps": 100 + }); + high_fps["session"]["negotiatedStreamProfile"] = json!({ + "codec": "AV1", + "fps": 300 + }); + let high_fps: SessionContext = serde_json::from_value(high_fps).expect("context"); + assert_eq!(media_stream_config(&high_fps).codec, MediaVideoCodec::Av1); + assert_eq!(media_stream_config(&high_fps).fps, 240); + } + + #[test] + fn start_validates_stores_context_and_prepares_session() { + let (sender, receiver) = std::sync::mpsc::channel(); + let mut engine = Engine::new(sender); + let context = synthetic_context("synthetic-session", json!([])); + let start = command(json!({ + "id": "start", + "type": "start", + "context": context, + })); + let (responses, _) = engine.handle(start); + + assert_eq!(responses[0]["type"], "ok"); + assert_eq!(responses[0]["transport"], "webrtc"); + let lifecycle = lock_lifecycle(&engine.lifecycle); + assert_eq!(lifecycle.state, State::Prepared); + let stored = serde_json::to_value(lifecycle.context.as_ref().expect("stored context")) + .expect("serializable stored context"); + assert_eq!(stored["session"]["sessionId"], "synthetic-session"); + assert_eq!(stored["session"]["syntheticExtension"], "preserved"); + assert_eq!(stored["syntheticContextExtension"], true); + drop(lifecycle); + let status = receiver.recv().expect("ready status"); + assert_eq!(status["status"], "ready"); + } + + #[test] + fn valid_nvst_handoff_starts_udp_video_and_bypasses_webrtc_offer_negotiation() { + let (sender, receiver) = std::sync::mpsc::channel(); + let (media_sender, _media_receiver) = std::sync::mpsc::sync_channel(4); + let mut engine = Engine::with_media_consumer(sender, media_sender); + let mut context = synthetic_context("nvst-session", json!([])); + context["settings"]["codec"] = json!("AV1"); + context["nvstVideo"] = json!({ + "clientUdpPort": unused_udp_port(), + "videoPeerIp": "127.0.0.1", + "videoPeerPort": 5004, + "srtpAesKeyHex": "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "srtpSaltHex": "00000000000000009ECA935E", + "codec": "H264" + }); + let (responses, _) = engine.handle(command(json!({ + "id": "start", + "type": "start", + "context": context.clone(), + }))); + + assert_eq!(responses[0]["type"], "ok"); + assert_eq!(responses[0]["transport"], "nvst"); + assert_eq!(responses[0]["capabilities"]["supportsOfferAnswer"], false); + assert_eq!(responses[0]["capabilities"]["supportsRemoteIce"], false); + assert_eq!(responses[0]["capabilities"]["supportsInput"], false); + assert_eq!(responses[0]["capabilities"]["supportsAudioDecode"], false); + assert_eq!(lifecycle_state(&engine), State::Connected); + assert!(engine.nvst_transport.is_some()); + assert!(engine.transport.is_none()); + assert!(receiver.try_iter().any(|message| { + message["type"] == "status" + && message["message"] + .as_str() + .is_some_and(|text| text.contains("NVST")) + })); + + let (responses, _) = engine.handle(command(json!({ + "id": "offer", + "type": "offer", + "context": context, + "sdp": synthetic_offer(), + }))); + assert_eq!(responses[0]["code"], "nvst-video-active"); + + let (responses, _) = engine.handle(command(json!({ + "id": "stop", + "type": "stop", + "reason": "test complete", + }))); + assert_eq!(responses[0]["type"], "ok"); + assert_eq!(lifecycle_state(&engine), State::Idle); + } + + #[test] + fn explicit_invalid_nvst_handoff_fails_closed_without_webrtc_fallback() { + let (sender, _receiver) = std::sync::mpsc::channel(); + let mut engine = Engine::new(sender); + let mut context = synthetic_context("invalid-nvst-session", json!([])); + context["nvstVideo"] = json!({ + "clientUdpPort": 0, + "codec": "H264" + }); + + let (responses, _) = engine.handle(command(json!({ + "id": "start-invalid-nvst", + "type": "start", + "context": context, + }))); + + assert_eq!(responses[0]["code"], "invalid-nvst-handoff"); + assert_eq!(lifecycle_state(&engine), State::Idle); + assert!(engine.transport.is_none()); + assert!(engine.nvst_transport.is_none()); + } + + #[test] + fn explicit_nvst_mode_without_handoff_fails_closed() { + let (sender, _receiver) = std::sync::mpsc::channel(); + let mut engine = Engine::new(sender); + let mut context = synthetic_context("missing-nvst-session", json!([])); + context["settings"]["transportMode"] = json!("nvst"); + + let (responses, _) = engine.handle(command(json!({ + "id": "start-missing-nvst", + "type": "start", + "context": context, + }))); + + assert_eq!(responses[0]["code"], "invalid-nvst-handoff"); + assert_eq!(lifecycle_state(&engine), State::Idle); + assert!(engine.transport.is_none()); + assert!(engine.nvst_transport.is_none()); + } + + #[test] + fn unused_nvst_reservation_can_be_released_idempotently() { + let (sender, _receiver) = std::sync::mpsc::channel(); + let mut engine = Engine::new(sender); + + let (responses, _) = engine.handle(command(json!({ + "id": "bind", + "type": "nvst-bind", + }))); + assert_eq!(responses[0]["type"], "nvst-bound"); + assert!(engine.reserved_nvst_bundle.is_some()); + + for id in ["unbind", "unbind-again"] { + let (responses, _) = engine.handle(command(json!({ + "id": id, + "type": "nvst-unbind", + }))); + assert_eq!(responses[0]["type"], "ok"); + assert!(engine.reserved_nvst_bundle.is_none()); + } + } + + #[test] + fn start_rejects_invalid_and_duplicate_sessions() { + let (sender, _receiver) = std::sync::mpsc::channel(); + let mut engine = Engine::new(sender); + let invalid = command(json!({ + "id": "invalid", + "type": "start", + "context": { + "session": { "sessionId": "", "serverIp": "host", "iceServers": [] }, + "settings": {}, + "shortcuts": {} + } + })); + let (responses, _) = engine.handle(invalid); + assert_eq!(responses[0]["code"], "invalid-context"); + assert_eq!(lifecycle_state(&engine), State::Idle); + + for id in ["first", "duplicate"] { + let start = command(json!({ + "id": id, + "type": "start", + "context": synthetic_context("synthetic-session", json!([])), + })); + let (responses, _) = engine.handle(start); + if id == "first" { + assert_eq!(responses[0]["type"], "ok"); + } else { + assert_eq!(responses[0]["code"], "invalid-state"); + } + } + } + + #[test] + fn offer_negotiates_directly_with_configured_ice_services() { + let (sender, _receiver) = std::sync::mpsc::channel(); + let (media_sender, _media_receiver) = std::sync::mpsc::sync_channel(4); + let mut engine = Engine::with_media_consumer(sender, media_sender); + let context = synthetic_context( + "synthetic-session", + json!([{ + "urls": ["stun:stun.synthetic.invalid:3478", "turn:turn.synthetic.invalid:3478"], + "username": "synthetic-user", + "credential": "synthetic-credential" + }]), + ); + let (responses, _) = engine.handle(command(json!({ + "id": "start", + "type": "start", + "context": context.clone(), + }))); + assert_eq!(responses[0]["type"], "ok"); + + let (responses, _) = engine.handle(command(json!({ + "id": "offer", + "type": "offer", + "context": context, + "sdp": synthetic_offer() + }))); + assert_eq!(responses[0]["type"], "answer"); + assert!( + responses[0]["answer"]["sdp"] + .as_str() + .is_some_and(|sdp| sdp.contains("m=video") && !sdp.contains("m=video 0")) + ); + assert_eq!(lifecycle_state(&engine), State::Negotiating); + } + + #[test] + fn offer_fails_typed_when_no_in_process_media_consumer_exists() { + let (sender, _receiver) = std::sync::mpsc::channel(); + let mut engine = Engine::new(sender); + let context = synthetic_context("synthetic-session", json!([])); + let (responses, _) = engine.handle(command(json!({ + "id": "start", + "type": "start", + "context": context.clone(), + }))); + assert_eq!(responses[0]["type"], "ok"); + + let (responses, _) = engine.handle(command(json!({ + "id": "offer", + "type": "offer", + "context": context, + "sdp": "v=0\r\n" + }))); + + assert_eq!(responses[0]["code"], "media-consumer-unavailable"); + assert_eq!(lifecycle_state(&engine), State::Prepared); + } + + #[test] + fn prepared_session_negotiates_synthetic_offer_for_typed_media_consumer() { + let (sender, receiver) = std::sync::mpsc::channel(); + let (media_sender, _media_receiver) = std::sync::mpsc::sync_channel(4); + let mut engine = Engine::with_media_consumer(sender, media_sender); + let context = synthetic_context("synthetic-session", json!([])); + let (responses, _) = engine.handle(command(json!({ + "id": "start", + "type": "start", + "context": context.clone(), + }))); + assert_eq!(responses[0]["type"], "ok"); + + let (responses, _) = engine.handle(command(json!({ + "id": "offer", + "type": "offer", + "context": context, + "sdp": synthetic_offer() + }))); + + assert_eq!(responses[0]["type"], "answer"); + assert!( + responses[0]["answer"]["sdp"] + .as_str() + .is_some_and(|sdp| sdp.contains("m=video") && !sdp.contains("m=video 0")) + ); + assert_eq!(lifecycle_state(&engine), State::Negotiating); + assert!( + receiver + .try_iter() + .any(|value| value["type"] == "local-ice") + ); + } + + #[test] + fn disconnect_clears_context_and_stale_disconnect_cannot_clear_new_session() { + let (sender, receiver) = std::sync::mpsc::channel(); + let mut engine = Engine::new(sender.clone()); + let (responses, _) = engine.handle(command(json!({ + "id": "first", + "type": "start", + "context": synthetic_context("first-session", json!([])), + }))); + assert_eq!(responses[0]["type"], "ok"); + let first_generation = lock_lifecycle(&engine.lifecycle).generation; + forward_transport_event( + &sender, + &engine.lifecycle, + first_generation, + TransportEvent::Disconnected("synthetic disconnect".to_owned()), + ); + { + let lifecycle = lock_lifecycle(&engine.lifecycle); + assert_eq!(lifecycle.state, State::Idle); + assert!(lifecycle.context.is_none()); + } + + let (responses, _) = engine.handle(command(json!({ + "id": "second", + "type": "start", + "context": synthetic_context("second-session", json!([])), + }))); + assert_eq!(responses[0]["type"], "ok"); + forward_transport_event( + &sender, + &engine.lifecycle, + first_generation, + TransportEvent::Disconnected("late stale disconnect".to_owned()), + ); + let lifecycle = lock_lifecycle(&engine.lifecycle); + assert_eq!(lifecycle.state, State::Prepared); + assert_eq!( + lifecycle + .context + .as_ref() + .map(|value| value.session.session_id.as_str()), + Some("second-session") + ); + drop(lifecycle); + + let events = receiver.try_iter().collect::>(); + assert!(events.iter().any(|value| value["status"] == "stopped")); + assert!( + !events + .iter() + .any(|value| value["message"] == "late stale disconnect") + ); + } + + #[test] + fn encoded_media_consumer_is_typed_in_process_and_preserves_arc_payload() { + let (sender, receiver) = std::sync::mpsc::channel(); + let (media_sender, media_receiver) = std::sync::mpsc::sync_channel(4); + let mut engine = Engine::with_media_consumer(sender, media_sender); + let (responses, _) = engine.handle(command(json!({ + "id": "start", + "type": "start", + "context": synthetic_context("synthetic-session", json!([])), + }))); + assert_eq!(responses[0]["type"], "ok"); + let payload: Arc<[u8]> = Arc::from([1_u8, 2, 3]); + engine + .media_consumer + .as_ref() + .expect("media consumer") + .send(EncodedMediaFrame { + mid: "video-0".to_owned(), + codec: "H264".to_owned(), + payload: payload.clone(), + rtp_timestamp: 90_000, + clock_rate_hz: 90_000, + channels: None, + received_at_us: 1_500, + keyframe: true, + contiguous: true, + }) + .expect("frame delivery"); + + let frame = media_receiver.recv().expect("encoded frame"); + assert!(Arc::ptr_eq(&frame.payload, &payload)); + assert_eq!(frame.rtp_timestamp, 90_000); + assert_eq!(frame.clock_rate_hz, 90_000); + assert_eq!(frame.received_at_us, 1_500); + assert!( + receiver + .try_iter() + .all(|value| value["type"] != "encoded-media") + ); + } + + #[test] + fn unapplied_commands_are_rejected_and_stop_clears_context() { + let (sender, _receiver) = std::sync::mpsc::channel(); + let mut engine = Engine::new(sender); + let (responses, _) = engine.handle(command(json!({ + "id": "surface", + "type": "surface", + "surface": {} + }))); + assert_eq!(responses[0]["code"], "unsupported-command"); + + let (responses, _) = engine.handle(command(json!({ + "id": "start", + "type": "start", + "context": synthetic_context("synthetic-session", json!([])), + }))); + assert_eq!(responses[0]["type"], "ok"); + let (responses, _) = engine.handle(command(json!({ + "id": "shortcuts", + "type": "update-shortcuts", + "shortcuts": { "stopStream": "Ctrl+Alt+Q" } + }))); + assert_eq!(responses[0]["code"], "unsupported-command"); + let (responses, _) = engine.handle(command(json!({ + "id": "stop", + "type": "stop", + "reason": "synthetic test complete" + }))); + assert_eq!(responses[0]["type"], "ok"); + let lifecycle = lock_lifecycle(&engine.lifecycle); + assert_eq!(lifecycle.state, State::Idle); + assert!(lifecycle.context.is_none()); + } + + #[test] + fn derives_initial_media_dimensions_from_session_settings() { + assert_eq!( + media_stream_config( + &serde_json::from_value(json!({ + "session": { + "sessionId": "test", + "serverIp": "127.0.0.1", + "negotiatedStreamProfile": { "resolution": "3840x2160" } + }, + "settings": { "resolution": "1920x1080" }, + "shortcuts": {} + })) + .expect("context") + ), + MediaStreamConfig { + width: 3840, + height: 2160, + ..MediaStreamConfig::default() + } + ); + assert_eq!( + media_stream_config( + &serde_json::from_value(json!({ + "session": { "sessionId": "test", "serverIp": "127.0.0.1" }, + "settings": { "resolution": "invalid" }, + "shortcuts": {} + })) + .expect("context") + ), + MediaStreamConfig::default() + ); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/Cargo.toml b/native/opennow-streamer/crates/opennow-streamer-platform-linux/Cargo.toml new file mode 100644 index 000000000..33f94169d --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "opennow-streamer-platform-linux" +version.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +description = "Linux media backend for the OpenNOW native streamer" + +[features] +default = ["vulkan"] +vaapi = ["dep:cros-codecs"] +vulkan = ["dep:ash", "dep:ash-window", "dep:raw-window-handle"] +ffmpeg = ["dep:ffmpeg-next"] +ffmpeg-bundled = [ + "ffmpeg", + "dep:ffmpeg-sys-next", + "ffmpeg-next/build", + "ffmpeg-sys-next/build-portable", + "ffmpeg-sys-next/build-nvdec", + "ffmpeg-sys-next/build-vulkan", +] + +[dependencies] +ash = { version = "0.38", optional = true } +ash-window = { version = "0.13", optional = true } +# This maintained fork zero-initializes libva extension fields, so it remains +# buildable when newer libva headers grow the VP9 parameter structures. +cros-codecs = { package = "cros-codecs-extended", version = "0.0.5-extended.2", features = ["vaapi"], optional = true } +ffmpeg-next = { version = "9.0.0", default-features = false, features = ["format", "software-scaling"], optional = true } +ffmpeg-sys-next = { version = "9.0.0", default-features = false, optional = true } +libc = "0.2" +libloading = "0.8" +raw-window-handle = { version = "0.6", optional = true } +thiserror = "2" + +[dev-dependencies] +static_assertions = "1" + +[lints.rust] +unsafe_op_in_unsafe_fn = "deny" diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/README.md b/native/opennow-streamer/crates/opennow-streamer-platform-linux/README.md new file mode 100644 index 000000000..cad21e1bd --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/README.md @@ -0,0 +1,32 @@ +# OpenNOW Linux platform backend + +This crate owns the Linux hardware decode, audio, and Vulkan presentation path used by the native-streamer workspace. + +The backend accepts H.264, HEVC/H.265, and AV1 video plus Opus audio. With the `ffmpeg` feature, automatic decode prefers CUDA/NVDEC when an NVIDIA driver is present, then Vulkan Video, and finally FFmpeg's software decoder. Native VA-API and stateful V4L2 M2M remain available for H.264. All decoder outputs are normalized to NV12. Presentation prefers a Vulkan swapchain attached to a caller-owned X11 or Wayland surface and automatically falls back to an SDL NV12 texture when Vulkan presentation is unavailable. The integrated streamer decodes Opus from its static library and sends PCM through its bundled SDL audio path; the standalone Linux-session API also exposes PipeWire and ALSA sinks. + +Runtime probing opens the real device or service. A compiled feature or a shared library by itself is never reported as an available decoder, presenter, or audio sink. + +`LinuxSession` owns the bounded decode and audio workers. Submit complete encoded access units and Opus packets, drain decoded frames and typed events, and call `reconfigure` or `stop` explicitly. Queue overflow drops the oldest media, flushes video reference state, and emits `NeedKeyframe` instead of allowing corrupted prediction chains to continue. If a decoder fails, the session advances through the configured fallback order and reuses the current keyframe when possible. + +Presentation stays on the caller's window-system thread. Construct `NativeSurface::borrow_x11` or `NativeSurface::borrow_wayland` from handles that the caller owns, then create `VulkanPresenter` and feed it frames returned by the session. The integrated runtime obtains either pair from SDL's raw window handles: X11 is reparented into Electron, while Wayland remains a compositor-managed top-level surface. The presenter owns its Vulkan instance, device, swapchain, and `VkSurfaceKHR`; it never destroys the borrowed X11 window, Xlib display, `wl_surface`, or `wl_display`. Its lifetime is tied to `NativeSurface`, and it is intentionally not `Send`. + +## Build requirements + +The default developer build needs a Linux C toolchain, Linux UAPI headers, libclang (for `v4l2-sys`), and a Vulkan loader at runtime. VA-API is optional because its maintained Rust bindings generate against the host libva headers. The `ffmpeg` feature uses installed FFmpeg development libraries. Production uses `ffmpeg-bundled`, which builds FFmpeg statically and needs CMake, Make, NASM, pkg-config, and Git but no FFmpeg development package: + +```sh +cargo test -p opennow-streamer-platform-linux +cargo test -p opennow-streamer-platform-linux --features ffmpeg-bundled +cargo check -p opennow-streamer-platform-linux --all-targets +cargo check -p opennow-streamer-platform-linux --all-targets --all-features +./scripts/check-linux.sh +``` + +The last command additionally needs the libva and DRM development packages. Cross-check the architecture-independent path with: + +```sh +rustup target add aarch64-unknown-linux-gnu +cargo check -p opennow-streamer-platform-linux --target aarch64-unknown-linux-gnu --no-default-features +``` + +The V4L2 fallback supports both single-planar and multi-planar stateful decoder nodes used on x86_64, aarch64, and Raspberry Pi. Actual decode tests require `/dev/video*`; VA-API tests require `/dev/dri/renderD*`; Vulkan presentation requires a live X11 or Wayland surface; audio requires an SDL-supported system audio service. The ignored `local_hardware_decodes_all_required_codecs` test performs real Vulkan Video and CUDA/NVDEC decoding when the FFmpeg command-line encoder is installed. Ordinary unit tests do not claim those devices exist. diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/scripts/check-linux.sh b/native/opennow-streamer/crates/opennow-streamer-platform-linux/scripts/check-linux.sh new file mode 100755 index 000000000..d5659f2b4 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/scripts/check-linux.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env sh +set -eu + +cargo check -p opennow-streamer-platform-linux --all-targets +cargo check -p opennow-streamer-platform-linux --all-targets --all-features +cargo test -p opennow-streamer-platform-linux --all-features +cargo clippy -p opennow-streamer-platform-linux --all-targets --all-features -- -D warnings + +if rustup target list --installed | grep -qx aarch64-unknown-linux-gnu; then + cargo check -p opennow-streamer-platform-linux --target aarch64-unknown-linux-gnu --no-default-features + cargo check -p opennow-streamer-platform-linux --target aarch64-unknown-linux-gnu --features vulkan +fi diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/shaders/nv12.frag b/native/opennow-streamer/crates/opennow-streamer-platform-linux/shaders/nv12.frag new file mode 100644 index 000000000..018ac8154 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/shaders/nv12.frag @@ -0,0 +1,56 @@ +#version 450 + +layout(set = 0, binding = 0) uniform sampler2D luma_texture; +layout(set = 0, binding = 1) uniform sampler2D chroma_texture; + +layout(push_constant) uniform Conversion { + vec2 texture_scale; + uint color_matrix; + uint full_range; +} conversion; + +layout(location = 0) in vec2 texture_coordinates; +layout(location = 0) out vec4 output_color; + +void main() { + vec2 source = (texture_coordinates - vec2(0.5)) * conversion.texture_scale + vec2(0.5); + if (any(lessThan(source, vec2(0.0))) || any(greaterThan(source, vec2(1.0)))) { + output_color = vec4(0.0, 0.0, 0.0, 1.0); + return; + } + + float y = texture(luma_texture, source).r; + vec2 uv = texture(chroma_texture, source).rg; + float u; + float v; + if (conversion.full_range != 0) { + u = uv.x - 0.5; + v = uv.y - 0.5; + } else { + y = max(0.0, y - (16.0 / 255.0)) * (255.0 / 219.0); + u = (uv.x - (128.0 / 255.0)) * (255.0 / 224.0); + v = (uv.y - (128.0 / 255.0)) * (255.0 / 224.0); + } + + vec3 rgb; + if (conversion.color_matrix == 0) { + rgb = vec3( + y + 1.402 * v, + y - 0.344136 * u - 0.714136 * v, + y + 1.772 * u + ); + } else if (conversion.color_matrix == 2) { + rgb = vec3( + y + 1.4746 * v, + y - 0.164553 * u - 0.571353 * v, + y + 1.8814 * u + ); + } else { + rgb = vec3( + y + 1.5748 * v, + y - 0.187324 * u - 0.468124 * v, + y + 1.8556 * u + ); + } + output_color = vec4(clamp(rgb, 0.0, 1.0), 1.0); +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/shaders/nv12.frag.spv b/native/opennow-streamer/crates/opennow-streamer-platform-linux/shaders/nv12.frag.spv new file mode 100644 index 000000000..ef0002214 Binary files /dev/null and b/native/opennow-streamer/crates/opennow-streamer-platform-linux/shaders/nv12.frag.spv differ diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/shaders/nv12.vert b/native/opennow-streamer/crates/opennow-streamer-platform-linux/shaders/nv12.vert new file mode 100644 index 000000000..be9612927 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/shaders/nv12.vert @@ -0,0 +1,14 @@ +#version 450 + +layout(location = 0) out vec2 texture_coordinates; + +void main() { + const vec2 positions[3] = vec2[3]( + vec2(-1.0, -1.0), + vec2( 3.0, -1.0), + vec2(-1.0, 3.0) + ); + vec2 position = positions[gl_VertexIndex]; + gl_Position = vec4(position, 0.0, 1.0); + texture_coordinates = (position + 1.0) * 0.5; +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/shaders/nv12.vert.spv b/native/opennow-streamer/crates/opennow-streamer-platform-linux/shaders/nv12.vert.spv new file mode 100644 index 000000000..4ec01555e Binary files /dev/null and b/native/opennow-streamer/crates/opennow-streamer-platform-linux/shaders/nv12.vert.spv differ diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/audio.rs b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/audio.rs new file mode 100644 index 000000000..e4039d4c8 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/audio.rs @@ -0,0 +1,555 @@ +use std::ffi::{CStr, CString, c_char, c_int, c_uint, c_void}; +use std::io::{self, Write}; +use std::mem; +use std::path::PathBuf; +use std::process::{Child, ChildStdin, Command, Stdio}; +use std::ptr::NonNull; +use std::slice; +use std::sync::Arc; + +use libloading::Library; + +use crate::{Error, Result, Subsystem}; + +const OPUS_OK: c_int = 0; +const OPUS_MAX_FRAME_MS: usize = 120; +const SND_PCM_STREAM_PLAYBACK: c_int = 0; +const SND_PCM_ACCESS_RW_INTERLEAVED: c_int = 3; +const SND_PCM_FORMAT_FLOAT_LE: c_int = 14; +const SND_PCM_NONBLOCK: c_int = 1; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AudioBackend { + PipeWire, + Alsa, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AudioBackendPreference { + PipeWireThenAlsa, + AlsaThenPipeWire, + PipeWireOnly, + AlsaOnly, +} + +#[derive(Debug, Clone)] +pub struct AudioConfig { + pub sample_rate: u32, + pub channels: u8, + pub queue_depth: usize, + pub preference: AudioBackendPreference, + pub alsa_device: String, +} + +impl Default for AudioConfig { + fn default() -> Self { + Self { + sample_rate: 48_000, + channels: 2, + queue_depth: 12, + preference: AudioBackendPreference::PipeWireThenAlsa, + alsa_device: "default".to_owned(), + } + } +} + +impl AudioConfig { + pub fn validate(&self) -> Result<()> { + if !matches!(self.sample_rate, 8_000 | 12_000 | 16_000 | 24_000 | 48_000) { + return Err(Error::InvalidFormat(format!( + "Opus sample rate {} is unsupported", + self.sample_rate + ))); + } + if !matches!(self.channels, 1 | 2) { + return Err(Error::InvalidFormat( + "Opus audio must be mono or stereo".to_owned(), + )); + } + if self.queue_depth == 0 || self.queue_depth > 256 { + return Err(Error::InvalidFormat( + "audio queue depth must be between 1 and 256".to_owned(), + )); + } + if self.alsa_device.trim().is_empty() { + return Err(Error::InvalidFormat( + "ALSA device name cannot be empty".to_owned(), + )); + } + Ok(()) + } +} + +#[derive(Debug, Clone)] +pub struct AudioPacket { + pub data: Arc<[u8]>, + pub timestamp_us: u64, +} + +impl AudioPacket { + pub fn new(data: impl Into>, timestamp_us: u64) -> Result { + let data = data.into(); + let packet = Self { data, timestamp_us }; + packet.validate()?; + Ok(packet) + } + + pub fn validate(&self) -> Result<()> { + if self.data.is_empty() { + return Err(Error::InvalidFormat("Opus packet is empty".to_owned())); + } + if self.data.len() > 1275 { + return Err(Error::InvalidFormat( + "Opus packet exceeds the maximum packet size".to_owned(), + )); + } + Ok(()) + } +} + +type OpusDecoderCreate = unsafe extern "C" fn(c_int, c_int, *mut c_int) -> *mut c_void; +type OpusDecodeFloat = + unsafe extern "C" fn(*mut c_void, *const u8, c_int, *mut f32, c_int, c_int) -> c_int; +type OpusDecoderDestroy = unsafe extern "C" fn(*mut c_void); +type OpusStrError = unsafe extern "C" fn(c_int) -> *const c_char; + +pub(crate) struct OpusDecoder { + _library: Library, + handle: NonNull, + decode_float: OpusDecodeFloat, + destroy: OpusDecoderDestroy, + strerror: OpusStrError, + sample_rate: u32, + channels: usize, + pcm: Vec, +} + +impl OpusDecoder { + pub fn open(config: &AudioConfig) -> Result { + config.validate()?; + unsafe { + let library = Library::new("libopus.so.0") + .or_else(|_| Library::new("libopus.so")) + .map_err(|error| Error::unavailable(Subsystem::Opus, error.to_string()))?; + let create: OpusDecoderCreate = *library + .get(b"opus_decoder_create\0") + .map_err(|error| Error::unavailable(Subsystem::Opus, error.to_string()))?; + let decode_float: OpusDecodeFloat = *library + .get(b"opus_decode_float\0") + .map_err(|error| Error::unavailable(Subsystem::Opus, error.to_string()))?; + let destroy: OpusDecoderDestroy = *library + .get(b"opus_decoder_destroy\0") + .map_err(|error| Error::unavailable(Subsystem::Opus, error.to_string()))?; + let strerror: OpusStrError = *library + .get(b"opus_strerror\0") + .map_err(|error| Error::unavailable(Subsystem::Opus, error.to_string()))?; + let mut status = 0; + let handle = NonNull::new(create( + config.sample_rate as c_int, + config.channels as c_int, + &mut status, + )); + if status != OPUS_OK || handle.is_none() { + return Err(Error::backend( + Subsystem::Opus, + opus_error(strerror, status), + )); + } + let channels = config.channels as usize; + let handle = handle.ok_or_else(|| { + Error::backend(Subsystem::Opus, "libopus returned a null decoder") + })?; + Ok(Self { + _library: library, + handle, + decode_float, + destroy, + strerror, + sample_rate: config.sample_rate, + channels, + pcm: vec![0.0; config.sample_rate as usize * OPUS_MAX_FRAME_MS / 1000 * channels], + }) + } + } + + pub fn decode<'a>(&'a mut self, packet: &AudioPacket) -> Result<&'a [f32]> { + let max_samples_per_channel = self.sample_rate as usize * OPUS_MAX_FRAME_MS / 1000; + let samples_per_channel = unsafe { + (self.decode_float)( + self.handle.as_ptr(), + packet.data.as_ptr(), + packet.data.len().min(c_int::MAX as usize) as c_int, + self.pcm.as_mut_ptr(), + max_samples_per_channel as c_int, + 0, + ) + }; + if samples_per_channel < 0 { + return Err(Error::backend(Subsystem::Opus, unsafe { + opus_error(self.strerror, samples_per_channel) + })); + } + Ok(&self.pcm[..samples_per_channel as usize * self.channels]) + } +} + +impl Drop for OpusDecoder { + fn drop(&mut self) { + unsafe { (self.destroy)(self.handle.as_ptr()) } + } +} + +unsafe fn opus_error(strerror: OpusStrError, code: c_int) -> String { + let pointer = unsafe { strerror(code) }; + if pointer.is_null() { + return format!("libopus error {code}"); + } + unsafe { CStr::from_ptr(pointer) } + .to_string_lossy() + .into_owned() +} + +pub(crate) trait AudioSink { + fn backend(&self) -> AudioBackend; + fn write(&mut self, pcm: &[f32], cancelled: &dyn Fn() -> bool) -> Result<()>; +} + +pub(crate) fn open_audio_sink(config: &AudioConfig) -> Result> { + config.validate()?; + let order: &[AudioBackend] = match config.preference { + AudioBackendPreference::PipeWireThenAlsa => &[AudioBackend::PipeWire, AudioBackend::Alsa], + AudioBackendPreference::AlsaThenPipeWire => &[AudioBackend::Alsa, AudioBackend::PipeWire], + AudioBackendPreference::PipeWireOnly => &[AudioBackend::PipeWire], + AudioBackendPreference::AlsaOnly => &[AudioBackend::Alsa], + }; + let mut failures = Vec::new(); + for backend in order { + let opened: Result> = match backend { + AudioBackend::PipeWire => { + PipeWireSink::open(config).map(|sink| Box::new(sink) as Box) + } + AudioBackend::Alsa => { + AlsaSink::open(config).map(|sink| Box::new(sink) as Box) + } + }; + match opened { + Ok(sink) => return Ok(sink), + Err(error) => failures.push(error.to_string()), + } + } + Err(Error::unavailable( + Subsystem::Session, + format!("no requested audio backend opened: {}", failures.join("; ")), + )) +} + +pub(crate) fn open_audio_fallback( + config: &AudioConfig, + current: AudioBackend, +) -> Result> { + let preference = match (config.preference, current) { + (AudioBackendPreference::PipeWireThenAlsa, AudioBackend::PipeWire) + | (AudioBackendPreference::AlsaThenPipeWire, AudioBackend::PipeWire) => { + AudioBackendPreference::AlsaOnly + } + (AudioBackendPreference::PipeWireThenAlsa, AudioBackend::Alsa) + | (AudioBackendPreference::AlsaThenPipeWire, AudioBackend::Alsa) => { + AudioBackendPreference::PipeWireOnly + } + _ => { + return Err(Error::unavailable( + Subsystem::Session, + "audio preference forbids fallback", + )); + } + }; + open_audio_sink(&AudioConfig { + preference, + ..config.clone() + }) +} + +pub(crate) fn probe_audio_backend(backend: AudioBackend) -> std::result::Result { + let config = AudioConfig { + preference: match backend { + AudioBackend::PipeWire => AudioBackendPreference::PipeWireOnly, + AudioBackend::Alsa => AudioBackendPreference::AlsaOnly, + }, + ..AudioConfig::default() + }; + open_audio_sink(&config) + .map(|sink| format!("{:?} opened at 48kHz stereo", sink.backend())) + .map_err(|error| error.to_string()) +} + +type SndPcmOpen = unsafe extern "C" fn(*mut *mut c_void, *const c_char, c_int, c_int) -> c_int; +type SndPcmSetParams = + unsafe extern "C" fn(*mut c_void, c_int, c_int, c_uint, c_uint, c_int, c_uint) -> c_int; +type SndPcmWriteI = unsafe extern "C" fn(*mut c_void, *const c_void, libc::c_ulong) -> libc::c_long; +type SndPcmRecover = unsafe extern "C" fn(*mut c_void, c_int, c_int) -> c_int; +type SndPcmDrop = unsafe extern "C" fn(*mut c_void) -> c_int; +type SndPcmClose = unsafe extern "C" fn(*mut c_void) -> c_int; +type SndStrError = unsafe extern "C" fn(c_int) -> *const c_char; + +struct AlsaSink { + _library: Library, + handle: NonNull, + writei: SndPcmWriteI, + recover: SndPcmRecover, + drop_pcm: SndPcmDrop, + close: SndPcmClose, + strerror: SndStrError, + channels: usize, +} + +unsafe impl Send for AlsaSink {} + +impl AlsaSink { + fn open(config: &AudioConfig) -> Result { + unsafe { + let library = Library::new("libasound.so.2") + .or_else(|_| Library::new("libasound.so")) + .map_err(|error| Error::unavailable(Subsystem::Alsa, error.to_string()))?; + let open: SndPcmOpen = *load_symbol(&library, b"snd_pcm_open\0")?; + let set_params: SndPcmSetParams = *load_symbol(&library, b"snd_pcm_set_params\0")?; + let writei: SndPcmWriteI = *load_symbol(&library, b"snd_pcm_writei\0")?; + let recover: SndPcmRecover = *load_symbol(&library, b"snd_pcm_recover\0")?; + let drop_pcm: SndPcmDrop = *load_symbol(&library, b"snd_pcm_drop\0")?; + let close: SndPcmClose = *load_symbol(&library, b"snd_pcm_close\0")?; + let strerror: SndStrError = *load_symbol(&library, b"snd_strerror\0")?; + let name = CString::new(config.alsa_device.as_str()).map_err(|_| { + Error::InvalidFormat("ALSA device contains an embedded NUL".to_owned()) + })?; + let mut raw = std::ptr::null_mut(); + let status = open( + &mut raw, + name.as_ptr(), + SND_PCM_STREAM_PLAYBACK, + SND_PCM_NONBLOCK, + ); + if status < 0 { + return Err(Error::unavailable( + Subsystem::Alsa, + alsa_error(strerror, status), + )); + } + let handle = NonNull::new(raw).ok_or_else(|| { + Error::backend(Subsystem::Alsa, "ALSA returned a null PCM handle") + })?; + let status = set_params( + handle.as_ptr(), + SND_PCM_FORMAT_FLOAT_LE, + SND_PCM_ACCESS_RW_INTERLEAVED, + config.channels as c_uint, + config.sample_rate, + 1, + 50_000, + ); + if status < 0 { + close(handle.as_ptr()); + return Err(Error::unavailable( + Subsystem::Alsa, + alsa_error(strerror, status), + )); + } + Ok(Self { + _library: library, + handle, + writei, + recover, + drop_pcm, + close, + strerror, + channels: config.channels as usize, + }) + } + } +} + +impl AudioSink for AlsaSink { + fn backend(&self) -> AudioBackend { + AudioBackend::Alsa + } + + fn write(&mut self, pcm: &[f32], cancelled: &dyn Fn() -> bool) -> Result<()> { + let mut offset = 0; + while offset < pcm.len() { + if cancelled() { + return Err(Error::QueueClosed); + } + let frames = (pcm.len() - offset) / self.channels; + let written = unsafe { + (self.writei)( + self.handle.as_ptr(), + pcm[offset..].as_ptr().cast(), + frames as libc::c_ulong, + ) + }; + if written < 0 { + if written as c_int == -libc::EAGAIN { + std::thread::sleep(std::time::Duration::from_millis(2)); + continue; + } + let recovered = + unsafe { (self.recover)(self.handle.as_ptr(), written as c_int, 1) }; + if recovered < 0 { + return Err(Error::DeviceLost { + subsystem: Subsystem::Alsa, + reason: unsafe { alsa_error(self.strerror, recovered) }, + }); + } + continue; + } + if written == 0 { + return Err(Error::backend(Subsystem::Alsa, "zero-length PCM write")); + } + offset += written as usize * self.channels; + } + Ok(()) + } +} + +impl Drop for AlsaSink { + fn drop(&mut self) { + unsafe { + (self.drop_pcm)(self.handle.as_ptr()); + (self.close)(self.handle.as_ptr()); + } + } +} + +unsafe fn load_symbol<'a, T>( + library: &'a Library, + name: &[u8], +) -> Result> { + unsafe { library.get(name) } + .map_err(|error| Error::unavailable(Subsystem::Alsa, error.to_string())) +} + +unsafe fn alsa_error(strerror: SndStrError, code: c_int) -> String { + let pointer = unsafe { strerror(code) }; + if pointer.is_null() { + return format!("ALSA error {code}"); + } + unsafe { CStr::from_ptr(pointer) } + .to_string_lossy() + .into_owned() +} + +struct PipeWireSink { + child: Child, + stdin: ChildStdin, +} + +impl PipeWireSink { + fn open(config: &AudioConfig) -> Result { + pipewire_socket().ok_or_else(|| { + Error::unavailable( + Subsystem::PipeWire, + "the PipeWire socket was not found under XDG_RUNTIME_DIR", + ) + })?; + let executable = find_in_path("pw-cat").ok_or_else(|| { + Error::unavailable(Subsystem::PipeWire, "pw-cat was not found in PATH") + })?; + let mut child = Command::new(executable) + .args([ + "--playback", + "--raw", + "--format", + "f32", + "--rate", + &config.sample_rate.to_string(), + "--channels", + &config.channels.to_string(), + "-", + ]) + .stdin(Stdio::piped()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .map_err(|error| Error::io(Subsystem::PipeWire, error))?; + let stdin = child + .stdin + .take() + .ok_or_else(|| Error::backend(Subsystem::PipeWire, "pw-cat stdin was not created"))?; + let descriptor = std::os::fd::AsRawFd::as_raw_fd(&stdin); + let flags = unsafe { libc::fcntl(descriptor, libc::F_GETFL) }; + if flags < 0 + || unsafe { libc::fcntl(descriptor, libc::F_SETFL, flags | libc::O_NONBLOCK) } < 0 + { + let error = io::Error::last_os_error(); + let _ = child.kill(); + let _ = child.wait(); + return Err(Error::io(Subsystem::PipeWire, error)); + } + std::thread::sleep(std::time::Duration::from_millis(30)); + if let Some(status) = child + .try_wait() + .map_err(|error| Error::io(Subsystem::PipeWire, error))? + { + return Err(Error::unavailable( + Subsystem::PipeWire, + format!("pw-cat exited during startup with {status}"), + )); + } + Ok(Self { child, stdin }) + } +} + +impl AudioSink for PipeWireSink { + fn backend(&self) -> AudioBackend { + AudioBackend::PipeWire + } + + fn write(&mut self, pcm: &[f32], cancelled: &dyn Fn() -> bool) -> Result<()> { + let bytes = + unsafe { slice::from_raw_parts(pcm.as_ptr().cast::(), mem::size_of_val(pcm)) }; + let mut offset = 0; + while offset < bytes.len() { + if cancelled() { + return Err(Error::QueueClosed); + } + match self.stdin.write(&bytes[offset..]) { + Ok(0) => { + return Err(Error::DeviceLost { + subsystem: Subsystem::PipeWire, + reason: "pw-cat closed its input".to_owned(), + }); + } + Ok(written) => offset += written, + Err(error) if error.kind() == io::ErrorKind::Interrupted => {} + Err(error) if error.kind() == io::ErrorKind::WouldBlock => { + std::thread::sleep(std::time::Duration::from_millis(2)); + } + Err(error) => { + return Err(Error::DeviceLost { + subsystem: Subsystem::PipeWire, + reason: error.to_string(), + }); + } + } + } + Ok(()) + } +} + +impl Drop for PipeWireSink { + fn drop(&mut self) { + let _ = self.stdin.flush(); + let _ = self.child.kill(); + let _ = self.child.wait(); + } +} + +fn pipewire_socket() -> Option { + let runtime = std::env::var_os("XDG_RUNTIME_DIR")?; + let socket = PathBuf::from(runtime).join("pipewire-0"); + socket.exists().then_some(socket) +} + +fn find_in_path(executable: &str) -> Option { + std::env::split_paths(&std::env::var_os("PATH")?) + .map(|path| path.join(executable)) + .find(|candidate| candidate.is_file()) +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/capability.rs b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/capability.rs new file mode 100644 index 000000000..1a54f2169 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/capability.rs @@ -0,0 +1,126 @@ +use crate::VideoCodec; +use crate::audio::{AudioBackend, probe_audio_backend}; +use crate::video::{ + probe_ffmpeg_cuda, probe_ffmpeg_software, probe_ffmpeg_vulkan, probe_v4l2_devices, probe_vaapi, +}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct BackendCapability { + pub name: &'static str, + pub available: bool, + pub detail: String, +} + +impl BackendCapability { + fn from_probe(name: &'static str, probe: std::result::Result) -> Self { + match probe { + Ok(detail) => Self { + name, + available: true, + detail, + }, + Err(detail) => Self { + name, + available: false, + detail, + }, + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PresentationCapability { + pub available: bool, + pub api: &'static str, + pub window_systems: Vec<&'static str>, + pub detail: String, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct CapabilityReport { + pub architecture: &'static str, + pub video_decoders: Vec, + pub presentation: PresentationCapability, + pub audio_outputs: Vec, +} + +pub fn probe_video_capabilities() -> (Vec, PresentationCapability) { + let v4l2_devices = probe_v4l2_devices(); + let v4l2 = if v4l2_devices.is_empty() { + Err("no usable stateful H.264 M2M node under /dev/video*".to_owned()) + } else { + Ok(v4l2_devices + .iter() + .map(|device| device.description()) + .collect::>() + .join(", ")) + }; + + #[cfg(feature = "vulkan")] + let presentation = match crate::presentation::probe_vulkan() { + Ok((window_systems, detail)) => PresentationCapability { + available: true, + api: "vulkan", + window_systems, + detail, + }, + Err(detail) => PresentationCapability { + available: false, + api: "vulkan", + window_systems: Vec::new(), + detail, + }, + }; + #[cfg(not(feature = "vulkan"))] + let presentation = PresentationCapability { + available: false, + api: "vulkan", + window_systems: Vec::new(), + detail: "crate was built without the vulkan feature".to_owned(), + }; + + ( + vec![ + BackendCapability::from_probe("vaapi-h264", probe_vaapi()), + BackendCapability::from_probe("v4l2-h264", v4l2), + BackendCapability::from_probe( + "vulkan-video-h264", + probe_ffmpeg_vulkan(VideoCodec::H264), + ), + BackendCapability::from_probe( + "vulkan-video-h265", + probe_ffmpeg_vulkan(VideoCodec::H265), + ), + BackendCapability::from_probe("vulkan-video-av1", probe_ffmpeg_vulkan(VideoCodec::Av1)), + BackendCapability::from_probe("cuda-h264", probe_ffmpeg_cuda(VideoCodec::H264)), + BackendCapability::from_probe("cuda-h265", probe_ffmpeg_cuda(VideoCodec::H265)), + BackendCapability::from_probe("cuda-av1", probe_ffmpeg_cuda(VideoCodec::Av1)), + BackendCapability::from_probe( + "ffmpeg-software-h264", + probe_ffmpeg_software(VideoCodec::H264), + ), + BackendCapability::from_probe( + "ffmpeg-software-h265", + probe_ffmpeg_software(VideoCodec::H265), + ), + BackendCapability::from_probe( + "ffmpeg-software-av1", + probe_ffmpeg_software(VideoCodec::Av1), + ), + ], + presentation, + ) +} + +pub fn probe_capabilities() -> CapabilityReport { + let (video_decoders, presentation) = probe_video_capabilities(); + CapabilityReport { + architecture: std::env::consts::ARCH, + video_decoders, + presentation, + audio_outputs: vec![ + BackendCapability::from_probe("pipewire", probe_audio_backend(AudioBackend::PipeWire)), + BackendCapability::from_probe("alsa", probe_audio_backend(AudioBackend::Alsa)), + ], + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/error.rs b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/error.rs new file mode 100644 index 000000000..82b25e893 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/error.rs @@ -0,0 +1,77 @@ +use std::io; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Subsystem { + VaApi, + V4l2, + Vulkan, + Ffmpeg, + Opus, + PipeWire, + Alsa, + Session, +} + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("{subsystem:?} is unavailable: {reason}")] + Unavailable { + subsystem: Subsystem, + reason: String, + }, + #[error("{subsystem:?} device was lost: {reason}")] + DeviceLost { + subsystem: Subsystem, + reason: String, + }, + #[error("invalid media format: {0}")] + InvalidFormat(String), + #[error("queue is closed")] + QueueClosed, + #[error("session is not running")] + NotRunning, + #[error("{subsystem:?} I/O failed: {source}")] + Io { + subsystem: Subsystem, + #[source] + source: io::Error, + }, + #[error("{subsystem:?} operation failed: {reason}")] + Backend { + subsystem: Subsystem, + reason: String, + }, + #[error("worker thread panicked: {0}")] + WorkerPanic(&'static str), +} + +impl Error { + pub(crate) fn unavailable(subsystem: Subsystem, reason: impl Into) -> Self { + Self::Unavailable { + subsystem, + reason: reason.into(), + } + } + + pub(crate) fn backend(subsystem: Subsystem, reason: impl Into) -> Self { + Self::Backend { + subsystem, + reason: reason.into(), + } + } + + pub(crate) fn io(subsystem: Subsystem, source: io::Error) -> Self { + if matches!( + source.raw_os_error(), + Some(libc::ENODEV | libc::EIO | libc::ENXIO) + ) { + return Self::DeviceLost { + subsystem, + reason: source.to_string(), + }; + } + Self::Io { subsystem, source } + } +} + +pub type Result = std::result::Result; diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/format.rs b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/format.rs new file mode 100644 index 000000000..6800f9262 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/format.rs @@ -0,0 +1,509 @@ +use std::fmt; +use std::os::fd::RawFd; +use std::sync::Arc; + +use crate::{Error, Result}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum VideoCodec { + H264, + H265, + Av1, +} + +impl VideoCodec { + pub const fn label(self) -> &'static str { + match self { + Self::H264 => "h264", + Self::H265 => "h265", + Self::Av1 => "av1", + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PixelFormat { + Nv12, + I420, + Bgra8, + Rgba8, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ColorRange { + Limited, + Full, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ColorMatrix { + Bt601, + Bt709, + Bt2020, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ChromaLocation { + Left, + Center, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct StreamFormat { + pub width: u32, + pub height: u32, + pub pixel_format: PixelFormat, + pub color_range: ColorRange, + pub color_matrix: ColorMatrix, + pub chroma_location: ChromaLocation, +} + +impl StreamFormat { + pub fn video_default(width: u32, height: u32) -> Result { + let format = Self { + width, + height, + pixel_format: PixelFormat::Nv12, + color_range: ColorRange::Limited, + color_matrix: if height > 576 { + ColorMatrix::Bt709 + } else { + ColorMatrix::Bt601 + }, + chroma_location: ChromaLocation::Left, + }; + format.validate()?; + Ok(format) + } + + pub fn h264_default(width: u32, height: u32) -> Result { + Self::video_default(width, height) + } + + pub fn validate(&self) -> Result<()> { + if self.width == 0 || self.height == 0 { + return Err(Error::InvalidFormat( + "video dimensions must be non-zero".to_owned(), + )); + } + if self.width > 16_384 || self.height > 16_384 { + return Err(Error::InvalidFormat( + "video dimensions exceed the Linux backend limit".to_owned(), + )); + } + if matches!(self.pixel_format, PixelFormat::Nv12 | PixelFormat::I420) + && (self.width % 2 != 0 || self.height % 2 != 0) + { + return Err(Error::InvalidFormat( + "4:2:0 video dimensions must be even".to_owned(), + )); + } + Ok(()) + } +} + +#[derive(Debug, Clone)] +pub struct EncodedVideoFrame { + pub data: Arc<[u8]>, + pub timestamp_us: u64, + pub keyframe: bool, +} + +impl EncodedVideoFrame { + pub fn new(data: impl Into>, timestamp_us: u64, keyframe: bool) -> Result { + let data = data.into(); + let frame = Self { + data, + timestamp_us, + keyframe, + }; + frame.validate()?; + Ok(frame) + } + + pub fn validate(&self) -> Result<()> { + if self.data.is_empty() { + return Err(Error::InvalidFormat( + "video access unit is empty".to_owned(), + )); + } + if self.data.len() > 16 * 1024 * 1024 { + return Err(Error::InvalidFormat( + "video access unit exceeds 16 MiB".to_owned(), + )); + } + Ok(()) + } +} + +#[derive(Debug, Clone)] +pub struct FramePlane { + pub data: Arc<[u8]>, + pub stride: usize, + pub rows: usize, +} + +#[derive(Debug, Clone)] +pub struct FrameOverlay { + pub origin_x: u32, + pub origin_y: u32, + pub width: u32, + pub height: u32, + pub luma: FramePlane, + pub chroma: FramePlane, +} + +impl FramePlane { + pub fn validate(&self, minimum_row_bytes: usize) -> Result<()> { + if self.stride < minimum_row_bytes { + return Err(Error::InvalidFormat(format!( + "plane stride {} is less than the required {minimum_row_bytes}", + self.stride + ))); + } + let required = self + .stride + .checked_mul(self.rows) + .ok_or_else(|| Error::InvalidFormat("plane size overflow".to_owned()))?; + if self.data.len() < required { + return Err(Error::InvalidFormat(format!( + "plane has {} bytes but requires {required}", + self.data.len() + ))); + } + Ok(()) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DmaBufObject { + pub fd: RawFd, + pub size: usize, + pub format_modifier: u64, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DmaBufPlane { + pub object_index: usize, + pub offset: usize, + pub pitch: usize, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct DmaBufLayer { + pub format: u32, + pub planes: Vec, +} + +/// A decoded hardware frame exported through DRM PRIME. `owner` retains the +/// FFmpeg/VAAPI frame and therefore the dma-buf file descriptors until the +/// Vulkan submission that samples them has completed. +pub struct DmaBufFrame { + pub objects: Vec, + pub layers: Vec, + owner: Arc, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct VulkanImage { + pub image: u64, + pub format: i32, + pub width: u32, + pub height: u32, + pub layout: i32, + pub access: u64, + pub semaphore: u64, + pub semaphore_value: u64, + pub queue_family: u32, +} + +/// A Vulkan Video output surface on the decoder's own Vulkan device. The +/// presenter adopts this device and samples these image handles directly. +pub struct VulkanVideoFrame { + pub instance: usize, + pub physical_device: usize, + pub device: usize, + pub queue_families: Vec, + pub image_usage: u32, + pub image_flags: u32, + pub images: Vec, + device_context: usize, + lock_queue: Option, + unlock_queue: Option, + owner: Arc, +} + +impl VulkanVideoFrame { + #[allow(clippy::too_many_arguments)] + pub fn new( + instance: usize, + physical_device: usize, + device: usize, + queue_families: Vec, + image_usage: u32, + image_flags: u32, + images: Vec, + device_context: usize, + lock_queue: Option, + unlock_queue: Option, + owner: Arc, + ) -> Self { + Self { + instance, + physical_device, + device, + queue_families, + image_usage, + image_flags, + images, + device_context, + lock_queue, + unlock_queue, + owner, + } + } + + pub fn validate(&self) -> Result<()> { + if self.instance == 0 + || self.physical_device == 0 + || self.device == 0 + || self.images.is_empty() + || self.images.len() > 2 + || self.queue_families.is_empty() + || self.images.iter().any(|image| image.image == 0) + { + return Err(Error::InvalidFormat( + "Vulkan Video frame has invalid device or image handles".to_owned(), + )); + } + Ok(()) + } + + pub fn retain_owner(&self) -> &Arc { + &self.owner + } + + pub(crate) fn lock_presentation_queue(&self, family: u32) { + if let Some(lock) = self.lock_queue { + unsafe { lock(self.device_context as *mut std::ffi::c_void, family, 0) }; + } + } + + pub(crate) fn unlock_presentation_queue(&self, family: u32) { + if let Some(unlock) = self.unlock_queue { + unsafe { unlock(self.device_context as *mut std::ffi::c_void, family, 0) }; + } + } +} + +impl fmt::Debug for VulkanVideoFrame { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("VulkanVideoFrame") + .field("instance", &self.instance) + .field("physical_device", &self.physical_device) + .field("device", &self.device) + .field("queue_families", &self.queue_families) + .field("images", &self.images) + .finish_non_exhaustive() + } +} + +impl DmaBufFrame { + pub fn new( + objects: Vec, + layers: Vec, + owner: Arc, + ) -> Self { + Self { + objects, + layers, + owner, + } + } + + pub fn validate(&self) -> Result<()> { + if self.objects.is_empty() || self.layers.is_empty() { + return Err(Error::InvalidFormat( + "DMA-BUF frame has no objects or layers".to_owned(), + )); + } + for object in &self.objects { + if object.fd < 0 || object.size == 0 { + return Err(Error::InvalidFormat( + "DMA-BUF frame has an invalid object".to_owned(), + )); + } + } + for layer in &self.layers { + if layer.planes.is_empty() + || layer + .planes + .iter() + .any(|plane| plane.object_index >= self.objects.len() || plane.pitch == 0) + { + return Err(Error::InvalidFormat( + "DMA-BUF frame has an invalid layer".to_owned(), + )); + } + } + Ok(()) + } + + pub fn retain_owner(&self) -> &Arc { + &self.owner + } +} + +impl fmt::Debug for DmaBufFrame { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("DmaBufFrame") + .field("objects", &self.objects) + .field("layers", &self.layers) + .finish_non_exhaustive() + } +} + +#[derive(Debug, Clone)] +pub struct DecodedVideoFrame { + pub format: StreamFormat, + pub planes: Vec, + pub dmabuf: Option>, + pub vulkan: Option>, + pub overlay: Option, + pub timestamp_us: u64, +} + +impl DecodedVideoFrame { + pub fn validate(&self) -> Result<()> { + self.format.validate()?; + if let Some(overlay) = &self.overlay { + if overlay.width == 0 + || overlay.height == 0 + || overlay.width % 2 != 0 + || overlay.height % 2 != 0 + || overlay.origin_x.saturating_add(overlay.width) > self.format.width + || overlay.origin_y.saturating_add(overlay.height) > self.format.height + { + return Err(Error::InvalidFormat( + "frame overlay has invalid bounds".to_owned(), + )); + } + overlay.luma.validate(overlay.width as usize)?; + overlay.chroma.validate(overlay.width as usize)?; + } + if let Some(vulkan) = &self.vulkan { + vulkan.validate()?; + return Ok(()); + } + if let Some(dmabuf) = &self.dmabuf { + dmabuf.validate()?; + return Ok(()); + } + let width = self.format.width as usize; + let height = self.format.height as usize; + match self.format.pixel_format { + PixelFormat::Nv12 => { + if self.planes.len() != 2 { + return Err(Error::InvalidFormat( + "NV12 frames require two planes".to_owned(), + )); + } + self.planes[0].validate(width)?; + self.planes[1].validate(width)?; + if self.planes[0].rows < height || self.planes[1].rows < height / 2 { + return Err(Error::InvalidFormat( + "NV12 plane height is too small".to_owned(), + )); + } + } + PixelFormat::I420 => { + if self.planes.len() != 3 { + return Err(Error::InvalidFormat( + "I420 frames require three planes".to_owned(), + )); + } + self.planes[0].validate(width)?; + self.planes[1].validate(width / 2)?; + self.planes[2].validate(width / 2)?; + if self.planes[0].rows < height + || self.planes[1].rows < height / 2 + || self.planes[2].rows < height / 2 + { + return Err(Error::InvalidFormat( + "I420 plane height is too small".to_owned(), + )); + } + } + PixelFormat::Bgra8 | PixelFormat::Rgba8 => { + if self.planes.len() != 1 { + return Err(Error::InvalidFormat( + "packed RGB frames require one plane".to_owned(), + )); + } + self.planes[0].validate(width * 4)?; + if self.planes[0].rows < height { + return Err(Error::InvalidFormat( + "packed RGB plane height is too small".to_owned(), + )); + } + } + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn accepts_padded_nv12_planes() { + let frame = DecodedVideoFrame { + format: StreamFormat::h264_default(4, 4).unwrap(), + planes: vec![ + FramePlane { + data: Arc::from(vec![0_u8; 32]), + stride: 8, + rows: 4, + }, + FramePlane { + data: Arc::from(vec![0_u8; 16]), + stride: 8, + rows: 2, + }, + ], + dmabuf: None, + vulkan: None, + overlay: None, + timestamp_us: 1, + }; + frame.validate().unwrap(); + } + + #[test] + fn rejects_odd_420_dimensions_and_short_planes() { + assert!(StreamFormat::h264_default(1919, 1080).is_err()); + let frame = DecodedVideoFrame { + format: StreamFormat::h264_default(4, 4).unwrap(), + planes: vec![ + FramePlane { + data: Arc::from(vec![0_u8; 15]), + stride: 4, + rows: 4, + }, + FramePlane { + data: Arc::from(vec![0_u8; 8]), + stride: 4, + rows: 2, + }, + ], + dmabuf: None, + vulkan: None, + overlay: None, + timestamp_us: 1, + }; + assert!(frame.validate().is_err()); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/lib.rs b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/lib.rs new file mode 100644 index 000000000..adb4c8afe --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/lib.rs @@ -0,0 +1,45 @@ +#[cfg(all( + target_os = "linux", + not(any(target_arch = "x86_64", target_arch = "aarch64")) +))] +compile_error!("the Linux backend currently supports x86_64 and aarch64"); + +#[cfg(target_os = "linux")] +mod audio; +#[cfg(target_os = "linux")] +mod capability; +#[cfg(target_os = "linux")] +mod error; +#[cfg(target_os = "linux")] +mod format; +#[cfg(all(target_os = "linux", feature = "vulkan"))] +mod presentation; +#[cfg(target_os = "linux")] +mod queue; +#[cfg(target_os = "linux")] +mod session; +#[cfg(target_os = "linux")] +mod video; + +#[cfg(target_os = "linux")] +pub use audio::{AudioBackend, AudioBackendPreference, AudioConfig, AudioPacket}; +#[cfg(target_os = "linux")] +pub use capability::{ + BackendCapability, CapabilityReport, PresentationCapability, probe_capabilities, + probe_video_capabilities, +}; +#[cfg(target_os = "linux")] +pub use error::{Error, Result, Subsystem}; +#[cfg(target_os = "linux")] +pub use format::{ + ChromaLocation, ColorMatrix, ColorRange, DecodedVideoFrame, DmaBufFrame, DmaBufLayer, + DmaBufObject, DmaBufPlane, EncodedVideoFrame, FrameOverlay, FramePlane, PixelFormat, + StreamFormat, VideoCodec, VulkanImage, VulkanVideoFrame, +}; +#[cfg(all(target_os = "linux", feature = "vulkan"))] +pub use presentation::{NativeSurface, VulkanPresenter}; +#[cfg(target_os = "linux")] +pub use session::{ + BackendEvent, DecoderBackend, DecoderPreference, LifecycleState, LinuxSession, PushOutcome, + SessionConfig, +}; diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/presentation.rs b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/presentation.rs new file mode 100644 index 000000000..4d155357d --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/presentation.rs @@ -0,0 +1,2609 @@ +use std::collections::HashMap; +use std::ffi::{CStr, c_void}; +use std::io::Cursor; +use std::marker::PhantomData; +use std::num::NonZeroU64; +use std::os::fd::RawFd; +use std::ptr::NonNull; +use std::rc::Rc; +use std::sync::Arc; + +use ash::vk::Handle; +use ash::{Entry, Instance, vk}; +use raw_window_handle::{ + RawDisplayHandle, RawWindowHandle, WaylandDisplayHandle, WaylandWindowHandle, + XlibDisplayHandle, XlibWindowHandle, +}; + +use crate::{ + ColorMatrix, ColorRange, DecodedVideoFrame, DmaBufFrame, DmaBufPlane, Error, PixelFormat, + Result, Subsystem, VulkanVideoFrame, +}; + +const PRESENT_WAIT_NS: u64 = 1_000_000_000; +const ACQUIRE_WAIT_NS: u64 = 50_000_000; +const NV12_VERTEX_SHADER: &[u8] = include_bytes!("../shaders/nv12.vert.spv"); +const NV12_FRAGMENT_SHADER: &[u8] = include_bytes!("../shaders/nv12.frag.spv"); +const DRM_FORMAT_NV12: u32 = fourcc(b'N', b'V', b'1', b'2'); +const DRM_FORMAT_R8: u32 = fourcc(b'R', b'8', b' ', b' '); +const DRM_FORMAT_GR88: u32 = fourcc(b'G', b'R', b'8', b'8'); +const MAX_IMPORTED_DMABUF_IMAGES: usize = 32; + +const fn fourcc(a: u8, b: u8, c: u8, d: u8) -> u32 { + a as u32 | ((b as u32) << 8) | ((c as u32) << 16) | ((d as u32) << 24) +} + +struct GpuImage { + image: vk::Image, + memory: vk::DeviceMemory, + view: vk::ImageView, +} + +struct Nv12Images { + width: u32, + height: u32, + luma: GpuImage, + chroma: GpuImage, + initialized: bool, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +struct DmaBufKey { + device: u64, + inode: u64, + width: u32, + height: u32, + modifier: u64, + luma_offset: usize, + luma_pitch: usize, + chroma_offset: usize, + chroma_pitch: usize, +} + +struct ImportedDmaBufImage { + image: vk::Image, + memory: vk::DeviceMemory, + luma_view: vk::ImageView, + chroma_view: vk::ImageView, +} + +struct DirectVulkanViews { + luma: vk::ImageView, + chroma: vk::ImageView, +} + +pub enum NativeSurface<'a> { + X11 { + display: NonNull, + window: NonZeroU64, + screen: i32, + _owner: PhantomData<&'a mut c_void>, + }, + Wayland { + display: NonNull, + surface: NonNull, + _owner: PhantomData<&'a mut c_void>, + }, +} + +impl<'a> NativeSurface<'a> { + /// Borrows an Xlib display and window owned by the caller. + /// + /// # Safety + /// + /// `display` and `window` must identify a live X11 surface, Xlib threading must be initialized + /// when other threads use the display, and both handles must outlive the returned value and + /// every presenter borrowing it. The backend never closes or destroys either handle. + pub unsafe fn borrow_x11(display: NonNull, window: NonZeroU64, screen: i32) -> Self { + Self::X11 { + display, + window, + screen, + _owner: PhantomData, + } + } + + /// Borrows a Wayland display and wl_surface owned by the caller. + /// + /// # Safety + /// + /// Both pointers must remain live, the surface must be used on its owning Wayland thread, and + /// they must outlive the returned value and every presenter borrowing it. The backend never + /// disconnects the display or destroys the wl_surface. + pub unsafe fn borrow_wayland(display: NonNull, surface: NonNull) -> Self { + Self::Wayland { + display, + surface, + _owner: PhantomData, + } + } + + fn raw_display_handle(&self) -> RawDisplayHandle { + match self { + Self::X11 { + display, screen, .. + } => RawDisplayHandle::Xlib(XlibDisplayHandle::new(Some(*display), *screen)), + Self::Wayland { display, .. } => { + RawDisplayHandle::Wayland(WaylandDisplayHandle::new(*display)) + } + } + } + + fn raw_window_handle(&self) -> RawWindowHandle { + match self { + Self::X11 { window, .. } => { + RawWindowHandle::Xlib(XlibWindowHandle::new(window.get() as libc::c_ulong)) + } + Self::Wayland { surface, .. } => { + RawWindowHandle::Wayland(WaylandWindowHandle::new(*surface)) + } + } + } +} + +pub struct VulkanPresenter { + _entry: Entry, + instance: Instance, + surface_loader: ash::khr::surface::Instance, + surface: vk::SurfaceKHR, + physical_device: vk::PhysicalDevice, + device: ash::Device, + owns_device: bool, + queue: vk::Queue, + queue_family: u32, + swapchain_loader: ash::khr::swapchain::Device, + swapchain: vk::SwapchainKHR, + images: Vec, + image_views: Vec, + framebuffers: Vec, + surface_format: vk::SurfaceFormatKHR, + extent: vk::Extent2D, + render_pass: vk::RenderPass, + descriptor_set_layout: vk::DescriptorSetLayout, + pipeline_layout: vk::PipelineLayout, + pipeline: vk::Pipeline, + descriptor_pool: vk::DescriptorPool, + descriptor_set: vk::DescriptorSet, + overlay_descriptor_set: vk::DescriptorSet, + sampler: vk::Sampler, + nv12_images: Option, + overlay_images: Option, + dmabuf_import_supported: bool, + dmabuf_import_reported: bool, + imported_dmabufs: HashMap, + in_flight_dmabuf: Option>, + direct_views: HashMap, DirectVulkanViews>, + shared_device_owner: Option>, + in_flight_vulkan: Option>, + command_pool: vk::CommandPool, + command_buffer: vk::CommandBuffer, + image_available: vk::Semaphore, + render_finished: Vec, + in_flight: vk::Fence, + staging_buffer: vk::Buffer, + staging_memory: vk::DeviceMemory, + staging_capacity: vk::DeviceSize, + needs_reconfigure: bool, + _thread_affinity: PhantomData>, +} + +impl VulkanPresenter { + pub fn new(target: &NativeSurface<'_>, width: u32, height: u32) -> Result { + Self::new_inner(target, width, height, None) + } + + pub fn new_for_vulkan_video( + target: &NativeSurface<'_>, + width: u32, + height: u32, + frame: &VulkanVideoFrame, + ) -> Result { + Self::new_inner(target, width, height, Some(frame)) + } + + fn new_inner( + target: &NativeSurface<'_>, + width: u32, + height: u32, + shared: Option<&VulkanVideoFrame>, + ) -> Result { + validate_presentation_extent(width, height)?; + let entry = unsafe { Entry::load() } + .map_err(|error| Error::unavailable(Subsystem::Vulkan, error.to_string()))?; + let owns_device = shared.is_none(); + let instance = if let Some(shared) = shared { + unsafe { + Instance::load( + entry.static_fn(), + vk::Instance::from_raw(shared.instance as u64), + ) + } + } else { + let application_name = c"OpenNOW"; + let application = vk::ApplicationInfo::default() + .application_name(application_name) + .application_version(vk::make_api_version(0, 0, 1, 0)) + .engine_name(application_name) + .engine_version(vk::make_api_version(0, 0, 1, 0)) + .api_version(vk::API_VERSION_1_1); + let extensions = ash_window::enumerate_required_extensions(target.raw_display_handle()) + .map_err(|error| vk_error("enumerate WSI extensions", error))?; + let instance_info = vk::InstanceCreateInfo::default() + .application_info(&application) + .enabled_extension_names(extensions); + unsafe { entry.create_instance(&instance_info, None) } + .map_err(|error| vk_error("create instance", error))? + }; + let surface = match unsafe { + ash_window::create_surface( + &entry, + &instance, + target.raw_display_handle(), + target.raw_window_handle(), + None, + ) + } { + Ok(surface) => surface, + Err(error) => { + if owns_device { + unsafe { instance.destroy_instance(None) }; + } + return Err(vk_error("create native surface", error)); + } + }; + let surface_loader = ash::khr::surface::Instance::new(&entry, &instance); + let selected = if let Some(shared) = shared { + select_shared_queue(&instance, &surface_loader, surface, shared) + } else { + select_device(&instance, &surface_loader, surface) + }; + let (physical_device, queue_family) = match selected { + Ok(selected) => selected, + Err(error) => { + unsafe { + surface_loader.destroy_surface(surface, None); + if owns_device { + instance.destroy_instance(None); + } + } + return Err(error); + } + }; + let dma_buf_extensions = [ + ash::khr::external_memory::NAME, + ash::khr::external_memory_fd::NAME, + ash::ext::external_memory_dma_buf::NAME, + ash::ext::image_drm_format_modifier::NAME, + ]; + let dmabuf_import_supported = + supports_device_extensions(&instance, physical_device, &dma_buf_extensions) + .unwrap_or(false); + let device = if let Some(shared) = shared { + unsafe { + ash::Device::load( + instance.fp_v1_0(), + vk::Device::from_raw(shared.device as u64), + ) + } + } else { + let priority = [1.0_f32]; + let queue_info = [vk::DeviceQueueCreateInfo::default() + .queue_family_index(queue_family) + .queue_priorities(&priority)]; + let mut device_extensions = vec![ash::khr::swapchain::NAME.as_ptr()]; + if dmabuf_import_supported { + device_extensions.extend(dma_buf_extensions.iter().map(|name| name.as_ptr())); + } + let device_info = vk::DeviceCreateInfo::default() + .queue_create_infos(&queue_info) + .enabled_extension_names(&device_extensions); + match unsafe { instance.create_device(physical_device, &device_info, None) } { + Ok(device) => device, + Err(error) => { + unsafe { + surface_loader.destroy_surface(surface, None); + instance.destroy_instance(None); + } + return Err(vk_error("create logical device", error)); + } + } + }; + let queue = unsafe { device.get_device_queue(queue_family, 0) }; + let swapchain_loader = ash::khr::swapchain::Device::new(&instance, &device); + let (command_pool, command_buffer, image_available, in_flight) = + match create_command_resources(&device, queue_family) { + Ok(resources) => resources, + Err(error) => { + unsafe { + if owns_device { + device.destroy_device(None); + } + surface_loader.destroy_surface(surface, None); + if owns_device { + instance.destroy_instance(None); + } + } + return Err(error); + } + }; + + let mut presenter = Self { + _entry: entry, + instance, + surface_loader, + surface, + physical_device, + device, + owns_device, + queue, + queue_family, + swapchain_loader, + swapchain: vk::SwapchainKHR::null(), + images: Vec::new(), + image_views: Vec::new(), + framebuffers: Vec::new(), + surface_format: vk::SurfaceFormatKHR::default(), + extent: vk::Extent2D { width, height }, + render_pass: vk::RenderPass::null(), + descriptor_set_layout: vk::DescriptorSetLayout::null(), + pipeline_layout: vk::PipelineLayout::null(), + pipeline: vk::Pipeline::null(), + descriptor_pool: vk::DescriptorPool::null(), + descriptor_set: vk::DescriptorSet::null(), + overlay_descriptor_set: vk::DescriptorSet::null(), + sampler: vk::Sampler::null(), + nv12_images: None, + overlay_images: None, + dmabuf_import_supported, + dmabuf_import_reported: false, + imported_dmabufs: HashMap::new(), + in_flight_dmabuf: None, + direct_views: HashMap::new(), + shared_device_owner: None, + in_flight_vulkan: None, + command_pool, + command_buffer, + image_available, + render_finished: Vec::new(), + in_flight, + staging_buffer: vk::Buffer::null(), + staging_memory: vk::DeviceMemory::null(), + staging_capacity: 0, + needs_reconfigure: false, + _thread_affinity: PhantomData, + }; + if let Err(error) = presenter.create_swapchain(width, height) { + drop(presenter); + return Err(error); + } + Ok(presenter) + } + + pub fn extent(&self) -> (u32, u32) { + (self.extent.width, self.extent.height) + } + + pub fn matches_vulkan_video_device(&self, frame: &VulkanVideoFrame) -> bool { + self.device.handle().as_raw() == frame.device as u64 + } + + pub fn reconfigure(&mut self, width: u32, height: u32) -> Result<()> { + validate_presentation_extent(width, height)?; + self.needs_reconfigure = true; + unsafe { self.device.device_wait_idle() } + .map_err(|error| vk_error("wait before swapchain rebuild", error))?; + self.destroy_swapchain(); + self.create_swapchain(width, height)?; + self.recreate_command_resources()?; + self.needs_reconfigure = false; + Ok(()) + } + + /// Presents one frame, returning `false` when the compositor temporarily + /// has no swapchain image available. A WSI timeout is normal while a + /// Wayland/X11 surface is being hidden or rearranged and must not tear + /// down the media session. + pub fn present(&mut self, frame: &DecodedVideoFrame) -> Result { + frame.validate()?; + if frame.format.pixel_format != PixelFormat::Nv12 + || (frame.vulkan.is_none() && frame.dmabuf.is_none() && frame.planes.len() != 2) + { + return Err(Error::InvalidFormat(format!( + "GPU presentation requires two-plane NV12, received {:?}", + frame.format.pixel_format + ))); + } + if self.needs_reconfigure { + return Err(Error::backend( + Subsystem::Vulkan, + "presentation synchronization is invalid; call VulkanPresenter::reconfigure", + )); + } + unsafe { + self.device + .wait_for_fences(&[self.in_flight], true, PRESENT_WAIT_NS) + } + .map_err(|error| vk_error("wait for presentation", error))?; + // The previous submission no longer references its decoder surface. + self.in_flight_dmabuf = None; + self.in_flight_vulkan = None; + + let luma_len = frame.format.width as usize * frame.format.height as usize; + let direct_vulkan = frame.vulkan.as_ref().map(Arc::clone); + let direct_image = if let Some(vulkan) = direct_vulkan.as_ref() { + if self.device.handle().as_raw() != vulkan.device as u64 { + return Err(Error::backend( + Subsystem::Vulkan, + "presenter and Vulkan Video decoder do not share a device", + )); + } + let (luma, chroma) = self.ensure_direct_vulkan_views(vulkan)?; + self.update_descriptors(luma, chroma); + None + } else if let Some(dmabuf) = frame.dmabuf.as_ref() { + if !self.dmabuf_import_supported { + return Err(Error::unavailable( + Subsystem::Vulkan, + "Vulkan device lacks DMA-BUF/modifier import extensions", + )); + } + let key = + self.ensure_imported_dmabuf(dmabuf, frame.format.width, frame.format.height)?; + let imported = self.imported_dmabufs.get(&key).ok_or_else(|| { + Error::backend( + Subsystem::Vulkan, + "DMA-BUF import cache lost the current frame", + ) + })?; + let handles = (imported.image, imported.luma_view, imported.chroma_view); + self.update_descriptors(handles.1, handles.2); + Some(handles.0) + } else { + self.ensure_nv12_images(frame.format.width, frame.format.height)?; + let chroma_len = luma_len / 2; + let upload_len = luma_len.checked_add(chroma_len).ok_or_else(|| { + Error::InvalidFormat("NV12 presentation buffer size overflow".to_owned()) + })?; + self.ensure_staging(upload_len as vk::DeviceSize)?; + let mapped = unsafe { + self.device.map_memory( + self.staging_memory, + 0, + upload_len as vk::DeviceSize, + vk::MemoryMapFlags::empty(), + ) + } + .map_err(|error| vk_error("map staging memory", error))?; + unsafe { + copy_plane_rows( + &frame.planes[0], + mapped.cast(), + frame.format.width as usize, + frame.format.height as usize, + ); + copy_plane_rows( + &frame.planes[1], + mapped.cast::().add(luma_len), + frame.format.width as usize, + frame.format.height as usize / 2, + ); + self.device.unmap_memory(self.staging_memory); + } + None + }; + let overlay_upload = if let Some(overlay) = frame.overlay.as_ref() { + self.ensure_overlay_images(overlay.width, overlay.height)?; + let luma_size = overlay.width as usize * overlay.height as usize; + let upload_size = luma_size + luma_size / 2; + self.ensure_staging(upload_size as vk::DeviceSize)?; + let mapped = unsafe { + self.device.map_memory( + self.staging_memory, + 0, + upload_size as vk::DeviceSize, + vk::MemoryMapFlags::empty(), + ) + } + .map_err(|error| vk_error("map overlay staging memory", error))?; + unsafe { + copy_plane_rows( + &overlay.luma, + mapped.cast(), + overlay.width as usize, + overlay.height as usize, + ); + copy_plane_rows( + &overlay.chroma, + mapped.cast::().add(luma_size), + overlay.width as usize, + overlay.height as usize / 2, + ); + self.device.unmap_memory(self.staging_memory); + } + Some((luma_size, overlay)) + } else { + None + }; + + let (image_index, acquire_suboptimal) = match unsafe { + self.swapchain_loader.acquire_next_image( + self.swapchain, + ACQUIRE_WAIT_NS, + self.image_available, + vk::Fence::null(), + ) + } { + Ok(result) => result, + Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => { + self.needs_reconfigure = true; + return Err(Error::backend( + Subsystem::Vulkan, + "surface is out of date; call VulkanPresenter::reconfigure", + )); + } + Err(vk::Result::TIMEOUT) | Err(vk::Result::NOT_READY) => return Ok(false), + Err(error) => return Err(vk_error("acquire swapchain image", error)), + }; + let image_index = image_index as usize; + if image_index >= self.images.len() + || image_index >= self.framebuffers.len() + || image_index >= self.render_finished.len() + { + self.needs_reconfigure = true; + return Err(Error::backend( + Subsystem::Vulkan, + "Vulkan returned an invalid swapchain image index", + )); + } + unsafe { + if let Err(error) = self + .device + .reset_command_buffer(self.command_buffer, vk::CommandBufferResetFlags::empty()) + { + self.needs_reconfigure = true; + return Err(vk_error("reset presentation command buffer", error)); + } + let begin = vk::CommandBufferBeginInfo::default() + .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT); + if let Err(error) = self + .device + .begin_command_buffer(self.command_buffer, &begin) + { + self.needs_reconfigure = true; + return Err(vk_error("begin presentation command buffer", error)); + } + if let Some(vulkan) = direct_vulkan.as_ref() { + let acquire = vulkan + .images + .iter() + .map(|image| { + let source_family = if image.queue_family == vk::QUEUE_FAMILY_IGNORED + || image.queue_family == self.queue_family + { + vk::QUEUE_FAMILY_IGNORED + } else { + image.queue_family + }; + vk::ImageMemoryBarrier::default() + .old_layout(vk::ImageLayout::from_raw(image.layout)) + .new_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) + .src_queue_family_index(source_family) + .dst_queue_family_index(if source_family == vk::QUEUE_FAMILY_IGNORED { + vk::QUEUE_FAMILY_IGNORED + } else { + self.queue_family + }) + .src_access_mask(vk::AccessFlags::MEMORY_WRITE) + .dst_access_mask(vk::AccessFlags::SHADER_READ) + .image(vk::Image::from_raw(image.image)) + .subresource_range(color_range()) + }) + .collect::>(); + self.device.cmd_pipeline_barrier( + self.command_buffer, + vk::PipelineStageFlags::ALL_COMMANDS, + vk::PipelineStageFlags::FRAGMENT_SHADER, + vk::DependencyFlags::empty(), + &[], + &[], + &acquire, + ); + } else if let Some(image) = direct_image { + let acquire = [vk::ImageMemoryBarrier::default() + .old_layout(vk::ImageLayout::GENERAL) + .new_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) + .src_queue_family_index(vk::QUEUE_FAMILY_EXTERNAL) + .dst_queue_family_index(self.queue_family) + .src_access_mask(vk::AccessFlags::MEMORY_WRITE) + .dst_access_mask(vk::AccessFlags::SHADER_READ) + .image(image) + .subresource_range(color_range())]; + self.device.cmd_pipeline_barrier( + self.command_buffer, + vk::PipelineStageFlags::ALL_COMMANDS, + vk::PipelineStageFlags::FRAGMENT_SHADER, + vk::DependencyFlags::empty(), + &[], + &[], + &acquire, + ); + } else { + let nv12 = self.nv12_images.as_ref().ok_or_else(|| { + Error::backend(Subsystem::Vulkan, "NV12 GPU images are unavailable") + })?; + let source_stage = if nv12.initialized { + vk::PipelineStageFlags::FRAGMENT_SHADER + } else { + vk::PipelineStageFlags::TOP_OF_PIPE + }; + let source_access = if nv12.initialized { + vk::AccessFlags::SHADER_READ + } else { + vk::AccessFlags::empty() + }; + let old_layout = if nv12.initialized { + vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL + } else { + vk::ImageLayout::UNDEFINED + }; + let to_transfer = [nv12.luma.image, nv12.chroma.image].map(|image| { + vk::ImageMemoryBarrier::default() + .old_layout(old_layout) + .new_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL) + .src_access_mask(source_access) + .dst_access_mask(vk::AccessFlags::TRANSFER_WRITE) + .image(image) + .subresource_range(color_range()) + }); + self.device.cmd_pipeline_barrier( + self.command_buffer, + source_stage, + vk::PipelineStageFlags::TRANSFER, + vk::DependencyFlags::empty(), + &[], + &[], + &to_transfer, + ); + let luma_copy = vk::BufferImageCopy::default() + .image_subresource( + vk::ImageSubresourceLayers::default() + .aspect_mask(vk::ImageAspectFlags::COLOR) + .layer_count(1), + ) + .image_extent(vk::Extent3D { + width: frame.format.width, + height: frame.format.height, + depth: 1, + }); + let chroma_copy = vk::BufferImageCopy::default() + .buffer_offset(luma_len as vk::DeviceSize) + .image_subresource( + vk::ImageSubresourceLayers::default() + .aspect_mask(vk::ImageAspectFlags::COLOR) + .layer_count(1), + ) + .image_extent(vk::Extent3D { + width: frame.format.width / 2, + height: frame.format.height / 2, + depth: 1, + }); + self.device.cmd_copy_buffer_to_image( + self.command_buffer, + self.staging_buffer, + nv12.luma.image, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + &[luma_copy], + ); + self.device.cmd_copy_buffer_to_image( + self.command_buffer, + self.staging_buffer, + nv12.chroma.image, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + &[chroma_copy], + ); + let to_sample = [nv12.luma.image, nv12.chroma.image].map(|image| { + vk::ImageMemoryBarrier::default() + .old_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL) + .new_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) + .src_access_mask(vk::AccessFlags::TRANSFER_WRITE) + .dst_access_mask(vk::AccessFlags::SHADER_READ) + .image(image) + .subresource_range(color_range()) + }); + self.device.cmd_pipeline_barrier( + self.command_buffer, + vk::PipelineStageFlags::TRANSFER, + vk::PipelineStageFlags::FRAGMENT_SHADER, + vk::DependencyFlags::empty(), + &[], + &[], + &to_sample, + ); + } + if let Some((overlay_luma_size, overlay)) = overlay_upload { + let images = self.overlay_images.as_ref().ok_or_else(|| { + Error::backend(Subsystem::Vulkan, "overlay GPU images are unavailable") + })?; + let source_stage = if images.initialized { + vk::PipelineStageFlags::FRAGMENT_SHADER + } else { + vk::PipelineStageFlags::TOP_OF_PIPE + }; + let old_layout = if images.initialized { + vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL + } else { + vk::ImageLayout::UNDEFINED + }; + let to_transfer = [images.luma.image, images.chroma.image].map(|image| { + vk::ImageMemoryBarrier::default() + .old_layout(old_layout) + .new_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL) + .src_access_mask(if images.initialized { + vk::AccessFlags::SHADER_READ + } else { + vk::AccessFlags::empty() + }) + .dst_access_mask(vk::AccessFlags::TRANSFER_WRITE) + .image(image) + .subresource_range(color_range()) + }); + self.device.cmd_pipeline_barrier( + self.command_buffer, + source_stage, + vk::PipelineStageFlags::TRANSFER, + vk::DependencyFlags::empty(), + &[], + &[], + &to_transfer, + ); + let luma_copy = vk::BufferImageCopy::default() + .image_subresource( + vk::ImageSubresourceLayers::default() + .aspect_mask(vk::ImageAspectFlags::COLOR) + .layer_count(1), + ) + .image_extent(vk::Extent3D { + width: overlay.width, + height: overlay.height, + depth: 1, + }); + let chroma_copy = vk::BufferImageCopy::default() + .buffer_offset(overlay_luma_size as vk::DeviceSize) + .image_subresource( + vk::ImageSubresourceLayers::default() + .aspect_mask(vk::ImageAspectFlags::COLOR) + .layer_count(1), + ) + .image_extent(vk::Extent3D { + width: overlay.width / 2, + height: overlay.height / 2, + depth: 1, + }); + self.device.cmd_copy_buffer_to_image( + self.command_buffer, + self.staging_buffer, + images.luma.image, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + &[luma_copy], + ); + self.device.cmd_copy_buffer_to_image( + self.command_buffer, + self.staging_buffer, + images.chroma.image, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + &[chroma_copy], + ); + let to_sample = [images.luma.image, images.chroma.image].map(|image| { + vk::ImageMemoryBarrier::default() + .old_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL) + .new_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) + .src_access_mask(vk::AccessFlags::TRANSFER_WRITE) + .dst_access_mask(vk::AccessFlags::SHADER_READ) + .image(image) + .subresource_range(color_range()) + }); + self.device.cmd_pipeline_barrier( + self.command_buffer, + vk::PipelineStageFlags::TRANSFER, + vk::PipelineStageFlags::FRAGMENT_SHADER, + vk::DependencyFlags::empty(), + &[], + &[], + &to_sample, + ); + } + let clear_values = [vk::ClearValue { + color: vk::ClearColorValue { + float32: [0.0, 0.0, 0.0, 1.0], + }, + }]; + let render_area = vk::Rect2D::default().extent(self.extent); + let render_begin = vk::RenderPassBeginInfo::default() + .render_pass(self.render_pass) + .framebuffer(self.framebuffers[image_index]) + .render_area(render_area) + .clear_values(&clear_values); + self.device.cmd_begin_render_pass( + self.command_buffer, + &render_begin, + vk::SubpassContents::INLINE, + ); + let viewport = vk::Viewport::default() + .width(self.extent.width as f32) + .height(self.extent.height as f32) + .max_depth(1.0); + self.device + .cmd_set_viewport(self.command_buffer, 0, &[viewport]); + self.device + .cmd_set_scissor(self.command_buffer, 0, &[render_area]); + self.device.cmd_bind_pipeline( + self.command_buffer, + vk::PipelineBindPoint::GRAPHICS, + self.pipeline, + ); + self.device.cmd_bind_descriptor_sets( + self.command_buffer, + vk::PipelineBindPoint::GRAPHICS, + self.pipeline_layout, + 0, + &[self.descriptor_set], + &[], + ); + let constants = conversion_constants(frame, self.extent); + let constants = std::slice::from_raw_parts( + (&constants as *const ConversionConstants).cast::(), + std::mem::size_of::(), + ); + self.device.cmd_push_constants( + self.command_buffer, + self.pipeline_layout, + vk::ShaderStageFlags::FRAGMENT, + 0, + constants, + ); + self.device.cmd_draw(self.command_buffer, 3, 1, 0, 0); + if let Some((_, overlay)) = overlay_upload { + let (fit_x, fit_y, fit_width, fit_height) = aspect_fit_extent( + frame.format.width, + frame.format.height, + self.extent.width, + self.extent.height, + ); + let x = fit_x + + (u64::from(overlay.origin_x) * u64::from(fit_width) + / u64::from(frame.format.width)) as u32; + let y = fit_y + + (u64::from(overlay.origin_y) * u64::from(fit_height) + / u64::from(frame.format.height)) as u32; + let width = (u64::from(overlay.width) * u64::from(fit_width) + / u64::from(frame.format.width)) as u32; + let height = (u64::from(overlay.height) * u64::from(fit_height) + / u64::from(frame.format.height)) as u32; + let overlay_viewport = vk::Viewport::default() + .x(x as f32) + .y(y as f32) + .width(width.max(1) as f32) + .height(height.max(1) as f32) + .max_depth(1.0); + let overlay_scissor = vk::Rect2D::default() + .offset(vk::Offset2D { + x: x as i32, + y: y as i32, + }) + .extent(vk::Extent2D { + width: width.max(1).min(self.extent.width.saturating_sub(x)), + height: height.max(1).min(self.extent.height.saturating_sub(y)), + }); + self.device + .cmd_set_viewport(self.command_buffer, 0, &[overlay_viewport]); + self.device + .cmd_set_scissor(self.command_buffer, 0, &[overlay_scissor]); + self.device.cmd_bind_descriptor_sets( + self.command_buffer, + vk::PipelineBindPoint::GRAPHICS, + self.pipeline_layout, + 0, + &[self.overlay_descriptor_set], + &[], + ); + let constants = ConversionConstants { + texture_scale: [1.0, 1.0], + color_matrix: 1, + full_range: 0, + }; + let constants = std::slice::from_raw_parts( + (&constants as *const ConversionConstants).cast::(), + std::mem::size_of::(), + ); + self.device.cmd_push_constants( + self.command_buffer, + self.pipeline_layout, + vk::ShaderStageFlags::FRAGMENT, + 0, + constants, + ); + self.device.cmd_draw(self.command_buffer, 3, 1, 0, 0); + } + self.device.cmd_end_render_pass(self.command_buffer); + if let Some(vulkan) = direct_vulkan.as_ref() { + let release = vulkan + .images + .iter() + .map(|image| { + let destination_family = if image.queue_family == vk::QUEUE_FAMILY_IGNORED + || image.queue_family == self.queue_family + { + vk::QUEUE_FAMILY_IGNORED + } else { + image.queue_family + }; + vk::ImageMemoryBarrier::default() + .old_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) + .new_layout(vk::ImageLayout::from_raw(image.layout)) + .src_queue_family_index( + if destination_family == vk::QUEUE_FAMILY_IGNORED { + vk::QUEUE_FAMILY_IGNORED + } else { + self.queue_family + }, + ) + .dst_queue_family_index(destination_family) + .src_access_mask(vk::AccessFlags::SHADER_READ) + .dst_access_mask(vk::AccessFlags::MEMORY_READ) + .image(vk::Image::from_raw(image.image)) + .subresource_range(color_range()) + }) + .collect::>(); + self.device.cmd_pipeline_barrier( + self.command_buffer, + vk::PipelineStageFlags::FRAGMENT_SHADER, + vk::PipelineStageFlags::ALL_COMMANDS, + vk::DependencyFlags::empty(), + &[], + &[], + &release, + ); + } else if let Some(image) = direct_image { + let release = [vk::ImageMemoryBarrier::default() + .old_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) + .new_layout(vk::ImageLayout::GENERAL) + .src_queue_family_index(self.queue_family) + .dst_queue_family_index(vk::QUEUE_FAMILY_EXTERNAL) + .src_access_mask(vk::AccessFlags::SHADER_READ) + .dst_access_mask(vk::AccessFlags::MEMORY_READ | vk::AccessFlags::MEMORY_WRITE) + .image(image) + .subresource_range(color_range())]; + self.device.cmd_pipeline_barrier( + self.command_buffer, + vk::PipelineStageFlags::FRAGMENT_SHADER, + vk::PipelineStageFlags::ALL_COMMANDS, + vk::DependencyFlags::empty(), + &[], + &[], + &release, + ); + } else if let Some(nv12) = self.nv12_images.as_mut() { + nv12.initialized = true; + } + if overlay_upload.is_some() + && let Some(images) = self.overlay_images.as_mut() + { + images.initialized = true; + } + if let Err(error) = self.device.end_command_buffer(self.command_buffer) { + self.needs_reconfigure = true; + return Err(vk_error("end presentation command buffer", error)); + } + let mut wait_semaphores = vec![self.image_available]; + let mut wait_stages = vec![vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; + let mut wait_values = vec![0_u64]; + if let Some(vulkan) = direct_vulkan.as_ref() { + for image in &vulkan.images { + if image.semaphore != 0 { + wait_semaphores.push(vk::Semaphore::from_raw(image.semaphore)); + wait_stages.push(vk::PipelineStageFlags::FRAGMENT_SHADER); + wait_values.push(image.semaphore_value); + } + } + } + let command_buffers = [self.command_buffer]; + let signal_semaphores = [self.render_finished[image_index]]; + let signal_values = [0_u64]; + let mut timeline = vk::TimelineSemaphoreSubmitInfo::default() + .wait_semaphore_values(&wait_values) + .signal_semaphore_values(&signal_values); + let mut submit_info = vk::SubmitInfo::default() + .wait_semaphores(&wait_semaphores) + .wait_dst_stage_mask(&wait_stages) + .command_buffers(&command_buffers) + .signal_semaphores(&signal_semaphores); + if direct_vulkan.is_some() { + submit_info = submit_info.push_next(&mut timeline); + } + let submit = [submit_info]; + if let Err(error) = self.device.reset_fences(&[self.in_flight]) { + self.needs_reconfigure = true; + return Err(vk_error("reset presentation fence", error)); + } + if let Some(vulkan) = direct_vulkan.as_ref() { + vulkan.lock_presentation_queue(self.queue_family); + } + let submit_result = self + .device + .queue_submit(self.queue, &submit, self.in_flight); + if let Some(vulkan) = direct_vulkan.as_ref() { + vulkan.unlock_presentation_queue(self.queue_family); + } + if let Err(error) = submit_result { + self.needs_reconfigure = true; + return Err(vk_error("submit presentation command buffer", error)); + } + if let Some(dmabuf) = frame.dmabuf.as_ref() { + self.in_flight_dmabuf = Some(Arc::clone(dmabuf)); + } + if let Some(vulkan) = direct_vulkan.as_ref() { + if self.shared_device_owner.is_none() { + self.shared_device_owner = Some(Arc::clone(vulkan)); + } + self.in_flight_vulkan = Some(Arc::clone(vulkan)); + } + let swapchains = [self.swapchain]; + let image_indices = [image_index as u32]; + let present = vk::PresentInfoKHR::default() + .wait_semaphores(&signal_semaphores) + .swapchains(&swapchains) + .image_indices(&image_indices); + if let Some(vulkan) = direct_vulkan.as_ref() { + vulkan.lock_presentation_queue(self.queue_family); + } + let present_result = self.swapchain_loader.queue_present(self.queue, &present); + if let Some(vulkan) = direct_vulkan.as_ref() { + vulkan.unlock_presentation_queue(self.queue_family); + } + match present_result { + Ok(false) => {} + Ok(true) | Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => { + self.needs_reconfigure = true; + return Err(Error::backend( + Subsystem::Vulkan, + "surface changed; call VulkanPresenter::reconfigure", + )); + } + Err(error) => { + self.needs_reconfigure = true; + return Err(vk_error("present swapchain image", error)); + } + } + } + if acquire_suboptimal { + self.needs_reconfigure = true; + return Err(Error::backend( + Subsystem::Vulkan, + "surface is suboptimal; call VulkanPresenter::reconfigure", + )); + } + Ok(true) + } + + fn create_swapchain(&mut self, requested_width: u32, requested_height: u32) -> Result<()> { + let capabilities = unsafe { + self.surface_loader + .get_physical_device_surface_capabilities(self.physical_device, self.surface) + } + .map_err(|error| vk_error("query surface capabilities", error))?; + if !capabilities + .supported_usage_flags + .contains(vk::ImageUsageFlags::COLOR_ATTACHMENT) + { + return Err(Error::unavailable( + Subsystem::Vulkan, + "surface swapchain images do not support color-attachment usage", + )); + } + let formats = unsafe { + self.surface_loader + .get_physical_device_surface_formats(self.physical_device, self.surface) + } + .map_err(|error| vk_error("query surface formats", error))?; + let present_modes = unsafe { + self.surface_loader + .get_physical_device_surface_present_modes(self.physical_device, self.surface) + } + .map_err(|error| vk_error("query surface present modes", error))?; + let present_mode = choose_present_mode(&present_modes); + self.surface_format = choose_surface_format(&formats)?; + self.extent = choose_extent(capabilities, requested_width, requested_height); + validate_presentation_extent(self.extent.width, self.extent.height)?; + let mut image_count = capabilities.min_image_count.saturating_add(1); + if capabilities.max_image_count > 0 { + image_count = image_count.min(capabilities.max_image_count); + } + let create = vk::SwapchainCreateInfoKHR::default() + .surface(self.surface) + .min_image_count(image_count) + .image_format(self.surface_format.format) + .image_color_space(self.surface_format.color_space) + .image_extent(self.extent) + .image_array_layers(1) + .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT) + .image_sharing_mode(vk::SharingMode::EXCLUSIVE) + .pre_transform(capabilities.current_transform) + .composite_alpha(choose_composite_alpha( + capabilities.supported_composite_alpha, + )) + .present_mode(present_mode) + .clipped(true); + self.swapchain = unsafe { self.swapchain_loader.create_swapchain(&create, None) } + .map_err(|error| vk_error("create swapchain", error))?; + self.images = unsafe { self.swapchain_loader.get_swapchain_images(self.swapchain) } + .map_err(|error| vk_error("get swapchain images", error))?; + eprintln!( + "Vulkan presenter configured: mode={present_mode:?} images={} extent={}x{}", + self.images.len(), + self.extent.width, + self.extent.height + ); + let semaphore_info = vk::SemaphoreCreateInfo::default(); + let mut render_finished = Vec::with_capacity(self.images.len()); + for _ in &self.images { + match unsafe { self.device.create_semaphore(&semaphore_info, None) } { + Ok(semaphore) => render_finished.push(semaphore), + Err(error) => { + for semaphore in render_finished { + unsafe { self.device.destroy_semaphore(semaphore, None) }; + } + return Err(vk_error("create per-image render semaphore", error)); + } + } + } + self.render_finished = render_finished; + self.create_render_resources()?; + Ok(()) + } + + fn create_render_resources(&mut self) -> Result<()> { + let attachment = [vk::AttachmentDescription::default() + .format(self.surface_format.format) + .samples(vk::SampleCountFlags::TYPE_1) + .load_op(vk::AttachmentLoadOp::CLEAR) + .store_op(vk::AttachmentStoreOp::STORE) + .stencil_load_op(vk::AttachmentLoadOp::DONT_CARE) + .stencil_store_op(vk::AttachmentStoreOp::DONT_CARE) + .initial_layout(vk::ImageLayout::UNDEFINED) + .final_layout(vk::ImageLayout::PRESENT_SRC_KHR)]; + let color_reference = [vk::AttachmentReference::default() + .attachment(0) + .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL)]; + let subpasses = [vk::SubpassDescription::default() + .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) + .color_attachments(&color_reference)]; + let dependencies = [vk::SubpassDependency::default() + .src_subpass(vk::SUBPASS_EXTERNAL) + .dst_subpass(0) + .src_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) + .dst_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) + .dst_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE)]; + let render_pass_info = vk::RenderPassCreateInfo::default() + .attachments(&attachment) + .subpasses(&subpasses) + .dependencies(&dependencies); + self.render_pass = unsafe { self.device.create_render_pass(&render_pass_info, None) } + .map_err(|error| vk_error("create NV12 render pass", error))?; + + let descriptor_bindings = [0, 1].map(|binding| { + vk::DescriptorSetLayoutBinding::default() + .binding(binding) + .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) + .descriptor_count(1) + .stage_flags(vk::ShaderStageFlags::FRAGMENT) + }); + let descriptor_layout_info = + vk::DescriptorSetLayoutCreateInfo::default().bindings(&descriptor_bindings); + self.descriptor_set_layout = unsafe { + self.device + .create_descriptor_set_layout(&descriptor_layout_info, None) + } + .map_err(|error| vk_error("create NV12 descriptor layout", error))?; + let descriptor_layouts = [self.descriptor_set_layout]; + let push_range = [vk::PushConstantRange::default() + .stage_flags(vk::ShaderStageFlags::FRAGMENT) + .size(std::mem::size_of::() as u32)]; + let pipeline_layout_info = vk::PipelineLayoutCreateInfo::default() + .set_layouts(&descriptor_layouts) + .push_constant_ranges(&push_range); + self.pipeline_layout = unsafe { + self.device + .create_pipeline_layout(&pipeline_layout_info, None) + } + .map_err(|error| vk_error("create NV12 pipeline layout", error))?; + + let vertex_words = ash::util::read_spv(&mut Cursor::new(NV12_VERTEX_SHADER)) + .map_err(|error| Error::backend(Subsystem::Vulkan, error.to_string()))?; + let fragment_words = ash::util::read_spv(&mut Cursor::new(NV12_FRAGMENT_SHADER)) + .map_err(|error| Error::backend(Subsystem::Vulkan, error.to_string()))?; + let vertex_info = vk::ShaderModuleCreateInfo::default().code(&vertex_words); + let fragment_info = vk::ShaderModuleCreateInfo::default().code(&fragment_words); + let vertex_module = unsafe { self.device.create_shader_module(&vertex_info, None) } + .map_err(|error| vk_error("create NV12 vertex shader", error))?; + let fragment_module = + match unsafe { self.device.create_shader_module(&fragment_info, None) } { + Ok(module) => module, + Err(error) => { + unsafe { self.device.destroy_shader_module(vertex_module, None) }; + return Err(vk_error("create NV12 fragment shader", error)); + } + }; + let shader_stages = [ + vk::PipelineShaderStageCreateInfo::default() + .stage(vk::ShaderStageFlags::VERTEX) + .module(vertex_module) + .name(c"main"), + vk::PipelineShaderStageCreateInfo::default() + .stage(vk::ShaderStageFlags::FRAGMENT) + .module(fragment_module) + .name(c"main"), + ]; + let vertex_input = vk::PipelineVertexInputStateCreateInfo::default(); + let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default() + .topology(vk::PrimitiveTopology::TRIANGLE_LIST); + let viewport_state = vk::PipelineViewportStateCreateInfo::default() + .viewport_count(1) + .scissor_count(1); + let rasterization = vk::PipelineRasterizationStateCreateInfo::default() + .polygon_mode(vk::PolygonMode::FILL) + .cull_mode(vk::CullModeFlags::NONE) + .front_face(vk::FrontFace::COUNTER_CLOCKWISE) + .line_width(1.0); + let multisample = vk::PipelineMultisampleStateCreateInfo::default() + .rasterization_samples(vk::SampleCountFlags::TYPE_1); + let color_attachment = [vk::PipelineColorBlendAttachmentState::default() + .color_write_mask(vk::ColorComponentFlags::RGBA)]; + let color_blend = + vk::PipelineColorBlendStateCreateInfo::default().attachments(&color_attachment); + let dynamic_states = [vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR]; + let dynamic = vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&dynamic_states); + let pipeline_info = [vk::GraphicsPipelineCreateInfo::default() + .stages(&shader_stages) + .vertex_input_state(&vertex_input) + .input_assembly_state(&input_assembly) + .viewport_state(&viewport_state) + .rasterization_state(&rasterization) + .multisample_state(&multisample) + .color_blend_state(&color_blend) + .dynamic_state(&dynamic) + .layout(self.pipeline_layout) + .render_pass(self.render_pass) + .subpass(0)]; + let pipeline_result = unsafe { + self.device + .create_graphics_pipelines(vk::PipelineCache::null(), &pipeline_info, None) + }; + unsafe { + self.device.destroy_shader_module(fragment_module, None); + self.device.destroy_shader_module(vertex_module, None); + } + self.pipeline = pipeline_result + .map_err(|(_, error)| vk_error("create NV12 graphics pipeline", error))?[0]; + + let sampler_info = vk::SamplerCreateInfo::default() + .mag_filter(vk::Filter::LINEAR) + .min_filter(vk::Filter::LINEAR) + .mipmap_mode(vk::SamplerMipmapMode::NEAREST) + .address_mode_u(vk::SamplerAddressMode::CLAMP_TO_EDGE) + .address_mode_v(vk::SamplerAddressMode::CLAMP_TO_EDGE) + .address_mode_w(vk::SamplerAddressMode::CLAMP_TO_EDGE) + .max_lod(0.0); + self.sampler = unsafe { self.device.create_sampler(&sampler_info, None) } + .map_err(|error| vk_error("create NV12 sampler", error))?; + let pool_sizes = [vk::DescriptorPoolSize::default() + .ty(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) + .descriptor_count(4)]; + let pool_info = vk::DescriptorPoolCreateInfo::default() + .max_sets(2) + .pool_sizes(&pool_sizes); + self.descriptor_pool = unsafe { self.device.create_descriptor_pool(&pool_info, None) } + .map_err(|error| vk_error("create NV12 descriptor pool", error))?; + let overlay_layouts = [self.descriptor_set_layout, self.descriptor_set_layout]; + let allocate_info = vk::DescriptorSetAllocateInfo::default() + .descriptor_pool(self.descriptor_pool) + .set_layouts(&overlay_layouts); + let allocated = unsafe { self.device.allocate_descriptor_sets(&allocate_info) } + .map_err(|error| vk_error("allocate NV12 descriptor sets", error))?; + self.descriptor_set = allocated[0]; + self.overlay_descriptor_set = allocated[1]; + + for image in &self.images { + let create = vk::ImageViewCreateInfo::default() + .image(*image) + .view_type(vk::ImageViewType::TYPE_2D) + .format(self.surface_format.format) + .subresource_range(color_range()); + let view = unsafe { self.device.create_image_view(&create, None) } + .map_err(|error| vk_error("create swapchain image view", error))?; + self.image_views.push(view); + } + for view in &self.image_views { + let attachments = [*view]; + let create = vk::FramebufferCreateInfo::default() + .render_pass(self.render_pass) + .attachments(&attachments) + .width(self.extent.width) + .height(self.extent.height) + .layers(1); + let framebuffer = unsafe { self.device.create_framebuffer(&create, None) } + .map_err(|error| vk_error("create swapchain framebuffer", error))?; + self.framebuffers.push(framebuffer); + } + if self.nv12_images.is_some() { + self.update_nv12_descriptors(); + } + if let Some(images) = self.overlay_images.as_ref() { + self.update_descriptor_set( + self.overlay_descriptor_set, + images.luma.view, + images.chroma.view, + ); + } + Ok(()) + } + + fn ensure_nv12_images(&mut self, width: u32, height: u32) -> Result<()> { + if self + .nv12_images + .as_ref() + .is_some_and(|images| images.width == width && images.height == height) + { + return Ok(()); + } + self.destroy_nv12_images(); + let luma = create_sampled_image( + &self.instance, + self.physical_device, + &self.device, + width, + height, + vk::Format::R8_UNORM, + )?; + let chroma = match create_sampled_image( + &self.instance, + self.physical_device, + &self.device, + width / 2, + height / 2, + vk::Format::R8G8_UNORM, + ) { + Ok(image) => image, + Err(error) => { + destroy_gpu_image(&self.device, luma); + return Err(error); + } + }; + self.nv12_images = Some(Nv12Images { + width, + height, + luma, + chroma, + initialized: false, + }); + self.update_nv12_descriptors(); + Ok(()) + } + + fn update_nv12_descriptors(&self) { + let Some(images) = self.nv12_images.as_ref() else { + return; + }; + self.update_descriptors(images.luma.view, images.chroma.view); + } + + fn update_descriptors(&self, luma_view: vk::ImageView, chroma_view: vk::ImageView) { + self.update_descriptor_set(self.descriptor_set, luma_view, chroma_view); + } + + fn update_descriptor_set( + &self, + descriptor_set: vk::DescriptorSet, + luma_view: vk::ImageView, + chroma_view: vk::ImageView, + ) { + if descriptor_set == vk::DescriptorSet::null() { + return; + } + let luma = [vk::DescriptorImageInfo::default() + .sampler(self.sampler) + .image_view(luma_view) + .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)]; + let chroma = [vk::DescriptorImageInfo::default() + .sampler(self.sampler) + .image_view(chroma_view) + .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)]; + let writes = [ + vk::WriteDescriptorSet::default() + .dst_set(descriptor_set) + .dst_binding(0) + .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) + .image_info(&luma), + vk::WriteDescriptorSet::default() + .dst_set(descriptor_set) + .dst_binding(1) + .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) + .image_info(&chroma), + ]; + unsafe { self.device.update_descriptor_sets(&writes, &[]) }; + } + + fn ensure_direct_vulkan_views( + &mut self, + frame: &VulkanVideoFrame, + ) -> Result<(vk::ImageView, vk::ImageView)> { + let key = frame + .images + .iter() + .map(|image| image.image) + .collect::>(); + if let Some(views) = self.direct_views.get(&key) { + return Ok((views.luma, views.chroma)); + } + if self.direct_views.len() >= MAX_IMPORTED_DMABUF_IMAGES { + for (_, views) in self.direct_views.drain() { + unsafe { + self.device.destroy_image_view(views.chroma, None); + self.device.destroy_image_view(views.luma, None); + } + } + } + let (luma, chroma) = if frame.images.len() == 1 { + let image = vk::Image::from_raw(frame.images[0].image); + ( + create_plane_view( + &self.device, + image, + vk::Format::R8_UNORM, + vk::ImageAspectFlags::PLANE_0, + )?, + create_plane_view( + &self.device, + image, + vk::Format::R8G8_UNORM, + vk::ImageAspectFlags::PLANE_1, + )?, + ) + } else { + let luma = create_plane_view( + &self.device, + vk::Image::from_raw(frame.images[0].image), + vk::Format::from_raw(frame.images[0].format), + vk::ImageAspectFlags::COLOR, + )?; + let chroma = match create_plane_view( + &self.device, + vk::Image::from_raw(frame.images[1].image), + vk::Format::from_raw(frame.images[1].format), + vk::ImageAspectFlags::COLOR, + ) { + Ok(view) => view, + Err(error) => { + unsafe { self.device.destroy_image_view(luma, None) }; + return Err(error); + } + }; + (luma, chroma) + }; + self.direct_views + .insert(key, DirectVulkanViews { luma, chroma }); + Ok((luma, chroma)) + } + + fn ensure_imported_dmabuf( + &mut self, + frame: &Arc, + width: u32, + height: u32, + ) -> Result { + let (object_index, luma, chroma) = nv12_dmabuf_layout(frame)?; + let object = frame.objects[object_index]; + let (device, inode) = fd_identity(object.fd)?; + let key = DmaBufKey { + device, + inode, + width, + height, + modifier: object.format_modifier, + luma_offset: luma.offset, + luma_pitch: luma.pitch, + chroma_offset: chroma.offset, + chroma_pitch: chroma.pitch, + }; + if self.imported_dmabufs.contains_key(&key) { + return Ok(key); + } + if self.imported_dmabufs.len() >= MAX_IMPORTED_DMABUF_IMAGES { + self.destroy_imported_dmabufs(); + } + let imported = import_nv12_dmabuf( + &self.instance, + self.physical_device, + &self.device, + object.fd, + object.size, + object.format_modifier, + luma, + chroma, + width, + height, + )?; + self.imported_dmabufs.insert(key, imported); + if !self.dmabuf_import_reported { + eprintln!( + "Vulkan presentation zero-copy enabled: DRM PRIME NV12 DMA-BUF import (modifier {:#x})", + object.format_modifier + ); + self.dmabuf_import_reported = true; + } + Ok(key) + } + + fn destroy_imported_dmabufs(&mut self) { + for (_, imported) in self.imported_dmabufs.drain() { + destroy_imported_dmabuf(&self.device, imported); + } + } + + fn destroy_nv12_images(&mut self) { + if let Some(images) = self.nv12_images.take() { + destroy_gpu_image(&self.device, images.chroma); + destroy_gpu_image(&self.device, images.luma); + } + } + + fn ensure_overlay_images(&mut self, width: u32, height: u32) -> Result<()> { + if self + .overlay_images + .as_ref() + .is_some_and(|images| images.width == width && images.height == height) + { + return Ok(()); + } + self.destroy_overlay_images(); + let luma = create_sampled_image( + &self.instance, + self.physical_device, + &self.device, + width, + height, + vk::Format::R8_UNORM, + )?; + let chroma = match create_sampled_image( + &self.instance, + self.physical_device, + &self.device, + width / 2, + height / 2, + vk::Format::R8G8_UNORM, + ) { + Ok(image) => image, + Err(error) => { + destroy_gpu_image(&self.device, luma); + return Err(error); + } + }; + self.overlay_images = Some(Nv12Images { + width, + height, + luma, + chroma, + initialized: false, + }); + let images = self.overlay_images.as_ref().expect("overlay images set"); + self.update_descriptor_set( + self.overlay_descriptor_set, + images.luma.view, + images.chroma.view, + ); + Ok(()) + } + + fn destroy_overlay_images(&mut self) { + if let Some(images) = self.overlay_images.take() { + destroy_gpu_image(&self.device, images.chroma); + destroy_gpu_image(&self.device, images.luma); + } + } + + fn recreate_command_resources(&mut self) -> Result<()> { + unsafe { + if self.in_flight != vk::Fence::null() { + self.device.destroy_fence(self.in_flight, None); + } + if self.image_available != vk::Semaphore::null() { + self.device.destroy_semaphore(self.image_available, None); + } + if self.command_pool != vk::CommandPool::null() { + self.device.destroy_command_pool(self.command_pool, None); + } + } + self.command_pool = vk::CommandPool::null(); + self.command_buffer = vk::CommandBuffer::null(); + self.image_available = vk::Semaphore::null(); + self.in_flight = vk::Fence::null(); + let (command_pool, command_buffer, image_available, in_flight) = + create_command_resources(&self.device, self.queue_family)?; + self.command_pool = command_pool; + self.command_buffer = command_buffer; + self.image_available = image_available; + self.in_flight = in_flight; + Ok(()) + } + + fn destroy_swapchain(&mut self) { + for framebuffer in self.framebuffers.drain(..) { + unsafe { self.device.destroy_framebuffer(framebuffer, None) }; + } + for image_view in self.image_views.drain(..) { + unsafe { self.device.destroy_image_view(image_view, None) }; + } + unsafe { + if self.pipeline != vk::Pipeline::null() { + self.device.destroy_pipeline(self.pipeline, None); + self.pipeline = vk::Pipeline::null(); + } + if self.pipeline_layout != vk::PipelineLayout::null() { + self.device + .destroy_pipeline_layout(self.pipeline_layout, None); + self.pipeline_layout = vk::PipelineLayout::null(); + } + if self.descriptor_pool != vk::DescriptorPool::null() { + self.device + .destroy_descriptor_pool(self.descriptor_pool, None); + self.descriptor_pool = vk::DescriptorPool::null(); + self.descriptor_set = vk::DescriptorSet::null(); + self.overlay_descriptor_set = vk::DescriptorSet::null(); + } + if self.descriptor_set_layout != vk::DescriptorSetLayout::null() { + self.device + .destroy_descriptor_set_layout(self.descriptor_set_layout, None); + self.descriptor_set_layout = vk::DescriptorSetLayout::null(); + } + if self.sampler != vk::Sampler::null() { + self.device.destroy_sampler(self.sampler, None); + self.sampler = vk::Sampler::null(); + } + if self.render_pass != vk::RenderPass::null() { + self.device.destroy_render_pass(self.render_pass, None); + self.render_pass = vk::RenderPass::null(); + } + } + for semaphore in self.render_finished.drain(..) { + unsafe { self.device.destroy_semaphore(semaphore, None) }; + } + if self.swapchain != vk::SwapchainKHR::null() { + unsafe { + self.swapchain_loader + .destroy_swapchain(self.swapchain, None) + }; + self.swapchain = vk::SwapchainKHR::null(); + self.images.clear(); + } + } + + fn ensure_staging(&mut self, required: vk::DeviceSize) -> Result<()> { + if required <= self.staging_capacity { + return Ok(()); + } + unsafe { self.device.device_wait_idle() } + .map_err(|error| vk_error("wait before staging resize", error))?; + if self.staging_buffer != vk::Buffer::null() { + unsafe { + self.device.destroy_buffer(self.staging_buffer, None); + self.device.free_memory(self.staging_memory, None); + } + self.staging_buffer = vk::Buffer::null(); + self.staging_memory = vk::DeviceMemory::null(); + self.staging_capacity = 0; + } + let buffer_info = vk::BufferCreateInfo::default() + .size(required) + .usage(vk::BufferUsageFlags::TRANSFER_SRC) + .sharing_mode(vk::SharingMode::EXCLUSIVE); + let staging_buffer = unsafe { self.device.create_buffer(&buffer_info, None) } + .map_err(|error| vk_error("create staging buffer", error))?; + let requirements = unsafe { self.device.get_buffer_memory_requirements(staging_buffer) }; + let memory_type = match find_memory_type( + &self.instance, + self.physical_device, + requirements.memory_type_bits, + vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT, + ) { + Ok(memory_type) => memory_type, + Err(error) => { + unsafe { self.device.destroy_buffer(staging_buffer, None) }; + return Err(error); + } + }; + let allocation = vk::MemoryAllocateInfo::default() + .allocation_size(requirements.size) + .memory_type_index(memory_type); + let staging_memory = match unsafe { self.device.allocate_memory(&allocation, None) } { + Ok(memory) => memory, + Err(error) => { + unsafe { self.device.destroy_buffer(staging_buffer, None) }; + return Err(vk_error("allocate staging memory", error)); + } + }; + if let Err(error) = unsafe { + self.device + .bind_buffer_memory(staging_buffer, staging_memory, 0) + } { + unsafe { + self.device.destroy_buffer(staging_buffer, None); + self.device.free_memory(staging_memory, None); + } + return Err(vk_error("bind staging memory", error)); + } + self.staging_buffer = staging_buffer; + self.staging_memory = staging_memory; + self.staging_capacity = requirements.size; + Ok(()) + } +} + +#[repr(C)] +struct ConversionConstants { + texture_scale: [f32; 2], + color_matrix: u32, + full_range: u32, +} + +fn conversion_constants(frame: &DecodedVideoFrame, extent: vk::Extent2D) -> ConversionConstants { + let (_, _, fitted_width, fitted_height) = aspect_fit_extent( + frame.format.width, + frame.format.height, + extent.width, + extent.height, + ); + ConversionConstants { + texture_scale: [ + extent.width as f32 / fitted_width.max(1) as f32, + extent.height as f32 / fitted_height.max(1) as f32, + ], + color_matrix: match frame.format.color_matrix { + ColorMatrix::Bt601 => 0, + ColorMatrix::Bt709 => 1, + ColorMatrix::Bt2020 => 2, + }, + full_range: u32::from(frame.format.color_range == ColorRange::Full), + } +} + +unsafe fn copy_plane_rows( + plane: &crate::FramePlane, + destination: *mut u8, + row_bytes: usize, + rows: usize, +) { + for row in 0..rows { + unsafe { + std::ptr::copy_nonoverlapping( + plane.data.as_ptr().add(row * plane.stride), + destination.add(row * row_bytes), + row_bytes, + ); + } + } +} + +fn nv12_dmabuf_layout(frame: &DmaBufFrame) -> Result<(usize, DmaBufPlane, DmaBufPlane)> { + let (luma, chroma) = if frame.layers.len() == 1 + && frame.layers[0].format == DRM_FORMAT_NV12 + && frame.layers[0].planes.len() >= 2 + { + (frame.layers[0].planes[0], frame.layers[0].planes[1]) + } else if frame.layers.len() >= 2 + && frame.layers[0].format == DRM_FORMAT_R8 + && frame.layers[1].format == DRM_FORMAT_GR88 + && !frame.layers[0].planes.is_empty() + && !frame.layers[1].planes.is_empty() + { + (frame.layers[0].planes[0], frame.layers[1].planes[0]) + } else { + return Err(Error::unavailable( + Subsystem::Vulkan, + format!( + "unsupported DMA-BUF NV12 layout ({} layers: {})", + frame.layers.len(), + frame + .layers + .iter() + .map(|layer| format!("{:#010x}/{}", layer.format, layer.planes.len())) + .collect::>() + .join(", ") + ), + )); + }; + if luma.object_index != chroma.object_index { + return Err(Error::unavailable( + Subsystem::Vulkan, + "disjoint multi-object NV12 DMA-BUF import is not supported", + )); + } + Ok((luma.object_index, luma, chroma)) +} + +fn fd_identity(fd: RawFd) -> Result<(u64, u64)> { + let mut metadata = std::mem::MaybeUninit::::zeroed(); + if unsafe { libc::fstat(fd, metadata.as_mut_ptr()) } != 0 { + return Err(Error::backend( + Subsystem::Vulkan, + format!( + "fstat on DMA-BUF failed: {}", + std::io::Error::last_os_error() + ), + )); + } + let metadata = unsafe { metadata.assume_init() }; + Ok((metadata.st_dev as u64, metadata.st_ino as u64)) +} + +#[allow(clippy::too_many_arguments)] +fn import_nv12_dmabuf( + instance: &Instance, + physical_device: vk::PhysicalDevice, + device: &ash::Device, + fd: RawFd, + object_size: usize, + modifier: u64, + luma: DmaBufPlane, + chroma: DmaBufPlane, + width: u32, + height: u32, +) -> Result { + if luma.offset >= object_size || chroma.offset >= object_size { + return Err(Error::InvalidFormat( + "DMA-BUF plane offset exceeds its object size".to_owned(), + )); + } + let plane_layouts = [ + vk::SubresourceLayout { + offset: luma.offset as vk::DeviceSize, + size: object_size.saturating_sub(luma.offset) as vk::DeviceSize, + row_pitch: luma.pitch as vk::DeviceSize, + array_pitch: 0, + depth_pitch: 0, + }, + vk::SubresourceLayout { + offset: chroma.offset as vk::DeviceSize, + size: object_size.saturating_sub(chroma.offset) as vk::DeviceSize, + row_pitch: chroma.pitch as vk::DeviceSize, + array_pitch: 0, + depth_pitch: 0, + }, + ]; + let mut external = vk::ExternalMemoryImageCreateInfo::default() + .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); + let mut drm_modifier = vk::ImageDrmFormatModifierExplicitCreateInfoEXT::default() + .drm_format_modifier(modifier) + .plane_layouts(&plane_layouts); + let image_info = vk::ImageCreateInfo::default() + .push_next(&mut external) + .push_next(&mut drm_modifier) + .flags(vk::ImageCreateFlags::MUTABLE_FORMAT) + .image_type(vk::ImageType::TYPE_2D) + .format(vk::Format::G8_B8R8_2PLANE_420_UNORM) + .extent(vk::Extent3D { + width, + height, + depth: 1, + }) + .mip_levels(1) + .array_layers(1) + .samples(vk::SampleCountFlags::TYPE_1) + .tiling(vk::ImageTiling::DRM_FORMAT_MODIFIER_EXT) + .usage(vk::ImageUsageFlags::SAMPLED) + .sharing_mode(vk::SharingMode::EXCLUSIVE) + .initial_layout(vk::ImageLayout::UNDEFINED); + let image = unsafe { device.create_image(&image_info, None) } + .map_err(|error| vk_error("create DMA-BUF NV12 image", error))?; + let requirements = unsafe { device.get_image_memory_requirements(image) }; + let fd_loader = ash::khr::external_memory_fd::Device::new(instance, device); + let mut fd_properties = vk::MemoryFdPropertiesKHR::default(); + if let Err(error) = unsafe { + fd_loader.get_memory_fd_properties( + vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT, + fd, + &mut fd_properties, + ) + } { + unsafe { device.destroy_image(image, None) }; + return Err(vk_error("query DMA-BUF memory properties", error)); + } + let memory_bits = requirements.memory_type_bits & fd_properties.memory_type_bits; + let memory_type = match find_memory_type( + instance, + physical_device, + memory_bits, + vk::MemoryPropertyFlags::empty(), + ) { + Ok(index) => index, + Err(error) => { + unsafe { device.destroy_image(image, None) }; + return Err(error); + } + }; + let imported_fd = unsafe { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, 0) }; + if imported_fd < 0 { + unsafe { device.destroy_image(image, None) }; + return Err(Error::backend( + Subsystem::Vulkan, + format!( + "duplicate DMA-BUF failed: {}", + std::io::Error::last_os_error() + ), + )); + } + let mut import = vk::ImportMemoryFdInfoKHR::default() + .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT) + .fd(imported_fd); + let mut dedicated = vk::MemoryDedicatedAllocateInfo::default().image(image); + let allocation = vk::MemoryAllocateInfo::default() + .push_next(&mut import) + .push_next(&mut dedicated) + .allocation_size(requirements.size.max(object_size as vk::DeviceSize)) + .memory_type_index(memory_type); + let memory = match unsafe { device.allocate_memory(&allocation, None) } { + Ok(memory) => memory, + Err(error) => { + unsafe { + libc::close(imported_fd); + device.destroy_image(image, None); + } + return Err(vk_error("import DMA-BUF memory", error)); + } + }; + if let Err(error) = unsafe { device.bind_image_memory(image, memory, 0) } { + unsafe { + device.free_memory(memory, None); + device.destroy_image(image, None); + } + return Err(vk_error("bind DMA-BUF image memory", error)); + } + let luma_view = match create_plane_view( + device, + image, + vk::Format::R8_UNORM, + vk::ImageAspectFlags::PLANE_0, + ) { + Ok(view) => view, + Err(error) => { + unsafe { + device.free_memory(memory, None); + device.destroy_image(image, None); + } + return Err(error); + } + }; + let chroma_view = match create_plane_view( + device, + image, + vk::Format::R8G8_UNORM, + vk::ImageAspectFlags::PLANE_1, + ) { + Ok(view) => view, + Err(error) => { + unsafe { + device.destroy_image_view(luma_view, None); + device.free_memory(memory, None); + device.destroy_image(image, None); + } + return Err(error); + } + }; + Ok(ImportedDmaBufImage { + image, + memory, + luma_view, + chroma_view, + }) +} + +fn create_plane_view( + device: &ash::Device, + image: vk::Image, + format: vk::Format, + aspect: vk::ImageAspectFlags, +) -> Result { + let range = vk::ImageSubresourceRange::default() + .aspect_mask(aspect) + .level_count(1) + .layer_count(1); + let create = vk::ImageViewCreateInfo::default() + .image(image) + .view_type(vk::ImageViewType::TYPE_2D) + .format(format) + .subresource_range(range); + unsafe { device.create_image_view(&create, None) } + .map_err(|error| vk_error("create DMA-BUF plane image view", error)) +} + +fn destroy_imported_dmabuf(device: &ash::Device, imported: ImportedDmaBufImage) { + unsafe { + device.destroy_image_view(imported.chroma_view, None); + device.destroy_image_view(imported.luma_view, None); + device.destroy_image(imported.image, None); + device.free_memory(imported.memory, None); + } +} + +fn create_sampled_image( + instance: &Instance, + physical_device: vk::PhysicalDevice, + device: &ash::Device, + width: u32, + height: u32, + format: vk::Format, +) -> Result { + let image_info = vk::ImageCreateInfo::default() + .image_type(vk::ImageType::TYPE_2D) + .format(format) + .extent(vk::Extent3D { + width, + height, + depth: 1, + }) + .mip_levels(1) + .array_layers(1) + .samples(vk::SampleCountFlags::TYPE_1) + .tiling(vk::ImageTiling::OPTIMAL) + .usage(vk::ImageUsageFlags::TRANSFER_DST | vk::ImageUsageFlags::SAMPLED) + .sharing_mode(vk::SharingMode::EXCLUSIVE) + .initial_layout(vk::ImageLayout::UNDEFINED); + let image = unsafe { device.create_image(&image_info, None) } + .map_err(|error| vk_error("create NV12 plane image", error))?; + let requirements = unsafe { device.get_image_memory_requirements(image) }; + let memory_type = match find_memory_type( + instance, + physical_device, + requirements.memory_type_bits, + vk::MemoryPropertyFlags::DEVICE_LOCAL, + ) { + Ok(memory_type) => memory_type, + Err(error) => { + unsafe { device.destroy_image(image, None) }; + return Err(error); + } + }; + let allocation = vk::MemoryAllocateInfo::default() + .allocation_size(requirements.size) + .memory_type_index(memory_type); + let memory = match unsafe { device.allocate_memory(&allocation, None) } { + Ok(memory) => memory, + Err(error) => { + unsafe { device.destroy_image(image, None) }; + return Err(vk_error("allocate NV12 plane memory", error)); + } + }; + if let Err(error) = unsafe { device.bind_image_memory(image, memory, 0) } { + unsafe { + device.free_memory(memory, None); + device.destroy_image(image, None); + } + return Err(vk_error("bind NV12 plane memory", error)); + } + let view_info = vk::ImageViewCreateInfo::default() + .image(image) + .view_type(vk::ImageViewType::TYPE_2D) + .format(format) + .subresource_range(color_range()); + let view = match unsafe { device.create_image_view(&view_info, None) } { + Ok(view) => view, + Err(error) => { + unsafe { + device.free_memory(memory, None); + device.destroy_image(image, None); + } + return Err(vk_error("create NV12 plane view", error)); + } + }; + Ok(GpuImage { + image, + memory, + view, + }) +} + +fn destroy_gpu_image(device: &ash::Device, image: GpuImage) { + unsafe { + device.destroy_image_view(image.view, None); + device.destroy_image(image.image, None); + device.free_memory(image.memory, None); + } +} + +fn create_command_resources( + device: &ash::Device, + queue_family: u32, +) -> Result<(vk::CommandPool, vk::CommandBuffer, vk::Semaphore, vk::Fence)> { + let command_pool_info = vk::CommandPoolCreateInfo::default() + .queue_family_index(queue_family) + .flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER); + let command_pool = unsafe { device.create_command_pool(&command_pool_info, None) } + .map_err(|error| vk_error("create command pool", error))?; + let command_info = vk::CommandBufferAllocateInfo::default() + .command_pool(command_pool) + .level(vk::CommandBufferLevel::PRIMARY) + .command_buffer_count(1); + let command_buffer = match unsafe { device.allocate_command_buffers(&command_info) } { + Ok(buffers) => buffers[0], + Err(error) => { + unsafe { device.destroy_command_pool(command_pool, None) }; + return Err(vk_error("allocate command buffer", error)); + } + }; + let semaphore_info = vk::SemaphoreCreateInfo::default(); + let image_available = match unsafe { device.create_semaphore(&semaphore_info, None) } { + Ok(semaphore) => semaphore, + Err(error) => { + unsafe { device.destroy_command_pool(command_pool, None) }; + return Err(vk_error("create acquire semaphore", error)); + } + }; + let fence_info = vk::FenceCreateInfo::default().flags(vk::FenceCreateFlags::SIGNALED); + let in_flight = match unsafe { device.create_fence(&fence_info, None) } { + Ok(fence) => fence, + Err(error) => { + unsafe { + device.destroy_semaphore(image_available, None); + device.destroy_command_pool(command_pool, None); + } + return Err(vk_error("create presentation fence", error)); + } + }; + Ok((command_pool, command_buffer, image_available, in_flight)) +} + +impl Drop for VulkanPresenter { + fn drop(&mut self) { + unsafe { + let _ = self.device.device_wait_idle(); + } + self.in_flight_dmabuf = None; + self.in_flight_vulkan = None; + self.destroy_swapchain(); + for (_, views) in self.direct_views.drain() { + unsafe { + self.device.destroy_image_view(views.chroma, None); + self.device.destroy_image_view(views.luma, None); + } + } + self.destroy_imported_dmabufs(); + self.destroy_overlay_images(); + self.destroy_nv12_images(); + unsafe { + if self.staging_buffer != vk::Buffer::null() { + self.device.destroy_buffer(self.staging_buffer, None); + self.device.free_memory(self.staging_memory, None); + } + if self.in_flight != vk::Fence::null() { + self.device.destroy_fence(self.in_flight, None); + } + if self.image_available != vk::Semaphore::null() { + self.device.destroy_semaphore(self.image_available, None); + } + if self.command_pool != vk::CommandPool::null() { + self.device.destroy_command_pool(self.command_pool, None); + } + if self.owns_device { + self.device.destroy_device(None); + } + self.surface_loader.destroy_surface(self.surface, None); + if self.owns_device { + self.instance.destroy_instance(None); + } + } + } +} + +pub(crate) fn probe_vulkan() -> std::result::Result<(Vec<&'static str>, String), String> { + let entry = unsafe { Entry::load() }.map_err(|error| error.to_string())?; + let extensions = unsafe { entry.enumerate_instance_extension_properties(None) } + .map_err(|error| error.to_string())?; + let has = |name: &CStr| { + extensions + .iter() + .any(|extension| (unsafe { CStr::from_ptr(extension.extension_name.as_ptr()) }) == name) + }; + if !has(ash::khr::surface::NAME) { + return Err("Vulkan loader lacks VK_KHR_surface".to_owned()); + } + let mut window_systems = Vec::new(); + let mut extension_names = vec![ash::khr::surface::NAME.as_ptr()]; + if has(ash::khr::xlib_surface::NAME) { + window_systems.push("x11"); + extension_names.push(ash::khr::xlib_surface::NAME.as_ptr()); + } + if has(ash::khr::wayland_surface::NAME) { + window_systems.push("wayland"); + extension_names.push(ash::khr::wayland_surface::NAME.as_ptr()); + } + if window_systems.is_empty() { + return Err("Vulkan loader has neither Xlib nor Wayland WSI".to_owned()); + } + let create = vk::InstanceCreateInfo::default().enabled_extension_names(&extension_names); + let instance = + unsafe { entry.create_instance(&create, None) }.map_err(|error| error.to_string())?; + let devices = match unsafe { instance.enumerate_physical_devices() } { + Ok(devices) => devices, + Err(error) => { + unsafe { instance.destroy_instance(None) }; + return Err(error.to_string()); + } + }; + let usable_devices = devices + .into_iter() + .filter(|device| { + supports_swapchain(&instance, *device).unwrap_or(false) + && unsafe { instance.get_physical_device_queue_family_properties(*device) } + .iter() + .any(|queue| queue.queue_flags.contains(vk::QueueFlags::GRAPHICS)) + }) + .count(); + unsafe { instance.destroy_instance(None) }; + if usable_devices == 0 { + Err("Vulkan found no graphics device with VK_KHR_swapchain".to_owned()) + } else { + let detail = format!( + "{} Vulkan physical device(s), {} WSI", + usable_devices, + window_systems.join(" and ") + ); + Ok((window_systems, detail)) + } +} + +fn select_device( + instance: &Instance, + surface_loader: &ash::khr::surface::Instance, + surface: vk::SurfaceKHR, +) -> Result<(vk::PhysicalDevice, u32)> { + let devices = unsafe { instance.enumerate_physical_devices() } + .map_err(|error| vk_error("enumerate physical devices", error))?; + for device in devices { + if !supports_swapchain(instance, device) + .map_err(|error| vk_error("enumerate device extensions", error))? + { + continue; + } + let queues = unsafe { instance.get_physical_device_queue_family_properties(device) }; + for (index, properties) in queues.iter().enumerate() { + if !properties.queue_flags.contains(vk::QueueFlags::GRAPHICS) { + continue; + } + let present = unsafe { + surface_loader.get_physical_device_surface_support(device, index as u32, surface) + } + .map_err(|error| vk_error("query queue presentation support", error))?; + if present { + return Ok((device, index as u32)); + } + } + } + Err(Error::unavailable( + Subsystem::Vulkan, + "no graphics queue can present to the supplied native surface", + )) +} + +fn select_shared_queue( + instance: &Instance, + surface_loader: &ash::khr::surface::Instance, + surface: vk::SurfaceKHR, + shared: &VulkanVideoFrame, +) -> Result<(vk::PhysicalDevice, u32)> { + let physical_device = vk::PhysicalDevice::from_raw(shared.physical_device as u64); + let properties = + unsafe { instance.get_physical_device_queue_family_properties(physical_device) }; + for queue_family in &shared.queue_families { + let Some(queue) = properties.get(*queue_family as usize) else { + continue; + }; + if !queue.queue_flags.contains(vk::QueueFlags::GRAPHICS) { + continue; + } + let present = unsafe { + surface_loader.get_physical_device_surface_support( + physical_device, + *queue_family, + surface, + ) + } + .map_err(|error| vk_error("query shared queue presentation support", error))?; + if present { + return Ok((physical_device, *queue_family)); + } + } + Err(Error::unavailable( + Subsystem::Vulkan, + "FFmpeg Vulkan device has no enabled graphics queue that can present this surface", + )) +} + +fn supports_swapchain( + instance: &Instance, + device: vk::PhysicalDevice, +) -> std::result::Result { + let extensions = unsafe { instance.enumerate_device_extension_properties(device) }?; + Ok(extensions.iter().any(|extension| { + (unsafe { CStr::from_ptr(extension.extension_name.as_ptr()) }) == ash::khr::swapchain::NAME + })) +} + +fn supports_device_extensions( + instance: &Instance, + device: vk::PhysicalDevice, + required: &[&CStr], +) -> std::result::Result { + let extensions = unsafe { instance.enumerate_device_extension_properties(device) }?; + Ok(required.iter().all(|required| { + extensions.iter().any(|extension| { + (unsafe { CStr::from_ptr(extension.extension_name.as_ptr()) }) == *required + }) + })) +} + +fn choose_surface_format(formats: &[vk::SurfaceFormatKHR]) -> Result { + for desired in [ + vk::Format::B8G8R8A8_UNORM, + vk::Format::B8G8R8A8_SRGB, + vk::Format::R8G8B8A8_UNORM, + vk::Format::R8G8B8A8_SRGB, + ] { + if let Some(format) = formats.iter().find(|format| format.format == desired) { + return Ok(*format); + } + } + Err(Error::unavailable( + Subsystem::Vulkan, + "surface has no 8-bit BGRA or RGBA transfer-destination format", + )) +} + +fn choose_extent( + capabilities: vk::SurfaceCapabilitiesKHR, + width: u32, + height: u32, +) -> vk::Extent2D { + if capabilities.current_extent.width != u32::MAX { + return capabilities.current_extent; + } + vk::Extent2D { + width: width.clamp( + capabilities.min_image_extent.width, + capabilities.max_image_extent.width, + ), + height: height.clamp( + capabilities.min_image_extent.height, + capabilities.max_image_extent.height, + ), + } +} + +fn choose_composite_alpha(supported: vk::CompositeAlphaFlagsKHR) -> vk::CompositeAlphaFlagsKHR { + [ + vk::CompositeAlphaFlagsKHR::OPAQUE, + vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED, + vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED, + vk::CompositeAlphaFlagsKHR::INHERIT, + ] + .into_iter() + .find(|mode| supported.contains(*mode)) + .unwrap_or(vk::CompositeAlphaFlagsKHR::OPAQUE) +} + +/// Match the official Linux client's synchronized swapchain. Frame selection +/// and stale-frame skipping happen before submission, so WSI receives at most +/// one intentional frame per display interval and does not need MAILBOX to +/// hide an upstream backlog. +fn choose_present_mode(supported: &[vk::PresentModeKHR]) -> vk::PresentModeKHR { + let preferred = [ + vk::PresentModeKHR::FIFO, + vk::PresentModeKHR::MAILBOX, + vk::PresentModeKHR::IMMEDIATE, + ]; + preferred + .into_iter() + .find(|mode| supported.contains(mode)) + .or_else(|| supported.first().copied()) + .unwrap_or(vk::PresentModeKHR::FIFO) +} + +fn find_memory_type( + instance: &Instance, + physical_device: vk::PhysicalDevice, + type_bits: u32, + required: vk::MemoryPropertyFlags, +) -> Result { + let properties = unsafe { instance.get_physical_device_memory_properties(physical_device) }; + (0..properties.memory_type_count) + .find(|index| { + type_bits & (1 << index) != 0 + && properties.memory_types[*index as usize] + .property_flags + .contains(required) + }) + .ok_or_else(|| { + Error::unavailable( + Subsystem::Vulkan, + "no coherent host-visible memory for the presentation staging buffer", + ) + }) +} + +fn color_range() -> vk::ImageSubresourceRange { + vk::ImageSubresourceRange::default() + .aspect_mask(vk::ImageAspectFlags::COLOR) + .level_count(1) + .layer_count(1) +} + +fn aspect_fit_extent( + source_width: u32, + source_height: u32, + target_width: u32, + target_height: u32, +) -> (u32, u32, u32, u32) { + let scale = (target_width as f64 / source_width as f64) + .min(target_height as f64 / source_height as f64); + let width = ((source_width as f64 * scale).round().max(1.0) as u32).min(target_width); + let height = ((source_height as f64 * scale).round().max(1.0) as u32).min(target_height); + ( + (target_width - width) / 2, + (target_height - height) / 2, + width, + height, + ) +} + +#[cfg(test)] +fn yuv_to_rgb(y: u8, u: u8, v: u8, matrix: ColorMatrix, range: ColorRange) -> (u8, u8, u8) { + let (y, u, v) = match range { + ColorRange::Limited => ( + ((y as f32 - 16.0) * (255.0 / 219.0)).max(0.0), + (u as f32 - 128.0) * (255.0 / 224.0), + (v as f32 - 128.0) * (255.0 / 224.0), + ), + ColorRange::Full => (y as f32, u as f32 - 128.0, v as f32 - 128.0), + }; + let (r, g, b) = match matrix { + ColorMatrix::Bt601 => ( + y + 1.402 * v, + y - 0.344_136 * u - 0.714_136 * v, + y + 1.772 * u, + ), + ColorMatrix::Bt709 => ( + y + 1.5748 * v, + y - 0.187_324 * u - 0.468_124 * v, + y + 1.8556 * u, + ), + ColorMatrix::Bt2020 => ( + y + 1.4746 * v, + y - 0.164_553 * u - 0.571_353 * v, + y + 1.8814 * u, + ), + }; + (clamp_u8(r), clamp_u8(g), clamp_u8(b)) +} + +#[cfg(test)] +fn clamp_u8(value: f32) -> u8 { + value.round().clamp(0.0, 255.0) as u8 +} + +fn validate_presentation_extent(width: u32, height: u32) -> Result<()> { + if width == 0 || height == 0 { + return Err(Error::InvalidFormat( + "presentation extent must be non-zero".to_owned(), + )); + } + if width > 16_384 || height > 16_384 { + return Err(Error::InvalidFormat( + "presentation extent exceeds the backend limit".to_owned(), + )); + } + Ok(()) +} + +fn vk_error(operation: &str, error: vk::Result) -> Error { + if error == vk::Result::ERROR_DEVICE_LOST { + return Error::DeviceLost { + subsystem: Subsystem::Vulkan, + reason: format!("{operation}: {error:?}"), + }; + } + Error::backend(Subsystem::Vulkan, format!("{operation}: {error:?}")) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn limited_bt709_black_and_white_are_mapped_correctly() { + assert_eq!( + yuv_to_rgb(16, 128, 128, ColorMatrix::Bt709, ColorRange::Limited), + (0, 0, 0) + ); + assert_eq!( + yuv_to_rgb(235, 128, 128, ColorMatrix::Bt709, ColorRange::Limited), + (255, 255, 255) + ); + } + + #[test] + fn presentation_preserves_source_aspect_ratio() { + assert_eq!(aspect_fit_extent(1920, 1080, 1024, 768), (0, 96, 1024, 576)); + assert_eq!( + aspect_fit_extent(1024, 768, 1920, 1080), + (240, 0, 1440, 1080) + ); + } + + #[test] + fn gpu_conversion_constants_preserve_range_matrix_and_letterboxing() { + use std::sync::Arc; + + use crate::{ChromaLocation, FramePlane, StreamFormat}; + + let frame = DecodedVideoFrame { + format: StreamFormat { + width: 1920, + height: 1080, + pixel_format: PixelFormat::Nv12, + color_range: ColorRange::Full, + color_matrix: ColorMatrix::Bt2020, + chroma_location: ChromaLocation::Left, + }, + planes: vec![ + FramePlane { + data: Arc::from(vec![0; 1920 * 1080]), + stride: 1920, + rows: 1080, + }, + FramePlane { + data: Arc::from(vec![0; 1920 * 540]), + stride: 1920, + rows: 540, + }, + ], + dmabuf: None, + vulkan: None, + overlay: None, + timestamp_us: 0, + }; + let constants = conversion_constants( + &frame, + vk::Extent2D { + width: 1024, + height: 768, + }, + ); + assert_eq!(constants.texture_scale, [1.0, 768.0 / 576.0]); + assert_eq!(constants.color_matrix, 2); + assert_eq!(constants.full_range, 1); + assert_eq!(std::mem::size_of::(), 16); + } + + #[test] + fn present_mode_uses_fifo_vsync_when_supported() { + assert_eq!( + choose_present_mode(&[vk::PresentModeKHR::FIFO, vk::PresentModeKHR::MAILBOX]), + vk::PresentModeKHR::FIFO + ); + assert_eq!( + choose_present_mode(&[vk::PresentModeKHR::MAILBOX, vk::PresentModeKHR::IMMEDIATE]), + vk::PresentModeKHR::MAILBOX + ); + assert_eq!( + choose_present_mode(&[vk::PresentModeKHR::FIFO]), + vk::PresentModeKHR::FIFO + ); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/queue.rs b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/queue.rs new file mode 100644 index 000000000..842a57202 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/queue.rs @@ -0,0 +1,256 @@ +use std::collections::VecDeque; +use std::sync::{Condvar, Mutex}; +use std::time::{Duration, Instant}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum QueuePush { + Added, + DroppedOldest, + Full, + Closed, +} + +#[derive(Debug, PartialEq, Eq)] +pub enum QueuePop { + Item(T), + TimedOut, + Closed, +} + +#[derive(Debug)] +struct State { + items: VecDeque, + closed: bool, +} + +#[derive(Debug)] +pub struct BoundedQueue { + capacity: usize, + state: Mutex>, + ready: Condvar, +} + +impl BoundedQueue { + pub fn new(capacity: usize) -> Self { + assert!(capacity > 0, "queue capacity must be non-zero"); + Self { + capacity, + state: Mutex::new(State { + items: VecDeque::with_capacity(capacity), + closed: false, + }), + ready: Condvar::new(), + } + } + + pub fn push_latest(&self, item: T) -> QueuePush { + let mut state = self + .state + .lock() + .unwrap_or_else(|poison| poison.into_inner()); + if state.closed { + return QueuePush::Closed; + } + let outcome = if state.items.len() == self.capacity { + state.items.pop_front(); + QueuePush::DroppedOldest + } else { + QueuePush::Added + }; + state.items.push_back(item); + self.ready.notify_one(); + outcome + } + + pub fn push(&self, item: T) -> QueuePush { + let mut state = self + .state + .lock() + .unwrap_or_else(|poison| poison.into_inner()); + if state.closed { + return QueuePush::Closed; + } + if state.items.len() == self.capacity { + return QueuePush::Full; + } + state.items.push_back(item); + self.ready.notify_one(); + QueuePush::Added + } + + pub fn replace(&self, item: T) -> QueuePush { + let mut state = self + .state + .lock() + .unwrap_or_else(|poison| poison.into_inner()); + if state.closed { + return QueuePush::Closed; + } + let outcome = if state.items.is_empty() { + QueuePush::Added + } else { + QueuePush::DroppedOldest + }; + state.items.clear(); + state.items.push_back(item); + self.ready.notify_one(); + outcome + } + + pub fn replace_where(&self, item: T, mut should_remove: impl FnMut(&T) -> bool) -> QueuePush { + let mut state = self + .state + .lock() + .unwrap_or_else(|poison| poison.into_inner()); + if state.closed { + return QueuePush::Closed; + } + let original_len = state.items.len(); + state.items.retain(|queued| !should_remove(queued)); + if state.items.len() == self.capacity { + return QueuePush::Full; + } + let outcome = if state.items.len() == original_len { + QueuePush::Added + } else { + QueuePush::DroppedOldest + }; + state.items.push_back(item); + self.ready.notify_one(); + outcome + } + + pub fn try_pop(&self) -> Option { + self.state + .lock() + .unwrap_or_else(|poison| poison.into_inner()) + .items + .pop_front() + } + + pub fn wait_pop(&self, timeout: Duration) -> QueuePop { + let start = Instant::now(); + let mut state = self + .state + .lock() + .unwrap_or_else(|poison| poison.into_inner()); + loop { + if let Some(item) = state.items.pop_front() { + return QueuePop::Item(item); + } + if state.closed { + return QueuePop::Closed; + } + let Some(remaining) = timeout.checked_sub(start.elapsed()) else { + return QueuePop::TimedOut; + }; + let (next, result) = self + .ready + .wait_timeout(state, remaining) + .unwrap_or_else(|poison| poison.into_inner()); + state = next; + if result.timed_out() { + return state + .items + .pop_front() + .map_or(QueuePop::TimedOut, QueuePop::Item); + } + } + } + + pub fn pop_timeout(&self, timeout: Duration) -> Option { + match self.wait_pop(timeout) { + QueuePop::Item(item) => Some(item), + QueuePop::TimedOut | QueuePop::Closed => None, + } + } + + pub fn clear(&self) { + self.state + .lock() + .unwrap_or_else(|poison| poison.into_inner()) + .items + .clear(); + } + + pub fn is_closed(&self) -> bool { + self.state + .lock() + .unwrap_or_else(|poison| poison.into_inner()) + .closed + } + + pub fn close(&self) { + let mut state = self + .state + .lock() + .unwrap_or_else(|poison| poison.into_inner()); + state.closed = true; + state.items.clear(); + self.ready.notify_all(); + } + + #[cfg(test)] + pub fn len(&self) -> usize { + self.state + .lock() + .unwrap_or_else(|poison| poison.into_inner()) + .items + .len() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn keeps_newest_items_at_capacity() { + let queue = BoundedQueue::new(2); + assert_eq!(queue.push_latest(1), QueuePush::Added); + assert_eq!(queue.push_latest(2), QueuePush::Added); + assert_eq!(queue.push_latest(3), QueuePush::DroppedOldest); + assert_eq!(queue.len(), 2); + assert_eq!(queue.try_pop(), Some(2)); + assert_eq!(queue.try_pop(), Some(3)); + } + + #[test] + fn close_wakes_waiters_and_rejects_pushes() { + let queue = BoundedQueue::new(1); + queue.close(); + assert_eq!(queue.wait_pop(Duration::from_secs(1)), QueuePop::Closed); + assert_eq!(queue.push_latest(1), QueuePush::Closed); + assert_eq!(queue.push(1), QueuePush::Closed); + } + + #[test] + fn timeout_does_not_close_an_idle_queue() { + let queue = BoundedQueue::new(1); + assert_eq!(queue.wait_pop(Duration::from_millis(1)), QueuePop::TimedOut); + assert_eq!(queue.push_latest(7), QueuePush::Added); + assert_eq!(queue.wait_pop(Duration::from_secs(1)), QueuePop::Item(7)); + } + + #[test] + fn non_evicting_push_and_atomic_replace_preserve_control() { + let queue = BoundedQueue::new(1); + assert_eq!(queue.push(1), QueuePush::Added); + assert_eq!(queue.push(2), QueuePush::Full); + assert_eq!(queue.replace(3), QueuePush::DroppedOldest); + assert_eq!(queue.try_pop(), Some(3)); + } + + #[test] + fn conditional_replace_never_removes_control() { + let queue = BoundedQueue::new(2); + assert_eq!(queue.push((false, 1)), QueuePush::Added); + assert_eq!(queue.push((true, 2)), QueuePush::Added); + assert_eq!( + queue.replace_where((true, 3), |(media, _)| *media), + QueuePush::DroppedOldest + ); + assert_eq!(queue.try_pop(), Some((false, 1))); + assert_eq!(queue.try_pop(), Some((true, 3))); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/session.rs b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/session.rs new file mode 100644 index 000000000..3f3be440f --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/session.rs @@ -0,0 +1,1090 @@ +use std::path::PathBuf; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::mpsc; +use std::sync::{Arc, Mutex}; +use std::thread::{self, JoinHandle}; +use std::time::Duration; + +use crate::audio::{AudioSink, OpusDecoder, open_audio_fallback, open_audio_sink}; +use crate::queue::{BoundedQueue, QueuePop, QueuePush}; +use crate::video::{VideoDecoder, open_v4l2}; +use crate::{ + AudioBackend, AudioConfig, AudioPacket, DecodedVideoFrame, EncodedVideoFrame, Error, Result, + StreamFormat, Subsystem, VideoCodec, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DecoderBackend { + Vulkan, + Cuda, + VaApi, + V4l2, + Ffmpeg, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DecoderPreference { + Automatic, + VulkanOnly, + CudaOnly, + VaApiThenV4l2, + V4l2ThenVaApi, + VaApiOnly, + V4l2Only, + SoftwareOnly, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum LifecycleState { + Starting, + Running, + Reconfiguring, + Stopping, + Stopped, + Failed, +} + +impl LifecycleState { + fn can_transition_to(self, next: Self) -> bool { + matches!( + (self, next), + ( + Self::Starting, + Self::Running | Self::Failed | Self::Stopping + ) | ( + Self::Running, + Self::Reconfiguring | Self::Stopping | Self::Failed + ) | ( + Self::Reconfiguring, + Self::Running | Self::Stopping | Self::Failed + ) | (Self::Stopping, Self::Stopped | Self::Failed) + | (Self::Failed, Self::Stopping) + ) || self == next + } +} + +#[derive(Debug, Clone)] +pub struct SessionConfig { + pub codec: VideoCodec, + pub stream_format: StreamFormat, + pub decoder_preference: DecoderPreference, + pub v4l2_device: Option, + pub encoded_queue_depth: usize, + pub decoded_queue_depth: usize, + pub audio: Option, +} + +impl SessionConfig { + pub fn new(stream_format: StreamFormat) -> Self { + Self { + codec: VideoCodec::H264, + stream_format, + decoder_preference: DecoderPreference::Automatic, + v4l2_device: None, + // Hardware decoders can briefly stop consuming while the driver + // retires a large frame or reallocates surfaces. Four frames is + // too small for a 120 Hz stream and turns a harmless burst into a + // decoder reset. Keep this bounded, but absorb roughly two frame + // batches before initiating keyframe recovery. + encoded_queue_depth: 16, + decoded_queue_depth: 3, + audio: Some(AudioConfig::default()), + } + } + + fn validate(&self) -> Result<()> { + self.stream_format.validate()?; + if self.encoded_queue_depth == 0 || self.encoded_queue_depth > 64 { + return Err(Error::InvalidFormat( + "encoded video queue depth must be between 1 and 64".to_owned(), + )); + } + if self.decoded_queue_depth == 0 || self.decoded_queue_depth > 16 { + return Err(Error::InvalidFormat( + "decoded video queue depth must be between 1 and 16".to_owned(), + )); + } + if let Some(audio) = &self.audio { + audio.validate()?; + } + Ok(()) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PushOutcome { + Queued, + DroppedOldest, + Paused, +} + +#[derive(Debug)] +pub enum BackendEvent { + StateChanged(LifecycleState), + DecoderSelected(DecoderBackend), + DecoderChanged { + from: DecoderBackend, + to: DecoderBackend, + reason: String, + }, + AudioSelected(AudioBackend), + FormatChanged(StreamFormat), + NeedKeyframe, + QueueOverflow { + media: &'static str, + }, + DeviceLost { + subsystem: Subsystem, + reason: String, + }, + Error(String), +} + +enum VideoCommand { + Decode { + frame: EncodedVideoFrame, + generation: u64, + reset: bool, + }, + Reconfigure { + format: StreamFormat, + generation: u64, + }, +} + +type EventQueue = Arc>; + +pub struct LinuxSession { + config: SessionConfig, + state: Arc>, + video_commands: Arc>, + decoded_frames: Arc>, + audio_packets: Option>>, + events: EventQueue, + video_generation: AtomicU64, + video_needs_keyframe: AtomicBool, + paused: AtomicBool, + video_submit: Mutex<()>, + video_worker: Option>, + audio_worker: Option>, +} + +impl LinuxSession { + pub fn start(config: SessionConfig) -> Result { + config.validate()?; + let state = Arc::new(Mutex::new(LifecycleState::Starting)); + let video_commands = Arc::new(BoundedQueue::new(config.encoded_queue_depth)); + let decoded_frames = Arc::new(BoundedQueue::new(config.decoded_queue_depth)); + let events = Arc::new(BoundedQueue::new(64)); + let (startup_tx, startup_rx) = mpsc::sync_channel(1); + let video_worker = { + let config = config.clone(); + let state = Arc::clone(&state); + let commands = Arc::clone(&video_commands); + let decoded = Arc::clone(&decoded_frames); + let events = Arc::clone(&events); + thread::Builder::new() + .name("opennow-linux-video".to_owned()) + .spawn(move || { + run_video_worker(config, state, commands, decoded, events, startup_tx) + }) + .map_err(|error| Error::io(Subsystem::Session, error))? + }; + match startup_rx.recv_timeout(Duration::from_secs(3)) { + Ok(Ok(_)) => {} + Ok(Err(error)) => { + video_commands.close(); + let _ = video_worker.join(); + return Err(error); + } + Err(mpsc::RecvTimeoutError::Disconnected) => { + video_commands.close(); + let _ = video_worker.join(); + return Err(Error::WorkerPanic("video startup")); + } + Err(mpsc::RecvTimeoutError::Timeout) => { + video_commands.close(); + let _ = video_worker.join(); + return Err(Error::backend( + Subsystem::Session, + "video worker startup timed out and was cancelled", + )); + } + } + + let (audio_packets, audio_worker) = if let Some(audio_config) = config.audio.clone() { + let queue = Arc::new(BoundedQueue::new(audio_config.queue_depth)); + let (audio_start_tx, audio_start_rx) = mpsc::sync_channel(1); + let worker = { + let queue = Arc::clone(&queue); + let events = Arc::clone(&events); + let state = Arc::clone(&state); + match thread::Builder::new() + .name("opennow-linux-audio".to_owned()) + .spawn(move || { + run_audio_worker(audio_config, queue, state, events, audio_start_tx) + }) { + Ok(worker) => worker, + Err(error) => { + video_commands.close(); + let _ = video_worker.join(); + return Err(Error::io(Subsystem::Session, error)); + } + } + }; + match audio_start_rx.recv_timeout(Duration::from_secs(3)) { + Ok(Ok(_)) => (Some(queue), Some(worker)), + Ok(Err(error)) => { + queue.close(); + let _ = worker.join(); + video_commands.close(); + let _ = video_worker.join(); + return Err(error); + } + Err(_) => { + queue.close(); + let _ = worker.join(); + video_commands.close(); + let _ = video_worker.join(); + return Err(Error::backend( + Subsystem::Session, + "audio worker startup timed out", + )); + } + } + } else { + (None, None) + }; + + Ok(Self { + config, + state, + video_commands, + decoded_frames, + audio_packets, + events, + video_generation: AtomicU64::new(0), + video_needs_keyframe: AtomicBool::new(false), + paused: AtomicBool::new(false), + video_submit: Mutex::new(()), + video_worker: Some(video_worker), + audio_worker, + }) + } + + pub fn state(&self) -> LifecycleState { + *self + .state + .lock() + .unwrap_or_else(|poison| poison.into_inner()) + } + + pub fn submit_video(&self, frame: EncodedVideoFrame) -> Result { + frame.validate()?; + if self.state() != LifecycleState::Running { + return Err(Error::NotRunning); + } + if self.paused.load(Ordering::Acquire) { + return Ok(PushOutcome::Paused); + } + let _submission = self + .video_submit + .lock() + .unwrap_or_else(|poison| poison.into_inner()); + queue_video_command( + &self.video_commands, + &self.events, + &self.video_generation, + &self.video_needs_keyframe, + frame, + ) + } + + pub fn submit_audio(&self, packet: AudioPacket) -> Result { + packet.validate()?; + if self.state() != LifecycleState::Running { + return Err(Error::NotRunning); + } + if self.paused.load(Ordering::Acquire) { + return Ok(PushOutcome::Paused); + } + let queue = self.audio_packets.as_ref().ok_or_else(|| { + Error::unavailable(Subsystem::Session, "audio is disabled for this session") + })?; + match queue.push_latest(packet) { + QueuePush::Added => Ok(PushOutcome::Queued), + QueuePush::DroppedOldest => { + emit(&self.events, BackendEvent::QueueOverflow { media: "audio" }); + Ok(PushOutcome::DroppedOldest) + } + QueuePush::Full => unreachable!(), + QueuePush::Closed => Err(Error::QueueClosed), + } + } + + pub fn reconfigure(&self, format: StreamFormat) -> Result<()> { + format.validate()?; + if self.state() != LifecycleState::Running { + return Err(Error::NotRunning); + } + let _submission = self + .video_submit + .lock() + .unwrap_or_else(|poison| poison.into_inner()); + self.video_needs_keyframe.store(true, Ordering::Release); + let generation = self.video_generation.fetch_add(1, Ordering::AcqRel) + 1; + match self + .video_commands + .replace(VideoCommand::Reconfigure { format, generation }) + { + QueuePush::Added | QueuePush::DroppedOldest => Ok(()), + QueuePush::Full => unreachable!(), + QueuePush::Closed => Err(Error::QueueClosed), + } + } + + pub fn set_paused(&self, paused: bool) -> Result<()> { + if self.state() != LifecycleState::Running { + return Err(Error::NotRunning); + } + let was_paused = self.paused.swap(paused, Ordering::AcqRel); + if was_paused == paused { + return Ok(()); + } + self.video_commands.clear(); + self.decoded_frames.clear(); + if let Some(audio) = &self.audio_packets { + audio.clear(); + } + if !paused { + self.reconfigure(self.config.stream_format)?; + } + Ok(()) + } + + pub fn try_recv_frame(&self) -> Option { + self.decoded_frames.try_pop() + } + + pub fn recv_frame_timeout(&self, timeout: Duration) -> Option { + self.decoded_frames.pop_timeout(timeout) + } + + pub fn try_recv_event(&self) -> Option { + self.events.try_pop() + } + + pub fn stop(&mut self) -> Result<()> { + let current = self.state(); + if matches!(current, LifecycleState::Stopped) { + return Ok(()); + } + transition_state(&self.state, LifecycleState::Stopping, &self.events); + self.video_commands.close(); + if let Some(queue) = &self.audio_packets { + queue.close(); + } + let mut failure = None; + if let Some(worker) = self.video_worker.take() { + if worker.join().is_err() { + failure = Some(Error::WorkerPanic("video")); + } + } + if let Some(worker) = self.audio_worker.take() { + if worker.join().is_err() && failure.is_none() { + failure = Some(Error::WorkerPanic("audio")); + } + } + self.decoded_frames.close(); + if self.state() == LifecycleState::Failed { + transition_state(&self.state, LifecycleState::Stopping, &self.events); + } + transition_state(&self.state, LifecycleState::Stopped, &self.events); + failure.map_or(Ok(()), Err) + } + + pub fn config(&self) -> &SessionConfig { + &self.config + } +} + +impl Drop for LinuxSession { + fn drop(&mut self) { + let _ = self.stop(); + } +} + +fn queue_video_command( + commands: &BoundedQueue, + events: &EventQueue, + generation: &AtomicU64, + needs_keyframe: &AtomicBool, + frame: EncodedVideoFrame, +) -> Result { + // Once an access unit has been dropped, later inter-frames are no longer + // decodable. Do not let them fill the queue or evict the recovery IDR. + // The first keyframe atomically replaces only decode work (never control + // commands) and starts a fresh decoder generation. + if needs_keyframe.load(Ordering::Acquire) { + if !frame.keyframe { + return Ok(PushOutcome::DroppedOldest); + } + let generation = generation.fetch_add(1, Ordering::AcqRel) + 1; + return match commands.replace_where( + VideoCommand::Decode { + frame, + generation, + reset: true, + }, + |queued| matches!(queued, VideoCommand::Decode { .. }), + ) { + QueuePush::Added => { + needs_keyframe.store(false, Ordering::Release); + Ok(PushOutcome::Queued) + } + QueuePush::DroppedOldest => { + needs_keyframe.store(false, Ordering::Release); + Ok(PushOutcome::DroppedOldest) + } + QueuePush::Full => Ok(PushOutcome::DroppedOldest), + QueuePush::Closed => Err(Error::QueueClosed), + }; + } + + let active_generation = generation.load(Ordering::Acquire); + match commands.push(VideoCommand::Decode { + frame: frame.clone(), + generation: active_generation, + reset: false, + }) { + QueuePush::Added => Ok(PushOutcome::Queued), + QueuePush::Full => { + emit(events, BackendEvent::QueueOverflow { media: "video" }); + needs_keyframe.store(true, Ordering::Release); + + // A keyframe that happens to arrive at the overflow boundary can + // recover immediately. Non-keyframes are deliberately discarded; + // preserving the already queued contiguous frames is preferable to + // repeatedly reopening the decoder with an undecodable P-frame. + if frame.keyframe { + let recovery_generation = generation.fetch_add(1, Ordering::AcqRel) + 1; + match commands.replace_where( + VideoCommand::Decode { + frame, + generation: recovery_generation, + reset: true, + }, + |queued| matches!(queued, VideoCommand::Decode { .. }), + ) { + QueuePush::Closed => return Err(Error::QueueClosed), + QueuePush::Added | QueuePush::DroppedOldest => { + needs_keyframe.store(false, Ordering::Release); + } + QueuePush::Full => {} + } + } else { + emit(events, BackendEvent::NeedKeyframe); + } + Ok(PushOutcome::DroppedOldest) + } + QueuePush::DroppedOldest => unreachable!(), + QueuePush::Closed => Err(Error::QueueClosed), + } +} + +fn run_video_worker( + config: SessionConfig, + state: Arc>, + commands: Arc>, + decoded: Arc>, + events: EventQueue, + startup: mpsc::SyncSender>, +) { + let (mut backend, mut decoder) = match open_preferred_decoder(&config, config.stream_format) { + Ok(opened) => opened, + Err(error) => { + let _ = startup.send(Err(error)); + transition_state(&state, LifecycleState::Failed, &events); + return; + } + }; + if startup.send(Ok(backend)).is_err() { + return; + } + emit(&events, BackendEvent::DecoderSelected(backend)); + transition_state(&state, LifecycleState::Running, &events); + // Never feed a fresh hardware decoder an inter-frame packet. In + // particular, an AV1 stream can deliver its sequence header separately; + // treating the following delta frame as startup input caused an avoidable + // backend fallback and a large visible hitch. + let mut need_keyframe = true; + emit(&events, BackendEvent::NeedKeyframe); + + let mut active_format = config.stream_format; + let mut active_generation = 0; + loop { + let command = match commands.wait_pop(Duration::from_millis(100)) { + QueuePop::Item(command) => command, + QueuePop::TimedOut => continue, + QueuePop::Closed => break, + }; + match command { + VideoCommand::Reconfigure { format, generation } => { + if generation < active_generation { + continue; + } + transition_state(&state, LifecycleState::Reconfiguring, &events); + if let Ok(frames) = flush_decoder(&mut decoder) { + enqueue_frames(&decoded, &events, frames); + } + decoded.clear(); + match open_preferred_decoder(&config, format) { + Ok((new_backend, new_decoder)) => { + if new_backend != backend { + emit( + &events, + BackendEvent::DecoderChanged { + from: backend, + to: new_backend, + reason: "stream format changed".to_owned(), + }, + ); + } + backend = new_backend; + decoder = new_decoder; + active_format = format; + active_generation = generation; + need_keyframe = true; + emit(&events, BackendEvent::FormatChanged(format)); + emit(&events, BackendEvent::NeedKeyframe); + transition_state(&state, LifecycleState::Running, &events); + } + Err(error) => { + report_worker_error(&state, &events, error); + return; + } + } + } + VideoCommand::Decode { + frame, + generation, + reset, + } => { + if generation < active_generation { + continue; + } + if reset || generation > active_generation { + decoded.clear(); + match open_preferred_decoder(&config, active_format) { + Ok((new_backend, new_decoder)) => { + if new_backend != backend { + emit( + &events, + BackendEvent::DecoderChanged { + from: backend, + to: new_backend, + reason: "encoded queue discontinuity".to_owned(), + }, + ); + } + backend = new_backend; + decoder = new_decoder; + active_generation = generation; + } + Err(error) => { + report_worker_error(&state, &events, error); + return; + } + } + need_keyframe = true; + } + if need_keyframe && !frame.keyframe { + continue; + } + match decode_frame(&mut decoder, &frame) { + Ok(frames) => { + need_keyframe = false; + if let Some(format) = decoder.take_format_change() { + active_format = format; + emit(&events, BackendEvent::FormatChanged(format)); + } + enqueue_frames(&decoded, &events, frames); + } + Err(error) => match open_fallback_decoder(&config, active_format, backend) { + Ok((new_backend, mut new_decoder)) => { + let reason = error.to_string(); + emit( + &events, + BackendEvent::DecoderChanged { + from: backend, + to: new_backend, + reason, + }, + ); + backend = new_backend; + if frame.keyframe { + match decode_frame(&mut new_decoder, &frame) { + Ok(frames) => { + if let Some(format) = new_decoder.take_format_change() { + active_format = format; + emit(&events, BackendEvent::FormatChanged(format)); + } + enqueue_frames(&decoded, &events, frames); + } + Err(fallback_error) => { + report_worker_error(&state, &events, fallback_error); + return; + } + } + need_keyframe = false; + } else { + need_keyframe = true; + emit(&events, BackendEvent::NeedKeyframe); + } + decoder = new_decoder; + } + Err(_) => { + report_worker_error(&state, &events, error); + return; + } + }, + } + } + } + } + if let Ok(frames) = flush_decoder(&mut decoder) { + enqueue_frames(&decoded, &events, frames); + } +} + +fn run_audio_worker( + config: AudioConfig, + packets: Arc>, + state: Arc>, + events: EventQueue, + startup: mpsc::SyncSender>, +) { + let mut opus = match OpusDecoder::open(&config) { + Ok(decoder) => decoder, + Err(error) => { + let _ = startup.send(Err(error)); + return; + } + }; + let mut sink: Box = match open_audio_sink(&config) { + Ok(sink) => sink, + Err(error) => { + let _ = startup.send(Err(error)); + return; + } + }; + let mut backend = sink.backend(); + let _ = startup.send(Ok(backend)); + emit(&events, BackendEvent::AudioSelected(backend)); + loop { + let packet = match packets.wait_pop(Duration::from_millis(100)) { + QueuePop::Item(packet) => packet, + QueuePop::TimedOut => continue, + QueuePop::Closed => break, + }; + let pcm = match opus.decode(&packet) { + Ok(pcm) => pcm, + Err(error) => { + packets.close(); + report_worker_error(&state, &events, error); + return; + } + }; + let cancelled = || packets.is_closed(); + if let Err(error) = sink.write(pcm, &cancelled) { + if packets.is_closed() { + return; + } + match open_audio_fallback(&config, backend) { + Ok(mut fallback) => { + if let Err(fallback_error) = fallback.write(pcm, &cancelled) { + if packets.is_closed() { + return; + } + packets.close(); + report_worker_error(&state, &events, fallback_error); + return; + } + backend = fallback.backend(); + sink = fallback; + emit(&events, BackendEvent::AudioSelected(backend)); + continue; + } + Err(fallback_error) => { + emit( + &events, + BackendEvent::Error(format!("audio fallback failed: {fallback_error}")), + ); + } + } + packets.close(); + report_worker_error(&state, &events, error); + return; + } + } +} + +fn open_preferred_decoder( + config: &SessionConfig, + format: StreamFormat, +) -> Result<(DecoderBackend, Box)> { + let order = decoder_order(config.decoder_preference); + let mut failures = Vec::new(); + for backend in order { + match open_decoder(config, format, *backend) { + Ok(decoder) => return Ok((*backend, decoder)), + Err(error) => failures.push(error.to_string()), + } + } + Err(Error::unavailable( + Subsystem::Session, + format!( + "no requested {} decoder opened: {}", + config.codec.label(), + failures.join("; ") + ), + )) +} + +fn open_fallback_decoder( + config: &SessionConfig, + format: StreamFormat, + current: DecoderBackend, +) -> Result<(DecoderBackend, Box)> { + let order = decoder_order(config.decoder_preference); + let Some(current_index) = order.iter().position(|backend| *backend == current) else { + return Err(Error::unavailable( + Subsystem::Session, + "active decoder is outside the configured fallback order", + )); + }; + let mut failures = Vec::new(); + for backend in &order[current_index + 1..] { + match open_decoder(config, format, *backend) { + Ok(decoder) => return Ok((*backend, decoder)), + Err(error) => failures.push(error.to_string()), + } + } + Err(Error::unavailable( + Subsystem::Session, + format!("no fallback decoder opened: {}", failures.join("; ")), + )) +} + +fn decoder_order(preference: DecoderPreference) -> &'static [DecoderBackend] { + match preference { + DecoderPreference::Automatic => &[ + DecoderBackend::Vulkan, + DecoderBackend::Cuda, + DecoderBackend::VaApi, + DecoderBackend::V4l2, + DecoderBackend::Ffmpeg, + ], + DecoderPreference::VulkanOnly => &[DecoderBackend::Vulkan], + DecoderPreference::CudaOnly => &[DecoderBackend::Cuda], + DecoderPreference::VaApiThenV4l2 => &[ + DecoderBackend::VaApi, + DecoderBackend::V4l2, + DecoderBackend::Ffmpeg, + ], + DecoderPreference::V4l2ThenVaApi => &[ + DecoderBackend::V4l2, + DecoderBackend::VaApi, + DecoderBackend::Ffmpeg, + ], + DecoderPreference::VaApiOnly => &[DecoderBackend::VaApi], + DecoderPreference::V4l2Only => &[DecoderBackend::V4l2], + DecoderPreference::SoftwareOnly => &[DecoderBackend::Ffmpeg], + } +} + +fn open_decoder( + config: &SessionConfig, + format: StreamFormat, + backend: DecoderBackend, +) -> Result> { + match backend { + DecoderBackend::Vulkan => open_ffmpeg_decoder(config.codec, format, backend), + DecoderBackend::Cuda => open_ffmpeg_decoder(config.codec, format, backend), + DecoderBackend::Ffmpeg => open_ffmpeg_decoder(config.codec, format, backend), + DecoderBackend::V4l2 if config.codec == VideoCodec::H264 => { + open_v4l2(format, config.v4l2_device.clone()) + } + DecoderBackend::V4l2 => Err(Error::unavailable( + Subsystem::V4l2, + format!( + "{} decode is not implemented by the V4L2 backend", + config.codec.label() + ), + )), + DecoderBackend::VaApi => { + if config.codec != VideoCodec::H264 { + return Err(Error::unavailable( + Subsystem::VaApi, + format!( + "{} decode is not implemented by the native VA-API backend", + config.codec.label() + ), + )); + } + #[cfg(feature = "vaapi")] + { + crate::video::open_vaapi(format) + } + #[cfg(not(feature = "vaapi"))] + { + let _ = format; + Err(Error::unavailable( + Subsystem::VaApi, + "crate was built without the vaapi feature", + )) + } + } + } +} + +fn open_ffmpeg_decoder( + codec: VideoCodec, + format: StreamFormat, + backend: DecoderBackend, +) -> Result> { + #[cfg(feature = "ffmpeg")] + { + use crate::video::{FfmpegDecoder, FfmpegMode}; + + let mode = match backend { + DecoderBackend::Vulkan => FfmpegMode::Vulkan, + DecoderBackend::Cuda => FfmpegMode::Cuda, + DecoderBackend::Ffmpeg => FfmpegMode::Software, + _ => unreachable!("non-FFmpeg backend passed to open_ffmpeg_decoder"), + }; + FfmpegDecoder::open(codec, format, mode) + .map(|decoder| Box::new(decoder) as Box) + } + #[cfg(not(feature = "ffmpeg"))] + { + let _ = (codec, format, backend); + Err(Error::unavailable( + Subsystem::Ffmpeg, + "crate was built without the ffmpeg feature", + )) + } +} + +fn enqueue_frames( + queue: &BoundedQueue, + events: &EventQueue, + frames: Vec, +) { + for frame in frames { + if queue.push_latest(frame) == QueuePush::DroppedOldest { + emit( + events, + BackendEvent::QueueOverflow { + media: "decoded-video", + }, + ); + } + } +} + +fn decode_frame( + decoder: &mut Box, + frame: &EncodedVideoFrame, +) -> Result> { + std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| decoder.decode(frame))).unwrap_or_else( + |panic| { + Err(Error::backend( + Subsystem::Session, + format!("decoder panicked: {}", panic_message(panic)), + )) + }, + ) +} + +fn flush_decoder(decoder: &mut Box) -> Result> { + std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| decoder.flush())).unwrap_or_else( + |panic| { + Err(Error::backend( + Subsystem::Session, + format!("decoder panicked while flushing: {}", panic_message(panic)), + )) + }, + ) +} + +fn panic_message(panic: Box) -> String { + if let Some(message) = panic.downcast_ref::<&str>() { + (*message).to_owned() + } else if let Some(message) = panic.downcast_ref::() { + message.clone() + } else { + "non-string panic payload".to_owned() + } +} + +fn transition_state(state: &Mutex, next: LifecycleState, events: &EventQueue) { + let mut current = state.lock().unwrap_or_else(|poison| poison.into_inner()); + if current.can_transition_to(next) && *current != next { + *current = next; + emit(events, BackendEvent::StateChanged(next)); + } +} + +fn report_worker_error(state: &Mutex, events: &EventQueue, error: Error) { + match error { + Error::DeviceLost { subsystem, reason } => { + emit(events, BackendEvent::DeviceLost { subsystem, reason }); + } + other => { + emit(events, BackendEvent::Error(other.to_string())); + } + } + transition_state(state, LifecycleState::Failed, events); +} + +fn emit(events: &EventQueue, event: BackendEvent) { + events.push_latest(event); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn lifecycle_allows_reconfigure_and_orderly_stop() { + assert!(LifecycleState::Starting.can_transition_to(LifecycleState::Running)); + assert!(LifecycleState::Running.can_transition_to(LifecycleState::Reconfiguring)); + assert!(LifecycleState::Reconfiguring.can_transition_to(LifecycleState::Running)); + assert!(LifecycleState::Running.can_transition_to(LifecycleState::Stopping)); + assert!(LifecycleState::Stopping.can_transition_to(LifecycleState::Stopped)); + } + + #[test] + fn lifecycle_rejects_restart_after_stop_or_failure() { + assert!(!LifecycleState::Stopped.can_transition_to(LifecycleState::Running)); + assert!(!LifecycleState::Failed.can_transition_to(LifecycleState::Running)); + assert!(!LifecycleState::Running.can_transition_to(LifecycleState::Starting)); + assert!(LifecycleState::Failed.can_transition_to(LifecycleState::Stopping)); + } + + #[test] + fn stop_can_recover_from_a_worker_failure_during_shutdown() { + assert!(LifecycleState::Stopping.can_transition_to(LifecycleState::Failed)); + assert!(LifecycleState::Failed.can_transition_to(LifecycleState::Stopping)); + assert!(LifecycleState::Stopping.can_transition_to(LifecycleState::Stopped)); + } + + #[test] + fn overflow_preserves_recovery_keyframe_and_rejects_inter_frames_until_it_arrives() { + let commands = BoundedQueue::new(2); + let events = Arc::new(BoundedQueue::new(8)); + let generation = AtomicU64::new(0); + let needs_keyframe = AtomicBool::new(false); + let frame = |timestamp_us, keyframe| { + EncodedVideoFrame::new(vec![timestamp_us as u8 + 1], timestamp_us, keyframe).unwrap() + }; + + assert_eq!( + queue_video_command( + &commands, + &events, + &generation, + &needs_keyframe, + frame(0, false), + ) + .unwrap(), + PushOutcome::Queued + ); + assert_eq!( + queue_video_command( + &commands, + &events, + &generation, + &needs_keyframe, + frame(1, false), + ) + .unwrap(), + PushOutcome::Queued + ); + assert_eq!( + queue_video_command( + &commands, + &events, + &generation, + &needs_keyframe, + frame(2, false), + ) + .unwrap(), + PushOutcome::DroppedOldest + ); + assert!(needs_keyframe.load(Ordering::Acquire)); + + // This P-frame is discarded instead of evicting queued recovery work. + assert_eq!( + queue_video_command( + &commands, + &events, + &generation, + &needs_keyframe, + frame(3, false), + ) + .unwrap(), + PushOutcome::DroppedOldest + ); + assert_eq!(commands.len(), 2); + + // The IDR atomically replaces stale decode work. Its following P-frame + // is queued behind it with the same generation. + assert_eq!( + queue_video_command( + &commands, + &events, + &generation, + &needs_keyframe, + frame(4, true), + ) + .unwrap(), + PushOutcome::DroppedOldest + ); + assert!(!needs_keyframe.load(Ordering::Acquire)); + assert_eq!( + queue_video_command( + &commands, + &events, + &generation, + &needs_keyframe, + frame(5, false), + ) + .unwrap(), + PushOutcome::Queued + ); + + let QueuePop::Item(VideoCommand::Decode { + frame, + generation: keyframe_generation, + reset, + }) = commands.wait_pop(Duration::ZERO) + else { + panic!("expected queued recovery keyframe"); + }; + assert!(frame.keyframe); + assert!(reset); + let QueuePop::Item(VideoCommand::Decode { + frame, + generation: inter_generation, + reset, + }) = commands.wait_pop(Duration::ZERO) + else { + panic!("expected inter-frame after recovery keyframe"); + }; + assert!(!frame.keyframe); + assert!(!reset); + assert_eq!(inter_generation, keyframe_generation); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/video/ffmpeg.rs b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/video/ffmpeg.rs new file mode 100644 index 000000000..767707a12 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/video/ffmpeg.rs @@ -0,0 +1,864 @@ +use std::ptr; +use std::sync::{Arc, OnceLock}; + +use ffmpeg::codec; +use ffmpeg::ffi; +use ffmpeg::format::Pixel; +use ffmpeg::frame; +use ffmpeg::software::scaling::{context::Context as Scaler, flag::Flags as ScaleFlags}; +use ffmpeg_next as ffmpeg; + +use crate::{ + ChromaLocation, ColorMatrix, ColorRange, DecodedVideoFrame, DmaBufFrame, DmaBufLayer, + DmaBufObject, DmaBufPlane, EncodedVideoFrame, Error, FramePlane, PixelFormat, Result, + StreamFormat, Subsystem, VideoCodec, VulkanImage, VulkanVideoFrame, +}; + +use super::VideoDecoder; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum FfmpegMode { + Vulkan, + Cuda, + Software, +} + +impl FfmpegMode { + pub(crate) const fn label(self) -> &'static str { + match self { + Self::Vulkan => "FFmpeg Vulkan Video", + Self::Cuda => "FFmpeg CUDA/NVDEC", + Self::Software => "FFmpeg software", + } + } + + const fn device_type(self) -> Option { + match self { + Self::Vulkan => Some(ffi::AVHWDeviceType::AV_HWDEVICE_TYPE_VULKAN), + Self::Cuda => Some(ffi::AVHWDeviceType::AV_HWDEVICE_TYPE_CUDA), + Self::Software => None, + } + } +} + +pub(crate) struct FfmpegDecoder { + // The decoder must be dropped before `wanted_hw_format`; libavcodec may + // consult the callback opaque pointer during decoder teardown. + decoder: ffmpeg::decoder::Video, + wanted_hw_format: Option>, + scaler: Option, + codec: VideoCodec, + mode: FfmpegMode, + configured_format: StreamFormat, + pending_format_change: Option, + last_timestamp_us: u64, + zero_copy_active: bool, + zero_copy_unavailable_reported: bool, +} + +struct HardwareFormatSelection { + pixel_format: ffi::AVPixelFormat, + exportable_vulkan_frames: bool, +} + +impl FfmpegDecoder { + pub(crate) fn open(codec: VideoCodec, format: StreamFormat, mode: FfmpegMode) -> Result { + initialize_ffmpeg()?; + let decoder_definition = if mode == FfmpegMode::Software { + ffmpeg::decoder::find(codec_id(codec)) + } else { + ffmpeg::decoder::find_by_name(native_decoder_name(codec)) + } + .ok_or_else(|| { + Error::unavailable( + Subsystem::Ffmpeg, + format!("FFmpeg was built without the {} decoder", codec.label()), + ) + })?; + let mut context = codec::Context::new_with_codec(decoder_definition); + unsafe { + let raw = context.as_mut_ptr(); + (*raw).width = format.width as i32; + (*raw).height = format.height as i32; + (*raw).thread_count = if mode == FfmpegMode::Software { 0 } else { 1 }; + } + + let mut wanted_hw_format = None; + if let Some(device_type) = mode.device_type() { + let pixel_format = + hardware_pixel_format(decoder_definition, device_type).ok_or_else(|| { + Error::unavailable( + Subsystem::Ffmpeg, + format!( + "{} does not expose {} decode through libavcodec", + mode.label(), + codec.label() + ), + ) + })?; + let mut device = ptr::null_mut(); + let mut options = ptr::null_mut(); + if mode == FfmpegMode::Vulkan { + unsafe { + ffi::av_dict_set( + &mut options, + c"instance_extensions".as_ptr(), + c"VK_KHR_surface+VK_KHR_xlib_surface+VK_KHR_wayland_surface".as_ptr(), + 0, + ); + ffi::av_dict_set( + &mut options, + c"device_extensions".as_ptr(), + c"VK_KHR_swapchain".as_ptr(), + 0, + ); + } + } + let create_result = unsafe { + ffi::av_hwdevice_ctx_create(&mut device, device_type, ptr::null(), options, 0) + }; + unsafe { ffi::av_dict_free(&mut options) }; + if create_result < 0 || device.is_null() { + return Err(ffmpeg_error( + format!("failed to create the {} device", mode.label()), + create_result, + )); + } + let mut selected = Box::new(HardwareFormatSelection { + pixel_format, + exportable_vulkan_frames: false, + }); + unsafe { + let raw = context.as_mut_ptr(); + (*raw).hw_device_ctx = ffi::av_buffer_ref(device); + (*raw).get_format = Some(select_hardware_format); + (*raw).opaque = (&mut *selected as *mut HardwareFormatSelection).cast(); + ffi::av_buffer_unref(&mut device); + if (*raw).hw_device_ctx.is_null() { + return Err(Error::backend( + Subsystem::Ffmpeg, + format!("failed to retain the {} device", mode.label()), + )); + } + } + wanted_hw_format = Some(selected); + } + + let decoder = context + .decoder() + .open_as(decoder_definition) + .and_then(|opened| opened.video()) + .map_err(|error| { + Error::backend( + Subsystem::Ffmpeg, + format!( + "{} {} decoder initialization failed: {error}", + mode.label(), + codec.label() + ), + ) + })?; + Ok(Self { + decoder, + wanted_hw_format, + scaler: None, + codec, + mode, + configured_format: format, + pending_format_change: None, + last_timestamp_us: 0, + zero_copy_active: false, + zero_copy_unavailable_reported: false, + }) + } + + pub(crate) fn probe( + codec: VideoCodec, + mode: FfmpegMode, + ) -> std::result::Result { + let format = StreamFormat::video_default(1920, 1080).map_err(|error| error.to_string())?; + let decoder = Self::open(codec, format, mode).map_err(|error| error.to_string())?; + Ok(format!( + "{} {} via libavcodec {}", + decoder.mode.label(), + decoder.codec.label(), + ffmpeg::codec::version() + )) + } + + fn drain(&mut self, draining: bool) -> Result> { + let mut frames = Vec::new(); + loop { + let mut decoded = frame::Video::empty(); + match self.decoder.receive_frame(&mut decoded) { + Ok(()) => frames.push(self.convert_frame(&decoded)?), + Err(ffmpeg::Error::Other { errno }) if errno == ffmpeg::error::EAGAIN => break, + Err(ffmpeg::Error::Eof) if draining => break, + Err(error) => { + return Err(Error::backend( + Subsystem::Ffmpeg, + format!( + "{} {} frame receive failed: {error}", + self.mode.label(), + self.codec.label() + ), + )); + } + } + } + Ok(frames) + } + + fn convert_frame(&mut self, decoded: &frame::Video) -> Result { + if self.mode == FfmpegMode::Vulkan + && self + .wanted_hw_format + .as_deref() + .is_some_and(|selection| Pixel::from(selection.pixel_format) == decoded.format()) + { + if let Ok(frame) = map_vulkan_frame_direct(decoded, self.last_timestamp_us) { + if !self.zero_copy_active { + eprintln!("Vulkan Video same-device zero-copy enabled"); + self.zero_copy_active = true; + } + return Ok(frame); + } + match map_vulkan_frame_to_dmabuf(decoded, self.last_timestamp_us) { + Ok(frame) => { + if !self.zero_copy_active { + eprintln!("Vulkan Video zero-copy enabled through DRM PRIME/DMA-BUF"); + self.zero_copy_active = true; + } + return Ok(frame); + } + Err(error) => { + if !self.zero_copy_unavailable_reported { + eprintln!( + "Vulkan Video DMA-BUF export unavailable; using bounded CPU transfer: {error}" + ); + self.zero_copy_unavailable_reported = true; + } + } + } + } + let software_frame; + let source = if self + .wanted_hw_format + .as_deref() + .is_some_and(|selection| Pixel::from(selection.pixel_format) == decoded.format()) + { + let mut transferred = frame::Video::empty(); + let transfer_result = unsafe { + ffi::av_hwframe_transfer_data(transferred.as_mut_ptr(), decoded.as_ptr(), 0) + }; + if transfer_result < 0 { + return Err(ffmpeg_error( + format!("{} frame download failed", self.mode.label()), + transfer_result, + )); + } + unsafe { + ffi::av_frame_copy_props(transferred.as_mut_ptr(), decoded.as_ptr()); + } + software_frame = transferred; + &software_frame + } else { + decoded + }; + + let width = source.width().max(1); + let height = source.height().max(1); + // NVDEC and Vulkan Video normally download NV12 already. Avoid a full + // swscale pass in that hot path; conversion is only needed for formats + // such as software-decoded YUV420P or 10-bit hardware output. + let converted; + let nv12 = if source.format() == Pixel::NV12 { + source + } else { + let scaler_changed = self.scaler.as_ref().is_none_or(|scaler| { + scaler.input().format != source.format() + || scaler.input().width != width + || scaler.input().height != height + }); + if scaler_changed { + self.scaler = Some( + Scaler::get( + source.format(), + width, + height, + Pixel::NV12, + width, + height, + ScaleFlags::BILINEAR, + ) + .map_err(|error| { + Error::backend( + Subsystem::Ffmpeg, + format!("NV12 conversion setup failed: {error}"), + ) + })?, + ); + } + let mut frame = frame::Video::empty(); + self.scaler + .as_mut() + .expect("scaler was initialized") + .run(source, &mut frame) + .map_err(|error| { + Error::backend( + Subsystem::Ffmpeg, + format!("NV12 conversion failed: {error}"), + ) + })?; + converted = frame; + &converted + }; + + let output_format = StreamFormat { + width, + height, + pixel_format: PixelFormat::Nv12, + color_range: map_color_range(source), + color_matrix: map_color_matrix(source), + chroma_location: map_chroma_location(source), + }; + output_format.validate()?; + if output_format != self.configured_format { + self.configured_format = output_format; + self.pending_format_change = Some(output_format); + } + let timestamp_us = decoded + .pts() + .and_then(|timestamp| u64::try_from(timestamp).ok()) + .unwrap_or(self.last_timestamp_us); + Ok(DecodedVideoFrame { + format: output_format, + planes: vec![ + FramePlane { + data: Arc::from(nv12.data(0).to_vec()), + stride: nv12.stride(0), + rows: height as usize, + }, + FramePlane { + data: Arc::from(nv12.data(1).to_vec()), + stride: nv12.stride(1), + rows: height as usize / 2, + }, + ], + dmabuf: None, + vulkan: None, + overlay: None, + timestamp_us, + }) + } +} + +fn map_vulkan_frame_direct( + decoded: &frame::Video, + fallback_timestamp_us: u64, +) -> Result { + let (vulkan_frame, vulkan_frames, device_context, vulkan_device) = unsafe { + let raw = decoded.as_ptr(); + let vulkan_frame = (*raw).data[0].cast::(); + let frames_ref = (*raw).hw_frames_ctx; + if vulkan_frame.is_null() || frames_ref.is_null() || (*frames_ref).data.is_null() { + return Err(Error::backend( + Subsystem::Ffmpeg, + "Vulkan Video frame has no hardware context", + )); + } + let frames_context = (*frames_ref).data.cast::(); + let vulkan_frames = (*frames_context).hwctx.cast::(); + let device_context = (*frames_context).device_ctx; + if vulkan_frames.is_null() || device_context.is_null() { + return Err(Error::backend( + Subsystem::Ffmpeg, + "Vulkan Video frame has incomplete hardware metadata", + )); + } + let vulkan_device = (*device_context).hwctx.cast::(); + if vulkan_device.is_null() { + return Err(Error::backend( + Subsystem::Ffmpeg, + "Vulkan Video frame has no Vulkan device", + )); + } + (vulkan_frame, vulkan_frames, device_context, vulkan_device) + }; + let image_count = unsafe { + (*vulkan_frame) + .img + .iter() + .position(|image| *image == 0) + .unwrap_or((*vulkan_frame).img.len()) + }; + if image_count == 0 || image_count > 2 { + return Err(Error::unavailable( + Subsystem::Ffmpeg, + format!("unsupported Vulkan Video image count {image_count}"), + )); + } + let width = decoded.width().max(1); + let height = decoded.height().max(1); + let mut images = Vec::with_capacity(image_count); + for index in 0..image_count { + let (plane_width, plane_height) = if index == 0 || image_count == 1 { + (width, height) + } else { + (width / 2, height / 2) + }; + images.push(VulkanImage { + image: unsafe { (*vulkan_frame).img[index] }, + format: unsafe { (*vulkan_frames).format[index] }, + width: plane_width, + height: plane_height, + layout: unsafe { (*vulkan_frame).layout[index] }, + access: unsafe { (*vulkan_frame).access[index] }, + semaphore: unsafe { (*vulkan_frame).sem[index] }, + semaphore_value: unsafe { (*vulkan_frame).sem_value[index] }, + queue_family: unsafe { (*vulkan_frame).queue_family[index] }, + }); + } + let queue_count = unsafe { (*vulkan_device).nb_qf.max(0) as usize }; + let queue_families = + unsafe { &(&(*vulkan_device).qf)[..queue_count.min((*vulkan_device).qf.len())] } + .iter() + .filter_map(|family| u32::try_from(family.idx).ok()) + .collect::>(); + let mut retained = frame::Video::empty(); + if unsafe { ffi::av_frame_ref(retained.as_mut_ptr(), decoded.as_ptr()) } < 0 { + return Err(Error::backend( + Subsystem::Ffmpeg, + "failed to retain Vulkan Video frame for presentation", + )); + } + let device = unsafe { + VulkanVideoFrame::new( + (*vulkan_device).inst as usize, + (*vulkan_device).phys_dev as usize, + (*vulkan_device).act_dev as usize, + queue_families, + (*vulkan_frames).usage as u32, + (*vulkan_frames).img_flags, + images, + device_context as usize, + (*vulkan_device).lock_queue.map(|callback| { + std::mem::transmute::< + unsafe extern "C" fn(*mut ffi::AVHWDeviceContext, u32, u32), + unsafe extern "C" fn(*mut std::ffi::c_void, u32, u32), + >(callback) + }), + (*vulkan_device).unlock_queue.map(|callback| { + std::mem::transmute::< + unsafe extern "C" fn(*mut ffi::AVHWDeviceContext, u32, u32), + unsafe extern "C" fn(*mut std::ffi::c_void, u32, u32), + >(callback) + }), + Arc::new(retained), + ) + }; + let output_format = StreamFormat { + width, + height, + pixel_format: PixelFormat::Nv12, + color_range: map_color_range(decoded), + color_matrix: map_color_matrix(decoded), + chroma_location: map_chroma_location(decoded), + }; + let timestamp_us = decoded + .pts() + .and_then(|timestamp| u64::try_from(timestamp).ok()) + .unwrap_or(fallback_timestamp_us); + let output = DecodedVideoFrame { + format: output_format, + planes: Vec::new(), + dmabuf: None, + vulkan: Some(Arc::new(device)), + overlay: None, + timestamp_us, + }; + output.validate()?; + Ok(output) +} + +fn map_vulkan_frame_to_dmabuf( + decoded: &frame::Video, + fallback_timestamp_us: u64, +) -> Result { + let mut mapped = frame::Video::empty(); + mapped.set_format(Pixel::DRM_PRIME); + let map_result = unsafe { + ffi::av_hwframe_map( + mapped.as_mut_ptr(), + decoded.as_ptr(), + ffi::AV_HWFRAME_MAP_READ as i32, + ) + }; + if map_result < 0 { + return Err(ffmpeg_error( + "Vulkan Video frame DMA-BUF export failed".to_owned(), + map_result, + )); + } + let descriptor = unsafe { + let data = (*mapped.as_ptr()).data[0]; + if data.is_null() { + return Err(Error::backend( + Subsystem::Ffmpeg, + "DMA-BUF mapping returned no DRM descriptor", + )); + } + &*data.cast::() + }; + let object_count = usize::try_from(descriptor.nb_objects).unwrap_or(usize::MAX); + let layer_count = usize::try_from(descriptor.nb_layers).unwrap_or(usize::MAX); + if object_count == 0 + || object_count > descriptor.objects.len() + || layer_count == 0 + || layer_count > descriptor.layers.len() + { + return Err(Error::backend( + Subsystem::Ffmpeg, + "DMA-BUF mapping returned invalid object/layer counts", + )); + } + let objects = descriptor.objects[..object_count] + .iter() + .map(|object| DmaBufObject { + fd: object.fd, + size: object.size, + format_modifier: object.format_modifier, + }) + .collect(); + let mut layers = Vec::with_capacity(layer_count); + for layer in &descriptor.layers[..layer_count] { + let plane_count = usize::try_from(layer.nb_planes).unwrap_or(usize::MAX); + if plane_count == 0 || plane_count > layer.planes.len() { + return Err(Error::backend( + Subsystem::Ffmpeg, + "DMA-BUF mapping returned an invalid plane count", + )); + } + let planes = layer.planes[..plane_count] + .iter() + .map(|plane| { + Ok(DmaBufPlane { + object_index: usize::try_from(plane.object_index).map_err(|_| { + Error::backend(Subsystem::Ffmpeg, "negative DMA-BUF object index") + })?, + offset: usize::try_from(plane.offset).map_err(|_| { + Error::backend(Subsystem::Ffmpeg, "negative DMA-BUF plane offset") + })?, + pitch: usize::try_from(plane.pitch).map_err(|_| { + Error::backend(Subsystem::Ffmpeg, "negative DMA-BUF plane pitch") + })?, + }) + }) + .collect::>>()?; + layers.push(DmaBufLayer { + format: layer.format, + planes, + }); + } + let width = decoded.width().max(1); + let height = decoded.height().max(1); + let output_format = StreamFormat { + width, + height, + pixel_format: PixelFormat::Nv12, + color_range: map_color_range(decoded), + color_matrix: map_color_matrix(decoded), + chroma_location: map_chroma_location(decoded), + }; + let timestamp_us = decoded + .pts() + .and_then(|timestamp| u64::try_from(timestamp).ok()) + .unwrap_or(fallback_timestamp_us); + let dmabuf = Arc::new(DmaBufFrame::new(objects, layers, Arc::new(mapped))); + let frame = DecodedVideoFrame { + format: output_format, + planes: Vec::new(), + dmabuf: Some(dmabuf), + vulkan: None, + overlay: None, + timestamp_us, + }; + frame.validate()?; + Ok(frame) +} + +impl VideoDecoder for FfmpegDecoder { + fn decode(&mut self, frame: &EncodedVideoFrame) -> Result> { + self.last_timestamp_us = frame.timestamp_us; + let mut packet = ffmpeg::Packet::copy(&frame.data); + packet.set_pts(i64::try_from(frame.timestamp_us).ok()); + packet.set_dts(i64::try_from(frame.timestamp_us).ok()); + if frame.keyframe { + packet.set_flags(ffmpeg::packet::Flags::KEY); + } + self.decoder.send_packet(&packet).map_err(|error| { + Error::backend( + Subsystem::Ffmpeg, + format!( + "{} {} packet submission failed: {error}", + self.mode.label(), + self.codec.label() + ), + ) + })?; + self.drain(false) + } + + fn flush(&mut self) -> Result> { + match self.decoder.send_eof() { + Ok(()) | Err(ffmpeg::Error::Eof) => self.drain(true), + Err(error) => Err(Error::backend( + Subsystem::Ffmpeg, + format!("{} decoder flush failed: {error}", self.mode.label()), + )), + } + } + + fn take_format_change(&mut self) -> Option { + self.pending_format_change.take() + } +} + +fn initialize_ffmpeg() -> Result<()> { + static INITIALIZED: OnceLock> = OnceLock::new(); + INITIALIZED + .get_or_init(|| ffmpeg::init().map_err(|error| error.to_string())) + .clone() + .map_err(|reason| Error::unavailable(Subsystem::Ffmpeg, reason)) +} + +fn codec_id(codec: VideoCodec) -> codec::Id { + match codec { + VideoCodec::H264 => codec::Id::H264, + VideoCodec::H265 => codec::Id::HEVC, + VideoCodec::Av1 => codec::Id::AV1, + } +} + +fn native_decoder_name(codec: VideoCodec) -> &'static str { + match codec { + VideoCodec::H264 => "h264", + VideoCodec::H265 => "hevc", + VideoCodec::Av1 => "av1", + } +} + +fn hardware_pixel_format( + codec: ffmpeg::Codec, + device_type: ffi::AVHWDeviceType, +) -> Option { + let mut index = 0; + loop { + let config = unsafe { ffi::avcodec_get_hw_config(codec.as_ptr(), index) }; + if config.is_null() { + return None; + } + let matches = unsafe { + (*config).device_type == device_type + && ((*config).methods as u32 & ffi::AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX as u32) + != 0 + }; + if matches { + return Some(unsafe { (*config).pix_fmt }); + } + index += 1; + } +} + +unsafe extern "C" fn select_hardware_format( + context: *mut ffi::AVCodecContext, + formats: *const ffi::AVPixelFormat, +) -> ffi::AVPixelFormat { + if context.is_null() || formats.is_null() || unsafe { (*context).opaque.is_null() } { + return ffi::AVPixelFormat::AV_PIX_FMT_NONE; + } + let selection = unsafe { &*((*context).opaque as *const HardwareFormatSelection) }; + let wanted = selection.pixel_format; + let mut current = formats; + while unsafe { *current } != ffi::AVPixelFormat::AV_PIX_FMT_NONE { + if unsafe { *current } == wanted { + if selection.exportable_vulkan_frames + && !unsafe { configure_exportable_vulkan_frames(context, wanted) } + { + return ffi::AVPixelFormat::AV_PIX_FMT_NONE; + } + return wanted; + } + current = unsafe { current.add(1) }; + } + ffi::AVPixelFormat::AV_PIX_FMT_NONE +} + +/// Replaces libavcodec's implicit optimal-tiled Vulkan pool with a +/// DRM-modifier pool. This has to happen inside `get_format`; FFmpeg resets +/// `hw_frames_ctx` immediately before invoking the callback. +unsafe fn configure_exportable_vulkan_frames( + context: *mut ffi::AVCodecContext, + pixel_format: ffi::AVPixelFormat, +) -> bool { + let device = unsafe { (*context).hw_device_ctx }; + if device.is_null() { + return false; + } + let mut frames = ptr::null_mut(); + let result = unsafe { + ffi::avcodec_get_hw_frames_parameters(context, device, pixel_format, &mut frames) + }; + if result < 0 || frames.is_null() { + return false; + } + let configured = (|| { + let frames_context = unsafe { (*frames).data.cast::() }; + if frames_context.is_null() { + return false; + } + let vulkan = unsafe { (*frames_context).hwctx.cast::() }; + if vulkan.is_null() { + return false; + } + // VkImageTiling is an i32 in the generated Vulkan ABI bindings. + // VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000. + unsafe { + (*vulkan).tiling = 1_000_158_000; + // NVIDIA exposes exportable modifiers for the component formats + // used by NV12, while its video decode profile rejects an + // exportable multi-planar image. Two images still remain entirely + // GPU-owned and are described as two DRM PRIME layers. + (*vulkan).flags = ffi::AVVkFrameFlags::AV_VK_FRAME_FLAG_DISABLE_MULTIPLANE; + } + if unsafe { ffi::av_hwframe_ctx_init(frames) } < 0 { + return false; + } + let retained = unsafe { ffi::av_buffer_ref(frames) }; + if retained.is_null() { + return false; + } + unsafe { + ffi::av_buffer_unref(&mut (*context).hw_frames_ctx); + (*context).hw_frames_ctx = retained; + } + true + })(); + unsafe { ffi::av_buffer_unref(&mut frames) }; + configured +} + +fn ffmpeg_error(operation: String, code: i32) -> Error { + Error::backend( + Subsystem::Ffmpeg, + format!("{operation}: {}", ffmpeg::Error::from(code)), + ) +} + +fn map_color_range(frame: &frame::Video) -> ColorRange { + match frame.color_range() { + ffmpeg::color::Range::JPEG => ColorRange::Full, + _ => ColorRange::Limited, + } +} + +fn map_color_matrix(frame: &frame::Video) -> ColorMatrix { + match frame.color_space() { + ffmpeg::color::Space::BT2020NCL | ffmpeg::color::Space::BT2020CL => ColorMatrix::Bt2020, + ffmpeg::color::Space::BT470BG | ffmpeg::color::Space::SMPTE170M => ColorMatrix::Bt601, + _ => ColorMatrix::Bt709, + } +} + +fn map_chroma_location(frame: &frame::Video) -> ChromaLocation { + match frame.chroma_location() { + ffmpeg::chroma::Location::Center => ChromaLocation::Center, + _ => ChromaLocation::Left, + } +} + +#[cfg(test)] +mod tests { + use std::process::Command; + + use super::*; + + #[test] + fn all_required_software_decoders_are_linked() { + initialize_ffmpeg().unwrap(); + for codec in [VideoCodec::H264, VideoCodec::H265, VideoCodec::Av1] { + assert!(ffmpeg::decoder::find(codec_id(codec)).is_some()); + } + } + + #[test] + #[ignore = "requires the FFmpeg CLI and local Vulkan/CUDA video hardware"] + fn local_hardware_decodes_all_required_codecs() { + for codec in [VideoCodec::H264, VideoCodec::H265, VideoCodec::Av1] { + let (encoder, muxer, codec_options): (&str, &str, &[&str]) = match codec { + VideoCodec::H264 => ("libx264", "h264", &["-tune", "zerolatency"]), + VideoCodec::H265 => ( + "libx265", + "hevc", + &["-x265-params", "log-level=error:pools=1"], + ), + VideoCodec::Av1 => ("libsvtav1", "obu", &["-preset", "13"]), + }; + let mut command = Command::new("ffmpeg"); + command.args([ + "-hide_banner", + "-loglevel", + "error", + "-f", + "lavfi", + "-i", + "color=c=blue:size=256x144:rate=60", + "-frames:v", + "1", + "-c:v", + encoder, + ]); + command.args(codec_options); + let encoded = command + .args(["-f", muxer, "pipe:1"]) + .output() + .expect("FFmpeg CLI must start"); + assert!( + encoded.status.success(), + "sample encode failed for {}: {}", + codec.label(), + String::from_utf8_lossy(&encoded.stderr) + ); + assert!(!encoded.stdout.is_empty()); + + for mode in [FfmpegMode::Vulkan, FfmpegMode::Cuda] { + let frame = (|| { + let format = StreamFormat::video_default(256, 144)?; + let mut decoder = FfmpegDecoder::open(codec, format, mode)?; + let packet = EncodedVideoFrame::new(encoded.stdout.clone(), 1, true)?; + let mut frames = decoder.decode(&packet)?; + frames.extend(decoder.flush()?); + if frames.len() != 1 { + return Err(Error::backend( + Subsystem::Ffmpeg, + format!("expected one frame, received {}", frames.len()), + )); + } + Ok(frames.remove(0)) + })() + .unwrap_or_else(|error: Error| { + panic!("{} failed via {}: {error}", codec.label(), mode.label()) + }); + eprintln!("{} decoded via {}", codec.label(), mode.label()); + frame.validate().unwrap(); + assert_eq!( + (frame.format.width, frame.format.height), + (256, 144), + "{} dimensions changed via {}", + codec.label(), + mode.label() + ); + } + } + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/video/mod.rs b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/video/mod.rs new file mode 100644 index 000000000..a404bdf14 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/video/mod.rs @@ -0,0 +1,71 @@ +use std::path::PathBuf; + +use crate::{DecodedVideoFrame, EncodedVideoFrame, Result, StreamFormat, VideoCodec}; + +#[cfg(feature = "ffmpeg")] +mod ffmpeg; +mod v4l2; +#[cfg(feature = "vaapi")] +mod vaapi; + +#[cfg(feature = "ffmpeg")] +pub(crate) use ffmpeg::{FfmpegDecoder, FfmpegMode}; +pub(crate) use v4l2::probe_v4l2_devices; + +#[cfg(feature = "ffmpeg")] +pub(crate) fn probe_ffmpeg_vulkan(codec: VideoCodec) -> std::result::Result { + FfmpegDecoder::probe(codec, FfmpegMode::Vulkan) +} + +#[cfg(feature = "ffmpeg")] +pub(crate) fn probe_ffmpeg_cuda(codec: VideoCodec) -> std::result::Result { + FfmpegDecoder::probe(codec, FfmpegMode::Cuda) +} + +#[cfg(feature = "ffmpeg")] +pub(crate) fn probe_ffmpeg_software(codec: VideoCodec) -> std::result::Result { + FfmpegDecoder::probe(codec, FfmpegMode::Software) +} + +#[cfg(not(feature = "ffmpeg"))] +pub(crate) fn probe_ffmpeg_vulkan(_: VideoCodec) -> std::result::Result { + Err("crate was built without the ffmpeg feature".to_owned()) +} + +#[cfg(not(feature = "ffmpeg"))] +pub(crate) fn probe_ffmpeg_cuda(_: VideoCodec) -> std::result::Result { + Err("crate was built without the ffmpeg feature".to_owned()) +} + +#[cfg(not(feature = "ffmpeg"))] +pub(crate) fn probe_ffmpeg_software(_: VideoCodec) -> std::result::Result { + Err("crate was built without the ffmpeg feature".to_owned()) +} + +pub(crate) trait VideoDecoder { + fn decode(&mut self, frame: &EncodedVideoFrame) -> Result>; + fn flush(&mut self) -> Result>; + fn take_format_change(&mut self) -> Option; +} + +pub(crate) fn open_v4l2( + format: StreamFormat, + device: Option, +) -> Result> { + Ok(Box::new(v4l2::V4l2Decoder::open(format, device)?)) +} + +#[cfg(feature = "vaapi")] +pub(crate) fn open_vaapi(format: StreamFormat) -> Result> { + Ok(Box::new(vaapi::VaApiDecoder::open(format)?)) +} + +#[cfg(feature = "vaapi")] +pub(crate) fn probe_vaapi() -> std::result::Result { + vaapi::VaApiDecoder::probe() +} + +#[cfg(not(feature = "vaapi"))] +pub(crate) fn probe_vaapi() -> std::result::Result { + Err("crate was built without the vaapi feature".to_owned()) +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/video/v4l2.rs b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/video/v4l2.rs new file mode 100644 index 000000000..940504465 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/video/v4l2.rs @@ -0,0 +1,1231 @@ +use std::fs::{File, OpenOptions}; +use std::io; +use std::mem; +use std::os::fd::{AsRawFd, RawFd}; +use std::os::unix::fs::OpenOptionsExt; +use std::path::{Path, PathBuf}; +use std::ptr::NonNull; +use std::slice; +use std::sync::Arc; +use std::time::{Duration, Instant}; + +#[path = "v4l2_ffi.rs"] +mod ffi; +use ffi::*; + +use super::VideoDecoder; +use crate::{ + ChromaLocation, ColorMatrix, ColorRange, DecodedVideoFrame, EncodedVideoFrame, Error, + FramePlane, PixelFormat, Result, StreamFormat, Subsystem, +}; + +const OUTPUT_BUFFER_COUNT: u32 = 6; +const CAPTURE_BUFFER_COUNT: u32 = 8; +const MAX_VIDEO_DEVICES: usize = 64; +const MAX_PLANES: usize = VIDEO_MAX_PLANES as usize; +const H264: u32 = fourcc(*b"H264"); +const NV12: u32 = fourcc(*b"NV12"); +const NV12M: u32 = fourcc(*b"NM12"); +const YUV420: u32 = fourcc(*b"YU12"); +const YUV420M: u32 = fourcc(*b"YM12"); +const IOC_WRITE: u64 = 1; +const IOC_READ: u64 = 2; +const VIDIOC_DQEVENT: vidioc::_IOC_TYPE = + ioctl_code(IOC_READ, 89, mem::size_of::() as u64); +const VIDIOC_SUBSCRIBE_EVENT: vidioc::_IOC_TYPE = ioctl_code( + IOC_WRITE, + 90, + mem::size_of::() as u64, +); + +const fn fourcc(bytes: [u8; 4]) -> u32 { + bytes[0] as u32 + | ((bytes[1] as u32) << 8) + | ((bytes[2] as u32) << 16) + | ((bytes[3] as u32) << 24) +} + +const fn ioctl_code(direction: u64, number: u64, size: u64) -> vidioc::_IOC_TYPE { + ((direction << 30) | ((b'V' as u64) << 8) | number | (size << 16)) as vidioc::_IOC_TYPE +} + +#[derive(Debug, Clone)] +pub(crate) struct V4l2DeviceInfo { + pub path: PathBuf, + pub driver: String, + pub card: String, + pub multiplanar: bool, + pub capture_fourcc: u32, +} + +impl V4l2DeviceInfo { + pub fn description(&self) -> String { + format!( + "{} ({}, {}, {})", + self.path.display(), + self.driver, + self.card, + fourcc_name(self.capture_fourcc) + ) + } +} + +#[derive(Debug)] +struct MappedPlane { + address: NonNull, + length: usize, +} + +impl MappedPlane { + fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.address.as_ptr(), self.length) } + } + + fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut(self.address.as_ptr(), self.length) } + } +} + +impl Drop for MappedPlane { + fn drop(&mut self) { + unsafe { + libc::munmap(self.address.as_ptr().cast(), self.length); + } + } +} + +#[derive(Debug)] +struct QueueBuffer { + planes: Vec, + queued: bool, +} + +pub(crate) struct V4l2Decoder { + file: File, + device: V4l2DeviceInfo, + format: StreamFormat, + output_type: u32, + capture_type: u32, + output: Vec, + capture: Vec, + output_streaming: bool, + capture_streaming: bool, + capture_format: Option, + pending_source_change: bool, + capture_last_seen: bool, + capture_frames_seen: u64, + pending_format_change: Option, +} + +impl V4l2Decoder { + pub fn open(format: StreamFormat, requested: Option) -> Result { + format.validate()?; + let devices = probe_v4l2_devices(); + let device = match requested { + Some(path) => devices + .into_iter() + .find(|device| device.path == path) + .ok_or_else(|| { + Error::unavailable( + Subsystem::V4l2, + format!("{} is not a usable stateful H.264 decoder", path.display()), + ) + })?, + None => devices.into_iter().next().ok_or_else(|| { + Error::unavailable( + Subsystem::V4l2, + "no /dev/video* node advertises stateful H.264 M2M decode with NV12/I420 output", + ) + })?, + }; + let file = open_device(&device.path).map_err(|error| Error::io(Subsystem::V4l2, error))?; + let output_type = if device.multiplanar { + v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE + } else { + v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT + }; + let capture_type = if device.multiplanar { + v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE + } else { + v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_CAPTURE + }; + let mut decoder = Self { + file, + device, + format, + output_type, + capture_type, + output: Vec::new(), + capture: Vec::new(), + output_streaming: false, + capture_streaming: false, + capture_format: None, + pending_source_change: false, + capture_last_seen: false, + capture_frames_seen: 0, + pending_format_change: None, + }; + decoder.configure()?; + Ok(decoder) + } + + fn configure(&mut self) -> Result<()> { + let mut subscription: v4l2_event_subscription = zeroed(); + subscription.type_ = V4L2_EVENT_SOURCE_CHANGE; + if let Err(error) = ioctl( + self.file.as_raw_fd(), + VIDIOC_SUBSCRIBE_EVENT, + &mut subscription, + ) { + if error.raw_os_error() != Some(libc::EINVAL) { + return Err(Error::io(Subsystem::V4l2, error)); + } + } + set_format( + self.file.as_raw_fd(), + self.output_type, + H264, + self.format.width, + self.format.height, + Some(compressed_buffer_size( + self.format.width, + self.format.height, + )), + )?; + let mut negotiated = set_format( + self.file.as_raw_fd(), + self.capture_type, + self.device.capture_fourcc, + self.format.width, + self.format.height, + None, + )?; + apply_visible_selection(self.file.as_raw_fd(), self.capture_type, &mut negotiated); + self.apply_negotiated_format(&negotiated)?; + + self.output = + request_and_map_buffers(self.file.as_raw_fd(), self.output_type, OUTPUT_BUFFER_COUNT)?; + self.capture = request_and_map_buffers( + self.file.as_raw_fd(), + self.capture_type, + CAPTURE_BUFFER_COUNT, + )?; + for index in 0..self.capture.len() { + queue_buffer( + self.file.as_raw_fd(), + self.capture_type, + index, + &self.capture[index], + None, + 0, + )?; + self.capture[index].queued = true; + } + stream_on(self.file.as_raw_fd(), self.capture_type)?; + self.capture_streaming = true; + stream_on(self.file.as_raw_fd(), self.output_type)?; + self.output_streaming = true; + Ok(()) + } + + fn apply_negotiated_format(&mut self, negotiated: &NegotiatedFormat) -> Result<()> { + if negotiated.width == 0 + || negotiated.height == 0 + || negotiated.width > 16_384 + || negotiated.height > 16_384 + || negotiated.visible_left + negotiated.visible_width > negotiated.width + || negotiated.visible_top + negotiated.visible_height > negotiated.height + { + return Err(Error::InvalidFormat( + "V4L2 returned invalid coded or visible dimensions".to_owned(), + )); + } + let previous = self.format; + self.format.width = negotiated.visible_width; + self.format.height = negotiated.visible_height; + self.format.pixel_format = match negotiated.fourcc { + NV12 | NV12M => PixelFormat::Nv12, + YUV420 | YUV420M => PixelFormat::I420, + other => { + return Err(Error::InvalidFormat(format!( + "V4L2 selected unsupported capture format {}", + fourcc_name(other) + ))); + } + }; + self.format.color_matrix = negotiated.color_matrix; + self.format.color_range = negotiated.color_range; + self.format.validate()?; + self.capture_format = Some(negotiated.clone()); + if self.format != previous { + self.pending_format_change = Some(self.format); + } + Ok(()) + } + + fn submit(&mut self, frame: &EncodedVideoFrame) -> Result> { + let deadline = Instant::now() + Duration::from_millis(100); + let mut ready = Vec::new(); + let index = loop { + self.drain_output()?; + ready.extend(self.collect_frames()?); + if let Some(index) = self.output.iter().position(|buffer| !buffer.queued) { + break index; + } + let Some(remaining) = deadline.checked_duration_since(Instant::now()) else { + return Err(Error::backend( + Subsystem::V4l2, + "decoder did not return an output buffer within 100ms", + )); + }; + self.wait_for_progress(remaining)?; + }; + let plane = self.output[index] + .planes + .first_mut() + .ok_or_else(|| Error::backend(Subsystem::V4l2, "output buffer has no planes"))?; + if frame.data.len() > plane.length { + return Err(Error::InvalidFormat(format!( + "H.264 access unit is {} bytes but the V4L2 buffer is {} bytes", + frame.data.len(), + plane.length + ))); + } + plane.as_mut_slice()[..frame.data.len()].copy_from_slice(&frame.data); + queue_buffer( + self.file.as_raw_fd(), + self.output_type, + index, + &self.output[index], + Some(frame.data.len()), + frame.timestamp_us, + )?; + self.output[index].queued = true; + Ok(ready) + } + + fn collect_frames(&mut self) -> Result> { + let mut frames = Vec::new(); + loop { + match dequeue_buffer( + self.file.as_raw_fd(), + self.capture_type, + self.capture.first().map_or(1, |buffer| buffer.planes.len()), + ) { + Ok(dequeued) => { + let index = dequeued.index; + if index >= self.capture.len() { + return Err(Error::backend( + Subsystem::V4l2, + format!("driver dequeued invalid capture buffer {index}"), + )); + } + self.capture[index].queued = false; + let is_last = dequeued.flags & V4L2_BUF_FLAG_LAST != 0; + let is_error = dequeued.flags & V4L2_BUF_FLAG_ERROR != 0; + let has_data = dequeued.bytes_used.iter().any(|used| *used > 0); + if !is_error && has_data { + let geometry = self.capture_format.as_ref().ok_or_else(|| { + Error::backend(Subsystem::V4l2, "capture format is unavailable") + })?; + frames.push(copy_capture_frame( + &self.capture[index], + &dequeued, + self.format, + geometry, + )?); + self.capture_frames_seen = self.capture_frames_seen.saturating_add(1); + } + if is_last { + self.capture_last_seen = true; + } else { + queue_buffer( + self.file.as_raw_fd(), + self.capture_type, + index, + &self.capture[index], + None, + 0, + )?; + self.capture[index].queued = true; + } + } + Err(error) if error.kind() == io::ErrorKind::WouldBlock => break, + Err(error) => return Err(Error::io(Subsystem::V4l2, error)), + } + } + if self.pending_source_change && self.capture_last_seen { + self.reconfigure_capture()?; + } + Ok(frames) + } + + fn drain_output(&mut self) -> Result<()> { + loop { + match dequeue_buffer( + self.file.as_raw_fd(), + self.output_type, + self.output.first().map_or(1, |buffer| buffer.planes.len()), + ) { + Ok(dequeued) => { + let buffer = self.output.get_mut(dequeued.index).ok_or_else(|| { + Error::backend( + Subsystem::V4l2, + format!("driver dequeued invalid output buffer {}", dequeued.index), + ) + })?; + buffer.queued = false; + } + Err(error) if error.kind() == io::ErrorKind::WouldBlock => return Ok(()), + Err(error) => return Err(Error::io(Subsystem::V4l2, error)), + } + } + } + + fn wait_for_progress(&mut self, timeout: Duration) -> Result<()> { + let mut descriptor = libc::pollfd { + fd: self.file.as_raw_fd(), + events: libc::POLLIN | libc::POLLOUT | libc::POLLPRI, + revents: 0, + }; + let result = unsafe { + libc::poll( + &mut descriptor, + 1, + timeout.as_millis().min(i32::MAX as u128) as i32, + ) + }; + if result < 0 { + let error = io::Error::last_os_error(); + if error.kind() == io::ErrorKind::Interrupted { + return Ok(()); + } + return Err(Error::io(Subsystem::V4l2, error)); + } + if descriptor.revents & (libc::POLLERR | libc::POLLHUP | libc::POLLNVAL) != 0 { + return Err(Error::DeviceLost { + subsystem: Subsystem::V4l2, + reason: format!("decoder poll failed with revents={:#x}", descriptor.revents), + }); + } + if result > 0 && descriptor.revents & libc::POLLPRI != 0 { + self.handle_events()?; + } + Ok(()) + } + + fn handle_events(&mut self) -> Result<()> { + loop { + let mut event: v4l2_event = zeroed(); + match ioctl(self.file.as_raw_fd(), VIDIOC_DQEVENT, &mut event) { + Ok(()) => { + if event.type_ != V4L2_EVENT_SOURCE_CHANGE { + continue; + } + let changes = unsafe { event.u.src_change.changes }; + if changes & V4L2_EVENT_SRC_CH_RESOLUTION != 0 { + if self.capture_frames_seen == 0 { + self.reconfigure_capture()?; + } else { + self.pending_source_change = true; + self.capture_last_seen = false; + } + } + } + Err(error) if error.kind() == io::ErrorKind::WouldBlock => return Ok(()), + Err(error) => return Err(Error::io(Subsystem::V4l2, error)), + } + } + } + + fn reconfigure_capture(&mut self) -> Result<()> { + if self.capture_streaming { + stream_off(self.file.as_raw_fd(), self.capture_type)?; + self.capture_streaming = false; + } + self.capture.clear(); + release_buffers(self.file.as_raw_fd(), self.capture_type)?; + let mut negotiated = get_format(self.file.as_raw_fd(), self.capture_type)?; + apply_visible_selection(self.file.as_raw_fd(), self.capture_type, &mut negotiated); + self.apply_negotiated_format(&negotiated)?; + self.capture = request_and_map_buffers( + self.file.as_raw_fd(), + self.capture_type, + CAPTURE_BUFFER_COUNT, + )?; + for index in 0..self.capture.len() { + queue_buffer( + self.file.as_raw_fd(), + self.capture_type, + index, + &self.capture[index], + None, + 0, + )?; + self.capture[index].queued = true; + } + stream_on(self.file.as_raw_fd(), self.capture_type)?; + self.capture_streaming = true; + self.pending_source_change = false; + self.capture_last_seen = false; + self.capture_frames_seen = 0; + Ok(()) + } + + fn shutdown(&mut self) { + if self.output_streaming { + let _ = stream_off(self.file.as_raw_fd(), self.output_type); + self.output_streaming = false; + } + if self.capture_streaming { + let _ = stream_off(self.file.as_raw_fd(), self.capture_type); + self.capture_streaming = false; + } + self.output.clear(); + self.capture.clear(); + let _ = release_buffers(self.file.as_raw_fd(), self.output_type); + let _ = release_buffers(self.file.as_raw_fd(), self.capture_type); + } +} + +impl VideoDecoder for V4l2Decoder { + fn decode(&mut self, frame: &EncodedVideoFrame) -> Result> { + let mut frames = self.submit(frame)?; + self.wait_for_progress(Duration::from_millis(1))?; + self.drain_output()?; + frames.extend(self.collect_frames()?); + Ok(frames) + } + + fn flush(&mut self) -> Result> { + let mut command: v4l2_decoder_cmd = zeroed(); + command.cmd = V4L2_DEC_CMD_STOP; + self.pending_source_change = false; + self.capture_last_seen = false; + let command_supported = match ioctl( + self.file.as_raw_fd(), + vidioc::VIDIOC_DECODER_CMD, + &mut command, + ) { + Ok(()) => true, + Err(error) if matches!(error.raw_os_error(), Some(libc::EINVAL | libc::ENOTTY)) => { + false + } + Err(error) => return Err(Error::io(Subsystem::V4l2, error)), + }; + let deadline = Instant::now() + Duration::from_millis(250); + let mut last_frame = Instant::now(); + let mut frames = Vec::new(); + while Instant::now() < deadline { + self.wait_for_progress(Duration::from_millis(10))?; + self.drain_output()?; + let ready = self.collect_frames()?; + if !ready.is_empty() { + last_frame = Instant::now(); + frames.extend(ready); + } + let output_idle = !self.output.iter().any(|buffer| buffer.queued); + if output_idle + && ((command_supported && self.capture_last_seen) + || (!command_supported && last_frame.elapsed() >= Duration::from_millis(30))) + { + break; + } + } + Ok(frames) + } + + fn take_format_change(&mut self) -> Option { + self.pending_format_change.take() + } +} + +impl Drop for V4l2Decoder { + fn drop(&mut self) { + self.shutdown(); + } +} + +pub(crate) fn probe_v4l2_devices() -> Vec { + (0..MAX_VIDEO_DEVICES) + .filter_map(|index| inspect_device(PathBuf::from(format!("/dev/video{index}"))).ok()) + .collect() +} + +fn inspect_device(path: PathBuf) -> io::Result { + let file = open_device(&path)?; + let fd = file.as_raw_fd(); + let mut capability: v4l2_capability = zeroed(); + ioctl(fd, vidioc::VIDIOC_QUERYCAP, &mut capability)?; + let caps = if capability.capabilities & V4L2_CAP_DEVICE_CAPS != 0 { + capability.device_caps + } else { + capability.capabilities + }; + if caps & V4L2_CAP_STREAMING == 0 { + return Err(io::Error::new( + io::ErrorKind::Unsupported, + "device does not support streaming I/O", + )); + } + let multiplanar = caps & V4L2_CAP_VIDEO_M2M_MPLANE != 0; + if !multiplanar && caps & V4L2_CAP_VIDEO_M2M == 0 { + return Err(io::Error::new( + io::ErrorKind::Unsupported, + "device is not a V4L2 M2M decoder", + )); + } + let output_type = if multiplanar { + v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE + } else { + v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT + }; + let capture_type = if multiplanar { + v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE + } else { + v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_CAPTURE + }; + if !enum_formats(fd, output_type)?.contains(&H264) { + return Err(io::Error::new( + io::ErrorKind::Unsupported, + "device does not accept H.264", + )); + } + let capture = enum_formats(fd, capture_type)?; + let capture_fourcc = [NV12, NV12M, YUV420, YUV420M] + .into_iter() + .find(|format| capture.contains(format)) + .ok_or_else(|| { + io::Error::new( + io::ErrorKind::Unsupported, + "device does not output NV12 or I420", + ) + })?; + Ok(V4l2DeviceInfo { + path, + driver: c_string(&capability.driver), + card: c_string(&capability.card), + multiplanar, + capture_fourcc, + }) +} + +fn open_device(path: &Path) -> io::Result { + OpenOptions::new() + .read(true) + .write(true) + .custom_flags(libc::O_CLOEXEC | libc::O_NONBLOCK) + .open(path) +} + +fn enum_formats(fd: RawFd, buffer_type: u32) -> io::Result> { + let mut formats = Vec::new(); + for index in 0..256 { + let mut description: v4l2_fmtdesc = zeroed(); + description.index = index; + description.type_ = buffer_type; + match ioctl(fd, vidioc::VIDIOC_ENUM_FMT, &mut description) { + Ok(()) => formats.push(description.pixelformat), + Err(error) if error.raw_os_error() == Some(libc::EINVAL) => break, + Err(error) => return Err(error), + } + } + Ok(formats) +} + +#[derive(Debug, Clone)] +struct PlaneGeometry { + stride: usize, + size: usize, +} + +#[derive(Debug, Clone)] +struct NegotiatedFormat { + width: u32, + height: u32, + visible_left: u32, + visible_top: u32, + visible_width: u32, + visible_height: u32, + fourcc: u32, + planes: Vec, + color_matrix: ColorMatrix, + color_range: ColorRange, +} + +fn set_format( + fd: RawFd, + buffer_type: u32, + pixel_format: u32, + width: u32, + height: u32, + size_image: Option, +) -> Result { + let mut format: v4l2_format = zeroed(); + format.type_ = buffer_type; + if is_multiplanar(buffer_type) { + let mut pixel: v4l2_pix_format_mplane = zeroed(); + pixel.width = width; + pixel.height = height; + pixel.pixelformat = pixel_format; + pixel.field = v4l2_field_V4L2_FIELD_NONE; + pixel.colorspace = v4l2_colorspace_V4L2_COLORSPACE_REC709; + pixel.num_planes = match pixel_format { + NV12M => 2, + YUV420M => 3, + _ => 1, + }; + if let Some(size_image) = size_image { + pixel.plane_fmt[0].sizeimage = size_image; + } + format.fmt.pix_mp = pixel; + } else { + let mut pixel: v4l2_pix_format = zeroed(); + pixel.width = width; + pixel.height = height; + pixel.pixelformat = pixel_format; + pixel.field = v4l2_field_V4L2_FIELD_NONE; + pixel.colorspace = v4l2_colorspace_V4L2_COLORSPACE_REC709; + if let Some(size_image) = size_image { + pixel.sizeimage = size_image; + } + format.fmt.pix = pixel; + } + ioctl(fd, vidioc::VIDIOC_S_FMT, &mut format) + .map_err(|error| Error::io(Subsystem::V4l2, error))?; + + negotiated_format(&format) +} + +fn get_format(fd: RawFd, buffer_type: u32) -> Result { + let mut format: v4l2_format = zeroed(); + format.type_ = buffer_type; + ioctl(fd, vidioc::VIDIOC_G_FMT, &mut format) + .map_err(|error| Error::io(Subsystem::V4l2, error))?; + negotiated_format(&format) +} + +fn negotiated_format(format: &v4l2_format) -> Result { + let (width, height, fourcc, colorspace, quantization, planes) = unsafe { + if is_multiplanar(format.type_) { + let pixel = format.fmt.pix_mp; + let plane_count = pixel.num_planes as usize; + if plane_count == 0 || plane_count > MAX_PLANES { + return Err(Error::InvalidFormat(format!( + "V4L2 returned invalid plane count {plane_count}" + ))); + } + let plane_formats = pixel.plane_fmt; + let planes = plane_formats[..plane_count] + .iter() + .enumerate() + .map(|(index, plane)| PlaneGeometry { + stride: (plane.bytesperline as usize).max(match (pixel.pixelformat, index) { + (YUV420M, 1 | 2) => pixel.width as usize / 2, + _ => pixel.width as usize, + }), + size: plane.sizeimage as usize, + }) + .collect(); + ( + pixel.width, + pixel.height, + pixel.pixelformat, + pixel.colorspace, + pixel.quantization as u32, + planes, + ) + } else { + let pixel = format.fmt.pix; + ( + pixel.width, + pixel.height, + pixel.pixelformat, + pixel.colorspace, + pixel.quantization, + vec![PlaneGeometry { + stride: (pixel.bytesperline as usize).max(pixel.width as usize), + size: pixel.sizeimage as usize, + }], + ) + } + }; + Ok(NegotiatedFormat { + width, + height, + visible_left: 0, + visible_top: 0, + visible_width: width, + visible_height: height, + fourcc, + planes, + color_matrix: if colorspace == v4l2_colorspace_V4L2_COLORSPACE_BT2020 { + ColorMatrix::Bt2020 + } else if colorspace == v4l2_colorspace_V4L2_COLORSPACE_REC709 { + ColorMatrix::Bt709 + } else { + ColorMatrix::Bt601 + }, + color_range: if quantization == v4l2_quantization_V4L2_QUANTIZATION_FULL_RANGE { + ColorRange::Full + } else { + ColorRange::Limited + }, + }) +} + +fn apply_visible_selection(fd: RawFd, buffer_type: u32, format: &mut NegotiatedFormat) { + let mut selection: v4l2_selection = zeroed(); + selection.type_ = buffer_type; + selection.target = V4L2_SEL_TGT_COMPOSE; + if ioctl(fd, vidioc::VIDIOC_G_SELECTION, &mut selection).is_ok() + && selection.r.left >= 0 + && selection.r.top >= 0 + && selection.r.width > 0 + && selection.r.height > 0 + { + let left = selection.r.left as u32; + let top = selection.r.top as u32; + if left < format.width && top < format.height { + format.visible_left = left; + format.visible_top = top; + format.visible_width = selection.r.width.min(format.width - left); + format.visible_height = selection.r.height.min(format.height - top); + } + } +} + +fn request_and_map_buffers(fd: RawFd, buffer_type: u32, count: u32) -> Result> { + let mut request: v4l2_requestbuffers = zeroed(); + request.count = count; + request.type_ = buffer_type; + request.memory = v4l2_memory_V4L2_MEMORY_MMAP; + ioctl(fd, vidioc::VIDIOC_REQBUFS, &mut request) + .map_err(|error| Error::io(Subsystem::V4l2, error))?; + if request.count < 2 { + return Err(Error::backend( + Subsystem::V4l2, + format!("driver allocated only {} MMAP buffers", request.count), + )); + } + (0..request.count) + .map(|index| map_buffer(fd, buffer_type, index as usize)) + .collect() +} + +fn map_buffer(fd: RawFd, buffer_type: u32, index: usize) -> Result { + let mut planes = [zeroed::(); MAX_PLANES]; + let mut buffer: v4l2_buffer = zeroed(); + buffer.index = index as u32; + buffer.type_ = buffer_type; + buffer.memory = v4l2_memory_V4L2_MEMORY_MMAP; + if is_multiplanar(buffer_type) { + buffer.length = MAX_PLANES as u32; + buffer.m.planes = planes.as_mut_ptr(); + } + ioctl(fd, vidioc::VIDIOC_QUERYBUF, &mut buffer) + .map_err(|error| Error::io(Subsystem::V4l2, error))?; + let plane_count = if is_multiplanar(buffer_type) { + buffer.length as usize + } else { + 1 + }; + let mut mappings = Vec::with_capacity(plane_count); + for plane in planes.iter().take(plane_count) { + let (length, offset) = unsafe { + if is_multiplanar(buffer_type) { + (plane.length as usize, plane.m.mem_offset as libc::off_t) + } else { + (buffer.length as usize, buffer.m.offset as libc::off_t) + } + }; + let address = unsafe { + libc::mmap( + std::ptr::null_mut(), + length, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_SHARED, + fd, + offset, + ) + }; + if address == libc::MAP_FAILED { + return Err(Error::io(Subsystem::V4l2, io::Error::last_os_error())); + } + let Some(address) = NonNull::new(address.cast()) else { + unsafe { libc::munmap(address, length) }; + return Err(Error::backend( + Subsystem::V4l2, + "MMAP returned a null address", + )); + }; + mappings.push(MappedPlane { address, length }); + } + Ok(QueueBuffer { + planes: mappings, + queued: false, + }) +} + +fn queue_buffer( + fd: RawFd, + buffer_type: u32, + index: usize, + mapped: &QueueBuffer, + bytes_used: Option, + timestamp_us: u64, +) -> Result<()> { + let mut planes = [zeroed::(); MAX_PLANES]; + let mut buffer: v4l2_buffer = zeroed(); + buffer.index = index as u32; + buffer.type_ = buffer_type; + buffer.memory = v4l2_memory_V4L2_MEMORY_MMAP; + buffer.timestamp.tv_sec = (timestamp_us / 1_000_000) as libc::time_t; + buffer.timestamp.tv_usec = (timestamp_us % 1_000_000) as libc::suseconds_t; + if is_multiplanar(buffer_type) { + for (plane, mapping) in planes.iter_mut().zip(&mapped.planes) { + plane.length = mapping.length as u32; + } + if let Some(bytes_used) = bytes_used { + planes[0].bytesused = bytes_used as u32; + } + buffer.length = mapped.planes.len() as u32; + buffer.m.planes = planes.as_mut_ptr(); + } else { + buffer.length = mapped.planes[0].length as u32; + buffer.bytesused = bytes_used.unwrap_or(0) as u32; + } + ioctl(fd, vidioc::VIDIOC_QBUF, &mut buffer).map_err(|error| Error::io(Subsystem::V4l2, error)) +} + +#[derive(Debug)] +struct DequeuedBuffer { + index: usize, + flags: u32, + timestamp_us: u64, + bytes_used: Vec, + data_offsets: Vec, +} + +fn dequeue_buffer(fd: RawFd, buffer_type: u32, plane_count: usize) -> io::Result { + let mut planes = [zeroed::(); MAX_PLANES]; + let mut buffer: v4l2_buffer = zeroed(); + buffer.type_ = buffer_type; + buffer.memory = v4l2_memory_V4L2_MEMORY_MMAP; + if is_multiplanar(buffer_type) { + buffer.length = plane_count as u32; + buffer.m.planes = planes.as_mut_ptr(); + } + ioctl(fd, vidioc::VIDIOC_DQBUF, &mut buffer)?; + let (bytes_used, data_offsets) = if is_multiplanar(buffer_type) { + ( + planes[..buffer.length as usize] + .iter() + .map(|plane| plane.bytesused as usize) + .collect(), + planes[..buffer.length as usize] + .iter() + .map(|plane| plane.data_offset as usize) + .collect(), + ) + } else { + (vec![buffer.bytesused as usize], vec![0]) + }; + Ok(DequeuedBuffer { + index: buffer.index as usize, + flags: buffer.flags, + timestamp_us: (buffer.timestamp.tv_sec as u64) + .saturating_mul(1_000_000) + .saturating_add(buffer.timestamp.tv_usec.max(0) as u64), + bytes_used, + data_offsets, + }) +} + +fn copy_capture_frame( + mapped: &QueueBuffer, + dequeued: &DequeuedBuffer, + format: StreamFormat, + geometry: &NegotiatedFormat, +) -> Result { + let width = format.width as usize; + let height = format.height as usize; + let coded_height = geometry.height as usize; + let left = geometry.visible_left as usize; + let top = geometry.visible_top as usize; + let mut planes = Vec::new(); + match (format.pixel_format, mapped.planes.len()) { + (PixelFormat::Nv12, 1) => { + let source = capture_plane(mapped, dequeued, geometry, 0)?; + let stride = geometry.planes[0].stride; + let uv_offset = stride * coded_height; + planes.push(FramePlane { + data: copy_rows(source, top * stride + left, stride, width, height)?, + stride: width, + rows: height, + }); + planes.push(FramePlane { + data: copy_rows( + source, + uv_offset + (top / 2) * stride + (left / 2) * 2, + stride, + width, + height / 2, + )?, + stride: width, + rows: height / 2, + }); + } + (PixelFormat::Nv12, _) => { + for (index, rows) in [height, height / 2].into_iter().enumerate() { + let source = capture_plane(mapped, dequeued, geometry, index)?; + let offset = if index == 0 { + top * geometry.planes[index].stride + left + } else { + (top / 2) * geometry.planes[index].stride + (left / 2) * 2 + }; + planes.push(FramePlane { + data: copy_rows(source, offset, geometry.planes[index].stride, width, rows)?, + stride: width, + rows, + }); + } + } + (PixelFormat::I420, 1) => { + let source = capture_plane(mapped, dequeued, geometry, 0)?; + let y_stride = geometry.planes[0].stride; + let y_len = y_stride * coded_height; + let chroma_stride = y_stride / 2; + let chroma_len = chroma_stride * coded_height / 2; + planes.push(FramePlane { + data: copy_rows(source, top * y_stride + left, y_stride, width, height)?, + stride: width, + rows: height, + }); + planes.push(FramePlane { + data: copy_rows( + source, + y_len + (top / 2) * chroma_stride + left / 2, + chroma_stride, + width / 2, + height / 2, + )?, + stride: width / 2, + rows: height / 2, + }); + planes.push(FramePlane { + data: copy_rows( + source, + y_len + chroma_len + (top / 2) * chroma_stride + left / 2, + chroma_stride, + width / 2, + height / 2, + )?, + stride: width / 2, + rows: height / 2, + }); + } + (PixelFormat::I420, _) => { + for (index, (rows, minimum_stride)) in [ + (height, width), + (height / 2, width / 2), + (height / 2, width / 2), + ] + .into_iter() + .enumerate() + { + let source = capture_plane(mapped, dequeued, geometry, index)?; + let offset = if index == 0 { + top * geometry.planes[index].stride + left + } else { + (top / 2) * geometry.planes[index].stride + left / 2 + }; + planes.push(FramePlane { + data: copy_rows( + source, + offset, + geometry.planes[index].stride, + minimum_stride, + rows, + )?, + stride: minimum_stride, + rows, + }); + } + } + _ => { + return Err(Error::InvalidFormat( + "V4L2 returned an unsupported frame layout".to_owned(), + )); + } + } + let frame = DecodedVideoFrame { + format: StreamFormat { + chroma_location: ChromaLocation::Left, + ..format + }, + planes, + dmabuf: None, + vulkan: None, + overlay: None, + timestamp_us: dequeued.timestamp_us, + }; + frame.validate()?; + Ok(frame) +} + +fn valid_plane_slice<'a>( + mapped: &'a QueueBuffer, + dequeued: &DequeuedBuffer, + index: usize, +) -> Result<&'a [u8]> { + let mapping = mapped + .planes + .get(index) + .ok_or_else(|| Error::InvalidFormat(format!("capture plane {index} is missing")))?; + let offset = dequeued.data_offsets.get(index).copied().unwrap_or(0); + let used = dequeued + .bytes_used + .get(index) + .copied() + .unwrap_or(0) + .min(mapping.length); + if offset > used { + return Err(Error::InvalidFormat(format!( + "capture plane {index} has an invalid data offset" + ))); + } + Ok(&mapping.as_slice()[offset..used]) +} + +fn capture_plane<'a>( + mapped: &'a QueueBuffer, + dequeued: &DequeuedBuffer, + geometry: &NegotiatedFormat, + index: usize, +) -> Result<&'a [u8]> { + let source = valid_plane_slice(mapped, dequeued, index)?; + let plane = geometry + .planes + .get(index) + .ok_or_else(|| Error::InvalidFormat(format!("capture plane {index} has no geometry")))?; + let length = if plane.size == 0 { + source.len() + } else { + source.len().min(plane.size) + }; + Ok(&source[..length]) +} + +fn copy_rows( + source: &[u8], + offset: usize, + source_stride: usize, + row_bytes: usize, + rows: usize, +) -> Result> { + if source_stride < row_bytes { + return Err(Error::InvalidFormat( + "capture plane stride is smaller than the visible row".to_owned(), + )); + } + let required = offset + .checked_add(source_stride.saturating_mul(rows.saturating_sub(1))) + .and_then(|value| value.checked_add(row_bytes)) + .ok_or_else(|| Error::InvalidFormat("capture plane size overflow".to_owned()))?; + if source.len() < required { + return Err(Error::InvalidFormat(format!( + "capture plane has {} bytes but geometry requires {required}", + source.len() + ))); + } + let mut output = Vec::with_capacity(row_bytes * rows); + for row in 0..rows { + let start = offset + row * source_stride; + output.extend_from_slice(&source[start..start + row_bytes]); + } + Ok(Arc::from(output)) +} + +fn stream_on(fd: RawFd, buffer_type: u32) -> Result<()> { + let mut buffer_type = buffer_type as libc::c_int; + ioctl(fd, vidioc::VIDIOC_STREAMON, &mut buffer_type) + .map_err(|error| Error::io(Subsystem::V4l2, error)) +} + +fn stream_off(fd: RawFd, buffer_type: u32) -> Result<()> { + let mut buffer_type = buffer_type as libc::c_int; + ioctl(fd, vidioc::VIDIOC_STREAMOFF, &mut buffer_type) + .map_err(|error| Error::io(Subsystem::V4l2, error)) +} + +fn release_buffers(fd: RawFd, buffer_type: u32) -> Result<()> { + let mut request: v4l2_requestbuffers = zeroed(); + request.type_ = buffer_type; + request.memory = v4l2_memory_V4L2_MEMORY_MMAP; + ioctl(fd, vidioc::VIDIOC_REQBUFS, &mut request) + .map_err(|error| Error::io(Subsystem::V4l2, error)) +} + +fn ioctl(fd: RawFd, request: vidioc::_IOC_TYPE, value: &mut T) -> io::Result<()> { + let result = unsafe { libc::ioctl(fd, request, (value as *mut T).cast::()) }; + if result < 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } +} + +fn zeroed() -> T { + unsafe { mem::zeroed() } +} + +fn is_multiplanar(buffer_type: u32) -> bool { + buffer_type == v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE + || buffer_type == v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE +} + +fn compressed_buffer_size(width: u32, height: u32) -> u32 { + width + .saturating_mul(height) + .clamp(1024 * 1024, 16 * 1024 * 1024) +} + +fn c_string(bytes: &[u8]) -> String { + String::from_utf8_lossy( + &bytes[..bytes + .iter() + .position(|byte| *byte == 0) + .unwrap_or(bytes.len())], + ) + .into_owned() +} + +fn fourcc_name(value: u32) -> String { + String::from_utf8_lossy(&value.to_le_bytes()).into_owned() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn copies_visible_rows_without_coded_padding() { + let source = [1, 2, 3, 4, 90, 90, 5, 6, 7, 8, 90, 90]; + let copied = copy_rows(&source, 0, 6, 4, 2).unwrap(); + assert_eq!(&*copied, &[1, 2, 3, 4, 5, 6, 7, 8]); + } + + #[test] + fn copies_visible_crop_from_coded_plane() { + let source = [90, 1, 2, 90, 90, 3, 4, 90]; + let copied = copy_rows(&source, 1, 4, 2, 2).unwrap(); + assert_eq!(&*copied, &[1, 2, 3, 4]); + } + + #[test] + fn rejects_capture_geometry_beyond_bytes_used() { + let error = copy_rows(&[0; 7], 0, 4, 4, 2).unwrap_err(); + assert!(matches!(error, Error::InvalidFormat(_))); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/video/v4l2_ffi.rs b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/video/v4l2_ffi.rs new file mode 100644 index 000000000..759a4d270 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/video/v4l2_ffi.rs @@ -0,0 +1,343 @@ +#![allow(non_camel_case_types, non_upper_case_globals)] + +use std::os::raw::{c_int, c_ulong}; + +pub const VIDEO_MAX_PLANES: u32 = 8; +pub const V4L2_CAP_VIDEO_M2M_MPLANE: u32 = 1 << 14; +pub const V4L2_CAP_VIDEO_M2M: u32 = 1 << 15; +pub const V4L2_CAP_STREAMING: u32 = 1 << 26; +pub const V4L2_CAP_DEVICE_CAPS: u32 = 1 << 31; +pub const V4L2_EVENT_SOURCE_CHANGE: u32 = 5; +pub const V4L2_EVENT_SRC_CH_RESOLUTION: u32 = 1; +pub const V4L2_DEC_CMD_STOP: u32 = 1; +pub const V4L2_BUF_FLAG_ERROR: u32 = 0x0040; +pub const V4L2_BUF_FLAG_LAST: u32 = 0x0010_0000; +pub const V4L2_SEL_TGT_COMPOSE: u32 = 0x0100; + +pub type v4l2_buf_type = u32; +pub const v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_CAPTURE: v4l2_buf_type = 1; +pub const v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT: v4l2_buf_type = 2; +pub const v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: v4l2_buf_type = 9; +pub const v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: v4l2_buf_type = 10; + +pub type v4l2_memory = u32; +pub const v4l2_memory_V4L2_MEMORY_MMAP: v4l2_memory = 1; +pub type v4l2_field = u32; +pub const v4l2_field_V4L2_FIELD_NONE: v4l2_field = 1; +pub type v4l2_colorspace = u32; +pub const v4l2_colorspace_V4L2_COLORSPACE_REC709: v4l2_colorspace = 3; +pub const v4l2_colorspace_V4L2_COLORSPACE_BT2020: v4l2_colorspace = 10; +pub type v4l2_quantization = u32; +pub const v4l2_quantization_V4L2_QUANTIZATION_FULL_RANGE: v4l2_quantization = 1; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_capability { + pub driver: [u8; 16], + pub card: [u8; 32], + pub bus_info: [u8; 32], + pub version: u32, + pub capabilities: u32, + pub device_caps: u32, + pub reserved: [u32; 3], +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_fmtdesc { + pub index: u32, + pub type_: u32, + pub flags: u32, + pub description: [u8; 32], + pub pixelformat: u32, + pub mbus_code: u32, + pub reserved: [u32; 3], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_pix_format { + pub width: u32, + pub height: u32, + pub pixelformat: u32, + pub field: u32, + pub bytesperline: u32, + pub sizeimage: u32, + pub colorspace: u32, + pub priv_: u32, + pub flags: u32, + pub __bindgen_anon_1: v4l2_pix_format__bindgen_ty_1, + pub quantization: u32, + pub xfer_func: u32, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_pix_format__bindgen_ty_1 { + pub ycbcr_enc: u32, + pub hsv_enc: u32, +} + +#[repr(C, packed)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_plane_pix_format { + pub sizeimage: u32, + pub bytesperline: u32, + pub reserved: [u16; 6], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_pix_format_mplane__bindgen_ty_1 { + pub ycbcr_enc: u8, + pub hsv_enc: u8, +} + +#[repr(C, packed)] +#[derive(Copy, Clone)] +pub struct v4l2_pix_format_mplane { + pub width: u32, + pub height: u32, + pub pixelformat: u32, + pub field: u32, + pub colorspace: u32, + pub plane_fmt: [v4l2_plane_pix_format; 8], + pub num_planes: u8, + pub flags: u8, + pub __bindgen_anon_1: v4l2_pix_format_mplane__bindgen_ty_1, + pub quantization: u8, + pub xfer_func: u8, + pub reserved: [u8; 7], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_format__bindgen_ty_1 { + pub pix: v4l2_pix_format, + pub pix_mp: v4l2_pix_format_mplane, + pub raw_data: [u64; 25], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_format { + pub type_: u32, + pub fmt: v4l2_format__bindgen_ty_1, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_requestbuffers { + pub count: u32, + pub type_: u32, + pub memory: u32, + pub capabilities: u32, + pub flags: u8, + pub reserved: [u8; 3], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_plane__bindgen_ty_1 { + pub mem_offset: u32, + pub userptr: c_ulong, + pub fd: i32, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_plane { + pub bytesused: u32, + pub length: u32, + pub m: v4l2_plane__bindgen_ty_1, + pub data_offset: u32, + pub reserved: [u32; 11], +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_timecode { + pub type_: u32, + pub flags: u32, + pub frames: u8, + pub seconds: u8, + pub minutes: u8, + pub hours: u8, + pub userbits: [u8; 4], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_buffer__bindgen_ty_1 { + pub offset: u32, + pub userptr: c_ulong, + pub planes: *mut v4l2_plane, + pub fd: i32, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_buffer__bindgen_ty_2 { + pub request_fd: i32, + pub reserved: u32, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_buffer { + pub index: u32, + pub type_: u32, + pub bytesused: u32, + pub flags: u32, + pub field: u32, + pub timestamp: libc::timeval, + pub timecode: v4l2_timecode, + pub sequence: u32, + pub memory: u32, + pub m: v4l2_buffer__bindgen_ty_1, + pub length: u32, + pub reserved2: u32, + pub __bindgen_anon_1: v4l2_buffer__bindgen_ty_2, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_event_src_change { + pub changes: u32, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_event__bindgen_ty_1 { + pub src_change: v4l2_event_src_change, + pub data: [u64; 8], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_event { + pub type_: u32, + pub u: v4l2_event__bindgen_ty_1, + pub pending: u32, + pub sequence: u32, + pub timestamp: libc::timespec, + pub id: u32, + pub reserved: [u32; 8], +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_event_subscription { + pub type_: u32, + pub id: u32, + pub flags: u32, + pub reserved: [u32; 5], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_decoder_cmd__bindgen_ty_1 { + pub raw: [u64; 8], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_decoder_cmd { + pub cmd: u32, + pub flags: u32, + pub __bindgen_anon_1: v4l2_decoder_cmd__bindgen_ty_1, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_rect { + pub left: i32, + pub top: i32, + pub width: u32, + pub height: u32, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_selection { + pub type_: u32, + pub target: u32, + pub flags: u32, + pub r: v4l2_rect, + pub reserved: [u32; 9], +} + +pub mod vidioc { + use super::*; + + pub type _IOC_TYPE = c_ulong; + + const IOC_WRITE: c_ulong = 1; + const IOC_READ: c_ulong = 2; + + const fn code(direction: c_ulong, number: c_ulong, size: usize) -> _IOC_TYPE { + (direction << 30) | ((b'V' as c_ulong) << 8) | number | ((size as c_ulong) << 16) + } + + pub const VIDIOC_QUERYCAP: _IOC_TYPE = + code(IOC_READ, 0, std::mem::size_of::()); + pub const VIDIOC_ENUM_FMT: _IOC_TYPE = + code(IOC_READ | IOC_WRITE, 2, std::mem::size_of::()); + pub const VIDIOC_G_FMT: _IOC_TYPE = + code(IOC_READ | IOC_WRITE, 4, std::mem::size_of::()); + pub const VIDIOC_S_FMT: _IOC_TYPE = + code(IOC_READ | IOC_WRITE, 5, std::mem::size_of::()); + pub const VIDIOC_REQBUFS: _IOC_TYPE = code( + IOC_READ | IOC_WRITE, + 8, + std::mem::size_of::(), + ); + pub const VIDIOC_QUERYBUF: _IOC_TYPE = + code(IOC_READ | IOC_WRITE, 9, std::mem::size_of::()); + pub const VIDIOC_QBUF: _IOC_TYPE = + code(IOC_READ | IOC_WRITE, 15, std::mem::size_of::()); + pub const VIDIOC_DQBUF: _IOC_TYPE = + code(IOC_READ | IOC_WRITE, 17, std::mem::size_of::()); + pub const VIDIOC_STREAMON: _IOC_TYPE = code(IOC_WRITE, 18, std::mem::size_of::()); + pub const VIDIOC_STREAMOFF: _IOC_TYPE = code(IOC_WRITE, 19, std::mem::size_of::()); + pub const VIDIOC_DECODER_CMD: _IOC_TYPE = code( + IOC_READ | IOC_WRITE, + 96, + std::mem::size_of::(), + ); + pub const VIDIOC_G_SELECTION: _IOC_TYPE = code( + IOC_READ | IOC_WRITE, + 94, + std::mem::size_of::(), + ); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn uapi_layout_matches_linux_x64_and_arm64() { + assert_eq!(std::mem::size_of::(), 104); + assert_eq!(std::mem::size_of::(), 64); + assert_eq!(std::mem::size_of::(), 48); + assert_eq!(std::mem::size_of::(), 192); + assert_eq!(std::mem::size_of::(), 208); + assert_eq!(std::mem::size_of::(), 64); + assert_eq!(std::mem::size_of::(), 88); + assert_eq!(std::mem::size_of::(), 136); + assert_eq!(std::mem::size_of::(), 32); + assert_eq!(std::mem::size_of::(), 72); + assert_eq!(std::mem::size_of::(), 64); + assert_eq!(std::mem::offset_of!(v4l2_pix_format, flags), 32); + assert_eq!(std::mem::offset_of!(v4l2_pix_format, quantization), 40); + assert_eq!(std::mem::offset_of!(v4l2_format, fmt), 8); + assert_eq!(std::mem::offset_of!(v4l2_plane, m), 8); + assert_eq!(std::mem::offset_of!(v4l2_plane, data_offset), 16); + assert_eq!(std::mem::offset_of!(v4l2_buffer, timestamp), 24); + assert_eq!(std::mem::offset_of!(v4l2_buffer, m), 64); + assert_eq!(std::mem::offset_of!(v4l2_buffer, length), 72); + assert_eq!(std::mem::offset_of!(v4l2_event, u), 8); + assert_eq!(std::mem::offset_of!(v4l2_event, timestamp), 80); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/video/vaapi.rs b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/video/vaapi.rs new file mode 100644 index 000000000..49b8b2e3f --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/src/video/vaapi.rs @@ -0,0 +1,348 @@ +use std::fmt; +use std::os::fd::AsRawFd; +use std::sync::{Arc, Mutex}; + +use cros_codecs::backend::vaapi::decoder::VaapiBackend; +use cros_codecs::decoder::stateless::h264::H264; +use cros_codecs::decoder::stateless::{DecodeError, StatelessDecoder, StatelessVideoDecoder}; +use cros_codecs::decoder::{DecodedHandle, DecoderEvent}; +use cros_codecs::libva::{self, Display, DrmPrimeSurfaceDescriptor, Surface, UsageHint}; +use cros_codecs::video_frame::{ReadMapping, VideoFrame, WriteMapping}; +use cros_codecs::{Fourcc, Resolution}; + +use super::VideoDecoder; +use crate::{ + ChromaLocation, DecodedVideoFrame, DmaBufFrame, DmaBufLayer, DmaBufObject, DmaBufPlane, + EncodedVideoFrame, Error, PixelFormat, Result, StreamFormat, Subsystem, +}; + +const MAX_DECODE_RETRIES: usize = 16; + +struct VaFrame { + visible: Resolution, + coded: Resolution, + stride: usize, + exported: Mutex>>, +} + +impl VaFrame { + fn new(visible: Resolution, coded: Resolution) -> Self { + let coded_width = align(coded.width.max(visible.width), 16); + let coded_height = align(coded.height.max(visible.height), 16); + let stride = align(coded_width, 64) as usize; + Self { + visible, + coded: Resolution::from((coded_width, coded_height)), + stride, + exported: Mutex::new(None), + } + } + + fn exported(&self) -> std::result::Result, String> { + self.exported + .lock() + .map_err(|_| "VA-API export state was poisoned".to_owned())? + .clone() + .ok_or_else(|| "VA-API frame has no exported DRM PRIME surface".to_owned()) + } +} + +impl fmt::Debug for VaFrame { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("VaFrame") + .field("visible", &self.visible) + .field("coded", &self.coded) + .field("stride", &self.stride) + .finish_non_exhaustive() + } +} + +impl VideoFrame for VaFrame { + type MemDescriptor = (); + type NativeHandle = Surface<()>; + + fn fourcc(&self) -> Fourcc { + Fourcc::from(b"NV12") + } + + fn resolution(&self) -> Resolution { + self.visible + } + + fn get_plane_size(&self) -> Vec { + vec![ + self.stride * self.coded.height as usize, + self.stride * self.coded.height as usize / 2, + ] + } + + fn get_plane_pitch(&self) -> Vec { + vec![self.stride, self.stride] + } + + fn map<'a>(&'a self) -> std::result::Result + 'a>, String> { + Err("VA-API zero-copy frames are not CPU mappable".to_owned()) + } + + fn map_mut<'a>(&'a mut self) -> std::result::Result + 'a>, String> { + Err("VA-API zero-copy frames are not CPU mappable".to_owned()) + } + + fn to_native_handle( + &self, + display: &Arc, + ) -> std::result::Result { + let surface = display + .create_surfaces( + libva::VA_RT_FORMAT_YUV420, + Some(libva::VA_FOURCC_NV12), + self.coded.width, + self.coded.height, + Some(UsageHint::USAGE_HINT_DECODER | UsageHint::USAGE_HINT_EXPORT), + vec![()], + ) + .map_err(|error| error.to_string())? + .pop() + .ok_or_else(|| "VA-API did not create a decode surface".to_owned())?; + let exported = Arc::new(surface.export_prime().map_err(|error| error.to_string())?); + *self + .exported + .lock() + .map_err(|_| "VA-API export state was poisoned".to_owned())? = Some(exported); + Ok(surface) + } +} + +pub(crate) struct VaApiDecoder { + decoder: H264VaapiDecoder, + requested_format: StreamFormat, + allocation_visible: Resolution, + allocation_coded: Resolution, + pending_format_change: Option, +} + +impl VaApiDecoder { + pub fn probe() -> std::result::Result { + let display = Display::open().ok_or_else(|| { + "no /dev/dri/renderD* or /dev/dri/card* node initialized through VA-API".to_owned() + })?; + validate_h264_display(&display)?; + let probe_frame = VaFrame::new(Resolution::from((16, 16)), Resolution::from((16, 16))); + drop( + probe_frame + .to_native_handle(&display) + .map_err(|error| format!("VA-API cannot allocate an NV12 user surface: {error}"))?, + ); + let vendor = display + .query_vendor_string() + .unwrap_or_else(|_| "VA-API H.264 device".to_owned()); + drop(open_h264_decoder(Arc::clone(&display))?); + Ok(vendor) + } + + pub fn open(format: StreamFormat) -> Result { + format.validate()?; + let display = Display::open().ok_or_else(|| { + Error::unavailable( + Subsystem::VaApi, + "no DRM node could be initialized through VA-API", + ) + })?; + validate_h264_display(&display) + .map_err(|error| Error::unavailable(Subsystem::VaApi, error))?; + let decoder = open_h264_decoder(display) + .map_err(|error| Error::unavailable(Subsystem::VaApi, error))?; + let resolution = Resolution::from((format.width, format.height)); + Ok(Self { + decoder, + requested_format: format, + allocation_visible: resolution, + allocation_coded: resolution, + pending_format_change: None, + }) + } + + fn drain_events(&mut self) -> Result> { + let mut frames = Vec::new(); + while let Some(event) = self.decoder.next_event() { + match event { + DecoderEvent::FormatChanged => { + let info = self.decoder.stream_info().ok_or_else(|| { + Error::backend(Subsystem::VaApi, "format change had no stream info") + })?; + self.allocation_visible = info.display_resolution; + self.allocation_coded = info.coded_resolution; + self.requested_format.width = info.display_resolution.width; + self.requested_format.height = info.display_resolution.height; + self.requested_format.pixel_format = PixelFormat::Nv12; + self.pending_format_change = Some(self.requested_format); + } + DecoderEvent::FrameReady(handle) => { + handle + .sync() + .map_err(|error| Error::backend(Subsystem::VaApi, error.to_string()))?; + let timestamp_us = handle.timestamp(); + let visible = handle.display_resolution(); + let frame = handle.video_frame(); + let exported = frame + .exported() + .map_err(|error| Error::backend(Subsystem::VaApi, error))?; + let objects = exported + .objects + .iter() + .map(|object| DmaBufObject { + fd: object.fd.as_raw_fd(), + size: object.size as usize, + format_modifier: object.drm_format_modifier, + }) + .collect(); + let layers = exported + .layers + .iter() + .map(|layer| DmaBufLayer { + format: layer.drm_format, + planes: (0..layer.num_planes.min(4) as usize) + .map(|index| DmaBufPlane { + object_index: layer.object_index[index] as usize, + offset: layer.offset[index] as usize, + pitch: layer.pitch[index] as usize, + }) + .collect(), + }) + .collect(); + let dmabuf = DmaBufFrame::new(objects, layers, frame); + let decoded = DecodedVideoFrame { + format: StreamFormat { + width: visible.width, + height: visible.height, + pixel_format: PixelFormat::Nv12, + chroma_location: ChromaLocation::Left, + ..self.requested_format + }, + planes: Vec::new(), + dmabuf: Some(Arc::new(dmabuf)), + vulkan: None, + overlay: None, + timestamp_us, + }; + decoded.validate()?; + frames.push(decoded); + } + } + } + Ok(frames) + } +} + +type H264VaapiDecoder = StatelessDecoder>; + +fn open_h264_decoder(display: Arc) -> std::result::Result { + // cros-codecs creates a 16x16 context without render targets in its + // constructor. Some drivers advertise H.264 and allocate surfaces but + // reject that context shape (notably nvidia-vaapi-driver). Exercise the + // exact operation first so an incompatible driver becomes a normal + // capability failure instead of reaching the dependency's `expect`. + validate_initial_context(&display)?; + std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + H264VaapiDecoder::new_vaapi(display, cros_codecs::decoder::BlockingMode::NonBlocking) + })) + .map_err(|_| "VA-API decoder initialization panicked".to_owned())? + .map_err(|error| error.to_string()) +} + +fn validate_initial_context(display: &Arc) -> std::result::Result<(), String> { + let config = display + .create_config( + vec![libva::VAConfigAttrib { + type_: libva::VAConfigAttribType::VAConfigAttribRTFormat, + value: libva::VA_RT_FORMAT_YUV420, + }], + libva::VAProfile::VAProfileH264Main, + libva::VAEntrypoint::VAEntrypointVLD, + ) + .map_err(|error| format!("VA-API cannot create the H.264 decoder config: {error}"))?; + drop( + display + .create_context::<()>(&config, 16, 16, None, true) + .map_err(|error| { + format!("VA-API cannot create the initial H.264 decoder context: {error}") + })?, + ); + Ok(()) +} + +impl VideoDecoder for VaApiDecoder { + fn decode(&mut self, frame: &EncodedVideoFrame) -> Result> { + let mut offset = 0; + let mut output = Vec::new(); + let mut retries = 0; + while offset < frame.data.len() { + let visible = self.allocation_visible; + let coded = self.allocation_coded; + let mut allocate = || Some(VaFrame::new(visible, coded)); + match self + .decoder + .decode(frame.timestamp_us, &frame.data[offset..], &mut allocate) + { + Ok(consumed) if consumed > 0 => { + offset += consumed; + retries = 0; + output.extend(self.drain_events()?); + } + Ok(_) => { + return Err(Error::backend( + Subsystem::VaApi, + "decoder accepted zero bytes", + )); + } + Err(DecodeError::CheckEvents | DecodeError::NotEnoughOutputBuffers(_)) => { + output.extend(self.drain_events()?); + retries += 1; + if retries > MAX_DECODE_RETRIES { + return Err(Error::backend( + Subsystem::VaApi, + "decoder made no progress after handling pending events", + )); + } + } + Err(error) => { + return Err(Error::backend(Subsystem::VaApi, error.to_string())); + } + } + } + output.extend(self.drain_events()?); + Ok(output) + } + + fn flush(&mut self) -> Result> { + self.decoder + .flush() + .map_err(|error| Error::backend(Subsystem::VaApi, error.to_string()))?; + self.drain_events() + } + + fn take_format_change(&mut self) -> Option { + self.pending_format_change.take() + } +} + +const fn align(value: u32, alignment: u32) -> u32 { + value.div_ceil(alignment) * alignment +} + +fn validate_h264_display(display: &Display) -> std::result::Result<(), String> { + let profiles = display + .query_config_profiles() + .map_err(|error| error.to_string())?; + if !profiles.contains(&libva::VAProfile::VAProfileH264Main) { + return Err("VA-API device exposes no H.264 Main profile".to_owned()); + } + let entrypoints = display + .query_config_entrypoints(libva::VAProfile::VAProfileH264Main) + .map_err(|error| error.to_string())?; + if !entrypoints.contains(&libva::VAEntrypoint::VAEntrypointVLD) { + return Err("VA-API device exposes no H.264 VLD entrypoint".to_owned()); + } + Ok(()) +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-linux/tests/linux_api.rs b/native/opennow-streamer/crates/opennow-streamer-platform-linux/tests/linux_api.rs new file mode 100644 index 000000000..3e6e8669c --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-linux/tests/linux_api.rs @@ -0,0 +1,30 @@ +#![cfg(target_os = "linux")] + +use opennow_streamer_platform_linux::{ + AudioConfig, AudioPacket, EncodedVideoFrame, LinuxSession, SessionConfig, StreamFormat, +}; +use static_assertions::assert_impl_all; +#[cfg(feature = "vulkan")] +use static_assertions::assert_not_impl_any; +use std::sync::Arc; + +assert_impl_all!(LinuxSession: Send); +#[cfg(feature = "vulkan")] +assert_not_impl_any!(opennow_streamer_platform_linux::NativeSurface<'static>: Send, Sync); + +#[test] +fn public_media_inputs_are_typed_and_validated() { + let format = StreamFormat::h264_default(1920, 1080).unwrap(); + let config = SessionConfig::new(format); + assert_eq!(config.stream_format, format); + assert!(EncodedVideoFrame::new(Arc::<[u8]>::from([]), 0, true).is_err()); + assert!(AudioPacket::new(Arc::<[u8]>::from([]), 0).is_err()); + assert!(AudioConfig::default().validate().is_ok()); +} + +#[test] +fn linux_compile_target_is_supported() { + assert!(matches!(std::env::consts::ARCH, "x86_64" | "aarch64")); + let _: fn() -> opennow_streamer_platform_linux::CapabilityReport = + opennow_streamer_platform_linux::probe_capabilities; +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/Cargo.toml b/native/opennow-streamer/crates/opennow-streamer-platform-macos/Cargo.toml new file mode 100644 index 000000000..332211c53 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "opennow-streamer-platform-macos" +version.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +description = "Native VideoToolbox, Metal, and CoreAudio backend for OpenNOW" +[dependencies] +thiserror.workspace = true + +[target.'cfg(target_os = "macos")'.dependencies] +libc = "0.2" +objc2 = "0.6.3" +objc2-app-kit = { version = "0.3.2", features = ["NSEvent"] } +objc2-audio-toolbox = "0.3.2" +objc2-core-audio-types = "0.3.2" +objc2-core-foundation = "0.3.2" +objc2-core-media = "0.3.2" +objc2-core-video = "0.3.2" +objc2-foundation = "0.3.2" +objc2-metal = "0.3.2" +objc2-quartz-core = "0.3.2" +objc2-video-toolbox = "0.3.2" +opus = "0.3.1" diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/README.md b/native/opennow-streamer/crates/opennow-streamer-platform-macos/README.md new file mode 100644 index 000000000..e252f646c --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/README.md @@ -0,0 +1,138 @@ +# OpenNOW native macOS platform backend + +This isolated crate implements the macOS media path without GStreamer or FFmpeg: + +- H.264 Annex B or four-byte AVCC access units are copied into CoreMedia sample buffers and + decoded asynchronously by VideoToolbox. +- VideoToolbox is asked for Metal-compatible, IOSurface-backed NV12 (`420v`) pixel buffers. A + `CVMetalTextureCache` maps both planes into Metal without a CPU pixel copy, and a + `CAMetalLayer` presents them through a small BT.601/BT.709 conversion shader. +- Opus packets are decoded to interleaved `f32` PCM by the reference libopus decoder. The + dependency builds libopus statically on macOS, so it adds no runtime media-framework + dependency. A default-output Audio Unit pulls PCM from a fixed-size SPSC ring in its real-time + callback. + +The crate is a member of the native-streamer workspace and is linked only on macOS. + +## Integration API + +Create `H264ParameterSets` from the current SPS and PPS, provide absolute Electron screen bounds, +and start the process-owned passive overlay on AppKit's main thread: + +```rust,no_run +use opennow_streamer_platform_macos::{ + AudioFormat, BackendConfig, H264Format, H264ParameterSets, MacOsBackend, + OwnedOverlayConfig, QueueLimits, ScreenRect, SurfaceTarget, VideoColorSpace, +}; + +let parameter_sets = H264ParameterSets::new(sps, pps)?; +let mut backend = MacOsBackend::start(BackendConfig { + surface: SurfaceTarget::OwnedOverlay(OwnedOverlayConfig::new( + ScreenRect::new(120.0, 80.0, 1280.0, 720.0), + true, + )), + video: H264Format::new(parameter_sets, VideoColorSpace::Bt709), + audio: AudioFormat::OPUS_STEREO_48KHZ, + queues: QueueLimits::default(), +})?; + +let sink = backend.sink(); +// Move `sink` to the transport thread and call submit_h264/submit_opus there. +// Keep `backend` on the AppKit main thread. + +backend.stop(); +# Ok::<(), Box>(()) +``` + +The native streamer never passes Electron's `NSView` or `NSWindow` address to this Rust child. +Live layout and visibility updates use only the absolute `screenRect` contract: + +```rust,no_run +use opennow_streamer_platform_macos::ScreenRect; + +backend.update_owned_overlay(ScreenRect::new(120.0, 80.0, 960.0, 540.0), true)?; +backend.update_owned_overlay(ScreenRect::new(120.0, 80.0, 960.0, 540.0), false)?; +# Ok::<(), Box>(()) +``` + +Screen rectangles use Electron's top-left device-independent coordinates. The backend converts +them to AppKit's bottom-left coordinate space. Its `NSPanel` is borderless and non-activating, +ignores mouse events, rejects key/main-window status, and orders without stealing focus. The +native streamer also compares the frontmost application with its Electron parent process on every +main-thread pump, ordering the panel out while another application is active. The separately owned +SDL window used by the software fallback applies the same parent/frontmost gate. + +`StreamSink` is `Send + Sync`; `MacOsBackend` is intentionally neither. Video and audio can be +reconfigured through `StreamSink` while running. Video reconfiguration constructs a new +VideoToolbox session before replacing the old one. Audio reconfiguration stops the old Audio Unit +and decoder worker before constructing the new format, so a failed audio reconfiguration leaves +audio stopped rather than running under an ambiguous format. + +Only H.264 is implemented. The workspace advertises this backend only when +`VTIsHardwareDecodeSupported` succeeds and Metal can create a device and command queue. This crate +makes no H.265, AV1, software-decoder, or non-macOS capability claim. + +The workspace performs full backend construction after the first SPS/PPS arrive. If VideoToolbox, +Metal, CoreAudio, or overlay construction fails at that point, the main-thread host destroys the +partial macOS output, initializes the existing SDL output, and hands the pending keyframe plus the +same bounded H.264/Opus queues to the OpenH264/software workers. Hardware selection is disabled for +later sessions in that process and later capability replies report VideoToolbox unavailable. + +## Queue and lifecycle behavior + +All buffering is explicitly bounded: + +- VideoToolbox admission returns `SubmitOutcome::Backpressured` when the in-flight decode limit is + reached; accepted decoder work is never silently invalidated. +- The decoded-frame queue drops its oldest frame when rendering falls behind, keeping latency + bounded. +- While a supplied-window child is hidden, decoded frames are discarded before requesting a + `CAMetalDrawable`; showing it resumes from the newest frame without accumulating hidden work. +- The Opus packet queue drops its oldest packet and reports `SubmitOutcome::ReplacedOldest`. +- The PCM ring never allocates or locks in the CoreAudio callback. If decoding outruns playback, + new samples are dropped and counted. If playback underruns, the callback emits silence and + counts the missing frames. + +`stop` is idempotent. It first rejects new submissions, waits for VideoToolbox's outstanding +callbacks, stops CoreAudio, discards queued work, joins both workers, and waits for submitted Metal +command buffers. A supplied view's previous backing layer is then restored; an owned window is +closed. A supplied window's passive child view is removed without modifying the BrowserWindow +content view or renderer layer. + +## Safety invariants + +`BorrowedNsView::from_raw` and `BorrowedNsWindow::from_raw` are the only public unsafe entry +points. Their pointers must be live objects of exactly the documented AppKit class and must be +created and consumed on AppKit's main thread. The backend retains the object for its lifetime. A +supplied view is treated as a dedicated presentation surface because its backing layer is replaced +until shutdown. A supplied window instead receives an owned child surface; geometry/visibility +updates, child insertion, and child removal all require AppKit's main thread. + +The `NativeSurfaceHandle` pointers borrow the running backend. For a supplied window, `ns_view` +identifies the owned passive child rather than the BrowserWindow content view. The pointers are +valid only until `stop` or `Drop`, may be used only on AppKit's main thread, and must never be +released by the caller. + +VideoToolbox and CoreAudio callback contexts are heap allocated at stable addresses and outlive +their registered sessions. The VideoToolbox session is accessed behind a mutex; decoded +`CVPixelBuffer`s are immutable after the callback and retained across the queue. The Metal worker +retains each `CVMetalTexture` until its command buffer completes. The CoreAudio callback has one +consumer and the Opus worker has one producer for the PCM ring. + +## Checks + +On macOS, run: + +```sh +cargo test +cargo clippy --all-targets -- -D warnings +``` + +Both Apple architectures can be type-checked from a non-macOS host when Rust's targets are +installed. A real build still requires the Apple SDK and a matching C compiler because vendored +libopus is compiled for the target: + +```sh +cargo check --target aarch64-apple-darwin +cargo check --target x86_64-apple-darwin +``` diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/failure.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/failure.rs new file mode 100644 index 000000000..4c0457852 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/failure.rs @@ -0,0 +1,219 @@ +use std::collections::VecDeque; +use std::sync::Mutex; +use std::sync::atomic::{AtomicUsize, Ordering}; + +const DECODE_LOSS_CAPACITY: usize = 4; +const REPEATED_FAILURE_THRESHOLD: usize = 3; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum BackendSubsystem { + VideoToolbox, + Metal, + AudioWorker, +} + +impl BackendSubsystem { + pub const fn name(self) -> &'static str { + match self { + Self::VideoToolbox => "VideoToolbox", + Self::Metal => "Metal", + Self::AudioWorker => "audio worker", + } + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct BackendFailure { + pub subsystem: BackendSubsystem, + pub message: String, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct VideoDecodeLoss { + pub status: Option, +} + +#[derive(Default)] +struct FailureState { + decode_losses: VecDeque, + fatal: Option, +} + +#[derive(Default)] +pub(crate) struct FailureReporter { + state: Mutex, + video_decode_streak: AtomicUsize, + metal_streak: AtomicUsize, + audio_streak: AtomicUsize, +} + +impl FailureReporter { + pub(crate) fn video_decode_succeeded(&self) { + self.video_decode_streak.store(0, Ordering::Release); + } + + pub(crate) fn video_decode_failed(&self, status: Option) { + { + let mut state = self + .state + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()); + if state.decode_losses.len() == DECODE_LOSS_CAPACITY { + state.decode_losses.pop_front(); + } + state.decode_losses.push_back(VideoDecodeLoss { status }); + } + if increment_streak(&self.video_decode_streak) >= REPEATED_FAILURE_THRESHOLD { + let detail = status.map_or_else( + || "without an output pixel buffer".to_owned(), + |status| format!("with OSStatus {status}"), + ); + self.report_fatal( + BackendSubsystem::VideoToolbox, + format!( + "VideoToolbox failed to decode {REPEATED_FAILURE_THRESHOLD} consecutive frames; last failure was {detail}" + ), + ); + } + } + + pub(crate) fn metal_succeeded(&self) { + self.metal_streak.store(0, Ordering::Release); + } + + pub(crate) fn metal_failed(&self, message: String) -> bool { + if increment_streak(&self.metal_streak) < REPEATED_FAILURE_THRESHOLD { + return false; + } + self.report_fatal( + BackendSubsystem::Metal, + format!( + "Metal presentation failed {REPEATED_FAILURE_THRESHOLD} consecutive times: {message}" + ), + ); + true + } + + pub(crate) fn audio_succeeded(&self) { + self.audio_streak.store(0, Ordering::Release); + } + + pub(crate) fn audio_failed(&self, message: String) -> bool { + if increment_streak(&self.audio_streak) < REPEATED_FAILURE_THRESHOLD { + return false; + } + self.report_fatal( + BackendSubsystem::AudioWorker, + format!( + "the audio worker failed {REPEATED_FAILURE_THRESHOLD} consecutive times: {message}" + ), + ); + true + } + + pub(crate) fn report_fatal(&self, subsystem: BackendSubsystem, message: String) { + let mut state = self + .state + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()); + if state.fatal.is_none() { + state.fatal = Some(BackendFailure { subsystem, message }); + } + } + + pub(crate) fn pop_video_decode_loss(&self) -> Option { + self.state + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()) + .decode_losses + .pop_front() + } + + pub(crate) fn fatal_failure(&self) -> Option { + self.state + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()) + .fatal + .clone() + } +} + +fn increment_streak(streak: &AtomicUsize) -> usize { + streak + .fetch_update(Ordering::AcqRel, Ordering::Acquire, |value| { + Some(value.saturating_add(1)) + }) + .unwrap_or(usize::MAX) + .saturating_add(1) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn decode_loss_queue_keeps_only_the_bounded_tail() { + let reporter = FailureReporter::default(); + for status in 1..=6 { + reporter.video_decode_failed(Some(status)); + } + let statuses: Vec<_> = std::iter::from_fn(|| reporter.pop_video_decode_loss()) + .map(|loss| loss.status.unwrap()) + .collect(); + assert_eq!(statuses, vec![3, 4, 5, 6]); + } + + #[test] + fn successful_work_resets_the_repeated_failure_streak() { + let reporter = FailureReporter::default(); + reporter.video_decode_failed(Some(-1)); + reporter.video_decode_failed(Some(-1)); + reporter.video_decode_succeeded(); + reporter.video_decode_failed(Some(-1)); + reporter.video_decode_failed(Some(-1)); + assert_eq!(reporter.fatal_failure(), None); + + reporter.video_decode_failed(Some(-2)); + assert_eq!( + reporter.fatal_failure().unwrap().subsystem, + BackendSubsystem::VideoToolbox + ); + } + + #[test] + fn repeated_metal_and_audio_failures_cross_the_same_bound() { + let metal = FailureReporter::default(); + assert!(!metal.metal_failed("drawable unavailable".to_owned())); + assert!(!metal.metal_failed("drawable unavailable".to_owned())); + assert!(metal.metal_failed("command buffer failed".to_owned())); + assert_eq!( + metal.fatal_failure().unwrap().subsystem, + BackendSubsystem::Metal + ); + + let audio = FailureReporter::default(); + assert!(!audio.audio_failed("invalid packet".to_owned())); + audio.audio_succeeded(); + assert!(!audio.audio_failed("invalid packet".to_owned())); + assert!(!audio.audio_failed("invalid packet".to_owned())); + assert!(audio.audio_failed("decoder stopped".to_owned())); + assert_eq!( + audio.fatal_failure().unwrap().subsystem, + BackendSubsystem::AudioWorker + ); + } + + #[test] + fn only_the_first_fatal_failure_is_published() { + let reporter = FailureReporter::default(); + reporter.report_fatal(BackendSubsystem::Metal, "device removed".to_owned()); + reporter.report_fatal(BackendSubsystem::AudioWorker, "worker stopped".to_owned()); + assert_eq!( + reporter.fatal_failure(), + Some(BackendFailure { + subsystem: BackendSubsystem::Metal, + message: "device removed".to_owned(), + }) + ); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/format.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/format.rs new file mode 100644 index 000000000..2a7b3bbbb --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/format.rs @@ -0,0 +1,608 @@ +use std::ffi::c_void; +use std::ptr::NonNull; + +use thiserror::Error; + +const MAX_PARAMETER_SET_BYTES: usize = 64 * 1024; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum H264Framing { + AnnexB, + Avcc, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum VideoColorSpace { + Bt601, + Bt709, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct FrameTiming { + pub presentation_value: i64, + pub duration_value: i64, + pub timescale: i32, +} + +impl FrameTiming { + pub const fn new(presentation_value: i64, duration_value: i64, timescale: i32) -> Self { + Self { + presentation_value, + duration_value, + timescale, + } + } + + pub const fn from_90khz(presentation_value: i64, duration_value: i64) -> Self { + Self::new(presentation_value, duration_value, 90_000) + } + + pub(crate) fn validate(self) -> Result<(), FormatError> { + if self.timescale <= 0 { + return Err(FormatError::InvalidTimescale); + } + if self.duration_value < 0 { + return Err(FormatError::InvalidDuration); + } + Ok(()) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct H264ParameterSets { + sequence: Vec, + picture: Vec, +} + +impl H264ParameterSets { + pub fn new(sequence: impl AsRef<[u8]>, picture: impl AsRef<[u8]>) -> Result { + let sequence = normalize_parameter_set(sequence.as_ref(), 7)?; + let picture = normalize_parameter_set(picture.as_ref(), 8)?; + Ok(Self { sequence, picture }) + } + + pub fn sequence(&self) -> &[u8] { + &self.sequence + } + + pub fn picture(&self) -> &[u8] { + &self.picture + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct H264Format { + pub parameter_sets: H264ParameterSets, + pub color_space: VideoColorSpace, +} + +impl H264Format { + pub const fn new(parameter_sets: H264ParameterSets, color_space: VideoColorSpace) -> Self { + Self { + parameter_sets, + color_space, + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct AudioFormat { + pub sample_rate: u32, + pub channels: u8, +} + +impl AudioFormat { + pub const OPUS_STEREO_48KHZ: Self = Self { + sample_rate: 48_000, + channels: 2, + }; + + pub const fn new(sample_rate: u32, channels: u8) -> Self { + Self { + sample_rate, + channels, + } + } + + pub(crate) fn validate(self) -> Result<(), FormatError> { + if !matches!(self.sample_rate, 8_000 | 12_000 | 16_000 | 24_000 | 48_000) { + return Err(FormatError::UnsupportedOpusSampleRate(self.sample_rate)); + } + if !matches!(self.channels, 1 | 2) { + return Err(FormatError::UnsupportedChannelCount(self.channels)); + } + Ok(()) + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct QueueLimits { + pub video_frames_in_flight: usize, + pub decoded_video_frames: usize, + pub opus_packets: usize, + pub pcm_milliseconds: u32, + pub max_video_access_unit_bytes: usize, +} + +impl Default for QueueLimits { + fn default() -> Self { + Self { + video_frames_in_flight: 8, + decoded_video_frames: 3, + opus_packets: 12, + pcm_milliseconds: 120, + max_video_access_unit_bytes: 8 * 1024 * 1024, + } + } +} + +impl QueueLimits { + pub(crate) fn validate(self) -> Result<(), FormatError> { + if self.video_frames_in_flight == 0 + || self.decoded_video_frames == 0 + || self.opus_packets == 0 + || self.pcm_milliseconds == 0 + || self.max_video_access_unit_bytes == 0 + { + return Err(FormatError::ZeroQueueLimit); + } + let pcm_ms = + usize::try_from(self.pcm_milliseconds).map_err(|_| FormatError::QueueTooLarge)?; + if pcm_ms > 5_000 { + return Err(FormatError::QueueTooLarge); + } + Ok(()) + } +} + +/// Absolute screen bounds in Electron's top-left, device-independent coordinate space. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct ScreenRect { + pub x: f64, + pub y: f64, + pub width: f64, + pub height: f64, +} + +impl ScreenRect { + pub const fn new(x: f64, y: f64, width: f64, height: f64) -> Self { + Self { + x, + y, + width, + height, + } + } + + pub(crate) fn validate(self) -> Result<(), FormatError> { + if !self.x.is_finite() + || !self.y.is_finite() + || !self.width.is_finite() + || !self.height.is_finite() + || self.width <= 0.0 + || self.height <= 0.0 + { + return Err(FormatError::InvalidScreenRect); + } + Ok(()) + } +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct OwnedOverlayConfig { + pub screen_rect: ScreenRect, + pub visible: bool, +} + +impl OwnedOverlayConfig { + pub const fn new(screen_rect: ScreenRect, visible: bool) -> Self { + Self { + screen_rect, + visible, + } + } + + pub(crate) fn validate(self) -> Result<(), FormatError> { + self.screen_rect.validate() + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct BorrowedNsView(NonNull); + +impl BorrowedNsView { + /// Creates a borrowed AppKit view handle. + /// + /// # Safety + /// + /// `view` must point to a live, dedicated `NSView` whose backing layer may be replaced for the + /// backend's lifetime. The object must belong to the current process, and creating the handle + /// and passing it to `MacOsBackend::start` must occur on AppKit's main thread. The backend + /// retains the view before this call's borrowed lifetime can end. + pub const unsafe fn from_raw(view: NonNull) -> Self { + Self(view) + } + + pub const fn as_ptr(self) -> NonNull { + self.0 + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct BorrowedNsWindow(NonNull); + +impl BorrowedNsWindow { + /// Creates a borrowed AppKit window handle. + /// + /// # Safety + /// + /// `window` must point to a live `NSWindow`. Construction and backend startup must occur on + /// AppKit's main thread. The backend does not replace the window content view or its layer; it + /// inserts a passive child view for stream presentation. + pub const unsafe fn from_raw(window: NonNull) -> Self { + Self(window) + } + + pub const fn as_ptr(self) -> NonNull { + self.0 + } +} + +/// A rectangle in renderer-relative, top-left AppKit points. +/// +/// Points match Electron's device-independent coordinates. Negative origins are allowed for +/// clipping, while width and height must be finite and non-negative. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct RendererRect { + pub x: f64, + pub y: f64, + pub width: f64, + pub height: f64, +} + +impl RendererRect { + pub const fn new(x: f64, y: f64, width: f64, height: f64) -> Self { + Self { + x, + y, + width, + height, + } + } + + pub(crate) fn validate(self) -> Result<(), FormatError> { + if !self.x.is_finite() + || !self.y.is_finite() + || !self.width.is_finite() + || !self.height.is_finite() + || self.width < 0.0 + || self.height < 0.0 + { + return Err(FormatError::InvalidRendererRect); + } + Ok(()) + } + + pub(crate) fn to_parent_coordinates( + self, + parent: RendererRect, + parent_is_flipped: bool, + ) -> Self { + let y = if parent_is_flipped { + parent.y + self.y + } else { + parent.y + parent.height - self.y - self.height + }; + Self::new(parent.x + self.x, y, self.width, self.height) + } +} + +/// Initial layout for a passive video child inside a supplied `NSWindow` content view. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct WindowSurfaceConfig { + pub window: BorrowedNsWindow, + pub bounds: RendererRect, + pub visible: bool, +} + +impl WindowSurfaceConfig { + pub const fn new(window: BorrowedNsWindow, bounds: RendererRect) -> Self { + Self { + window, + bounds, + visible: true, + } + } + + pub(crate) fn validate(self) -> Result<(), FormatError> { + self.bounds.validate() + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum SurfaceTarget { + /// Creates a borderless, non-activating, mouse-ignoring overlay owned by this process. + OwnedOverlay(OwnedOverlayConfig), + /// Uses a caller-owned view that is explicitly dedicated to video presentation. Its backing + /// layer is replaced until backend shutdown and restored afterwards. + NsView(BorrowedNsView), + /// Adds an owned, passive child view to the supplied window's content view. The existing + /// content view and its backing layer are never replaced. + NsWindow(WindowSurfaceConfig), +} + +#[derive(Clone, Debug, PartialEq)] +pub struct BackendConfig { + pub surface: SurfaceTarget, + pub video: H264Format, + pub audio: AudioFormat, + pub queues: QueueLimits, +} + +impl BackendConfig { + pub(crate) fn validate(&self) -> Result<(), FormatError> { + self.audio.validate()?; + self.queues.validate()?; + if let SurfaceTarget::OwnedOverlay(overlay) = self.surface { + overlay.validate()?; + } + if let SurfaceTarget::NsWindow(window) = &self.surface { + window.validate()?; + } + Ok(()) + } +} + +#[derive(Debug, Error, Eq, PartialEq)] +pub enum FormatError { + #[error("H.264 parameter set is empty")] + EmptyParameterSet, + #[error("H.264 parameter set exceeds the supported size")] + ParameterSetTooLarge, + #[error("expected H.264 NAL type {expected}, got {actual}")] + UnexpectedNalType { expected: u8, actual: u8 }, + #[error("multiple NAL units were supplied where one parameter set was expected")] + MultipleParameterSets, + #[error("H.264 access unit has no NAL units")] + EmptyAccessUnit, + #[error("H.264 access unit contains an empty NAL unit")] + EmptyNalUnit, + #[error("H.264 access unit has invalid AVCC framing")] + InvalidAvcc, + #[error("H.264 NAL unit is too large for AVCC framing")] + NalUnitTooLarge, + #[error("frame timescale must be positive")] + InvalidTimescale, + #[error("frame duration must not be negative")] + InvalidDuration, + #[error("unsupported Opus sample rate {0}")] + UnsupportedOpusSampleRate(u32), + #[error("unsupported Opus channel count {0}")] + UnsupportedChannelCount(u8), + #[error("queue limits must be non-zero")] + ZeroQueueLimit, + #[error("queue configuration is too large")] + QueueTooLarge, + #[error("absolute screen bounds must be finite with positive dimensions")] + InvalidScreenRect, + #[error("renderer-relative surface bounds must be finite with non-negative dimensions")] + InvalidRendererRect, +} + +pub(crate) fn access_unit_to_avcc( + bytes: &[u8], + framing: H264Framing, +) -> Result, FormatError> { + match framing { + H264Framing::AnnexB => annex_b_to_avcc(bytes), + H264Framing::Avcc => { + validate_avcc(bytes)?; + Ok(bytes.to_vec()) + } + } +} + +fn normalize_parameter_set(bytes: &[u8], expected_type: u8) -> Result, FormatError> { + let bytes = strip_start_code(bytes); + if bytes.is_empty() { + return Err(FormatError::EmptyParameterSet); + } + if bytes.len() > MAX_PARAMETER_SET_BYTES { + return Err(FormatError::ParameterSetTooLarge); + } + if find_start_code(bytes, 1).is_some() { + return Err(FormatError::MultipleParameterSets); + } + let actual = bytes[0] & 0x1f; + if actual != expected_type { + return Err(FormatError::UnexpectedNalType { + expected: expected_type, + actual, + }); + } + Ok(bytes.to_vec()) +} + +fn strip_start_code(bytes: &[u8]) -> &[u8] { + if bytes.starts_with(&[0, 0, 0, 1]) { + &bytes[4..] + } else if bytes.starts_with(&[0, 0, 1]) { + &bytes[3..] + } else { + bytes + } +} + +fn annex_b_to_avcc(bytes: &[u8]) -> Result, FormatError> { + let Some((mut start, prefix_len)) = find_start_code(bytes, 0) else { + return Err(FormatError::EmptyAccessUnit); + }; + if bytes[..start].iter().any(|byte| *byte != 0) { + return Err(FormatError::EmptyAccessUnit); + } + start += prefix_len; + let mut output = Vec::with_capacity(bytes.len()); + loop { + let next = find_start_code(bytes, start); + let end = next.map_or(bytes.len(), |(offset, _)| offset); + if end == start { + return Err(FormatError::EmptyNalUnit); + } + write_avcc_nal(&mut output, &bytes[start..end])?; + let Some((next_start, next_prefix)) = next else { + break; + }; + start = next_start + next_prefix; + } + if output.is_empty() { + return Err(FormatError::EmptyAccessUnit); + } + Ok(output) +} + +fn find_start_code(bytes: &[u8], from: usize) -> Option<(usize, usize)> { + let mut index = from; + while index + 3 <= bytes.len() { + if bytes[index..].starts_with(&[0, 0, 1]) { + return Some((index, 3)); + } + if bytes[index..].starts_with(&[0, 0, 0, 1]) { + return Some((index, 4)); + } + index += 1; + } + None +} + +fn write_avcc_nal(output: &mut Vec, nal: &[u8]) -> Result<(), FormatError> { + if nal.is_empty() { + return Err(FormatError::EmptyNalUnit); + } + let len = u32::try_from(nal.len()).map_err(|_| FormatError::NalUnitTooLarge)?; + output.extend_from_slice(&len.to_be_bytes()); + output.extend_from_slice(nal); + Ok(()) +} + +fn validate_avcc(bytes: &[u8]) -> Result<(), FormatError> { + if bytes.is_empty() { + return Err(FormatError::EmptyAccessUnit); + } + let mut offset = 0usize; + while offset < bytes.len() { + let header = bytes + .get(offset..offset + 4) + .ok_or(FormatError::InvalidAvcc)?; + let len = u32::from_be_bytes(header.try_into().expect("four-byte AVCC length")) as usize; + if len == 0 { + return Err(FormatError::EmptyNalUnit); + } + offset = offset.checked_add(4).ok_or(FormatError::InvalidAvcc)?; + offset = offset.checked_add(len).ok_or(FormatError::InvalidAvcc)?; + if offset > bytes.len() { + return Err(FormatError::InvalidAvcc); + } + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn converts_mixed_annex_b_start_codes_to_avcc() { + let annex_b = [0, 0, 0, 1, 0x65, 0xaa, 0xbb, 0, 0, 1, 0x41, 0xcc]; + assert_eq!( + annex_b_to_avcc(&annex_b).unwrap(), + [0, 0, 0, 3, 0x65, 0xaa, 0xbb, 0, 0, 0, 2, 0x41, 0xcc] + ); + } + + #[test] + fn rejects_truncated_avcc_access_unit() { + assert_eq!( + access_unit_to_avcc(&[0, 0, 0, 3, 0x65], H264Framing::Avcc), + Err(FormatError::InvalidAvcc) + ); + } + + #[test] + fn normalizes_parameter_set_start_codes() { + let sets = H264ParameterSets::new( + [0, 0, 0, 1, 0x67, 0x64, 0x00, 0x29], + [0, 0, 1, 0x68, 0xee, 0x3c, 0x80], + ) + .unwrap(); + assert_eq!(sets.sequence(), &[0x67, 0x64, 0x00, 0x29]); + assert_eq!(sets.picture(), &[0x68, 0xee, 0x3c, 0x80]); + } + + #[test] + fn rejects_wrong_parameter_set_type() { + assert_eq!( + H264ParameterSets::new([0x68, 1], [0x68, 2]), + Err(FormatError::UnexpectedNalType { + expected: 7, + actual: 8 + }) + ); + } + + #[test] + fn validates_audio_and_queue_formats() { + assert!(AudioFormat::OPUS_STEREO_48KHZ.validate().is_ok()); + assert_eq!( + AudioFormat::new(44_100, 2).validate(), + Err(FormatError::UnsupportedOpusSampleRate(44_100)) + ); + let limits = QueueLimits { + opus_packets: 0, + ..QueueLimits::default() + }; + assert_eq!(limits.validate(), Err(FormatError::ZeroQueueLimit)); + } + + #[test] + fn converts_renderer_top_left_bounds_for_unflipped_appkit_parent() { + let parent = RendererRect::new(0.0, 0.0, 1280.0, 720.0); + let renderer = RendererRect::new(20.0, 30.0, 640.0, 360.0); + assert_eq!( + renderer.to_parent_coordinates(parent, false), + RendererRect::new(20.0, 330.0, 640.0, 360.0) + ); + } + + #[test] + fn preserves_renderer_y_for_flipped_parent_and_accounts_for_bounds_origin() { + let parent = RendererRect::new(5.0, 10.0, 1280.0, 720.0); + let renderer = RendererRect::new(20.0, 30.0, 640.0, 360.0); + assert_eq!( + renderer.to_parent_coordinates(parent, true), + RendererRect::new(25.0, 40.0, 640.0, 360.0) + ); + } + + #[test] + fn rejects_invalid_renderer_geometry() { + assert_eq!( + RendererRect::new(0.0, 0.0, -1.0, 10.0).validate(), + Err(FormatError::InvalidRendererRect) + ); + assert_eq!( + RendererRect::new(f64::NAN, 0.0, 10.0, 10.0).validate(), + Err(FormatError::InvalidRendererRect) + ); + } + + #[test] + fn recomputes_unflipped_child_position_after_parent_resize() { + let renderer = RendererRect::new(20.0, 30.0, 640.0, 360.0); + let initial = + renderer.to_parent_coordinates(RendererRect::new(0.0, 0.0, 1280.0, 720.0), false); + let resized = + renderer.to_parent_coordinates(RendererRect::new(0.0, 0.0, 1280.0, 920.0), false); + assert_eq!(initial.y, 330.0); + assert_eq!(resized.y, 530.0); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/lib.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/lib.rs new file mode 100644 index 000000000..ddec4c0ee --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/lib.rs @@ -0,0 +1,73 @@ +//! Native macOS media backend for OpenNOW. +//! +//! `opennow-streamer-platform` conditionally uses this crate on macOS and passes encoded media +//! through [`StreamSink`]. Video is decoded by VideoToolbox into IOSurface +//! backed NV12 pixel buffers and sampled directly by Metal. Opus is decoded by the statically +//! built reference libopus implementation and written to a CoreAudio output unit as interleaved +//! `f32` PCM. +//! +//! # Threading and safety invariants +//! +//! - [`MacOsBackend::start`] must run on the AppKit main thread. `MacOsBackend` is deliberately +//! `!Send` and owns all AppKit objects, so its `stop` and `Drop` paths also run on that thread. +//! - The native streamer integration uses only the process-owned overlay target and never +//! dereferences an Electron AppKit pointer. A supplied [`BorrowedNsView`] must be dedicated to +//! video because its layer is temporarily +//! replaced. A supplied [`BorrowedNsWindow`] keeps its existing content view and renderer layer; +//! the backend inserts a passive, non-focusable child view and removes it on shutdown. +//! - Supplied-window geometry and visibility changes go through +//! [`MacOsBackend::update_window_surface`] and are applied only on the AppKit main thread. +//! - [`StreamSink`] is `Send + Sync`. VideoToolbox, CoreAudio, and Metal callbacks never borrow +//! caller memory. Encoded access units and packets are copied before a submit call returns. +//! - Every media queue is bounded. Video admission rejects new work at the configured in-flight +//! limit, decoded video and Opus queues drop their oldest item, and the PCM ring drops new +//! samples rather than blocking CoreAudio's real-time callback. +//! - VideoToolbox callbacks retain immutable `CVPixelBuffer`s before enqueueing them. The Metal +//! presenter retains `CVMetalTexture`s until their command buffer has completed. Shutdown waits +//! for VideoToolbox callbacks and GPU work before releasing either callback context. + +#![deny(unsafe_op_in_unsafe_fn)] +#![cfg_attr(not(target_os = "macos"), allow(dead_code))] + +mod failure; +mod format; +mod lifecycle; +mod queue; +mod ring; + +#[cfg(target_os = "macos")] +mod macos; + +pub use failure::{BackendFailure, BackendSubsystem, VideoDecodeLoss}; +pub use format::{ + AudioFormat, BackendConfig, BorrowedNsView, BorrowedNsWindow, FrameTiming, H264Format, + H264Framing, H264ParameterSets, OwnedOverlayConfig, QueueLimits, RendererRect, ScreenRect, + SurfaceTarget, VideoColorSpace, WindowSurfaceConfig, +}; +pub use lifecycle::BackendState; + +pub(crate) const fn overlay_should_be_ordered( + requested_visible: bool, + parent_frontmost: bool, +) -> bool { + requested_visible && parent_frontmost +} + +#[cfg(target_os = "macos")] +pub use macos::{ + BackendError, BackendStats, MacOsBackend, NativeSurfaceHandle, StreamSink, SubmitOutcome, + debug_show_overlay_window, probe_h264_hardware, pump_app_events, +}; + +#[cfg(test)] +mod tests { + use super::overlay_should_be_ordered; + + #[test] + fn overlay_requires_requested_visibility_and_frontmost_parent() { + assert!(!overlay_should_be_ordered(false, false)); + assert!(!overlay_should_be_ordered(false, true)); + assert!(!overlay_should_be_ordered(true, false)); + assert!(overlay_should_be_ordered(true, true)); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/lifecycle.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/lifecycle.rs new file mode 100644 index 000000000..4603ddac5 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/lifecycle.rs @@ -0,0 +1,78 @@ +use std::sync::atomic::{AtomicU8, Ordering}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u8)] +pub enum BackendState { + Running = 1, + Stopping = 2, + Stopped = 3, +} + +pub(crate) struct Lifecycle(AtomicU8); + +pub(crate) struct AttachmentLifecycle { + attached: bool, +} + +impl AttachmentLifecycle { + pub(crate) const fn attached() -> Self { + Self { attached: true } + } + + pub(crate) fn begin_detach(&mut self) -> bool { + std::mem::replace(&mut self.attached, false) + } +} + +impl Lifecycle { + pub(crate) const fn running() -> Self { + Self(AtomicU8::new(BackendState::Running as u8)) + } + + pub(crate) fn state(&self) -> BackendState { + match self.0.load(Ordering::Acquire) { + 1 => BackendState::Running, + 2 => BackendState::Stopping, + _ => BackendState::Stopped, + } + } + + pub(crate) fn begin_stop(&self) -> bool { + self.0 + .compare_exchange( + BackendState::Running as u8, + BackendState::Stopping as u8, + Ordering::AcqRel, + Ordering::Acquire, + ) + .is_ok() + } + + pub(crate) fn finish_stop(&self) { + self.0.store(BackendState::Stopped as u8, Ordering::Release); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn stop_transition_is_idempotent() { + let lifecycle = Lifecycle::running(); + assert_eq!(lifecycle.state(), BackendState::Running); + assert!(lifecycle.begin_stop()); + assert!(!lifecycle.begin_stop()); + assert_eq!(lifecycle.state(), BackendState::Stopping); + lifecycle.finish_stop(); + assert_eq!(lifecycle.state(), BackendState::Stopped); + assert!(!lifecycle.begin_stop()); + } + + #[test] + fn surface_attachment_detaches_exactly_once() { + let mut lifecycle = AttachmentLifecycle::attached(); + assert!(lifecycle.begin_detach()); + assert!(!lifecycle.begin_detach()); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/audio.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/audio.rs new file mode 100644 index 000000000..9037f3407 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/audio.rs @@ -0,0 +1,348 @@ +use std::ffi::c_void; +use std::mem; +use std::ptr::{self, NonNull}; +use std::sync::Arc; +use std::sync::atomic::Ordering; +use std::thread::{self, JoinHandle}; + +use objc2_audio_toolbox::{ + AURenderCallbackStruct, AudioComponentDescription, AudioComponentFindNext, + AudioComponentInstanceDispose, AudioComponentInstanceNew, AudioOutputUnitStart, + AudioOutputUnitStop, AudioUnit, AudioUnitInitialize, AudioUnitRenderActionFlags, + AudioUnitSetProperty, AudioUnitUninitialize, kAudioUnitManufacturer_Apple, + kAudioUnitProperty_SetRenderCallback, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, + kAudioUnitSubType_DefaultOutput, kAudioUnitType_Output, +}; +use objc2_core_audio_types::{ + AudioBufferList, AudioStreamBasicDescription, AudioTimeStamp, kAudioFormatFlagIsFloat, + kAudioFormatFlagIsPacked, kAudioFormatLinearPCM, +}; +use opus::{Channels, Decoder}; + +use crate::failure::{BackendSubsystem, FailureReporter}; +use crate::format::AudioFormat; +use crate::queue::{BoundedQueue, PushResult}; +use crate::ring::PcmRing; + +use super::{BackendError, Counters}; + +const MAX_OPUS_FRAME_SAMPLES_PER_CHANNEL: usize = 5_760; + +pub(super) struct AudioPipeline { + packets: Arc>>, + ring: Arc, + output: Option, + worker: Option>, +} + +impl AudioPipeline { + pub(super) fn start( + format: AudioFormat, + packet_capacity: usize, + pcm_milliseconds: u32, + counters: Arc, + failures: Arc, + ) -> Result { + format.validate()?; + let channels = usize::from(format.channels); + let pcm_capacity = usize::try_from(format.sample_rate) + .ok() + .and_then(|rate| rate.checked_mul(channels)) + .and_then(|samples| samples.checked_mul(pcm_milliseconds as usize)) + .map(|samples| samples / 1_000) + .filter(|samples| *samples > 0) + .ok_or(crate::format::FormatError::QueueTooLarge)?; + let ring = Arc::new(PcmRing::new(pcm_capacity)); + let packets: Arc>> = Arc::new(BoundedQueue::new(packet_capacity)); + let decoder_channels = if format.channels == 1 { + Channels::Mono + } else { + Channels::Stereo + }; + let mut decoder = Decoder::new(format.sample_rate, decoder_channels) + .map_err(|error| BackendError::Opus(error.to_string()))?; + let worker_packets = Arc::clone(&packets); + let worker_ring = Arc::clone(&ring); + let worker_counters = Arc::clone(&counters); + let worker_failures = Arc::clone(&failures); + let worker = thread::Builder::new() + .name("opennow-opus-decode".into()) + .spawn(move || { + let run_failures = Arc::clone(&worker_failures); + let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(move || { + let mut pcm = vec![0.0; MAX_OPUS_FRAME_SAMPLES_PER_CHANNEL * channels]; + while let Some(packet) = worker_packets.pop_wait() { + match decoder.decode_float(&packet, &mut pcm, false) { + Ok(samples_per_channel) => { + run_failures.audio_succeeded(); + let sample_count = samples_per_channel * channels; + let written = worker_ring.push(&pcm[..sample_count]); + if written != sample_count { + worker_counters.pcm_samples_dropped.fetch_add( + (sample_count - written) as u64, + Ordering::Relaxed, + ); + } + } + Err(error) => { + worker_counters + .opus_decode_errors + .fetch_add(1, Ordering::Relaxed); + if run_failures.audio_failed(error.to_string()) { + break; + } + } + } + } + })); + if result.is_err() { + worker_failures.report_fatal( + BackendSubsystem::AudioWorker, + "the audio decode worker stopped unexpectedly".to_owned(), + ); + } + }) + .map_err(|_| BackendError::Thread("Opus decoder"))?; + + let output = match AudioOutput::start(format, Arc::clone(&ring), counters) { + Ok(output) => output, + Err(error) => { + packets.close(); + let _ = worker.join(); + return Err(error); + } + }; + Ok(Self { + packets, + ring, + output: Some(output), + worker: Some(worker), + }) + } + + pub(super) fn submit(&self, packet: Vec) -> PushResult> { + self.packets.push_drop_oldest(packet) + } + + pub(super) fn set_paused(&mut self, paused: bool) -> Result<(), BackendError> { + if paused && let Some(output) = self.output.as_mut() { + output.set_paused(true)?; + } + self.packets.clear(); + self.ring.clear(); + if !paused && let Some(output) = self.output.as_mut() { + output.set_paused(false)?; + } + Ok(()) + } + + pub(super) fn stop(mut self) { + drop(self.output.take()); + self.packets.close_and_discard(); + if let Some(worker) = self.worker.take() { + let _ = worker.join(); + } + } +} + +impl Drop for AudioPipeline { + fn drop(&mut self) { + drop(self.output.take()); + self.packets.close_and_discard(); + if let Some(worker) = self.worker.take() { + let _ = worker.join(); + } + } +} + +struct AudioCallbackContext { + ring: Arc, + counters: Arc, + channels: usize, +} + +struct AudioOutput { + unit: AudioUnit, + initialized: bool, + started: bool, + callback_context: Box, +} + +// Audio Unit control calls have no thread affinity and AudioOutput is always owned behind Shared's +// audio Mutex. CoreAudio's concurrent render callback touches only the stable callback context. +unsafe impl Send for AudioOutput {} + +impl AudioOutput { + fn start( + format: AudioFormat, + ring: Arc, + counters: Arc, + ) -> Result { + let mut description = AudioComponentDescription { + componentType: kAudioUnitType_Output, + componentSubType: kAudioUnitSubType_DefaultOutput, + componentManufacturer: kAudioUnitManufacturer_Apple, + componentFlags: 0, + componentFlagsMask: 0, + }; + let component = + unsafe { AudioComponentFindNext(ptr::null_mut(), NonNull::from(&mut description)) }; + if component.is_null() { + return Err(BackendError::AppleApi { + api: "AudioComponentFindNext", + status: -1, + }); + } + let mut unit = ptr::null_mut(); + let status = unsafe { AudioComponentInstanceNew(component, NonNull::from(&mut unit)) }; + check_status("AudioComponentInstanceNew", status)?; + if unit.is_null() { + return Err(BackendError::AppleApi { + api: "AudioComponentInstanceNew", + status: -1, + }); + } + + let mut output = Self { + unit, + initialized: false, + started: false, + callback_context: Box::new(AudioCallbackContext { + ring, + counters, + channels: usize::from(format.channels), + }), + }; + let bytes_per_frame = u32::from(format.channels) * mem::size_of::() as u32; + let stream_format = AudioStreamBasicDescription { + mSampleRate: f64::from(format.sample_rate), + mFormatID: kAudioFormatLinearPCM, + mFormatFlags: kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked, + mBytesPerPacket: bytes_per_frame, + mFramesPerPacket: 1, + mBytesPerFrame: bytes_per_frame, + mChannelsPerFrame: u32::from(format.channels), + mBitsPerChannel: 32, + mReserved: 0, + }; + let status = unsafe { + AudioUnitSetProperty( + output.unit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + (&stream_format as *const AudioStreamBasicDescription).cast(), + mem::size_of_val(&stream_format) as u32, + ) + }; + check_status("AudioUnitSetProperty(StreamFormat)", status)?; + + let callback = AURenderCallbackStruct { + inputProc: Some(render_callback), + inputProcRefCon: (&mut *output.callback_context as *mut AudioCallbackContext).cast(), + }; + let status = unsafe { + AudioUnitSetProperty( + output.unit, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, + 0, + (&callback as *const AURenderCallbackStruct).cast(), + mem::size_of_val(&callback) as u32, + ) + }; + check_status("AudioUnitSetProperty(SetRenderCallback)", status)?; + + check_status("AudioUnitInitialize", unsafe { + AudioUnitInitialize(output.unit) + })?; + output.initialized = true; + check_status("AudioOutputUnitStart", unsafe { + AudioOutputUnitStart(output.unit) + })?; + output.started = true; + Ok(output) + } + + fn set_paused(&mut self, paused: bool) -> Result<(), BackendError> { + if paused && self.started { + check_status("AudioOutputUnitStop", unsafe { + AudioOutputUnitStop(self.unit) + })?; + self.started = false; + } else if !paused && !self.started { + check_status("AudioOutputUnitStart", unsafe { + AudioOutputUnitStart(self.unit) + })?; + self.started = true; + } + Ok(()) + } +} + +impl Drop for AudioOutput { + fn drop(&mut self) { + if self.started { + let _ = unsafe { AudioOutputUnitStop(self.unit) }; + self.started = false; + } + if self.initialized { + let _ = unsafe { AudioUnitUninitialize(self.unit) }; + self.initialized = false; + } + if !self.unit.is_null() { + let _ = unsafe { AudioComponentInstanceDispose(self.unit) }; + self.unit = ptr::null_mut(); + } + } +} + +unsafe extern "C-unwind" fn render_callback( + context: NonNull, + mut action_flags: NonNull, + _timestamp: NonNull, + _bus_number: u32, + frame_count: u32, + buffers: *mut AudioBufferList, +) -> i32 { + let context = unsafe { context.cast::().as_ref() }; + let Some(buffers) = NonNull::new(buffers) else { + return -50; + }; + let buffers = unsafe { buffers.as_ref() }; + if buffers.mNumberBuffers == 0 { + return -50; + } + let buffer = &buffers.mBuffers[0]; + let requested = frame_count as usize * context.channels; + let available_samples = buffer.mDataByteSize as usize / mem::size_of::(); + let sample_count = requested.min(available_samples); + let Some(data) = NonNull::new(buffer.mData.cast::()) else { + return -50; + }; + let output = unsafe { std::slice::from_raw_parts_mut(data.as_ptr(), sample_count) }; + let read = context.ring.pop_into(output); + output[read..].fill(0.0); + if read < requested { + context.counters.pcm_underrun_frames.fetch_add( + ((requested - read) / context.channels) as u64, + Ordering::Relaxed, + ); + } + if read == 0 { + unsafe { + action_flags + .as_mut() + .insert(AudioUnitRenderActionFlags::UnitRenderAction_OutputIsSilence) + }; + } + 0 +} + +fn check_status(api: &'static str, status: i32) -> Result<(), BackendError> { + if status == 0 { + Ok(()) + } else { + Err(BackendError::AppleApi { api, status }) + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/mod.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/mod.rs new file mode 100644 index 000000000..79d94d054 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/mod.rs @@ -0,0 +1,572 @@ +mod audio; +mod presentation; +mod surface; +mod video; + +use std::marker::PhantomData; +use std::rc::Rc; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::{Arc, Mutex}; + +use objc2::MainThreadMarker; +use objc2_metal::{MTLCreateSystemDefaultDevice, MTLDevice}; +use thiserror::Error; + +use crate::failure::{BackendFailure, FailureReporter, VideoDecodeLoss}; +use crate::format::{ + AudioFormat, BackendConfig, FormatError, FrameTiming, H264Format, H264Framing, RendererRect, + ScreenRect, access_unit_to_avcc, +}; +use crate::lifecycle::{BackendState, Lifecycle}; +use crate::queue::{BoundedQueue, PushResult}; + +use self::audio::AudioPipeline; +use self::presentation::PresenterHandle; +use self::surface::SurfaceOwner; +use self::video::{DecodedFrame, VideoDecoder}; + +const MAX_OPUS_PACKET_BYTES: usize = 1_275; + +/// Shows a standalone overlay window through the exact production creation path. +/// Debug-only aid for isolating window-server behavior without a streaming session. +pub fn debug_show_overlay_window() { + let Some(main_thread) = MainThreadMarker::new() else { + return; + }; + surface::debug_overlay_window(main_thread); +} + +/// Drains pending AppKit events and window-server work on the main thread. +/// +/// The streamer's main thread runs the host command loop instead of `NSApplication.run()`, so +/// window ordering, compositing, and window controls only make progress when this is called. +pub fn pump_app_events() { + use objc2_app_kit::{NSApplication, NSEventMask}; + + let Some(main_thread) = MainThreadMarker::new() else { + return; + }; + let application = NSApplication::sharedApplication(main_thread); + unsafe { + while let Some(event) = application.nextEventMatchingMask_untilDate_inMode_dequeue( + NSEventMask::Any, + None, + objc2_foundation::NSDefaultRunLoopMode, + true, + ) { + application.sendEvent(&event); + } + } + application.updateWindows(); +} + +#[derive(Debug, Error)] +pub enum BackendError { + #[error(transparent)] + Format(#[from] FormatError), + #[error("the operation must run on the AppKit main thread")] + MainThreadRequired, + #[error("the backend is stopping or stopped")] + Stopped, + #[error("H.264 access unit is {actual} bytes; configured maximum is {maximum}")] + AccessUnitTooLarge { actual: usize, maximum: usize }, + #[error("Opus packet is {0} bytes; the maximum is 1275")] + OpusPacketTooLarge(usize), + #[error("Opus packet is empty")] + EmptyOpusPacket, + #[error("{api} failed with OSStatus {status}")] + AppleApi { api: &'static str, status: i32 }, + #[error("{0}")] + Metal(String), + #[error("Opus decoder failed: {0}")] + Opus(String), + #[error("failed to start {0} worker thread")] + Thread(&'static str), + #[error("the supplied NSWindow has no content view")] + MissingContentView, + #[error("surface layout updates require a supplied NSWindow target")] + NotWindowSurface, + #[error("surface updates require an owned overlay target")] + NotOwnedOverlay, + #[error("macOS did not report a primary screen")] + MissingPrimaryScreen, +} + +#[link(name = "VideoToolbox", kind = "framework")] +unsafe extern "C" { + fn VTIsHardwareDecodeSupported(codec_type: u32) -> u8; +} + +pub fn probe_h264_hardware() -> bool { + const H264_CODEC_TYPE: u32 = u32::from_be_bytes(*b"avc1"); + if unsafe { VTIsHardwareDecodeSupported(H264_CODEC_TYPE) } == 0 { + return false; + } + MTLCreateSystemDefaultDevice().is_some_and(|device| device.newCommandQueue().is_some()) +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum SubmitOutcome { + Accepted, + ReplacedOldest, + Backpressured, + Paused, +} + +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +pub struct BackendStats { + pub video_submitted: u64, + pub video_backpressured: u64, + pub video_decoded: u64, + pub video_decode_errors: u64, + pub video_frames_dropped: u64, + pub video_presented: u64, + pub video_present_errors: u64, + pub opus_submitted: u64, + pub opus_packets_dropped: u64, + pub opus_decode_errors: u64, + pub pcm_samples_dropped: u64, + pub pcm_underrun_frames: u64, +} + +#[derive(Default)] +pub(super) struct Counters { + video_submitted: AtomicU64, + video_backpressured: AtomicU64, + video_decoded: AtomicU64, + video_decode_errors: AtomicU64, + video_frames_dropped: AtomicU64, + video_presented: AtomicU64, + video_present_errors: AtomicU64, + opus_submitted: AtomicU64, + opus_packets_dropped: AtomicU64, + opus_decode_errors: AtomicU64, + pcm_samples_dropped: AtomicU64, + pcm_underrun_frames: AtomicU64, +} + +impl Counters { + fn snapshot(&self) -> BackendStats { + BackendStats { + video_submitted: self.video_submitted.load(Ordering::Relaxed), + video_backpressured: self.video_backpressured.load(Ordering::Relaxed), + video_decoded: self.video_decoded.load(Ordering::Relaxed), + video_decode_errors: self.video_decode_errors.load(Ordering::Relaxed), + video_frames_dropped: self.video_frames_dropped.load(Ordering::Relaxed), + video_presented: self.video_presented.load(Ordering::Relaxed), + video_present_errors: self.video_present_errors.load(Ordering::Relaxed), + opus_submitted: self.opus_submitted.load(Ordering::Relaxed), + opus_packets_dropped: self.opus_packets_dropped.load(Ordering::Relaxed), + opus_decode_errors: self.opus_decode_errors.load(Ordering::Relaxed), + pcm_samples_dropped: self.pcm_samples_dropped.load(Ordering::Relaxed), + pcm_underrun_frames: self.pcm_underrun_frames.load(Ordering::Relaxed), + } + } +} + +/// Raw AppKit handles owned or retained by a running backend. +/// +/// Both pointers remain valid only until [`MacOsBackend::stop`] or `Drop`. Callers must use them +/// on AppKit's main thread and must not transfer ownership or release them. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct NativeSurfaceHandle { + pub ns_window: Option>, + /// The dedicated presentation view. For `SurfaceTarget::NsWindow`, this is the backend-owned + /// passive child view, never the supplied window's content view. + pub ns_view: std::ptr::NonNull, +} + +/// Thread-safe encoded media input for a running [`MacOsBackend`]. +#[derive(Clone)] +pub struct StreamSink { + shared: Arc, +} + +impl StreamSink { + pub fn submit_h264( + &self, + access_unit: &[u8], + framing: H264Framing, + timing: FrameTiming, + ) -> Result { + if self.shared.lifecycle.state() != BackendState::Running { + return Err(BackendError::Stopped); + } + if self.shared.paused.load(Ordering::Acquire) { + return Ok(SubmitOutcome::Paused); + } + timing.validate()?; + if access_unit.len() > self.shared.max_video_access_unit_bytes { + return Err(BackendError::AccessUnitTooLarge { + actual: access_unit.len(), + maximum: self.shared.max_video_access_unit_bytes, + }); + } + let avcc = access_unit_to_avcc(access_unit, framing)?; + let decoder = self + .shared + .video + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()); + if self.shared.lifecycle.state() != BackendState::Running { + return Err(BackendError::Stopped); + } + if self.shared.paused.load(Ordering::Acquire) { + return Ok(SubmitOutcome::Paused); + } + let decoder = decoder.as_ref().ok_or(BackendError::Stopped)?; + if !decoder.submit(&avcc, timing)? { + self.shared + .counters + .video_backpressured + .fetch_add(1, Ordering::Relaxed); + return Ok(SubmitOutcome::Backpressured); + } + self.shared + .counters + .video_submitted + .fetch_add(1, Ordering::Relaxed); + Ok(SubmitOutcome::Accepted) + } + + pub fn submit_opus(&self, packet: &[u8]) -> Result { + if packet.is_empty() { + return Err(BackendError::EmptyOpusPacket); + } + if packet.len() > MAX_OPUS_PACKET_BYTES { + return Err(BackendError::OpusPacketTooLarge(packet.len())); + } + self.submit_opus_owned(packet.to_vec()) + } + + fn submit_opus_owned(&self, packet: Vec) -> Result { + if self.shared.lifecycle.state() != BackendState::Running { + return Err(BackendError::Stopped); + } + if self.shared.paused.load(Ordering::Acquire) { + return Ok(SubmitOutcome::Paused); + } + let audio = self + .shared + .audio + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()); + if self.shared.lifecycle.state() != BackendState::Running { + return Err(BackendError::Stopped); + } + if self.shared.paused.load(Ordering::Acquire) { + return Ok(SubmitOutcome::Paused); + } + let audio = audio.as_ref().ok_or(BackendError::Stopped)?; + let outcome = match audio.submit(packet) { + PushResult::Pushed => SubmitOutcome::Accepted, + PushResult::Replaced(_) => { + self.shared + .counters + .opus_packets_dropped + .fetch_add(1, Ordering::Relaxed); + SubmitOutcome::ReplacedOldest + } + PushResult::Closed(_) => return Err(BackendError::Stopped), + }; + self.shared + .counters + .opus_submitted + .fetch_add(1, Ordering::Relaxed); + Ok(outcome) + } + + pub fn reconfigure_h264(&self, format: H264Format) -> Result<(), BackendError> { + if self.shared.lifecycle.state() != BackendState::Running { + return Err(BackendError::Stopped); + } + let replacement = VideoDecoder::new( + &format, + self.shared.video_queue.clone(), + Arc::clone(&self.shared.counters), + Arc::clone(&self.shared.failures), + self.shared.video_frames_in_flight, + )?; + let mut decoder = self + .shared + .video + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()); + if self.shared.lifecycle.state() != BackendState::Running { + drop(replacement); + return Err(BackendError::Stopped); + } + let previous = decoder.replace(replacement); + drop(previous); + let discarded = self.shared.video_queue.clear(); + self.shared + .counters + .video_frames_dropped + .fetch_add(discarded as u64, Ordering::Relaxed); + drop(decoder); + Ok(()) + } + + pub fn reconfigure_audio(&self, format: AudioFormat) -> Result<(), BackendError> { + format.validate()?; + if self.shared.lifecycle.state() != BackendState::Running { + return Err(BackendError::Stopped); + } + let mut audio = self + .shared + .audio + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()); + if self.shared.lifecycle.state() != BackendState::Running { + return Err(BackendError::Stopped); + } + if let Some(previous) = audio.take() { + previous.stop(); + } + *audio = Some(AudioPipeline::start( + format, + self.shared.opus_packets, + self.shared.pcm_milliseconds, + Arc::clone(&self.shared.counters), + Arc::clone(&self.shared.failures), + )?); + Ok(()) + } + + pub fn state(&self) -> BackendState { + self.shared.lifecycle.state() + } + + pub fn stats(&self) -> BackendStats { + self.shared.counters.snapshot() + } + + pub fn pop_video_decode_loss(&self) -> Option { + self.shared.failures.pop_video_decode_loss() + } + + pub fn fatal_failure(&self) -> Option { + self.shared.failures.fatal_failure() + } +} + +struct Shared { + lifecycle: Lifecycle, + paused: AtomicBool, + counters: Arc, + failures: Arc, + video_queue: Arc>, + video: Mutex>, + audio: Mutex>, + presenter: Mutex>, + video_frames_in_flight: usize, + opus_packets: usize, + pcm_milliseconds: u32, + max_video_access_unit_bytes: usize, +} + +impl Shared { + fn stop(&self) { + if !self.lifecycle.begin_stop() { + return; + } + let decoder = self + .video + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()) + .take(); + drop(decoder); + if let Some(audio) = self + .audio + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()) + .take() + { + audio.stop(); + } + if let Some(presenter) = self + .presenter + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()) + .take() + { + presenter.stop(); + } + self.lifecycle.finish_stop(); + } +} + +/// Main-thread owner for the native macOS backend. +pub struct MacOsBackend { + shared: Arc, + surface: Option, + _main_thread_only: PhantomData>, +} + +impl MacOsBackend { + pub fn start(config: BackendConfig) -> Result { + let main_thread = MainThreadMarker::new().ok_or(BackendError::MainThreadRequired)?; + config.validate()?; + let surface = SurfaceOwner::attach(config.surface, main_thread)?; + let counters = Arc::new(Counters::default()); + let failures = Arc::new(FailureReporter::default()); + let video_queue = Arc::new(BoundedQueue::new(config.queues.decoded_video_frames)); + let presenter = PresenterHandle::start( + surface.metal_layer(), + surface.presentation_visibility(), + Arc::clone(&video_queue), + Arc::clone(&counters), + Arc::clone(&failures), + )?; + let video = VideoDecoder::new( + &config.video, + Arc::clone(&video_queue), + Arc::clone(&counters), + Arc::clone(&failures), + config.queues.video_frames_in_flight, + )?; + let audio = AudioPipeline::start( + config.audio, + config.queues.opus_packets, + config.queues.pcm_milliseconds, + Arc::clone(&counters), + Arc::clone(&failures), + )?; + let shared = Arc::new(Shared { + lifecycle: Lifecycle::running(), + paused: AtomicBool::new(false), + counters, + failures, + video_queue, + video: Mutex::new(Some(video)), + audio: Mutex::new(Some(audio)), + presenter: Mutex::new(Some(presenter)), + video_frames_in_flight: config.queues.video_frames_in_flight, + opus_packets: config.queues.opus_packets, + pcm_milliseconds: config.queues.pcm_milliseconds, + max_video_access_unit_bytes: config.queues.max_video_access_unit_bytes, + }); + Ok(Self { + shared, + surface: Some(surface), + _main_thread_only: PhantomData, + }) + } + + pub fn sink(&self) -> StreamSink { + StreamSink { + shared: Arc::clone(&self.shared), + } + } + + pub fn native_surface(&self) -> Option { + self.surface.as_ref().map(SurfaceOwner::native_handle) + } + + /// Updates a supplied-window child surface in renderer-relative, top-left AppKit points. + /// + /// This method is available only for `SurfaceTarget::NsWindow` and returns + /// `MainThreadRequired` instead of dispatching implicitly when called off AppKit's main thread. + pub fn update_window_surface( + &mut self, + bounds: RendererRect, + visible: bool, + ) -> Result<(), BackendError> { + let main_thread = MainThreadMarker::new().ok_or(BackendError::MainThreadRequired)?; + if self.shared.lifecycle.state() != BackendState::Running { + return Err(BackendError::Stopped); + } + bounds.validate()?; + self.surface + .as_mut() + .ok_or(BackendError::Stopped)? + .update_window_child(bounds, visible, main_thread) + } + + /// Repositions the process-owned passive overlay using absolute Electron screen coordinates. + pub fn update_owned_overlay( + &mut self, + screen_rect: ScreenRect, + visible: bool, + ) -> Result<(), BackendError> { + let main_thread = MainThreadMarker::new().ok_or(BackendError::MainThreadRequired)?; + if self.shared.lifecycle.state() != BackendState::Running { + return Err(BackendError::Stopped); + } + screen_rect.validate()?; + self.surface + .as_mut() + .ok_or(BackendError::Stopped)? + .update_owned_overlay(screen_rect, visible, main_thread) + } + + pub fn refresh_overlay_ordering(&mut self) -> Result<(), BackendError> { + let _main_thread = MainThreadMarker::new().ok_or(BackendError::MainThreadRequired)?; + if self.shared.lifecycle.state() != BackendState::Running { + return Err(BackendError::Stopped); + } + self.surface + .as_mut() + .ok_or(BackendError::Stopped)? + .refresh_overlay_ordering() + } + + pub fn state(&self) -> BackendState { + self.shared.lifecycle.state() + } + + pub fn stats(&self) -> BackendStats { + self.shared.counters.snapshot() + } + + pub fn fatal_failure(&self) -> Option { + self.shared.failures.fatal_failure() + } + + pub fn set_paused(&mut self, paused: bool) -> Result<(), BackendError> { + let _main_thread = MainThreadMarker::new().ok_or(BackendError::MainThreadRequired)?; + if self.shared.lifecycle.state() != BackendState::Running { + return Err(BackendError::Stopped); + } + if paused { + self.shared.paused.store(true, Ordering::Release); + } + let discarded = self.shared.video_queue.clear(); + self.shared + .counters + .video_frames_dropped + .fetch_add(discarded as u64, Ordering::Relaxed); + if let Some(audio) = self + .shared + .audio + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()) + .as_mut() + { + audio.set_paused(paused)?; + } + if !paused { + self.shared.paused.store(false, Ordering::Release); + } + Ok(()) + } + + pub fn stop(&mut self) { + self.shared.stop(); + if let Some(mut surface) = self.surface.take() { + surface.detach(); + } + } +} + +impl Drop for MacOsBackend { + fn drop(&mut self) { + self.stop(); + } +} + +#[allow(dead_code)] +fn assert_stream_sink_is_send_and_sync() { + fn assert_send_sync() {} + assert_send_sync::(); +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/presentation.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/presentation.rs new file mode 100644 index 000000000..6255235c3 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/presentation.rs @@ -0,0 +1,428 @@ +use std::collections::VecDeque; +use std::ffi::c_void; +use std::ptr::{self, NonNull}; +use std::sync::Arc; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering; +use std::thread::{self, JoinHandle}; + +use objc2::rc::{Retained, autoreleasepool}; +use objc2::runtime::ProtocolObject; +use objc2_core_foundation::CFRetained; +use objc2_core_video::{ + CVMetalTexture, CVMetalTextureCache, CVMetalTextureGetTexture, CVPixelBufferGetHeightOfPlane, + CVPixelBufferGetPixelFormatType, CVPixelBufferGetPlaneCount, CVPixelBufferGetWidthOfPlane, + kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, +}; +use objc2_foundation::NSString; +use objc2_metal::{ + MTLClearColor, MTLCommandBuffer, MTLCommandBufferStatus, MTLCommandEncoder, MTLCommandQueue, + MTLCreateSystemDefaultDevice, MTLDevice, MTLDrawable, MTLLibrary, MTLLoadAction, + MTLPixelFormat, MTLPrimitiveType, MTLRenderCommandEncoder, MTLRenderPassDescriptor, + MTLRenderPipelineDescriptor, MTLRenderPipelineState, MTLStoreAction, MTLTexture, MTLViewport, +}; +use objc2_quartz_core::{CAMetalDrawable, CAMetalLayer}; + +use crate::failure::{BackendSubsystem, FailureReporter}; +use crate::format::VideoColorSpace; +use crate::queue::BoundedQueue; + +use super::video::DecodedFrame; +use super::{BackendError, Counters}; + +const SHADER_SOURCE: &str = r#" +#include +using namespace metal; + +struct VertexOut { + float4 position [[position]]; + float2 texcoord; +}; + +vertex VertexOut video_vertex(uint vertex_id [[vertex_id]]) { + const float2 positions[3] = { float2(-1.0, -1.0), float2(3.0, -1.0), float2(-1.0, 3.0) }; + const float2 texcoords[3] = { float2(0.0, 1.0), float2(2.0, 1.0), float2(0.0, -1.0) }; + VertexOut out; + out.position = float4(positions[vertex_id], 0.0, 1.0); + out.texcoord = texcoords[vertex_id]; + return out; +} + +fragment float4 video_fragment( + VertexOut in [[stage_in]], + texture2d luma [[texture(0)]], + texture2d chroma [[texture(1)]], + constant uint &color_space [[buffer(0)]]) { + constexpr sampler linear_sampler(coord::normalized, address::clamp_to_edge, filter::linear); + float y = (luma.sample(linear_sampler, in.texcoord).r - (16.0 / 255.0)) * (255.0 / 219.0); + float2 cbcr = chroma.sample(linear_sampler, in.texcoord).rg - float2(0.5); + float3 rgb; + if (color_space == 0) { + rgb = float3( + y + 1.596027 * cbcr.y, + y - 0.391762 * cbcr.x - 0.812968 * cbcr.y, + y + 2.017232 * cbcr.x); + } else { + rgb = float3( + y + 1.792741 * cbcr.y, + y - 0.213249 * cbcr.x - 0.532909 * cbcr.y, + y + 2.112402 * cbcr.x); + } + return float4(saturate(rgb), 1.0); +} +"#; + +pub(super) struct PresenterHandle { + queue: Arc>, + worker: Option>, +} + +impl PresenterHandle { + pub(super) fn start( + layer: Retained, + visible: Arc, + queue: Arc>, + counters: Arc, + failures: Arc, + ) -> Result { + let mut presenter = MetalPresenter::new(layer)?; + let worker_queue = Arc::clone(&queue); + let worker_failures = Arc::clone(&failures); + let worker = thread::Builder::new() + .name("opennow-metal-present".into()) + .spawn(move || { + let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + while let Some(frame) = worker_queue.pop_wait() { + if !visible.load(Ordering::Acquire) { + counters + .video_frames_dropped + .fetch_add(1, Ordering::Relaxed); + continue; + } + let result = autoreleasepool(|_| presenter.present(frame)); + match result { + Ok(()) => { + failures.metal_succeeded(); + counters.video_presented.fetch_add(1, Ordering::Relaxed); + } + Err(error) => { + counters + .video_present_errors + .fetch_add(1, Ordering::Relaxed); + if failures.metal_failed(error.to_string()) { + break; + } + } + } + } + presenter.finish(); + })); + if result.is_err() { + worker_failures.report_fatal( + BackendSubsystem::Metal, + "the Metal presentation worker stopped unexpectedly".to_owned(), + ); + } + }) + .map_err(|_| BackendError::Thread("Metal presenter"))?; + Ok(Self { + queue, + worker: Some(worker), + }) + } + + pub(super) fn stop(mut self) { + self.queue.close_and_discard(); + if let Some(worker) = self.worker.take() { + let _ = worker.join(); + } + } +} + +impl Drop for PresenterHandle { + fn drop(&mut self) { + self.queue.close_and_discard(); + if let Some(worker) = self.worker.take() { + let _ = worker.join(); + } + } +} + +struct PendingFrame { + command_buffer: Retained>, + _luma_cv_texture: CFRetained, + _chroma_cv_texture: CFRetained, + _luma_texture: Retained>, + _chroma_texture: Retained>, +} + +struct MetalPresenter { + layer: Retained, + command_queue: Retained>, + pipeline: Retained>, + texture_cache: CFRetained, + pending: VecDeque, +} + +// Metal objects are thread-safe. AppKit attaches and detaches the layer on the main thread; after +// construction this worker only uses CAMetalLayer's thread-safe drawable API. +unsafe impl Send for MetalPresenter {} + +impl MetalPresenter { + fn new(layer: Retained) -> Result { + let device = MTLCreateSystemDefaultDevice() + .ok_or_else(|| BackendError::Metal("Metal is unavailable on this Mac".into()))?; + layer.setDevice(Some(&device)); + layer.setPixelFormat(MTLPixelFormat::BGRA8Unorm); + layer.setFramebufferOnly(true); + layer.setMaximumDrawableCount(3); + layer.setPresentsWithTransaction(false); + layer.setDisplaySyncEnabled(true); + layer.setAllowsNextDrawableTimeout(true); + + let command_queue = device + .newCommandQueue() + .ok_or_else(|| BackendError::Metal("failed to create Metal command queue".into()))?; + let source = NSString::from_str(SHADER_SOURCE); + let library = device + .newLibraryWithSource_options_error(&source, None) + .map_err(|error| BackendError::Metal(error.localizedDescription().to_string()))?; + let vertex = library + .newFunctionWithName(&NSString::from_str("video_vertex")) + .ok_or_else(|| BackendError::Metal("video_vertex shader is missing".into()))?; + let fragment = library + .newFunctionWithName(&NSString::from_str("video_fragment")) + .ok_or_else(|| BackendError::Metal("video_fragment shader is missing".into()))?; + let descriptor = MTLRenderPipelineDescriptor::new(); + descriptor.setVertexFunction(Some(&vertex)); + descriptor.setFragmentFunction(Some(&fragment)); + let attachments = descriptor.colorAttachments(); + let attachment = unsafe { attachments.objectAtIndexedSubscript(0) }; + attachment.setPixelFormat(MTLPixelFormat::BGRA8Unorm); + let pipeline = device + .newRenderPipelineStateWithDescriptor_error(&descriptor) + .map_err(|error| BackendError::Metal(error.localizedDescription().to_string()))?; + + let mut cache_ptr = ptr::null_mut(); + let status = unsafe { + CVMetalTextureCache::create(None, None, &device, None, NonNull::from(&mut cache_ptr)) + }; + if status != 0 { + return Err(BackendError::AppleApi { + api: "CVMetalTextureCacheCreate", + status, + }); + } + let cache_ptr = NonNull::new(cache_ptr).ok_or(BackendError::AppleApi { + api: "CVMetalTextureCacheCreate", + status: -1, + })?; + let texture_cache = unsafe { CFRetained::from_raw(cache_ptr) }; + Ok(Self { + layer, + command_queue, + pipeline, + texture_cache, + pending: VecDeque::with_capacity(3), + }) + } + + fn present(&mut self, frame: DecodedFrame) -> Result<(), BackendError> { + if self.pending.len() >= 2 { + self.wait_for_oldest()?; + } + if CVPixelBufferGetPixelFormatType(&frame.image) + != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange + || CVPixelBufferGetPlaneCount(&frame.image) != 2 + { + return Err(BackendError::Metal( + "VideoToolbox returned a non-NV12 pixel buffer".into(), + )); + } + + let width = CVPixelBufferGetWidthOfPlane(&frame.image, 0); + let height = CVPixelBufferGetHeightOfPlane(&frame.image, 0); + let chroma_width = CVPixelBufferGetWidthOfPlane(&frame.image, 1); + let chroma_height = CVPixelBufferGetHeightOfPlane(&frame.image, 1); + let luma_cv_texture = + self.make_texture(&frame, MTLPixelFormat::R8Unorm, width, height, 0)?; + let chroma_cv_texture = self.make_texture( + &frame, + MTLPixelFormat::RG8Unorm, + chroma_width, + chroma_height, + 1, + )?; + let luma_texture = CVMetalTextureGetTexture(&luma_cv_texture) + .ok_or_else(|| BackendError::Metal("failed to get Metal luma texture".into()))?; + let chroma_texture = CVMetalTextureGetTexture(&chroma_cv_texture) + .ok_or_else(|| BackendError::Metal("failed to get Metal chroma texture".into()))?; + let drawable = self + .layer + .nextDrawable() + .ok_or_else(|| BackendError::Metal("CAMetalLayer has no drawable".into()))?; + let drawable_texture = drawable.texture(); + + let render_pass = MTLRenderPassDescriptor::renderPassDescriptor(); + let attachments = render_pass.colorAttachments(); + let attachment = unsafe { attachments.objectAtIndexedSubscript(0) }; + attachment.setTexture(Some(&drawable_texture)); + attachment.setLoadAction(MTLLoadAction::Clear); + attachment.setStoreAction(MTLStoreAction::Store); + attachment.setClearColor(MTLClearColor { + red: 0.0, + green: 0.0, + blue: 0.0, + alpha: 1.0, + }); + + let command_buffer = self + .command_queue + .commandBuffer() + .ok_or_else(|| BackendError::Metal("failed to create Metal command buffer".into()))?; + let encoder = command_buffer + .renderCommandEncoderWithDescriptor(&render_pass) + .ok_or_else(|| BackendError::Metal("failed to create Metal render encoder".into()))?; + encoder.setRenderPipelineState(&self.pipeline); + unsafe { + encoder.setFragmentTexture_atIndex(Some(&luma_texture), 0); + encoder.setFragmentTexture_atIndex(Some(&chroma_texture), 1); + } + let color_space = match frame.color_space { + VideoColorSpace::Bt601 => 0u32, + VideoColorSpace::Bt709 => 1u32, + }; + unsafe { + encoder.setFragmentBytes_length_atIndex( + NonNull::from(&color_space).cast::(), + std::mem::size_of_val(&color_space), + 0, + ) + }; + let destination_width = drawable_texture.width() as f64; + let destination_height = drawable_texture.height() as f64; + encoder.setViewport(aspect_fit_viewport( + width as f64, + height as f64, + destination_width, + destination_height, + )); + unsafe { encoder.drawPrimitives_vertexStart_vertexCount(MTLPrimitiveType::Triangle, 0, 3) }; + encoder.endEncoding(); + let drawable_ref: &ProtocolObject = &drawable; + let drawable_as_base: &ProtocolObject = drawable_ref.as_ref(); + command_buffer.presentDrawable(drawable_as_base); + command_buffer.commit(); + self.pending.push_back(PendingFrame { + command_buffer, + _luma_cv_texture: luma_cv_texture, + _chroma_cv_texture: chroma_cv_texture, + _luma_texture: luma_texture, + _chroma_texture: chroma_texture, + }); + Ok(()) + } + + fn make_texture( + &self, + frame: &DecodedFrame, + pixel_format: MTLPixelFormat, + width: usize, + height: usize, + plane: usize, + ) -> Result, BackendError> { + let mut texture_ptr = ptr::null_mut(); + let status = unsafe { + CVMetalTextureCache::create_texture_from_image( + None, + &self.texture_cache, + &frame.image, + None, + pixel_format, + width, + height, + plane, + NonNull::from(&mut texture_ptr), + ) + }; + if status != 0 { + return Err(BackendError::AppleApi { + api: "CVMetalTextureCacheCreateTextureFromImage", + status, + }); + } + let texture_ptr = NonNull::new(texture_ptr).ok_or(BackendError::AppleApi { + api: "CVMetalTextureCacheCreateTextureFromImage", + status: -1, + })?; + Ok(unsafe { CFRetained::from_raw(texture_ptr) }) + } + + fn wait_for_oldest(&mut self) -> Result<(), BackendError> { + if let Some(frame) = self.pending.pop_front() { + frame.command_buffer.waitUntilCompleted(); + if frame.command_buffer.status() == MTLCommandBufferStatus::Error { + let message = frame.command_buffer.error().map_or_else( + || "Metal command buffer failed without an error description".to_owned(), + |error| error.localizedDescription().to_string(), + ); + return Err(BackendError::Metal(message)); + } + } + Ok(()) + } + + fn finish(&mut self) { + while !self.pending.is_empty() { + let _ = self.wait_for_oldest(); + } + self.texture_cache.flush(0); + } +} + +impl Drop for MetalPresenter { + fn drop(&mut self) { + self.finish(); + } +} + +fn aspect_fit_viewport( + source_width: f64, + source_height: f64, + destination_width: f64, + destination_height: f64, +) -> MTLViewport { + let source_aspect = source_width / source_height; + let destination_aspect = destination_width / destination_height; + let (width, height) = if source_aspect > destination_aspect { + (destination_width, destination_width / source_aspect) + } else { + (destination_height * source_aspect, destination_height) + }; + MTLViewport { + originX: (destination_width - width) * 0.5, + originY: (destination_height - height) * 0.5, + width, + height, + znear: 0.0, + zfar: 1.0, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn aspect_fit_letterboxes_without_distortion() { + let viewport = aspect_fit_viewport(1920.0, 1080.0, 1024.0, 768.0); + assert_eq!(viewport.width, 1024.0); + assert_eq!(viewport.height, 576.0); + assert_eq!(viewport.originY, 96.0); + + let portrait = aspect_fit_viewport(1080.0, 1920.0, 1024.0, 768.0); + assert_eq!(portrait.height, 768.0); + assert_eq!(portrait.width, 432.0); + assert_eq!(portrait.originX, 296.0); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/surface.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/surface.rs new file mode 100644 index 000000000..c2450810b --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/surface.rs @@ -0,0 +1,381 @@ +use std::ffi::c_void; +use std::ptr::NonNull; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; + +use objc2::rc::Retained; +use objc2::{MainThreadMarker, MainThreadOnly, define_class, msg_send}; +use objc2_app_kit::{ + NSApplication, NSBackingStoreType, NSColor, NSScreen, NSView, NSWindow, NSWindowStyleMask, + NSWorkspace, +}; +use objc2_core_foundation::{CGPoint, CGRect, CGSize}; +use objc2_quartz_core::{CALayer, CAMetalLayer}; + +use crate::format::{RendererRect, ScreenRect, SurfaceTarget}; +use crate::lifecycle::AttachmentLifecycle; +use crate::overlay_should_be_ordered; + +use super::{BackendError, NativeSurfaceHandle}; + +define_class!( + // NSView has no additional initialization or destruction requirements for a subclass with no + // ivars. MainThreadOnly preserves AppKit's thread contract. + #[unsafe(super(NSView))] + #[thread_kind = MainThreadOnly] + struct PassiveSurfaceView; + + impl PassiveSurfaceView { + // Returning nil lets hit testing continue through the BrowserWindow content view instead + // of routing pointer, gesture, or drag input to the video surface. + #[unsafe(method(hitTest:))] + fn hit_test(&self, _point: CGPoint) -> Option<&NSView> { + None + } + + #[unsafe(method(acceptsFirstResponder))] + fn accepts_first_responder(&self) -> bool { + false + } + + #[unsafe(method(becomeFirstResponder))] + fn become_first_responder(&self) -> bool { + false + } + + #[unsafe(method(canBecomeKeyView))] + fn can_become_key_view(&self) -> bool { + false + } + } +); + +enum Attachment { + Dedicated { + previous_layer: Option>, + previous_wants_layer: bool, + }, + WindowChild { + parent: Retained, + }, +} + +/// Creates the overlay window exactly as `SurfaceOwner::attach` does for `OwnedOverlay`, +/// for isolating window-server behavior without a streaming session. +pub(super) fn debug_overlay_window(main_thread: MainThreadMarker) { + let application = NSApplication::sharedApplication(main_thread); + application.setActivationPolicy(objc2_app_kit::NSApplicationActivationPolicy::Accessory); + application.finishLaunching(); + application.activate(); + let rect = ScreenRect::new(200.0, 167.0, 1400.0, 868.0); + let styles = + NSWindowStyleMask::Titled | NSWindowStyleMask::Closable | NSWindowStyleMask::Resizable; + let window: Retained = unsafe { + msg_send![ + main_thread.alloc::(), + initWithContentRect: appkit_screen_frame(rect, main_thread).expect("screen frame"), + styleMask: styles, + backing: NSBackingStoreType::Buffered, + defer: false + ] + }; + window.setTitle(&objc2_foundation::NSString::from_str("OpenNOW Video")); + window.orderFront(None); + eprintln!("NVST debug-overlay-window created"); + std::mem::forget(window); +} + +pub(super) struct SurfaceOwner { + window: Option>, + view: Retained, + layer: Retained, + attachment: Attachment, + visible: Arc, + requested_visible: bool, + parent_pid: Option, + owns_window: bool, + overlay: bool, + lifecycle: AttachmentLifecycle, +} + +impl SurfaceOwner { + pub(super) fn attach( + target: SurfaceTarget, + main_thread: MainThreadMarker, + ) -> Result { + let ordered_visible; + let (window, view, owns_window, overlay, child_parent, requested_visible, parent_pid) = + match target { + SurfaceTarget::OwnedOverlay(config) => { + let application = NSApplication::sharedApplication(main_thread); + // A bare executable defaults to NSApplicationActivationPolicyProhibited, + // which makes the window server refuse to show any of its windows. + // Accessory lets the overlay appear without a dock icon or menu bar. + application.setActivationPolicy( + objc2_app_kit::NSApplicationActivationPolicy::Accessory, + ); + application.finishLaunching(); + config.validate()?; + let parent_pid = unsafe { libc::getppid() }; + let frontmost = application_is_frontmost(parent_pid); + let ordered = overlay_should_be_ordered(config.visible, frontmost); + let styles = NSWindowStyleMask::Titled + | NSWindowStyleMask::Closable + | NSWindowStyleMask::Resizable; + // A runtime-defined NSWindow/NSPanel subclass never composites in this + // process (the window server lists it but keeps it offscreen and + // unsynced); a plain NSWindow through the same init path works. + let window: Retained = unsafe { + msg_send![ + main_thread.alloc::(), + initWithContentRect: appkit_screen_frame(config.screen_rect, main_thread)?, + styleMask: styles, + backing: NSBackingStoreType::Buffered, + defer: false + ] + }; + unsafe { window.setReleasedWhenClosed(false) }; + window.setTitle(&objc2_foundation::NSString::from_str("OpenNOW Video")); + window.setIgnoresMouseEvents(false); + window.setAcceptsMouseMovedEvents(false); + window.setHasShadow(true); + window.setOpaque(true); + window.setBackgroundColor(Some(&NSColor::blackColor())); + let view = window + .contentView() + .ok_or(BackendError::MissingContentView)?; + if ordered { + window.orderFront(None); + } else { + window.orderOut(None); + } + ordered_visible = ordered; + ( + Some(window), + view, + true, + true, + None, + config.visible, + Some(parent_pid), + ) + } + SurfaceTarget::NsView(view) => { + let view = unsafe { Retained::retain(view.as_ptr().as_ptr().cast::()) } + .ok_or(BackendError::MissingContentView)?; + let window = view.window(); + ordered_visible = true; + (window, view, false, false, None, true, None) + } + SurfaceTarget::NsWindow(config) => { + config.validate()?; + let window = unsafe { + Retained::retain(config.window.as_ptr().as_ptr().cast::()) + } + .ok_or(BackendError::MissingContentView)?; + let parent = window + .contentView() + .ok_or(BackendError::MissingContentView)?; + let frame = appkit_frame(&parent, config.bounds); + let child: Retained = unsafe { + msg_send![main_thread.alloc::(), initWithFrame: frame] + }; + child.setHidden(!config.visible); + ordered_visible = config.visible; + ( + Some(window), + child.into_super(), + false, + false, + Some(parent), + config.visible, + None, + ) + } + }; + + let attachment = if let Some(parent) = child_parent { + Attachment::WindowChild { parent } + } else { + Attachment::Dedicated { + previous_layer: view.layer(), + previous_wants_layer: view.wantsLayer(), + } + }; + let layer = CAMetalLayer::new(); + layer.setFrame(view.bounds()); + let scale = window + .as_ref() + .map_or(1.0, |window| window.backingScaleFactor()); + layer.setContentsScale(scale); + view.setWantsLayer(true); + view.setLayer(Some(&layer)); + if let Attachment::WindowChild { parent } = &attachment { + parent.addSubview(&view); + } + + Ok(Self { + window, + view, + layer, + attachment, + visible: Arc::new(AtomicBool::new(ordered_visible)), + requested_visible, + parent_pid, + owns_window, + overlay, + lifecycle: AttachmentLifecycle::attached(), + }) + } + + pub(super) fn metal_layer(&self) -> Retained { + self.layer.clone() + } + + pub(super) fn presentation_visibility(&self) -> Arc { + Arc::clone(&self.visible) + } + + pub(super) fn native_handle(&self) -> NativeSurfaceHandle { + NativeSurfaceHandle { + ns_window: self.window.as_ref().map(|window| { + NonNull::new(Retained::as_ptr(window).cast_mut().cast::()) + .expect("retained NSWindow is non-null") + }), + ns_view: NonNull::new(Retained::as_ptr(&self.view).cast_mut().cast::()) + .expect("retained NSView is non-null"), + } + } + + pub(super) fn update_window_child( + &mut self, + bounds: RendererRect, + visible: bool, + _main_thread: MainThreadMarker, + ) -> Result<(), BackendError> { + bounds.validate()?; + let Attachment::WindowChild { parent } = &self.attachment else { + return Err(BackendError::NotWindowSurface); + }; + self.view.setFrame(appkit_frame(parent, bounds)); + self.view.setHidden(!visible); + self.layer.setFrame(self.view.bounds()); + self.visible.store(visible, Ordering::Release); + Ok(()) + } + + pub(super) fn update_owned_overlay( + &mut self, + screen_rect: ScreenRect, + visible: bool, + main_thread: MainThreadMarker, + ) -> Result<(), BackendError> { + if !self.overlay { + return Err(BackendError::NotOwnedOverlay); + } + screen_rect.validate()?; + let window = self.window.as_ref().ok_or(BackendError::Stopped)?; + window.setFrame_display(appkit_screen_frame(screen_rect, main_thread)?, true); + self.layer.setFrame(self.view.bounds()); + self.layer.setContentsScale(window.backingScaleFactor()); + self.requested_visible = visible; + let frontmost = self.parent_pid.is_some_and(application_is_frontmost); + let ordered = overlay_should_be_ordered(visible, frontmost); + if self.visible.swap(ordered, Ordering::AcqRel) != ordered { + if ordered { + window.orderFront(None); + } else { + window.orderOut(None); + } + } + Ok(()) + } + + pub(super) fn refresh_overlay_ordering(&mut self) -> Result<(), BackendError> { + if !self.overlay { + return Ok(()); + } + let window = self.window.as_ref().ok_or(BackendError::Stopped)?; + let frontmost = self.parent_pid.is_some_and(application_is_frontmost); + let ordered = overlay_should_be_ordered(self.requested_visible, frontmost); + if self.visible.swap(ordered, Ordering::AcqRel) == ordered { + return Ok(()); + } + if ordered { + window.orderFront(None); + } else { + window.orderOut(None); + } + Ok(()) + } + + pub(super) fn detach(&mut self) { + if !self.lifecycle.begin_detach() { + return; + } + match &self.attachment { + Attachment::Dedicated { + previous_layer, + previous_wants_layer, + } => { + if self.view.layer().is_some_and(|current| { + Retained::as_ptr(¤t) == Retained::as_ptr(&self.layer).cast() + }) { + self.view.setLayer(previous_layer.as_deref()); + self.view.setWantsLayer(*previous_wants_layer); + } + } + Attachment::WindowChild { .. } => self.view.removeFromSuperview(), + } + if self.owns_window { + if let Some(window) = &self.window { + window.close(); + } + } + } +} + +impl Drop for SurfaceOwner { + fn drop(&mut self) { + self.detach(); + } +} + +fn appkit_frame(parent: &NSView, bounds: RendererRect) -> CGRect { + let parent_bounds = parent.bounds(); + let parent_rect = RendererRect::new( + parent_bounds.origin.x, + parent_bounds.origin.y, + parent_bounds.size.width, + parent_bounds.size.height, + ); + let frame = bounds.to_parent_coordinates(parent_rect, parent.isFlipped()); + CGRect::new( + CGPoint::new(frame.x, frame.y), + CGSize::new(frame.width, frame.height), + ) +} + +fn appkit_screen_frame( + screen_rect: ScreenRect, + main_thread: MainThreadMarker, +) -> Result { + screen_rect.validate()?; + let primary = NSScreen::screens(main_thread) + .firstObject() + .ok_or(BackendError::MissingPrimaryScreen)?; + let primary_frame = primary.frame(); + Ok(CGRect::new( + CGPoint::new( + primary_frame.origin.x + screen_rect.x, + primary_frame.origin.y + primary_frame.size.height - screen_rect.y - screen_rect.height, + ), + CGSize::new(screen_rect.width, screen_rect.height), + )) +} + +fn application_is_frontmost(process_id: libc::pid_t) -> bool { + NSWorkspace::sharedWorkspace() + .frontmostApplication() + .is_some_and(|application| application.processIdentifier() == process_id) +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/video.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/video.rs new file mode 100644 index 000000000..daf87dbe4 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/video.rs @@ -0,0 +1,379 @@ +use std::ffi::c_void; +use std::ptr::{self, NonNull}; +use std::sync::Arc; +use std::sync::atomic::{AtomicUsize, Ordering}; + +use objc2_core_foundation::{ + CFDictionary, CFNumber, CFNumberType, CFRetained, kCFBooleanTrue, + kCFTypeDictionaryKeyCallBacks, kCFTypeDictionaryValueCallBacks, +}; +use objc2_core_media::{ + CMBlockBuffer, CMFormatDescription, CMSampleBuffer, CMSampleTimingInfo, CMTime, + CMVideoFormatDescriptionCreateFromH264ParameterSets, kCMTimeInvalid, +}; +use objc2_core_video::{ + CVImageBuffer, kCVPixelBufferIOSurfacePropertiesKey, kCVPixelBufferMetalCompatibilityKey, + kCVPixelBufferPixelFormatTypeKey, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, +}; +use objc2_video_toolbox::{ + VTDecodeFrameFlags, VTDecodeInfoFlags, VTDecompressionOutputCallbackRecord, + VTDecompressionSession, kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder, +}; + +use crate::failure::FailureReporter; +use crate::format::{FrameTiming, H264Format, VideoColorSpace}; +use crate::queue::{BoundedQueue, PushResult}; + +use super::{BackendError, Counters}; + +pub(super) struct DecodedFrame { + pub(super) image: CFRetained, + pub(super) color_space: VideoColorSpace, +} + +// The callback retains the CVImageBuffer and no code mutates it after publication to the queue. +unsafe impl Send for DecodedFrame {} + +struct InFlight { + count: AtomicUsize, + maximum: usize, +} + +impl InFlight { + fn try_acquire(&self) -> bool { + self.count + .fetch_update(Ordering::AcqRel, Ordering::Acquire, |count| { + (count < self.maximum).then_some(count + 1) + }) + .is_ok() + } + + fn release(&self) { + let previous = self.count.fetch_sub(1, Ordering::AcqRel); + debug_assert!(previous > 0); + } +} + +struct CallbackContext { + queue: Arc>, + counters: Arc, + failures: Arc, + in_flight: Arc, + color_space: VideoColorSpace, +} + +pub(super) struct VideoDecoder { + session: Option>, + format_description: CFRetained, + callback_context: Box, + in_flight: Arc, +} + +// VTDecompressionSession has no thread affinity. Shared owns VideoDecoder behind a Mutex, so +// decode, reconfiguration, and invalidation are serialized even when StreamSink moves threads. +unsafe impl Send for VideoDecoder {} + +impl VideoDecoder { + pub(super) fn new( + format: &H264Format, + queue: Arc>, + counters: Arc, + failures: Arc, + maximum_in_flight: usize, + ) -> Result { + let format_description = create_format_description(format)?; + let in_flight = Arc::new(InFlight { + count: AtomicUsize::new(0), + maximum: maximum_in_flight, + }); + let mut callback_context = Box::new(CallbackContext { + queue, + counters, + failures, + in_flight: Arc::clone(&in_flight), + color_space: format.color_space, + }); + let callback = VTDecompressionOutputCallbackRecord { + decompressionOutputCallback: Some(decompression_callback), + decompressionOutputRefCon: (&mut *callback_context as *mut CallbackContext).cast(), + }; + + let pixel_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange as i32; + let pixel_format_number = unsafe { + CFNumber::new( + None, + CFNumberType::SInt32Type, + (&pixel_format as *const i32).cast(), + ) + } + .ok_or_else(|| BackendError::Metal("failed to create CV pixel format number".into()))?; + let empty_properties = make_dictionary(&[])?; + let true_value = unsafe { kCFBooleanTrue }.ok_or_else(|| { + BackendError::Metal("CoreFoundation true value is unavailable".into()) + })?; + let pixel_format_key = unsafe { kCVPixelBufferPixelFormatTypeKey }; + let metal_compatibility_key = unsafe { kCVPixelBufferMetalCompatibilityKey }; + let io_surface_properties_key = unsafe { kCVPixelBufferIOSurfacePropertiesKey }; + let hardware_decoder_key = + unsafe { kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder }; + let destination_attributes = make_dictionary(&[ + (cf_ptr(pixel_format_key), cf_ptr(&*pixel_format_number)), + (cf_ptr(metal_compatibility_key), cf_ptr(true_value)), + ( + cf_ptr(io_surface_properties_key), + cf_ptr(&*empty_properties), + ), + ])?; + let decoder_specification = + make_dictionary(&[(cf_ptr(hardware_decoder_key), cf_ptr(true_value))])?; + + let mut session_ptr = ptr::null_mut(); + let status = unsafe { + VTDecompressionSession::create( + None, + &format_description, + Some(&decoder_specification), + Some(&destination_attributes), + &callback, + NonNull::from(&mut session_ptr), + ) + }; + check_status("VTDecompressionSessionCreate", status)?; + let session_ptr = NonNull::new(session_ptr).ok_or(BackendError::AppleApi { + api: "VTDecompressionSessionCreate", + status: -1, + })?; + let session = unsafe { CFRetained::from_raw(session_ptr) }; + + Ok(Self { + session: Some(session), + format_description, + callback_context, + in_flight, + }) + } + + pub(super) fn submit( + &self, + avcc_access_unit: &[u8], + timing: FrameTiming, + ) -> Result { + if !self.in_flight.try_acquire() { + return Ok(false); + } + let result = self.submit_acquired(avcc_access_unit, timing); + if result.is_err() { + self.in_flight.release(); + self.callback_context + .counters + .video_decode_errors + .fetch_add(1, Ordering::Relaxed); + let status = match &result { + Err(BackendError::AppleApi { status, .. }) => Some(*status), + _ => None, + }; + self.callback_context.failures.video_decode_failed(status); + } + result.map(|()| true) + } + + fn submit_acquired( + &self, + avcc_access_unit: &[u8], + timing: FrameTiming, + ) -> Result<(), BackendError> { + let mut block_ptr = ptr::null_mut(); + let status = unsafe { + CMBlockBuffer::create_with_memory_block( + None, + ptr::null_mut(), + avcc_access_unit.len(), + None, + ptr::null(), + 0, + avcc_access_unit.len(), + 0, + NonNull::from(&mut block_ptr), + ) + }; + check_status("CMBlockBufferCreateWithMemoryBlock", status)?; + let block_ptr = NonNull::new(block_ptr).ok_or(BackendError::AppleApi { + api: "CMBlockBufferCreateWithMemoryBlock", + status: -1, + })?; + let block = unsafe { CFRetained::from_raw(block_ptr) }; + let source = NonNull::new(avcc_access_unit.as_ptr().cast_mut().cast::()) + .expect("validated AVCC access unit is not empty"); + let status = + unsafe { CMBlockBuffer::replace_data_bytes(source, &block, 0, avcc_access_unit.len()) }; + check_status("CMBlockBufferReplaceDataBytes", status)?; + + let sample_timing = CMSampleTimingInfo { + duration: unsafe { CMTime::new(timing.duration_value, timing.timescale) }, + presentationTimeStamp: unsafe { + CMTime::new(timing.presentation_value, timing.timescale) + }, + decodeTimeStamp: unsafe { kCMTimeInvalid }, + }; + let sample_size = avcc_access_unit.len(); + let mut sample_ptr = ptr::null_mut(); + let status = unsafe { + CMSampleBuffer::create_ready( + None, + Some(&block), + Some(&self.format_description), + 1, + 1, + &sample_timing, + 1, + &sample_size, + NonNull::from(&mut sample_ptr), + ) + }; + check_status("CMSampleBufferCreateReady", status)?; + let sample_ptr = NonNull::new(sample_ptr).ok_or(BackendError::AppleApi { + api: "CMSampleBufferCreateReady", + status: -1, + })?; + let sample = unsafe { CFRetained::from_raw(sample_ptr) }; + let session = self.session.as_ref().ok_or(BackendError::Stopped)?; + let status = unsafe { + session.decode_frame( + &sample, + VTDecodeFrameFlags::Frame_EnableAsynchronousDecompression, + ptr::null_mut(), + ptr::null_mut(), + ) + }; + check_status("VTDecompressionSessionDecodeFrame", status) + } +} + +impl Drop for VideoDecoder { + fn drop(&mut self) { + if let Some(session) = self.session.take() { + let _ = unsafe { session.wait_for_asynchronous_frames() }; + unsafe { session.invalidate() }; + drop(session); + } + debug_assert_eq!(self.in_flight.count.load(Ordering::Acquire), 0); + let _ = &self.callback_context; + } +} + +unsafe extern "C-unwind" fn decompression_callback( + output_refcon: *mut c_void, + _source_refcon: *mut c_void, + status: i32, + _info_flags: VTDecodeInfoFlags, + image_buffer: *mut CVImageBuffer, + _presentation_time_stamp: CMTime, + _presentation_duration: CMTime, +) { + let Some(context) = NonNull::new(output_refcon.cast::()) else { + return; + }; + let context = unsafe { context.as_ref() }; + if status == 0 { + if let Some(image_buffer) = NonNull::new(image_buffer) { + let image = unsafe { CFRetained::retain(image_buffer) }; + let frame = DecodedFrame { + image, + color_space: context.color_space, + }; + context + .counters + .video_decoded + .fetch_add(1, Ordering::Relaxed); + context.failures.video_decode_succeeded(); + if matches!( + context.queue.push_drop_oldest(frame), + PushResult::Replaced(_) | PushResult::Closed(_) + ) { + context + .counters + .video_frames_dropped + .fetch_add(1, Ordering::Relaxed); + } + } else { + context + .counters + .video_decode_errors + .fetch_add(1, Ordering::Relaxed); + context.failures.video_decode_failed(None); + } + } else { + context + .counters + .video_decode_errors + .fetch_add(1, Ordering::Relaxed); + context.failures.video_decode_failed(Some(status)); + } + context.in_flight.release(); +} + +fn create_format_description( + format: &H264Format, +) -> Result, BackendError> { + let mut pointers = [ + NonNull::new(format.parameter_sets.sequence().as_ptr().cast_mut()) + .expect("validated SPS is non-empty"), + NonNull::new(format.parameter_sets.picture().as_ptr().cast_mut()) + .expect("validated PPS is non-empty"), + ]; + let mut sizes = [ + format.parameter_sets.sequence().len(), + format.parameter_sets.picture().len(), + ]; + let mut description_ptr: *const CMFormatDescription = ptr::null(); + let status = unsafe { + CMVideoFormatDescriptionCreateFromH264ParameterSets( + None, + pointers.len(), + NonNull::new(pointers.as_mut_ptr()).expect("parameter set array is non-empty"), + NonNull::new(sizes.as_mut_ptr()).expect("parameter set size array is non-empty"), + 4, + NonNull::from(&mut description_ptr), + ) + }; + check_status( + "CMVideoFormatDescriptionCreateFromH264ParameterSets", + status, + )?; + let description_ptr = + NonNull::new(description_ptr.cast_mut()).ok_or(BackendError::AppleApi { + api: "CMVideoFormatDescriptionCreateFromH264ParameterSets", + status: -1, + })?; + Ok(unsafe { CFRetained::from_raw(description_ptr) }) +} + +fn make_dictionary( + entries: &[(*const c_void, *const c_void)], +) -> Result, BackendError> { + let mut keys: Vec<_> = entries.iter().map(|(key, _)| *key).collect(); + let mut values: Vec<_> = entries.iter().map(|(_, value)| *value).collect(); + unsafe { + CFDictionary::new( + None, + keys.as_mut_ptr(), + values.as_mut_ptr(), + entries.len() as isize, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks, + ) + } + .ok_or_else(|| BackendError::Metal("failed to create CoreFoundation dictionary".into())) +} + +fn cf_ptr(value: &T) -> *const c_void { + (value as *const T).cast() +} + +fn check_status(api: &'static str, status: i32) -> Result<(), BackendError> { + if status == 0 { + Ok(()) + } else { + Err(BackendError::AppleApi { api, status }) + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/queue.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/queue.rs new file mode 100644 index 000000000..f4d87e544 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/queue.rs @@ -0,0 +1,155 @@ +use std::collections::VecDeque; +use std::sync::{Condvar, Mutex}; + +pub(crate) enum PushResult { + Pushed, + Replaced(T), + Closed(T), +} + +pub(crate) struct BoundedQueue { + capacity: usize, + state: Mutex>, + ready: Condvar, +} + +struct QueueState { + values: VecDeque, + closed: bool, +} + +impl BoundedQueue { + pub(crate) fn new(capacity: usize) -> Self { + assert!(capacity > 0); + Self { + capacity, + state: Mutex::new(QueueState { + values: VecDeque::with_capacity(capacity), + closed: false, + }), + ready: Condvar::new(), + } + } + + pub(crate) fn push_drop_oldest(&self, value: T) -> PushResult { + let mut state = self + .state + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()); + if state.closed { + return PushResult::Closed(value); + } + let replaced = if state.values.len() == self.capacity { + state.values.pop_front() + } else { + None + }; + state.values.push_back(value); + self.ready.notify_one(); + replaced.map_or(PushResult::Pushed, PushResult::Replaced) + } + + pub(crate) fn pop_wait(&self) -> Option { + let mut state = self + .state + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()); + loop { + if let Some(value) = state.values.pop_front() { + return Some(value); + } + if state.closed { + return None; + } + state = self + .ready + .wait(state) + .unwrap_or_else(|poisoned| poisoned.into_inner()); + } + } + + pub(crate) fn close(&self) { + let mut state = self + .state + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()); + state.closed = true; + self.ready.notify_all(); + } + + pub(crate) fn close_and_discard(&self) { + let mut state = self + .state + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()); + state.closed = true; + state.values.clear(); + self.ready.notify_all(); + } + + pub(crate) fn clear(&self) -> usize { + let mut state = self + .state + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()); + let discarded = state.values.len(); + state.values.clear(); + discarded + } + + #[cfg(test)] + pub(crate) fn len(&self) -> usize { + self.state + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()) + .values + .len() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::sync::Arc; + use std::thread; + + #[test] + fn replaces_oldest_at_capacity() { + let queue = BoundedQueue::new(2); + assert!(matches!(queue.push_drop_oldest(1), PushResult::Pushed)); + assert!(matches!(queue.push_drop_oldest(2), PushResult::Pushed)); + assert!(matches!(queue.push_drop_oldest(3), PushResult::Replaced(1))); + assert_eq!(queue.len(), 2); + assert_eq!(queue.pop_wait(), Some(2)); + assert_eq!(queue.pop_wait(), Some(3)); + } + + #[test] + fn close_wakes_waiter_and_rejects_pushes() { + let queue = Arc::new(BoundedQueue::::new(1)); + let waiter = { + let queue = Arc::clone(&queue); + thread::spawn(move || queue.pop_wait()) + }; + queue.close(); + assert_eq!(waiter.join().unwrap(), None); + assert!(matches!(queue.push_drop_oldest(7), PushResult::Closed(7))); + } + + #[test] + fn discard_close_drops_queued_work() { + let queue = BoundedQueue::new(2); + assert!(matches!(queue.push_drop_oldest(1), PushResult::Pushed)); + queue.close_and_discard(); + assert_eq!(queue.pop_wait(), None); + } + + #[test] + fn clear_keeps_queue_open() { + let queue = BoundedQueue::new(2); + assert!(matches!(queue.push_drop_oldest(1), PushResult::Pushed)); + assert_eq!(queue.clear(), 1); + assert!(matches!(queue.push_drop_oldest(2), PushResult::Pushed)); + assert_eq!(queue.pop_wait(), Some(2)); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/ring.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/ring.rs new file mode 100644 index 000000000..0cd626cad --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/ring.rs @@ -0,0 +1,103 @@ +use std::cell::UnsafeCell; +use std::sync::atomic::{AtomicUsize, Ordering}; + +pub(crate) struct PcmRing { + samples: Box<[UnsafeCell]>, + read: AtomicUsize, + write: AtomicUsize, +} + +// Exactly one Opus worker calls push and exactly one CoreAudio callback calls pop_into. Acquire and +// release publication prevents either side from accessing a slot while the other side owns it. +unsafe impl Send for PcmRing {} +unsafe impl Sync for PcmRing {} + +impl PcmRing { + pub(crate) fn new(capacity: usize) -> Self { + assert!(capacity > 0 && capacity < usize::MAX / 2); + Self { + samples: (0..capacity).map(|_| UnsafeCell::new(0.0)).collect(), + read: AtomicUsize::new(0), + write: AtomicUsize::new(0), + } + } + + pub(crate) fn push(&self, input: &[f32]) -> usize { + let write = self.write.load(Ordering::Relaxed); + let read = self.read.load(Ordering::Acquire); + let available = self.samples.len().saturating_sub(write.wrapping_sub(read)); + let count = input.len().min(available); + for (offset, sample) in input[..count].iter().enumerate() { + let index = write.wrapping_add(offset) % self.samples.len(); + unsafe { *self.samples[index].get() = *sample }; + } + self.write + .store(write.wrapping_add(count), Ordering::Release); + count + } + + pub(crate) fn pop_into(&self, output: &mut [f32]) -> usize { + let read = self.read.load(Ordering::Relaxed); + let write = self.write.load(Ordering::Acquire); + let count = output.len().min(write.wrapping_sub(read)); + for (offset, sample) in output[..count].iter_mut().enumerate() { + let index = read.wrapping_add(offset) % self.samples.len(); + unsafe { *sample = *self.samples[index].get() }; + } + self.read.store(read.wrapping_add(count), Ordering::Release); + count + } + + pub(crate) fn clear(&self) { + let write = self.write.load(Ordering::Acquire); + self.read.store(write, Ordering::Release); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::sync::Arc; + use std::thread; + + #[test] + fn wraps_and_preserves_pcm_order() { + let ring = PcmRing::new(4); + assert_eq!(ring.push(&[1.0, 2.0, 3.0]), 3); + let mut first = [0.0; 2]; + assert_eq!(ring.pop_into(&mut first), 2); + assert_eq!(first, [1.0, 2.0]); + assert_eq!(ring.push(&[4.0, 5.0, 6.0]), 3); + let mut second = [0.0; 4]; + assert_eq!(ring.pop_into(&mut second), 4); + assert_eq!(second, [3.0, 4.0, 5.0, 6.0]); + } + + #[test] + fn producer_and_consumer_can_run_concurrently() { + const COUNT: usize = 20_000; + let ring = Arc::new(PcmRing::new(256)); + let producer = { + let ring = Arc::clone(&ring); + thread::spawn(move || { + for value in 0..COUNT { + let sample = value as f32; + while ring.push(&[sample]) == 0 { + thread::yield_now(); + } + } + }) + }; + let mut expected = 0usize; + let mut sample = [0.0]; + while expected < COUNT { + if ring.pop_into(&mut sample) == 0 { + thread::yield_now(); + continue; + } + assert_eq!(sample[0], expected as f32); + expected += 1; + } + producer.join().unwrap(); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-windows/Cargo.toml b/native/opennow-streamer/crates/opennow-streamer-platform-windows/Cargo.toml new file mode 100644 index 000000000..47ad13535 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-windows/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "opennow-streamer-platform-windows" +version.workspace = true +edition.workspace = true +license.workspace = true +readme = "README.md" +rust-version.workspace = true + + +[target.'cfg(windows)'.dependencies] +windows = { version = "0.62", features = [ + "Win32_Foundation", + "Win32_Graphics_Direct3D10", + "Win32_Graphics_Direct3D", + "Win32_Graphics_Direct3D11", + "Win32_Graphics_Direct3D11on12", + "Win32_Graphics_Direct3D12", + "Win32_Graphics_Dxgi", + "Win32_Graphics_Dxgi_Common", + "Win32_Graphics_Gdi", + "Win32_Media_Audio", + "Win32_Media_MediaFoundation", + "Win32_Media_Multimedia", + "Win32_System_Com", + "Win32_System_Com_StructuredStorage", + "Win32_System_LibraryLoader", + "Win32_System_Threading", + "Win32_System_Variant", + "Win32_UI_WindowsAndMessaging", +] } diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-windows/README.md b/native/opennow-streamer/crates/opennow-streamer-platform-windows/README.md new file mode 100644 index 000000000..beb8303ef --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-windows/README.md @@ -0,0 +1,70 @@ +# OpenNOW Windows media backend + +This isolated crate provides the Windows media end of the native streamer. It accepts complete H.264 Annex B access units and interleaved `f32` PCM that has already been decoded from Opus. + +The backend uses only Windows system APIs: + +- Media Foundation asynchronous hardware MFTs for H.264-to-NV12 decode. The backend requires a registered hardware decoder, D3D11 awareness, and D3D11-backed output samples. It does not silently select the Media Foundation software decoder. +- A D3D11 video processor and a two-buffer flip-model DXGI swap chain for NV12 conversion, aspect-correct scaling, and presentation. The swap chain can target a caller-owned HWND, or the backend can create and own a child or top-level HWND. +- WASAPI shared-mode rendering for interleaved IEEE-float PCM. Windows performs endpoint format conversion when the active mix format differs. + +`WindowsBackend::probe_for` creates a hidden presentation path using either D3D11 or a D3D12-backed D3D11-on-12 device, configures an adapter-matched hardware H.264 transform, and starts a 48 kHz stereo WASAPI client. A capability is reported only when that complete operation succeeds. `WindowsBackend::probe` remains the D3D11 compatibility entry point. Non-Windows builds expose the same typed API but report the backend as unavailable. + +## Integration API + +```rust,no_run +use std::num::NonZeroU32; +use opennow_streamer_platform_windows::{ + AudioFormat, BackendConfig, Bounds, OwnedWindow, SurfaceTarget, VideoFormat, + WindowsBackend, +}; + +let backend = WindowsBackend::start(BackendConfig { + video: VideoFormat { + width: 1920, + height: 1080, + frame_rate_numerator: NonZeroU32::new(120).unwrap(), + frame_rate_denominator: NonZeroU32::new(1).unwrap(), + average_bitrate: 75_000_000, + }, + audio: AudioFormat { + sample_rate: 48_000, + channels: 2, + }, + surface: SurfaceTarget::Owned(OwnedWindow { + parent: None, + bounds: Bounds { + x: 0, + y: 0, + width: 1920, + height: 1080, + }, + visible: true, + }), + video_queue_capacity: 3, + audio_queue_capacity: 8, +})?; +# Ok::<(), Box>(()) +``` + +`submit_video` and `submit_audio` never wait for the media thread. When a configured queue is full, the oldest packet is discarded and the method returns `PushOutcome::DroppedOldest`. The WASAPI staging buffer is independently capped at two endpoint buffers. Events use a bounded drop-oldest queue as well, so a stalled event consumer cannot create unbounded memory growth. + +### Electron surfaces + +`SurfaceTarget::Existing` is only for a dedicated HWND that the caller reserves for D3D presentation. Do not pass an Electron `BrowserWindow` HWND as an existing surface because the swap chain and window input policy would then share Electron's interactive window. + +Electron integration must use `SurfaceTarget::Owned` with the Electron HWND in `OwnedWindow::parent`. The backend creates a child with `WS_EX_NOACTIVATE | WS_EX_TRANSPARENT`, returns `HTTRANSPARENT` from `WM_NCHITTEST`, and rejects mouse activation. The child therefore cannot take focus or consume pointer input from the renderer. `OwnedWindow::bounds` are parent-client coordinates relative to the Electron renderer. Calling `set_surface` with the same parent updates those bounds and `visible` state in place with `SWP_NOACTIVATE`; changing the parent recreates the owned child and its swap chain. + +Video and audio reconfiguration flush their respective queues. D3D11 or WASAPI failures move the backend to `Recovering`, clear stale packets, and retry for five seconds. Successful D3D recovery emits `KeyFrameRequired`; exhausted recovery emits a fatal device-loss event. `stop` closes both queues and joins the media thread, including when recovery is in progress. + +## Checks + +The crate is a member of the native streamer workspace and can also be checked directly: + +```sh +cargo test --manifest-path native/opennow-streamer/crates/opennow-streamer-platform-windows/Cargo.toml +cargo check --manifest-path native/opennow-streamer/crates/opennow-streamer-platform-windows/Cargo.toml --all-targets --target x86_64-pc-windows-msvc +cargo check --manifest-path native/opennow-streamer/crates/opennow-streamer-platform-windows/Cargo.toml --all-targets --target aarch64-pc-windows-msvc +``` + +The cross-target checks validate the Win32 bindings for x64 and ARM64. Hardware decode, presentation, audio output, device removal, and endpoint switching still require tests on real Windows hardware. diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/format.rs b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/format.rs new file mode 100644 index 000000000..53a658e3c --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/format.rs @@ -0,0 +1,373 @@ +use std::num::{NonZeroIsize, NonZeroU32}; + +use crate::BackendError; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum VideoCodec { + H264, + H265, + Av1, +} + +impl VideoCodec { + pub const fn label(self) -> &'static str { + match self { + Self::H264 => "H.264", + Self::H265 => "H.265", + Self::Av1 => "AV1", + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct VideoFormat { + pub codec: VideoCodec, + pub width: u32, + pub height: u32, + pub frame_rate_numerator: NonZeroU32, + pub frame_rate_denominator: NonZeroU32, + pub average_bitrate: u32, +} + +impl VideoFormat { + pub fn validate(self) -> Result<(), BackendError> { + if !(48..=4096).contains(&self.width) || !(48..=2304).contains(&self.height) { + return Err(BackendError::InvalidConfig(format!( + "{} dimensions must be at least 48x48 and no larger than 4096x2304", + self.codec.label() + ))); + } + let fps = self.frame_rate_numerator.get() as f64 / self.frame_rate_denominator.get() as f64; + if !(1.0..=240.0).contains(&fps) { + return Err(BackendError::InvalidConfig( + "video frame rate must be between 1 and 240 fps".to_owned(), + )); + } + if self.average_bitrate == 0 { + return Err(BackendError::InvalidConfig( + "average video bitrate must be non-zero".to_owned(), + )); + } + Ok(()) + } + + pub fn frame_duration_100ns(self) -> i64 { + (10_000_000_u64 * self.frame_rate_denominator.get() as u64 + / self.frame_rate_numerator.get() as u64) as i64 + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AudioFormat { + pub sample_rate: u32, + pub channels: u16, +} + +impl AudioFormat { + pub fn validate(self) -> Result<(), BackendError> { + if !(8_000..=192_000).contains(&self.sample_rate) { + return Err(BackendError::InvalidConfig( + "PCM sample rate must be between 8 kHz and 192 kHz".to_owned(), + )); + } + if !(1..=8).contains(&self.channels) { + return Err(BackendError::InvalidConfig( + "PCM channel count must be between 1 and 8".to_owned(), + )); + } + Ok(()) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(transparent)] +pub struct WindowHandle(NonZeroIsize); + +impl WindowHandle { + pub fn new(raw: isize) -> Option { + NonZeroIsize::new(raw).map(Self) + } + + pub fn get(self) -> isize { + self.0.get() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Bounds { + pub x: i32, + pub y: i32, + pub width: u32, + pub height: u32, +} + +impl Bounds { + pub fn validate(self) -> Result<(), BackendError> { + if self.width == 0 || self.height == 0 { + return Err(BackendError::InvalidConfig( + "surface bounds must be non-empty".to_owned(), + )); + } + if self.width > i32::MAX as u32 || self.height > i32::MAX as u32 { + return Err(BackendError::InvalidConfig( + "surface bounds exceed Win32 coordinate limits".to_owned(), + )); + } + Ok(()) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ExistingWindow { + pub hwnd: WindowHandle, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct OwnedWindow { + pub parent: Option, + pub bounds: Bounds, + pub visible: bool, +} + +impl OwnedWindow { + #[cfg_attr(not(windows), allow(dead_code))] + pub(crate) fn has_same_parent(self, other: Self) -> bool { + self.parent == other.parent + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SurfaceTarget { + /// A dedicated renderer HWND whose ownership, activation, and input policy belongs to the caller. + Existing(ExistingWindow), + /// An input-transparent, non-activating HWND owned by this backend. + Owned(OwnedWindow), +} + +impl SurfaceTarget { + pub fn validate(self) -> Result<(), BackendError> { + if let Self::Owned(window) = self { + window.bounds.validate()?; + } + Ok(()) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EncodedVideoFrame { + pub codec: VideoCodec, + pub data: Vec, + pub timestamp_100ns: i64, + pub duration_100ns: i64, + pub key_frame: bool, +} + +impl EncodedVideoFrame { + pub fn validate(&self) -> Result<(), BackendError> { + if self.data.is_empty() { + return Err(BackendError::InvalidFrame(format!( + "{} access unit is empty", + self.codec.label() + ))); + } + if matches!(self.codec, VideoCodec::H264 | VideoCodec::H265) + && !self.data.starts_with(&[0, 0, 1]) + && !self.data.starts_with(&[0, 0, 0, 1]) + { + return Err(BackendError::InvalidFrame(format!( + "{} input must use Annex B start codes", + self.codec.label() + ))); + } + if self.timestamp_100ns < 0 || self.duration_100ns <= 0 { + return Err(BackendError::InvalidFrame( + "video timestamps must be non-negative with positive duration".to_owned(), + )); + } + Ok(()) + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct PcmFrame { + pub samples: Vec, + pub format: AudioFormat, +} + +impl PcmFrame { + pub fn validate(&self) -> Result<(), BackendError> { + self.format.validate().map_err(|error| { + BackendError::InvalidFrame(format!("PCM packet format is invalid: {error}")) + })?; + if self.samples.is_empty() { + return Err(BackendError::InvalidFrame( + "PCM frame must contain samples and at least one channel".to_owned(), + )); + } + if self.samples.len() % self.format.channels as usize != 0 { + return Err(BackendError::InvalidFrame( + "interleaved PCM sample count is not divisible by channel count".to_owned(), + )); + } + if self.samples.iter().any(|sample| !sample.is_finite()) { + return Err(BackendError::InvalidFrame( + "PCM samples must be finite f32 values".to_owned(), + )); + } + let maximum_frames = self.format.sample_rate as usize * 120 / 1_000; + if self.frame_count() > maximum_frames { + return Err(BackendError::InvalidFrame( + "PCM packet exceeds the 120 ms Opus frame limit".to_owned(), + )); + } + Ok(()) + } + + pub fn frame_count(&self) -> usize { + self.samples.len() / self.format.channels as usize + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct BackendConfig { + pub video: VideoFormat, + pub audio: AudioFormat, + pub surface: SurfaceTarget, + pub video_queue_capacity: usize, + pub audio_queue_capacity: usize, +} + +impl BackendConfig { + pub fn validate(self) -> Result<(), BackendError> { + self.video.validate()?; + self.audio.validate()?; + self.surface.validate()?; + if !(1..=32).contains(&self.video_queue_capacity) { + return Err(BackendError::InvalidConfig( + "video queue capacity must be between 1 and 32 frames".to_owned(), + )); + } + if !(1..=256).contains(&self.audio_queue_capacity) { + return Err(BackendError::InvalidConfig( + "audio queue capacity must be between 1 and 256 packets".to_owned(), + )); + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn video_format() -> VideoFormat { + VideoFormat { + codec: VideoCodec::H264, + width: 1920, + height: 1080, + frame_rate_numerator: NonZeroU32::new(120).unwrap(), + frame_rate_denominator: NonZeroU32::new(1).unwrap(), + average_bitrate: 75_000_000, + } + } + + #[test] + fn validates_supported_h264_format() { + let format = video_format(); + assert!(format.validate().is_ok()); + assert_eq!(format.frame_duration_100ns(), 83_333); + } + + #[test] + fn rejects_out_of_range_h264_format() { + assert!( + VideoFormat { + width: 16, + ..video_format() + } + .validate() + .is_err() + ); + assert!( + VideoFormat { + average_bitrate: 0, + ..video_format() + } + .validate() + .is_err() + ); + } + + #[test] + fn requires_annex_b_access_units() { + let valid = EncodedVideoFrame { + codec: VideoCodec::H264, + data: vec![0, 0, 0, 1, 0x67], + timestamp_100ns: 0, + duration_100ns: 166_667, + key_frame: true, + }; + assert!(valid.validate().is_ok()); + assert!( + EncodedVideoFrame { + data: vec![1, 2, 3], + ..valid + } + .validate() + .is_err() + ); + } + + #[test] + fn validates_interleaved_pcm_shape() { + let frame = PcmFrame { + samples: vec![0.0, 0.25, -0.25, 0.0], + format: AudioFormat { + sample_rate: 48_000, + channels: 2, + }, + }; + assert_eq!(frame.frame_count(), 2); + assert!(frame.validate().is_ok()); + assert!( + PcmFrame { + samples: vec![0.0], + format: frame.format, + } + .validate() + .is_err() + ); + } + + #[test] + fn owned_surface_updates_preserve_parent_ownership() { + let parent = WindowHandle::new(1).unwrap(); + let original = OwnedWindow { + parent: Some(parent), + bounds: Bounds { + x: 0, + y: 0, + width: 1280, + height: 720, + }, + visible: true, + }; + let moved_and_hidden = OwnedWindow { + bounds: Bounds { + x: 40, + y: 20, + width: 960, + height: 540, + }, + visible: false, + ..original + }; + let reparented = OwnedWindow { + parent: WindowHandle::new(2), + ..moved_and_hidden + }; + + assert!(original.has_same_parent(moved_and_hidden)); + assert!(!original.has_same_parent(reparented)); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/lib.rs b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/lib.rs new file mode 100644 index 000000000..c01b9c8dc --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/lib.rs @@ -0,0 +1,586 @@ +#![deny(unsafe_op_in_unsafe_fn)] + +mod format; +mod queue; + +#[cfg(windows)] +mod windows; + +use std::sync::atomic::{AtomicU8, AtomicU64, Ordering}; +use std::sync::{Arc, Mutex, mpsc}; +use std::thread::JoinHandle; + +use crate::queue::BoundedQueue; + +pub use format::{ + AudioFormat, BackendConfig, Bounds, EncodedVideoFrame, ExistingWindow, OwnedWindow, PcmFrame, + SurfaceTarget, VideoCodec, VideoFormat, WindowHandle, +}; +pub use queue::PushOutcome; + +/// Burst allowance for adaptive video delivery. The decoded presenter uses +/// the same bound and trims stale frames before presentation, keeping latency +/// low without treating ordinary game-FPS fluctuations as decoder loss. +pub const ADAPTIVE_VIDEO_QUEUE_CAPACITY: usize = 7; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +pub enum LifecycleState { + Starting = 0, + Running = 1, + Reconfiguring = 2, + Recovering = 3, + Stopping = 4, + Stopped = 5, + Failed = 6, +} + +impl LifecycleState { + fn from_raw(value: u8) -> Self { + match value { + 0 => Self::Starting, + 1 => Self::Running, + 2 => Self::Reconfiguring, + 3 => Self::Recovering, + 4 => Self::Stopping, + 5 => Self::Stopped, + _ => Self::Failed, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Subsystem { + VideoDecode, + VideoPresentation, + Audio, +} + +/// Graphics API that owns the Windows decode/presentation device. D3D12 uses +/// Microsoft's D3D11-on-12 layer so Media Foundation can keep its required +/// D3D11 device-manager contract while work is submitted to a D3D12 queue. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum WindowsGraphicsApi { + D3d11, + D3d12, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum BackendEvent { + StateChanged(LifecycleState), + FirstFramePresented, + QueueOverflow(Subsystem), + VideoFormatChanged(VideoFormat), + DeviceLost { + subsystem: Subsystem, + message: String, + }, + DeviceRecovered(Subsystem), + KeyFrameRequired, + Fatal(BackendError), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct CapabilityProbe { + pub available: bool, + pub h264_hardware_decode: bool, + pub h265_hardware_decode: bool, + pub av1_hardware_decode: bool, + pub d3d11_presentation: bool, + pub wasapi_render: bool, + pub reason: Option, +} + +impl CapabilityProbe { + pub const fn bundled_backend_available(&self) -> bool { + (self.h264_hardware_decode || self.h265_hardware_decode || self.av1_hardware_decode) + && self.d3d11_presentation + && self.wasapi_render + } +} + +#[cfg(any(windows, test))] +struct DefaultEndpointTracker { + active_id: String, + reported_id: Option, +} + +#[cfg(any(windows, test))] +impl DefaultEndpointTracker { + fn new(active_id: String) -> Self { + Self { + active_id, + reported_id: None, + } + } + + fn observe(&mut self, current_id: String) -> bool { + if current_id == self.active_id { + self.reported_id = None; + return false; + } + if self.reported_id.as_ref() == Some(¤t_id) { + return false; + } + self.reported_id = Some(current_id); + true + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum BackendError { + UnsupportedPlatform, + InvalidConfig(String), + InvalidFrame(String), + NotRunning(LifecycleState), + Startup(String), + Reconfigure(String), + DeviceLost { + subsystem: Subsystem, + message: String, + }, + WorkerDisconnected, +} + +impl std::fmt::Display for BackendError { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::UnsupportedPlatform => { + formatter.write_str("the Windows media backend is unavailable on this platform") + } + Self::InvalidConfig(message) => { + write!(formatter, "invalid backend configuration: {message}") + } + Self::InvalidFrame(message) => write!(formatter, "invalid media frame: {message}"), + Self::NotRunning(state) => write!(formatter, "backend is not running ({state:?})"), + Self::Startup(message) => write!(formatter, "backend startup failed: {message}"), + Self::Reconfigure(message) => { + write!(formatter, "backend reconfiguration failed: {message}") + } + Self::DeviceLost { subsystem, message } => { + write!(formatter, "{subsystem:?} device was lost: {message}") + } + Self::WorkerDisconnected => formatter.write_str("backend worker disconnected"), + } + } +} + +impl std::error::Error for BackendError {} + +#[derive(Debug)] +#[cfg_attr(not(windows), allow(dead_code))] +enum Control { + ReconfigureVideo(VideoFormat), + ReconfigureAudio(AudioFormat), + SetSurface(SurfaceTarget), + SetPaused(bool), + Stop, +} + +#[derive(Debug)] +struct Shared { + video: BoundedQueue, + audio: BoundedQueue, + video_format: Mutex, + audio_format: Mutex, + surface: Mutex, + state: AtomicU8, + paused: std::sync::atomic::AtomicBool, + events: BoundedQueue, + presented_frames: AtomicU64, +} + +impl Shared { + fn state(&self) -> LifecycleState { + LifecycleState::from_raw(self.state.load(Ordering::Acquire)) + } + + fn set_state(&self, state: LifecycleState) { + self.state.store(state as u8, Ordering::Release); + let _ = self.events.push(BackendEvent::StateChanged(state)); + } +} + +pub struct WindowsBackend { + shared: Arc, + control: mpsc::Sender, + worker: Mutex>>, +} + +impl WindowsBackend { + pub fn probe() -> CapabilityProbe { + Self::probe_for(WindowsGraphicsApi::D3d11) + } + + pub fn probe_for(api: WindowsGraphicsApi) -> CapabilityProbe { + #[cfg(windows)] + { + windows::probe(api) + } + #[cfg(not(windows))] + { + CapabilityProbe { + available: false, + h264_hardware_decode: false, + h265_hardware_decode: false, + av1_hardware_decode: false, + d3d11_presentation: false, + wasapi_render: false, + reason: Some("the current target is not Windows".to_owned()), + } + } + } + + pub fn start(config: BackendConfig) -> Result { + Self::start_for(WindowsGraphicsApi::D3d11, config) + } + + pub fn start_for(api: WindowsGraphicsApi, config: BackendConfig) -> Result { + config.validate()?; + + #[cfg(not(windows))] + { + let _ = config; + Err(BackendError::UnsupportedPlatform) + } + + #[cfg(windows)] + { + let shared = Arc::new(Shared { + video: BoundedQueue::new(config.video_queue_capacity), + audio: BoundedQueue::new(config.audio_queue_capacity), + video_format: Mutex::new(config.video), + audio_format: Mutex::new(config.audio), + surface: Mutex::new(config.surface), + state: AtomicU8::new(LifecycleState::Starting as u8), + paused: std::sync::atomic::AtomicBool::new(false), + events: BoundedQueue::new(64), + presented_frames: AtomicU64::new(0), + }); + let (control_sender, control_receiver) = mpsc::channel(); + let worker = windows::spawn(api, config, Arc::clone(&shared), control_receiver)?; + Ok(Self { + shared, + control: control_sender, + worker: Mutex::new(Some(worker)), + }) + } + } + + pub fn state(&self) -> LifecycleState { + self.shared.state() + } + + pub fn presented_frames(&self) -> u64 { + self.shared.presented_frames.load(Ordering::Relaxed) + } + + pub fn submit_video(&self, frame: EncodedVideoFrame) -> Result { + frame.validate()?; + self.ensure_media_accepting()?; + if self.shared.paused.load(Ordering::Acquire) { + return Ok(PushOutcome::Paused); + } + let outcome = self + .shared + .video + .push_or_clear_on_overflow(frame) + .map_err(|_| BackendError::NotRunning(self.state()))?; + if outcome == PushOutcome::DroppedOldest { + let _ = self + .shared + .events + .push(BackendEvent::QueueOverflow(Subsystem::VideoDecode)); + } + Ok(outcome) + } + + pub fn submit_audio(&self, frame: PcmFrame) -> Result { + frame.validate()?; + self.ensure_media_accepting()?; + if self.shared.paused.load(Ordering::Acquire) { + return Ok(PushOutcome::Paused); + } + let expected_format = *self + .shared + .audio_format + .lock() + .unwrap_or_else(|error| error.into_inner()); + if frame.format != expected_format { + return Err(BackendError::InvalidFrame(format!( + "PCM packet format {:?} does not match active format {:?}", + frame.format, expected_format + ))); + } + let outcome = self + .shared + .audio + .push(frame) + .map_err(|_| BackendError::NotRunning(self.state()))?; + if outcome == PushOutcome::DroppedOldest { + let _ = self + .shared + .events + .push(BackendEvent::QueueOverflow(Subsystem::Audio)); + } + Ok(outcome) + } + + pub fn reconfigure_video(&self, format: VideoFormat) -> Result<(), BackendError> { + format.validate()?; + self.ensure_controllable()?; + self.shared.video.clear(); + *self + .shared + .video_format + .lock() + .unwrap_or_else(|error| error.into_inner()) = format; + self.shared.set_state(LifecycleState::Reconfiguring); + self.control + .send(Control::ReconfigureVideo(format)) + .map_err(|_| BackendError::WorkerDisconnected) + } + + pub fn reconfigure_audio(&self, format: AudioFormat) -> Result<(), BackendError> { + format.validate()?; + self.ensure_controllable()?; + self.shared.audio.clear(); + *self + .shared + .audio_format + .lock() + .unwrap_or_else(|error| error.into_inner()) = format; + self.shared.set_state(LifecycleState::Reconfiguring); + self.control + .send(Control::ReconfigureAudio(format)) + .map_err(|_| BackendError::WorkerDisconnected) + } + + pub fn set_surface(&self, surface: SurfaceTarget) -> Result<(), BackendError> { + surface.validate()?; + self.ensure_controllable()?; + *self + .shared + .surface + .lock() + .unwrap_or_else(|error| error.into_inner()) = surface; + self.shared.set_state(LifecycleState::Reconfiguring); + self.control + .send(Control::SetSurface(surface)) + .map_err(|_| BackendError::WorkerDisconnected) + } + + pub fn set_paused(&self, paused: bool) -> Result<(), BackendError> { + self.ensure_controllable()?; + if self.shared.paused.swap(paused, Ordering::AcqRel) == paused { + return Ok(()); + } + self.shared.video.clear(); + self.shared.audio.clear(); + self.control + .send(Control::SetPaused(paused)) + .map_err(|_| BackendError::WorkerDisconnected) + } + + pub fn try_event(&self) -> Option { + self.shared.events.try_pop() + } + + pub fn stop(&self) { + let state = self.state(); + if matches!(state, LifecycleState::Stopped | LifecycleState::Stopping) { + return; + } + let was_failed = state == LifecycleState::Failed; + if !was_failed { + self.shared.set_state(LifecycleState::Stopping); + } + self.shared.video.close(); + self.shared.audio.close(); + let _ = self.control.send(Control::Stop); + if let Some(worker) = self + .worker + .lock() + .unwrap_or_else(|error| error.into_inner()) + .take() + { + let _ = worker.join(); + } + if !was_failed && self.state() != LifecycleState::Failed { + self.shared.set_state(LifecycleState::Stopped); + } + } + + fn ensure_media_accepting(&self) -> Result<(), BackendError> { + let state = self.state(); + if matches!( + state, + LifecycleState::Running | LifecycleState::Reconfiguring + ) { + Ok(()) + } else { + Err(BackendError::NotRunning(state)) + } + } + + fn ensure_controllable(&self) -> Result<(), BackendError> { + let state = self.state(); + if matches!( + state, + LifecycleState::Running | LifecycleState::Reconfiguring | LifecycleState::Recovering + ) { + Ok(()) + } else { + Err(BackendError::NotRunning(state)) + } + } +} + +impl Drop for WindowsBackend { + fn drop(&mut self) { + self.stop(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn test_backend(state: LifecycleState) -> (WindowsBackend, Arc) { + let (control_sender, _control_receiver) = mpsc::channel(); + let shared = Arc::new(Shared { + video: BoundedQueue::new(2), + audio: BoundedQueue::new(2), + video_format: Mutex::new(VideoFormat { + codec: VideoCodec::H264, + width: 1920, + height: 1080, + frame_rate_numerator: std::num::NonZeroU32::new(60).unwrap(), + frame_rate_denominator: std::num::NonZeroU32::new(1).unwrap(), + average_bitrate: 10_000_000, + }), + audio_format: Mutex::new(AudioFormat { + sample_rate: 48_000, + channels: 2, + }), + surface: Mutex::new(SurfaceTarget::Owned(OwnedWindow { + parent: None, + bounds: Bounds { + x: 0, + y: 0, + width: 1280, + height: 720, + }, + visible: false, + })), + state: AtomicU8::new(state as u8), + paused: std::sync::atomic::AtomicBool::new(false), + events: BoundedQueue::new(8), + presented_frames: AtomicU64::new(0), + }); + let backend = WindowsBackend { + shared: Arc::clone(&shared), + control: control_sender, + worker: Mutex::new(None), + }; + (backend, shared) + } + + #[test] + fn non_windows_probe_never_advertises_capabilities() { + if !cfg!(windows) { + let probe = WindowsBackend::probe(); + assert!(!probe.available); + assert!(!probe.h264_hardware_decode); + assert!(!probe.h265_hardware_decode); + assert!(!probe.av1_hardware_decode); + assert!(!probe.d3d11_presentation); + assert!(!probe.wasapi_render); + } + } + + #[test] + fn bundled_backend_requires_wasapi_start() { + let mut probe = CapabilityProbe { + available: false, + h264_hardware_decode: true, + h265_hardware_decode: true, + av1_hardware_decode: true, + d3d11_presentation: true, + wasapi_render: false, + reason: Some("WASAPI failed to start".to_owned()), + }; + + assert!(!probe.bundled_backend_available()); + probe.wasapi_render = true; + assert!(probe.bundled_backend_available()); + } + + #[test] + fn endpoint_change_is_reported_once_per_transition() { + let mut tracker = DefaultEndpointTracker::new("speakers".to_owned()); + + assert!(!tracker.observe("speakers".to_owned())); + assert!(tracker.observe("headset".to_owned())); + assert!(!tracker.observe("headset".to_owned())); + assert!(!tracker.observe("speakers".to_owned())); + assert!(tracker.observe("headset".to_owned())); + } + + #[test] + fn lifecycle_state_round_trips_atomic_values() { + for state in [ + LifecycleState::Starting, + LifecycleState::Running, + LifecycleState::Reconfiguring, + LifecycleState::Recovering, + LifecycleState::Stopping, + LifecycleState::Stopped, + LifecycleState::Failed, + ] { + assert_eq!(LifecycleState::from_raw(state as u8), state); + } + } + + #[test] + fn stop_closes_media_queues_and_is_idempotent() { + let (backend, shared) = test_backend(LifecycleState::Running); + + backend.stop(); + backend.stop(); + + assert_eq!(backend.state(), LifecycleState::Stopped); + assert!(shared.video.is_closed()); + assert!(shared.audio.is_closed()); + + shared + .state + .store(LifecycleState::Failed as u8, Ordering::Release); + backend.stop(); + assert_eq!(backend.state(), LifecycleState::Failed); + } + + #[test] + fn surface_reconfiguration_keeps_accepting_media_frames() { + let (backend, shared) = test_backend(LifecycleState::Reconfiguring); + let video_outcome = backend.submit_video(EncodedVideoFrame { + codec: VideoCodec::H264, + data: vec![0, 0, 0, 1, 0x67], + timestamp_100ns: 0, + duration_100ns: 166_667, + key_frame: true, + }); + let audio_outcome = backend.submit_audio(PcmFrame { + samples: vec![0.0, 0.0], + format: AudioFormat { + sample_rate: 48_000, + channels: 2, + }, + }); + + assert_eq!(video_outcome, Ok(PushOutcome::Queued)); + assert_eq!(audio_outcome, Ok(PushOutcome::Queued)); + assert!(shared.video.try_pop().is_some()); + assert!(shared.audio.try_pop().is_some()); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/queue.rs b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/queue.rs new file mode 100644 index 000000000..b9f9f8ea0 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/queue.rs @@ -0,0 +1,161 @@ +use std::collections::VecDeque; +use std::sync::{Condvar, Mutex}; +#[cfg(test)] +use std::time::Duration; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PushOutcome { + Queued, + DroppedOldest, + Paused, +} + +#[derive(Debug)] +struct Inner { + values: VecDeque, + closed: bool, +} + +#[derive(Debug)] +pub(crate) struct BoundedQueue { + capacity: usize, + inner: Mutex>, + ready: Condvar, +} + +#[cfg_attr(not(windows), allow(dead_code))] +impl BoundedQueue { + pub(crate) fn new(capacity: usize) -> Self { + assert!(capacity > 0, "queue capacity must be non-zero"); + Self { + capacity, + inner: Mutex::new(Inner { + values: VecDeque::with_capacity(capacity), + closed: false, + }), + ready: Condvar::new(), + } + } + + pub(crate) fn push(&self, value: T) -> Result { + let mut inner = self.inner.lock().unwrap_or_else(|error| error.into_inner()); + if inner.closed { + return Err(value); + } + let outcome = if inner.values.len() == self.capacity { + inner.values.pop_front(); + PushOutcome::DroppedOldest + } else { + PushOutcome::Queued + }; + inner.values.push_back(value); + self.ready.notify_one(); + Ok(outcome) + } + + /// Queues compressed inter-frame video without creating a broken reference + /// chain. Once full, every pending access unit and the incoming unit are + /// stale; retaining any of them after dropping an older reference frame can + /// make the hardware decoder reject the stream. The caller requests a new + /// keyframe after receiving `DroppedOldest`. + pub(crate) fn push_or_clear_on_overflow(&self, value: T) -> Result { + let mut inner = self.inner.lock().unwrap_or_else(|error| error.into_inner()); + if inner.closed { + return Err(value); + } + if inner.values.len() == self.capacity { + inner.values.clear(); + return Ok(PushOutcome::DroppedOldest); + } + inner.values.push_back(value); + self.ready.notify_one(); + Ok(PushOutcome::Queued) + } + + pub(crate) fn try_pop(&self) -> Option { + self.inner + .lock() + .unwrap_or_else(|error| error.into_inner()) + .values + .pop_front() + } + + #[cfg(test)] + pub(crate) fn pop_timeout(&self, timeout: Duration) -> Option { + let inner = self.inner.lock().unwrap_or_else(|error| error.into_inner()); + let mut inner = self + .ready + .wait_timeout_while(inner, timeout, |inner| { + inner.values.is_empty() && !inner.closed + }) + .unwrap_or_else(|error| error.into_inner()) + .0; + inner.values.pop_front() + } + + pub(crate) fn clear(&self) { + self.inner + .lock() + .unwrap_or_else(|error| error.into_inner()) + .values + .clear(); + } + + pub(crate) fn close(&self) { + let mut inner = self.inner.lock().unwrap_or_else(|error| error.into_inner()); + inner.closed = true; + inner.values.clear(); + self.ready.notify_all(); + } + + #[cfg(test)] + pub(crate) fn is_closed(&self) -> bool { + self.inner + .lock() + .unwrap_or_else(|error| error.into_inner()) + .closed + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn drops_oldest_value_when_full() { + let queue = BoundedQueue::new(2); + assert_eq!(queue.push(1), Ok(PushOutcome::Queued)); + assert_eq!(queue.push(2), Ok(PushOutcome::Queued)); + assert_eq!(queue.push(3), Ok(PushOutcome::DroppedOldest)); + assert_eq!(queue.try_pop(), Some(2)); + assert_eq!(queue.try_pop(), Some(3)); + } + + #[test] + fn video_overflow_discards_the_pending_reference_chain() { + let queue = BoundedQueue::new(2); + assert_eq!(queue.push_or_clear_on_overflow(1), Ok(PushOutcome::Queued)); + assert_eq!(queue.push_or_clear_on_overflow(2), Ok(PushOutcome::Queued)); + assert_eq!( + queue.push_or_clear_on_overflow(3), + Ok(PushOutcome::DroppedOldest) + ); + assert_eq!(queue.try_pop(), None); + } + + #[test] + fn close_discards_values_and_rejects_writes() { + let queue = BoundedQueue::new(2); + queue.push(1).unwrap(); + queue.close(); + assert!(queue.is_closed()); + assert_eq!(queue.try_pop(), None); + assert_eq!(queue.push(2), Err(2)); + } + + #[test] + fn timeout_returns_without_a_value() { + let queue = BoundedQueue::::new(1); + assert_eq!(queue.pop_timeout(Duration::from_millis(1)), None); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/audio.rs b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/audio.rs new file mode 100644 index 000000000..a7961e225 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/audio.rs @@ -0,0 +1,200 @@ +use std::collections::VecDeque; +use std::time::{Duration, Instant}; + +use ::windows::Win32::Media::Audio::{ + AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM, + AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY, IAudioClient, IAudioRenderClient, IMMDeviceEnumerator, + MMDeviceEnumerator, WAVEFORMATEX, eConsole, eRender, +}; +use ::windows::Win32::System::Com::{CLSCTX_ALL, CoCreateInstance, CoTaskMemFree}; + +use crate::queue::BoundedQueue; +use crate::{AudioFormat, DefaultEndpointTracker, PcmFrame}; + +const WAVE_FORMAT_IEEE_FLOAT: u16 = 3; +const BUFFER_DURATION_100NS: i64 = 200_000; +const ENDPOINT_CHECK_INTERVAL: Duration = Duration::from_millis(250); + +pub(super) struct AudioRenderer { + enumerator: IMMDeviceEnumerator, + render: IAudioRenderClient, + client: IAudioClient, + buffer_frames: u32, + format: AudioFormat, + pending: VecDeque, + pending_capacity: usize, + paused: bool, + endpoint_tracker: DefaultEndpointTracker, + next_endpoint_check: Instant, +} + +impl AudioRenderer { + pub(super) fn probe() -> Result<(), String> { + let mut renderer = Self::new(AudioFormat { + sample_rate: 48_000, + channels: 2, + })?; + renderer.stop(); + Ok(()) + } + + pub(super) fn new(format: AudioFormat) -> Result { + let block_align = format + .channels + .checked_mul(4) + .ok_or("PCM block alignment overflow")?; + let wave_format = WAVEFORMATEX { + wFormatTag: WAVE_FORMAT_IEEE_FLOAT, + nChannels: format.channels, + nSamplesPerSec: format.sample_rate, + nAvgBytesPerSec: format + .sample_rate + .checked_mul(block_align as u32) + .ok_or("PCM byte rate overflow")?, + nBlockAlign: block_align, + wBitsPerSample: 32, + cbSize: 0, + }; + + unsafe { + let enumerator: IMMDeviceEnumerator = + CoCreateInstance(&MMDeviceEnumerator, None, CLSCTX_ALL) + .map_err(|error| error.to_string())?; + let device = enumerator + .GetDefaultAudioEndpoint(eRender, eConsole) + .map_err(|error| error.to_string())?; + let endpoint_id = device_id(&device)?; + let client: IAudioClient = device + .Activate(CLSCTX_ALL, None) + .map_err(|error| error.to_string())?; + client + .Initialize( + AUDCLNT_SHAREMODE_SHARED, + AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY, + BUFFER_DURATION_100NS, + 0, + &wave_format, + None, + ) + .map_err(|error| error.to_string())?; + let buffer_frames = client.GetBufferSize().map_err(|error| error.to_string())?; + let render: IAudioRenderClient = + client.GetService().map_err(|error| error.to_string())?; + client.Start().map_err(|error| error.to_string())?; + Ok(Self { + enumerator, + render, + client, + buffer_frames, + format, + pending: VecDeque::new(), + pending_capacity: buffer_frames as usize * format.channels as usize * 2, + paused: false, + endpoint_tracker: DefaultEndpointTracker::new(endpoint_id), + next_endpoint_check: Instant::now() + ENDPOINT_CHECK_INTERVAL, + }) + } + } + + pub(super) fn default_endpoint_changed(&mut self) -> Result { + let now = Instant::now(); + if now < self.next_endpoint_check { + return Ok(false); + } + self.next_endpoint_check = now + ENDPOINT_CHECK_INTERVAL; + let device = unsafe { + self.enumerator + .GetDefaultAudioEndpoint(eRender, eConsole) + .map_err(|error| error.to_string())? + }; + let endpoint_id = device_id(&device)?; + Ok(self.endpoint_tracker.observe(endpoint_id)) + } + + pub(super) fn render(&mut self, queue: &BoundedQueue) -> Result { + let mut dropped = false; + while let Some(frame) = queue.try_pop() { + if frame.format != self.format { + return Err(format!( + "PCM packet format {:?} does not match active format {:?}", + frame.format, self.format + )); + } + self.pending.extend(frame.samples); + while self.pending.len() > self.pending_capacity { + self.pending.pop_front(); + dropped = true; + } + } + if self.pending.is_empty() { + return Ok(dropped); + } + + unsafe { + let padding = self + .client + .GetCurrentPadding() + .map_err(|error| error.to_string())?; + let available_frames = self.buffer_frames.saturating_sub(padding); + let pending_frames = self.pending.len() / self.format.channels as usize; + let write_frames = available_frames.min(pending_frames as u32); + if write_frames == 0 { + return Ok(dropped); + } + let sample_count = write_frames as usize * self.format.channels as usize; + let destination = self + .render + .GetBuffer(write_frames) + .map_err(|error| error.to_string())? as *mut f32; + for index in 0..sample_count { + destination + .add(index) + .write(self.pending.pop_front().unwrap_or(0.0)); + } + self.render + .ReleaseBuffer(write_frames, 0) + .map_err(|error| error.to_string())?; + } + Ok(dropped) + } + + pub(super) fn stop(&mut self) { + unsafe { + let _ = self.client.Stop(); + } + self.pending.clear(); + self.paused = true; + } + + pub(super) fn set_paused(&mut self, paused: bool) -> Result<(), String> { + if self.paused == paused { + return Ok(()); + } + self.pending.clear(); + unsafe { + if paused { + self.client.Stop() + } else { + self.client.Start() + } + .map_err(|error| error.to_string()) + }?; + self.paused = paused; + Ok(()) + } +} + +impl Drop for AudioRenderer { + fn drop(&mut self) { + self.stop(); + } +} + +fn device_id(device: &::windows::Win32::Media::Audio::IMMDevice) -> Result { + unsafe { + let id = device.GetId().map_err(|error| error.to_string())?; + let result = id.to_string().map_err(|error| error.to_string()); + CoTaskMemFree(Some(id.0.cast())); + result + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/decoder.rs b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/decoder.rs new file mode 100644 index 000000000..28c34ead0 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/decoder.rs @@ -0,0 +1,557 @@ +use std::collections::VecDeque; +use std::ffi::c_void; +use std::mem::ManuallyDrop; +use std::mem::size_of; +use std::ptr; + +use ::windows::Win32::Foundation::{E_NOTIMPL, LUID}; +use ::windows::Win32::Graphics::Direct3D11::ID3D11Texture2D; +use ::windows::Win32::Media::MediaFoundation::{ + IMFActivate, IMFAttributes, IMFDXGIBuffer, IMFMediaEventGenerator, IMFSample, IMFTransform, + METransformHaveOutput, METransformNeedInput, MF_E_NO_EVENTS_AVAILABLE, + MF_E_TRANSFORM_NEED_MORE_INPUT, MF_E_TRANSFORM_STREAM_CHANGE, MF_EVENT_FLAG_NO_WAIT, + MF_LOW_LATENCY, MF_MT_AVG_BITRATE, MF_MT_FRAME_RATE, MF_MT_FRAME_SIZE, MF_MT_INTERLACE_MODE, + MF_MT_MAJOR_TYPE, MF_MT_PIXEL_ASPECT_RATIO, MF_MT_SUBTYPE, MF_SA_D3D11_AWARE, + MF_TRANSFORM_ASYNC, MF_TRANSFORM_ASYNC_UNLOCK, MFCreateAttributes, MFCreateMediaType, + MFCreateMemoryBuffer, MFCreateSample, MFMediaType_Video, MFSampleExtension_CleanPoint, + MFT_CATEGORY_VIDEO_DECODER, MFT_ENUM_ADAPTER_LUID, MFT_ENUM_FLAG, MFT_ENUM_FLAG_HARDWARE, + MFT_ENUM_FLAG_SORTANDFILTER, MFT_ENUM_FLAG_SYNCMFT, MFT_MESSAGE_COMMAND_FLUSH, + MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, MFT_MESSAGE_NOTIFY_END_OF_STREAM, + MFT_MESSAGE_NOTIFY_END_STREAMING, MFT_MESSAGE_NOTIFY_START_OF_STREAM, + MFT_MESSAGE_SET_D3D_MANAGER, MFT_OUTPUT_DATA_BUFFER, MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES, + MFT_OUTPUT_STREAM_PROVIDES_SAMPLES, MFT_REGISTER_TYPE_INFO, MFTEnum2, MFVideoFormat_AV1, + MFVideoFormat_H264, MFVideoFormat_HEVC, MFVideoFormat_NV12, MFVideoFormat_P010, + MFVideoInterlace_MixedInterlaceOrProgressive, +}; +use ::windows::Win32::System::Com::CoTaskMemFree; +use ::windows::core::Interface; + +use crate::queue::BoundedQueue; +use crate::{ + ADAPTIVE_VIDEO_QUEUE_CAPACITY, BackendEvent, EncodedVideoFrame, Subsystem, VideoCodec, + VideoFormat, +}; + +use super::graphics::Graphics; + +pub(super) struct DecodedVideoFrame { + pub(super) texture: ID3D11Texture2D, + pub(super) subresource: u32, + pub(super) timestamp_100ns: i64, + pub(super) duration_100ns: i64, +} + +pub(super) struct Decoder { + events: Option, + transform: IMFTransform, + activation: IMFActivate, + input_stream: u32, + output_stream: u32, + input_credits: u32, + format: VideoFormat, + output_provides_samples: bool, + stopped: bool, +} + +impl Decoder { + pub(super) fn probe(graphics: &Graphics, codec: VideoCodec) -> Result<(), String> { + let mut decoder = Self::new( + graphics, + VideoFormat { + codec, + ..graphics.video_format() + }, + )?; + decoder.stop(); + Ok(()) + } + + pub(super) fn new(graphics: &Graphics, format: VideoFormat) -> Result { + let activations = enumerate_decoders(graphics.adapter_luid()?, format.codec)?; + let mut failures = Vec::new(); + for activation in activations { + match configure_transform(&activation, graphics, format) { + Ok((transform, events, input_stream, output_stream, output_provides_samples)) => { + let input_credits = u32::from(events.is_none()); + return Ok(Self { + events, + transform, + activation, + input_stream, + output_stream, + input_credits, + format, + output_provides_samples, + stopped: false, + }); + } + Err(error) => { + failures.push(error); + unsafe { + let _ = activation.ShutdownObject(); + } + } + } + } + Err(if failures.is_empty() { + format!( + "no D3D11-aware {} decoder MFT is registered", + format.codec.label() + ) + } else { + format!( + "registered {} decoders rejected the D3D11 configuration: {}", + format.codec.label(), + failures.join("; ") + ) + }) + } + + pub(super) fn wants_input(&self) -> bool { + self.input_credits > 0 && !self.stopped + } + + pub(super) fn format(&self) -> VideoFormat { + self.format + } + + pub(super) fn submit(&mut self, frame: EncodedVideoFrame) -> Result<(), String> { + if self.input_credits == 0 { + return Err("decoder input was submitted without a NeedInput credit".to_owned()); + } + unsafe { + if frame.codec != self.format.codec { + return Err(format!( + "{} decoder received a {} access unit", + self.format.codec.label(), + frame.codec.label() + )); + } + let buffer = + MFCreateMemoryBuffer(frame.data.len() as u32).map_err(|error| error.to_string())?; + let mut destination = ptr::null_mut(); + buffer + .Lock(&mut destination, None, None) + .map_err(|error| error.to_string())?; + ptr::copy_nonoverlapping(frame.data.as_ptr(), destination, frame.data.len()); + let unlock_result = buffer.Unlock(); + unlock_result.map_err(|error| error.to_string())?; + buffer + .SetCurrentLength(frame.data.len() as u32) + .map_err(|error| error.to_string())?; + let sample = MFCreateSample().map_err(|error| error.to_string())?; + sample + .AddBuffer(&buffer) + .map_err(|error| error.to_string())?; + sample + .SetSampleTime(frame.timestamp_100ns) + .map_err(|error| error.to_string())?; + sample + .SetSampleDuration(frame.duration_100ns) + .map_err(|error| error.to_string())?; + if frame.key_frame { + sample + .SetUINT32(&MFSampleExtension_CleanPoint, 1) + .map_err(|error| error.to_string())?; + } + self.transform + .ProcessInput(self.input_stream, &sample, 0) + .map_err(|error| error.to_string())?; + } + self.input_credits -= 1; + Ok(()) + } + + pub(super) fn poll_output( + &mut self, + decoded_frames: &mut VecDeque, + event_queue: &BoundedQueue, + ) -> Result { + let mut produced = 0; + if let Some(events) = self.events.clone() { + loop { + let event = match unsafe { events.GetEvent(MF_EVENT_FLAG_NO_WAIT) } { + Ok(event) => event, + Err(error) if error.code() == MF_E_NO_EVENTS_AVAILABLE => break, + Err(error) => return Err(error.to_string()), + }; + let status = unsafe { event.GetStatus().map_err(|error| error.to_string())? }; + status.ok().map_err(|error| error.to_string())?; + let event_type = unsafe { event.GetType().map_err(|error| error.to_string())? }; + if event_type == METransformNeedInput.0 as u32 { + self.input_credits = self.input_credits.saturating_add(1); + } else if event_type == METransformHaveOutput.0 as u32 { + if self.process_output(decoded_frames, event_queue)? == OutputPoll::Produced { + produced += 1; + } + // Keep decode and presentation interleaved on the shared + // media worker. Draining every pending MFT output here can + // create an artificial burst that looks stale even when + // the source cadence and display cadence are healthy. + break; + } + } + } else { + if self.process_output(decoded_frames, event_queue)? == OutputPoll::Produced { + produced += 1; + } + self.input_credits = 1; + } + Ok(produced) + } + + fn process_output( + &mut self, + decoded_frames: &mut VecDeque, + event_queue: &BoundedQueue, + ) -> Result { + let mut output = MFT_OUTPUT_DATA_BUFFER { + dwStreamID: self.output_stream, + ..Default::default() + }; + let mut status = 0; + let result = unsafe { + self.transform + .ProcessOutput(0, std::slice::from_mut(&mut output), &mut status) + }; + let sample = unsafe { ManuallyDrop::take(&mut output.pSample) }; + let output_events = unsafe { ManuallyDrop::take(&mut output.pEvents) }; + drop(output_events); + + if let Err(error) = result { + drop(sample); + if error.code() == MF_E_TRANSFORM_NEED_MORE_INPUT { + return Ok(OutputPoll::NeedsInput); + } + if error.code() == MF_E_TRANSFORM_STREAM_CHANGE { + self.select_video_output_type()?; + let dimensions = self.output_dimensions()?; + let updated = VideoFormat { + width: dimensions.0, + height: dimensions.1, + ..self.format + }; + self.format = updated; + let _ = event_queue.push(BackendEvent::VideoFormatChanged(updated)); + return Ok(OutputPoll::Produced); + } + return Err(error.to_string()); + } + + let sample = sample.ok_or_else(|| { + if self.output_provides_samples { + "hardware decoder reported output without a sample".to_owned() + } else { + "hardware decoder requires caller-allocated output samples".to_owned() + } + })?; + let (texture, subresource) = dxgi_surface(&sample)?; + let timestamp_100ns = unsafe { sample.GetSampleTime().unwrap_or(0) }; + let duration_100ns = unsafe { + sample + .GetSampleDuration() + .ok() + .filter(|duration| *duration > 0) + .unwrap_or_else(|| self.format.frame_duration_100ns()) + }; + if decoded_frames.len() == ADAPTIVE_VIDEO_QUEUE_CAPACITY { + decoded_frames.pop_front(); + let _ = event_queue.push(BackendEvent::QueueOverflow(Subsystem::VideoPresentation)); + } + decoded_frames.push_back(DecodedVideoFrame { + texture, + subresource, + timestamp_100ns, + duration_100ns, + }); + Ok(OutputPoll::Produced) + } + + pub(super) fn stop(&mut self) { + if self.stopped { + return; + } + unsafe { + let _ = self + .transform + .ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0); + let _ = self.transform.ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0); + let _ = self + .transform + .ProcessMessage(MFT_MESSAGE_NOTIFY_END_STREAMING, 0); + let _ = self.activation.ShutdownObject(); + } + self.input_credits = 0; + self.stopped = true; + } + + fn select_video_output_type(&self) -> Result<(), String> { + select_video_output_type(&self.transform, self.output_stream) + } + + fn output_dimensions(&self) -> Result<(u32, u32), String> { + unsafe { + let media_type = self + .transform + .GetOutputCurrentType(self.output_stream) + .map_err(|error| error.to_string())?; + let packed = media_type + .GetUINT64(&MF_MT_FRAME_SIZE) + .map_err(|error| error.to_string())?; + Ok(((packed >> 32) as u32, packed as u32)) + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +enum OutputPoll { + Produced, + NeedsInput, +} + +impl Drop for Decoder { + fn drop(&mut self) { + self.stop(); + } +} + +fn configure_transform( + activation: &IMFActivate, + graphics: &Graphics, + format: VideoFormat, +) -> Result<(IMFTransform, Option, u32, u32, bool), String> { + unsafe { + let transform: IMFTransform = activation + .ActivateObject() + .map_err(|error| error.to_string())?; + let attributes = transform + .GetAttributes() + .map_err(|error| error.to_string())?; + let asynchronous = attributes.GetUINT32(&MF_TRANSFORM_ASYNC).unwrap_or(0) != 0; + let d3d11_aware = attributes.GetUINT32(&MF_SA_D3D11_AWARE).unwrap_or(0) != 0; + if !d3d11_aware { + return Err("MFT is not D3D11-aware".to_owned()); + } + attributes + .SetUINT32(&MF_LOW_LATENCY, 1) + .map_err(|error| format!("decoder low-latency mode: {error}"))?; + if asynchronous { + attributes + .SetUINT32(&MF_TRANSFORM_ASYNC_UNLOCK, 1) + .map_err(|error| error.to_string())?; + } + transform + .ProcessMessage( + MFT_MESSAGE_SET_D3D_MANAGER, + graphics.device_manager().as_raw() as usize, + ) + .map_err(|error| error.to_string())?; + + let (input_stream, output_stream) = stream_ids(&transform)?; + let input_type = MFCreateMediaType().map_err(|error| error.to_string())?; + input_type + .SetGUID(&MF_MT_MAJOR_TYPE, &MFMediaType_Video) + .map_err(|error| error.to_string())?; + input_type + .SetGUID(&MF_MT_SUBTYPE, video_subtype(format.codec)) + .map_err(|error| error.to_string())?; + input_type + .SetUINT64(&MF_MT_FRAME_SIZE, pack_pair(format.width, format.height)) + .map_err(|error| error.to_string())?; + input_type + .SetUINT64( + &MF_MT_FRAME_RATE, + pack_pair( + format.frame_rate_numerator.get(), + format.frame_rate_denominator.get(), + ), + ) + .map_err(|error| error.to_string())?; + input_type + .SetUINT64(&MF_MT_PIXEL_ASPECT_RATIO, pack_pair(1, 1)) + .map_err(|error| error.to_string())?; + input_type + .SetUINT32( + &MF_MT_INTERLACE_MODE, + MFVideoInterlace_MixedInterlaceOrProgressive.0 as u32, + ) + .map_err(|error| error.to_string())?; + input_type + .SetUINT32(&MF_MT_AVG_BITRATE, format.average_bitrate) + .map_err(|error| error.to_string())?; + transform + .SetInputType(input_stream, &input_type, 0) + .map_err(|error| error.to_string())?; + select_video_output_type(&transform, output_stream)?; + + let stream_info = transform + .GetOutputStreamInfo(output_stream) + .map_err(|error| error.to_string())?; + let provider_flags = MFT_OUTPUT_STREAM_PROVIDES_SAMPLES.0 as u32 + | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES.0 as u32; + if stream_info.dwFlags & provider_flags == 0 { + return Err("MFT cannot allocate D3D11 output samples".to_owned()); + } + let events = asynchronous + .then(|| transform.cast::()) + .transpose() + .map_err(|error| error.to_string())?; + transform + .ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0) + .map_err(|error| error.to_string())?; + transform + .ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0) + .map_err(|error| error.to_string())?; + Ok((transform, events, input_stream, output_stream, true)) + } +} + +fn enumerate_decoders(adapter_luid: LUID, codec: VideoCodec) -> Result, String> { + unsafe { + let mut attributes = None; + MFCreateAttributes(&mut attributes, 1).map_err(|error| error.to_string())?; + let attributes = attributes.ok_or("MFCreateAttributes returned no attribute store")?; + let luid_bytes = std::slice::from_raw_parts( + (&adapter_luid as *const LUID).cast::(), + size_of::(), + ); + attributes + .SetBlob(&MFT_ENUM_ADAPTER_LUID, luid_bytes) + .map_err(|error| error.to_string())?; + + let mut activations = enumerate_matching_decoders( + MFT_ENUM_FLAG(MFT_ENUM_FLAG_HARDWARE.0 | MFT_ENUM_FLAG_SORTANDFILTER.0), + Some(&attributes), + codec, + )?; + activations.extend(enumerate_matching_decoders( + MFT_ENUM_FLAG(MFT_ENUM_FLAG_SYNCMFT.0 | MFT_ENUM_FLAG_SORTANDFILTER.0), + None, + codec, + )?); + Ok(activations) + } +} + +unsafe fn enumerate_matching_decoders( + flags: MFT_ENUM_FLAG, + attributes: Option<&IMFAttributes>, + codec: VideoCodec, +) -> Result, String> { + let input = MFT_REGISTER_TYPE_INFO { + guidMajorType: MFMediaType_Video, + guidSubtype: *video_subtype(codec), + }; + let output = MFT_REGISTER_TYPE_INFO { + guidMajorType: MFMediaType_Video, + guidSubtype: MFVideoFormat_NV12, + }; + let mut entries: *mut Option = ptr::null_mut(); + let mut count = 0; + unsafe { + MFTEnum2( + MFT_CATEGORY_VIDEO_DECODER, + flags, + Some(&input), + Some(&output), + attributes, + &mut entries, + &mut count, + ) + .map_err(|error| error.to_string())?; + } + let mut activations = Vec::with_capacity(count as usize); + if !entries.is_null() { + unsafe { + for index in 0..count as usize { + if let Some(activation) = (*entries.add(index)).take() { + activations.push(activation); + } + } + CoTaskMemFree(Some(entries as *const c_void)); + } + } + Ok(activations) +} + +fn stream_ids(transform: &IMFTransform) -> Result<(u32, u32), String> { + unsafe { + let mut input_count = 0; + let mut output_count = 0; + transform + .GetStreamCount(&mut input_count, &mut output_count) + .map_err(|error| error.to_string())?; + if input_count != 1 || output_count != 1 { + return Err(format!( + "expected one input and output stream, got {input_count} and {output_count}" + )); + } + let mut input = [0]; + let mut output = [0]; + if let Err(error) = transform.GetStreamIDs(&mut input, &mut output) { + if error.code() == E_NOTIMPL { + return Ok((0, 0)); + } + return Err(error.to_string()); + } + Ok((input[0], output[0])) + } +} + +fn select_video_output_type(transform: &IMFTransform, output_stream: u32) -> Result<(), String> { + for index in 0..64 { + let media_type = match unsafe { transform.GetOutputAvailableType(output_stream, index) } { + Ok(media_type) => media_type, + Err(error) => return Err(format!("NV12 output type is unavailable: {error}")), + }; + let subtype = unsafe { + media_type + .GetGUID(&MF_MT_SUBTYPE) + .map_err(|error| error.to_string())? + }; + if subtype == MFVideoFormat_NV12 || subtype == MFVideoFormat_P010 { + unsafe { + transform + .SetOutputType(output_stream, &media_type, 0) + .map_err(|error| error.to_string())?; + } + return Ok(()); + } + } + Err("hardware decoder did not expose NV12 or P010 output".to_owned()) +} + +fn video_subtype(codec: VideoCodec) -> &'static ::windows::core::GUID { + match codec { + VideoCodec::H264 => &MFVideoFormat_H264, + VideoCodec::H265 => &MFVideoFormat_HEVC, + VideoCodec::Av1 => &MFVideoFormat_AV1, + } +} + +fn dxgi_surface(sample: &IMFSample) -> Result<(ID3D11Texture2D, u32), String> { + unsafe { + let buffer = sample + .GetBufferByIndex(0) + .map_err(|error| error.to_string())?; + let dxgi_buffer: IMFDXGIBuffer = buffer.cast().map_err(|_| { + "hardware decoder returned a system-memory buffer instead of a D3D11 surface".to_owned() + })?; + let mut resource = ptr::null_mut(); + dxgi_buffer + .GetResource(&ID3D11Texture2D::IID, &mut resource) + .map_err(|error| error.to_string())?; + if resource.is_null() { + return Err("decoder returned a null D3D11 texture".to_owned()); + } + let texture = ID3D11Texture2D::from_raw(resource); + let subresource = dxgi_buffer + .GetSubresourceIndex() + .map_err(|error| error.to_string())?; + Ok((texture, subresource)) + } +} + +fn pack_pair(high: u32, low: u32) -> u64 { + ((high as u64) << 32) | low as u64 +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/graphics.rs b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/graphics.rs new file mode 100644 index 000000000..1bc0f05fc --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/graphics.rs @@ -0,0 +1,953 @@ +use std::collections::HashMap; +use std::ffi::c_void; +use std::mem::ManuallyDrop; +use std::mem::size_of; +use std::num::NonZeroU32; + +use ::windows::Win32::Foundation::{ + ERROR_CLASS_ALREADY_EXISTS, GetLastError, HANDLE, HINSTANCE, HMODULE, HWND, LPARAM, LRESULT, + LUID, RECT, WAIT_FAILED, WAIT_OBJECT_0, WAIT_TIMEOUT, WPARAM, +}; +use ::windows::Win32::Graphics::Direct3D::{ + D3D_DRIVER_TYPE_HARDWARE, D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1, +}; +use ::windows::Win32::Graphics::Direct3D10::ID3D10Multithread; +use ::windows::Win32::Graphics::Direct3D11::{ + D3D11_CREATE_DEVICE_BGRA_SUPPORT, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, D3D11_SDK_VERSION, + D3D11_TEX2D_VPIV, D3D11_TEX2D_VPOV, D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE, + D3D11_VIDEO_PROCESSOR_CONTENT_DESC, D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC, + D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC_0, D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC, + D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC_0, D3D11_VIDEO_PROCESSOR_STREAM, + D3D11_VIDEO_USAGE_OPTIMAL_SPEED, D3D11_VPIV_DIMENSION_TEXTURE2D, + D3D11_VPOV_DIMENSION_TEXTURE2D, D3D11CreateDevice, ID3D11Device, ID3D11DeviceContext, + ID3D11Texture2D, ID3D11VideoContext, ID3D11VideoDevice, ID3D11VideoProcessor, + ID3D11VideoProcessorEnumerator, ID3D11VideoProcessorInputView, ID3D11VideoProcessorOutputView, +}; +use ::windows::Win32::Graphics::Direct3D11on12::{D3D11On12CreateDevice, ID3D11On12Device}; +use ::windows::Win32::Graphics::Direct3D12::{ + D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_DESC, D3D12_COMMAND_QUEUE_FLAG_NONE, + D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, D3D12CreateDevice, ID3D12CommandQueue, ID3D12Device, +}; +use ::windows::Win32::Graphics::Dxgi::Common::{ + DXGI_ALPHA_MODE_IGNORE, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_RATIONAL, + DXGI_SAMPLE_DESC, +}; +use ::windows::Win32::Graphics::Dxgi::{ + DXGI_FEATURE_PRESENT_ALLOW_TEARING, DXGI_MWA_NO_ALT_ENTER, DXGI_PRESENT, + DXGI_PRESENT_ALLOW_TEARING, DXGI_SCALING_STRETCH, DXGI_SWAP_CHAIN_DESC1, DXGI_SWAP_CHAIN_FLAG, + DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING, DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT, + DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_USAGE_RENDER_TARGET_OUTPUT, IDXGIAdapter, IDXGIDevice, + IDXGIFactory2, IDXGIFactory5, IDXGISwapChain1, IDXGISwapChain2, +}; +use ::windows::Win32::Media::MediaFoundation::{IMFDXGIDeviceManager, MFCreateDXGIDeviceManager}; +use ::windows::Win32::System::LibraryLoader::GetModuleHandleW; +use ::windows::Win32::System::Threading::WaitForSingleObject; +#[cfg(test)] +use ::windows::Win32::UI::WindowsAndMessaging::WS_POPUP; +use ::windows::Win32::UI::WindowsAndMessaging::{ + CS_HREDRAW, CS_VREDRAW, CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW, + GetClientRect, HTTRANSPARENT, IsWindow, MA_NOACTIVATE, MSG, PM_REMOVE, PeekMessageW, + RegisterClassW, SWP_HIDEWINDOW, SWP_NOACTIVATE, SWP_NOZORDER, SWP_SHOWWINDOW, SetWindowPos, + TranslateMessage, WINDOW_EX_STYLE, WINDOW_STYLE, WM_MOUSEACTIVATE, WM_NCHITTEST, WNDCLASSW, + WS_CHILD, WS_CLIPCHILDREN, WS_CLIPSIBLINGS, WS_EX_APPWINDOW, WS_EX_NOACTIVATE, + WS_EX_TRANSPARENT, WS_OVERLAPPEDWINDOW, +}; +use ::windows::core::{BOOL, IUnknown, Interface, w}; + +use crate::{ + Bounds, ExistingWindow, OwnedWindow, SurfaceTarget, VideoCodec, VideoFormat, WindowHandle, + WindowsGraphicsApi, +}; + +const WINDOW_CLASS: ::windows::core::PCWSTR = w!("OpenNOWStreamerD3D11Surface"); + +struct DeviceResources { + device: ID3D11Device, + context: ID3D11DeviceContext, + video_device: ID3D11VideoDevice, + video_context: ID3D11VideoContext, + manager: IMFDXGIDeviceManager, + _d3d12: Option, +} + +struct D3d12Owners { + _device: ID3D12Device, + _queue: ID3D12CommandQueue, + _on12: ID3D11On12Device, +} + +impl DeviceResources { + fn new(api: WindowsGraphicsApi) -> Result { + match api { + WindowsGraphicsApi::D3d11 => Self::new_d3d11(), + WindowsGraphicsApi::D3d12 => Self::new_d3d12(), + } + } + + fn finish_d3d11_device( + device: ID3D11Device, + context: ID3D11DeviceContext, + d3d12: Option, + ) -> Result { + unsafe { + let multithread: ID3D10Multithread = + context.cast().map_err(|error| error.to_string())?; + let _ = multithread.SetMultithreadProtected(true); + let video_device: ID3D11VideoDevice = + device.cast().map_err(|error| error.to_string())?; + let video_context: ID3D11VideoContext = + context.cast().map_err(|error| error.to_string())?; + let mut reset_token = 0; + let mut manager = None; + MFCreateDXGIDeviceManager(&mut reset_token, &mut manager) + .map_err(|error| error.to_string())?; + let manager = manager.ok_or("MFCreateDXGIDeviceManager returned no manager")?; + manager + .ResetDevice(&device, reset_token) + .map_err(|error| error.to_string())?; + Ok(Self { + device, + context, + video_device, + video_context, + manager, + _d3d12: d3d12, + }) + } + } + + fn new_d3d11() -> Result { + unsafe { + let mut device = None; + let mut context = None; + let levels = [ + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + ]; + D3D11CreateDevice( + None::<&IDXGIAdapter>, + D3D_DRIVER_TYPE_HARDWARE, + HMODULE::default(), + D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_VIDEO_SUPPORT, + Some(&levels), + D3D11_SDK_VERSION, + Some(&mut device), + None, + Some(&mut context), + ) + .map_err(|error| error.to_string())?; + Self::finish_d3d11_device( + device.ok_or("D3D11CreateDevice returned no device")?, + context.ok_or("D3D11CreateDevice returned no immediate context")?, + None, + ) + } + } + + fn new_d3d12() -> Result { + unsafe { + let mut d3d12_device = None; + D3D12CreateDevice(None::<&IUnknown>, D3D_FEATURE_LEVEL_11_0, &mut d3d12_device) + .map_err(|error| format!("D3D12CreateDevice: {error}"))?; + let d3d12_device: ID3D12Device = + d3d12_device.ok_or("D3D12CreateDevice returned no device")?; + let queue: ID3D12CommandQueue = d3d12_device + .CreateCommandQueue(&D3D12_COMMAND_QUEUE_DESC { + Type: D3D12_COMMAND_LIST_TYPE_DIRECT, + Priority: D3D12_COMMAND_QUEUE_PRIORITY_NORMAL.0, + Flags: D3D12_COMMAND_QUEUE_FLAG_NONE, + NodeMask: 0, + }) + .map_err(|error| format!("ID3D12Device::CreateCommandQueue: {error}"))?; + let queue_unknown = queue.cast().map_err(|error| error.to_string())?; + let mut device = None; + let mut context = None; + D3D11On12CreateDevice( + &d3d12_device, + (D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_VIDEO_SUPPORT).0 as u32, + Some(&[D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0]), + Some(&[Some(queue_unknown)]), + 0, + Some(&mut device), + Some(&mut context), + None, + ) + .map_err(|error| format!("D3D11On12CreateDevice: {error}"))?; + let device = device.ok_or("D3D11On12CreateDevice returned no D3D11 device")?; + let context = context.ok_or("D3D11On12CreateDevice returned no immediate context")?; + let on12 = device + .cast() + .map_err(|error| format!("D3D11-on-12 device interface: {error}"))?; + Self::finish_d3d11_device( + device, + context, + Some(D3d12Owners { + _device: d3d12_device, + _queue: queue, + _on12: on12, + }), + ) + } + } +} + +enum RenderWindow { + Existing(HWND), + Owned { + hwnd: HWND, + parent: Option, + visible: bool, + }, +} + +impl RenderWindow { + fn new(target: SurfaceTarget) -> Result { + match target { + SurfaceTarget::Existing(ExistingWindow { hwnd }) => { + let hwnd = hwnd_from_handle(hwnd); + if unsafe { !IsWindow(Some(hwnd)).as_bool() } { + return Err("supplied HWND is not a live Win32 window".to_owned()); + } + Ok(Self::Existing(hwnd)) + } + SurfaceTarget::Owned(window) => create_owned_window(window).map(|hwnd| Self::Owned { + hwnd, + parent: window.parent, + visible: window.visible, + }), + } + } + + fn hwnd(&self) -> HWND { + match self { + Self::Existing(hwnd) | Self::Owned { hwnd, .. } => *hwnd, + } + } + + fn can_update(&self, target: SurfaceTarget) -> bool { + match (self, target) { + (Self::Existing(current), SurfaceTarget::Existing(target)) => { + current.0 == hwnd_from_handle(target.hwnd).0 + } + ( + Self::Owned { + parent: current, .. + }, + SurfaceTarget::Owned(target), + ) => OwnedWindow { + parent: *current, + bounds: target.bounds, + visible: target.visible, + } + .has_same_parent(target), + _ => false, + } + } + + fn update(&mut self, target: SurfaceTarget) -> Result<(), String> { + match (self, target) { + (Self::Existing(hwnd), SurfaceTarget::Existing(_)) => { + if unsafe { IsWindow(Some(*hwnd)).as_bool() } { + Ok(()) + } else { + Err("supplied HWND is no longer a live Win32 window".to_owned()) + } + } + (Self::Owned { hwnd, visible, .. }, SurfaceTarget::Owned(window)) => { + position_owned_window(*hwnd, window)?; + *visible = window.visible; + Ok(()) + } + _ => Err("surface ownership changed during in-place update".to_owned()), + } + } + + fn client_size(&self) -> Result<(u32, u32), String> { + let mut rect = RECT::default(); + unsafe { + GetClientRect(self.hwnd(), &mut rect).map_err(|error| error.to_string())?; + } + Ok(( + (rect.right - rect.left).max(1) as u32, + (rect.bottom - rect.top).max(1) as u32, + )) + } + + fn is_visible(&self) -> bool { + match self { + Self::Existing(_) => true, + Self::Owned { visible, .. } => *visible, + } + } +} + +impl Drop for RenderWindow { + fn drop(&mut self) { + if let Self::Owned { hwnd, .. } = self { + unsafe { + let _ = DestroyWindow(*hwnd); + } + } + } +} + +struct ProcessorResources { + input_width: u32, + input_height: u32, + output_width: u32, + output_height: u32, + enumerator: ID3D11VideoProcessorEnumerator, + processor: ID3D11VideoProcessor, + input_views: HashMap<(usize, u32), ID3D11VideoProcessorInputView>, + output_view: ID3D11VideoProcessorOutputView, +} + +struct SwapChainResources { + swap_chain: IDXGISwapChain1, + frame_latency_waitable: HANDLE, + flags: DXGI_SWAP_CHAIN_FLAG, + allow_tearing: bool, +} + +pub(super) struct Graphics { + processor: Option, + swap_chain: IDXGISwapChain1, + frame_latency_waitable: HANDLE, + swap_chain_flags: DXGI_SWAP_CHAIN_FLAG, + allow_tearing: bool, + has_presented: bool, + window: RenderWindow, + resources: DeviceResources, + video_format: VideoFormat, + swap_size: (u32, u32), +} + +impl Graphics { + pub(super) fn probe(api: WindowsGraphicsApi) -> Result { + let format = VideoFormat { + codec: VideoCodec::H264, + width: 1920, + height: 1080, + frame_rate_numerator: NonZeroU32::new(60).expect("non-zero"), + frame_rate_denominator: NonZeroU32::new(1).expect("non-zero"), + average_bitrate: 10_000_000, + }; + Self::new( + api, + SurfaceTarget::Owned(OwnedWindow { + parent: None, + bounds: Bounds { + x: 0, + y: 0, + width: 64, + height: 64, + }, + visible: false, + }), + format, + ) + } + + pub(super) fn new( + api: WindowsGraphicsApi, + target: SurfaceTarget, + video_format: VideoFormat, + ) -> Result { + let resources = DeviceResources::new(api)?; + let window = RenderWindow::new(target)?; + let swap_size = window.client_size()?; + let swap_chain = create_swap_chain(&resources.device, window.hwnd(), swap_size)?; + let mut graphics = Self { + processor: None, + swap_chain: swap_chain.swap_chain, + frame_latency_waitable: swap_chain.frame_latency_waitable, + swap_chain_flags: swap_chain.flags, + allow_tearing: swap_chain.allow_tearing, + has_presented: false, + window, + resources, + video_format, + swap_size, + }; + graphics.ensure_processor(video_format.width, video_format.height)?; + Ok(graphics) + } + + pub(super) fn device_manager(&self) -> &IMFDXGIDeviceManager { + &self.resources.manager + } + + pub(super) fn adapter_luid(&self) -> Result { + unsafe { + let dxgi_device: IDXGIDevice = self + .resources + .device + .cast() + .map_err(|error| error.to_string())?; + let adapter = dxgi_device + .GetAdapter() + .map_err(|error| error.to_string())?; + Ok(adapter + .GetDesc() + .map_err(|error| error.to_string())? + .AdapterLuid) + } + } + + pub(super) fn video_format(&self) -> VideoFormat { + self.video_format + } + + pub(super) fn is_visible(&self) -> bool { + self.window.is_visible() + } + + pub(super) fn set_surface( + &mut self, + target: SurfaceTarget, + video_format: VideoFormat, + ) -> Result<(), String> { + if self.window.can_update(target) { + self.window.update(target)?; + self.video_format = video_format; + self.resize_if_needed()?; + return self.ensure_processor(video_format.width, video_format.height); + } + let window = RenderWindow::new(target)?; + let swap_size = window.client_size()?; + let swap_chain = create_swap_chain(&self.resources.device, window.hwnd(), swap_size)?; + self.processor = None; + let old_swap_chain = std::mem::replace(&mut self.swap_chain, swap_chain.swap_chain); + drop(old_swap_chain); + self.frame_latency_waitable = swap_chain.frame_latency_waitable; + self.swap_chain_flags = swap_chain.flags; + self.allow_tearing = swap_chain.allow_tearing; + self.has_presented = false; + self.window = window; + self.swap_size = swap_size; + self.video_format = video_format; + self.ensure_processor(video_format.width, video_format.height) + } + + pub(super) fn reconfigure_video(&mut self, format: VideoFormat) -> Result<(), String> { + self.video_format = format; + self.processor = None; + self.ensure_processor(format.width, format.height) + } + + pub(super) fn is_present_ready(&self) -> Result { + if !self.has_presented { + return Ok(true); + } + let result = unsafe { WaitForSingleObject(self.frame_latency_waitable, 0) }; + if result == WAIT_OBJECT_0 { + Ok(true) + } else if result == WAIT_TIMEOUT { + Ok(false) + } else if result == WAIT_FAILED { + Err(format!( + "DXGI frame-latency wait failed: {}", + unsafe { GetLastError() }.0 + )) + } else { + Err(format!( + "unexpected DXGI frame-latency wait result: {}", + result.0 + )) + } + } + + pub(super) fn present( + &mut self, + texture: &ID3D11Texture2D, + subresource: u32, + _timestamp_100ns: i64, + _duration_100ns: i64, + ) -> Result<(), String> { + self.resize_if_needed()?; + let mut texture_description = Default::default(); + unsafe { + texture.GetDesc(&mut texture_description); + } + self.ensure_processor(texture_description.Width, texture_description.Height)?; + let processor = self + .processor + .as_mut() + .ok_or("video processor is unavailable")?; + + unsafe { + let input_description = D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC { + FourCC: 0, + ViewDimension: D3D11_VPIV_DIMENSION_TEXTURE2D, + Anonymous: D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC_0 { + Texture2D: D3D11_TEX2D_VPIV { + MipSlice: 0, + ArraySlice: subresource, + }, + }, + }; + let input_key = (texture.as_raw() as usize, subresource); + let input_view = if let Some(view) = processor.input_views.get(&input_key) { + view.clone() + } else { + let mut input_view = None; + self.resources + .video_device + .CreateVideoProcessorInputView( + texture, + &processor.enumerator, + &input_description, + Some(&mut input_view), + ) + .map_err(|error| error.to_string())?; + let input_view = + input_view.ok_or("D3D11 returned no video processor input view")?; + processor.input_views.insert(input_key, input_view.clone()); + input_view + }; + + let source = RECT { + left: 0, + top: 0, + right: processor.input_width as i32, + bottom: processor.input_height as i32, + }; + let destination = fit_rect( + processor.input_width, + processor.input_height, + processor.output_width, + processor.output_height, + ); + self.resources + .video_context + .VideoProcessorSetStreamFrameFormat( + &processor.processor, + 0, + D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE, + ); + self.resources + .video_context + .VideoProcessorSetStreamSourceRect(&processor.processor, 0, true, Some(&source)); + self.resources + .video_context + .VideoProcessorSetStreamDestRect(&processor.processor, 0, true, Some(&destination)); + self.resources + .video_context + .VideoProcessorSetOutputTargetRect( + &processor.processor, + true, + Some(&RECT { + left: 0, + top: 0, + right: processor.output_width as i32, + bottom: processor.output_height as i32, + }), + ); + let mut stream = D3D11_VIDEO_PROCESSOR_STREAM { + Enable: true.into(), + pInputSurface: ManuallyDrop::new(Some(input_view)), + ..Default::default() + }; + let blit = self.resources.video_context.VideoProcessorBlt( + &processor.processor, + &processor.output_view, + 0, + std::slice::from_ref(&stream), + ); + ManuallyDrop::drop(&mut stream.pInputSurface); + blit.map_err(|error| error.to_string())?; + if self.resources._d3d12.is_some() { + self.resources.context.Flush(); + } + let present_flags = if self.allow_tearing { + DXGI_PRESENT_ALLOW_TEARING + } else { + DXGI_PRESENT(0) + }; + self.swap_chain + .Present(0, present_flags) + .ok() + .map_err(|error| error.to_string())?; + self.has_presented = true; + } + Ok(()) + } + + pub(super) fn pump_window_messages(&self) { + let mut message = MSG::default(); + unsafe { + while PeekMessageW(&mut message, None, 0, 0, PM_REMOVE).as_bool() { + let _ = TranslateMessage(&message); + DispatchMessageW(&message); + } + } + } + + fn resize_if_needed(&mut self) -> Result<(), String> { + let size = self.window.client_size()?; + if size == self.swap_size { + return Ok(()); + } + self.processor = None; + unsafe { + self.swap_chain + .ResizeBuffers( + 2, + size.0, + size.1, + DXGI_FORMAT_UNKNOWN, + self.swap_chain_flags, + ) + .map_err(|error| error.to_string())?; + } + self.swap_size = size; + Ok(()) + } + + fn ensure_processor(&mut self, input_width: u32, input_height: u32) -> Result<(), String> { + if self.processor.as_ref().is_some_and(|processor| { + processor.input_width == input_width + && processor.input_height == input_height + && processor.output_width == self.swap_size.0 + && processor.output_height == self.swap_size.1 + }) { + return Ok(()); + } + let description = D3D11_VIDEO_PROCESSOR_CONTENT_DESC { + InputFrameFormat: D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE, + InputFrameRate: DXGI_RATIONAL { + Numerator: self.video_format.frame_rate_numerator.get(), + Denominator: self.video_format.frame_rate_denominator.get(), + }, + InputWidth: input_width, + InputHeight: input_height, + OutputFrameRate: DXGI_RATIONAL { + Numerator: self.video_format.frame_rate_numerator.get(), + Denominator: self.video_format.frame_rate_denominator.get(), + }, + OutputWidth: self.swap_size.0, + OutputHeight: self.swap_size.1, + Usage: D3D11_VIDEO_USAGE_OPTIMAL_SPEED, + }; + unsafe { + let enumerator = self + .resources + .video_device + .CreateVideoProcessorEnumerator(&description) + .map_err(|error| error.to_string())?; + let processor = self + .resources + .video_device + .CreateVideoProcessor(&enumerator, 0) + .map_err(|error| error.to_string())?; + let back_buffer: ID3D11Texture2D = self + .swap_chain + .GetBuffer(0) + .map_err(|error| error.to_string())?; + let output_description = D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC { + ViewDimension: D3D11_VPOV_DIMENSION_TEXTURE2D, + Anonymous: D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC_0 { + Texture2D: D3D11_TEX2D_VPOV { MipSlice: 0 }, + }, + }; + let mut output_view = None; + self.resources + .video_device + .CreateVideoProcessorOutputView( + &back_buffer, + &enumerator, + &output_description, + Some(&mut output_view), + ) + .map_err(|error| error.to_string())?; + self.processor = Some(ProcessorResources { + input_width, + input_height, + output_width: self.swap_size.0, + output_height: self.swap_size.1, + enumerator, + processor, + input_views: HashMap::new(), + output_view: output_view.ok_or("D3D11 returned no video processor output view")?, + }); + } + Ok(()) + } +} + +fn create_swap_chain( + device: &ID3D11Device, + hwnd: HWND, + size: (u32, u32), +) -> Result { + unsafe { + let dxgi_device: IDXGIDevice = device.cast().map_err(|error| error.to_string())?; + let adapter = dxgi_device + .GetAdapter() + .map_err(|error| error.to_string())?; + let factory: IDXGIFactory2 = adapter.GetParent().map_err(|error| error.to_string())?; + let allow_tearing = supports_tearing(&factory); + let flags = if allow_tearing { + DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT | DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING + } else { + DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT + }; + let description = DXGI_SWAP_CHAIN_DESC1 { + Width: size.0, + Height: size.1, + Format: DXGI_FORMAT_B8G8R8A8_UNORM, + Stereo: false.into(), + SampleDesc: DXGI_SAMPLE_DESC { + Count: 1, + Quality: 0, + }, + BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT, + BufferCount: 2, + Scaling: DXGI_SCALING_STRETCH, + SwapEffect: DXGI_SWAP_EFFECT_FLIP_DISCARD, + AlphaMode: DXGI_ALPHA_MODE_IGNORE, + // IDXGISwapChain2::SetMaximumFrameLatency is only valid for a + // waitable swap chain. Preserve the flag in ResizeBuffers too. + Flags: flags.0 as u32, + }; + let swap_chain = factory + .CreateSwapChainForHwnd(device, hwnd, &description, None, None) + .map_err(|error| error.to_string())?; + let _ = factory.MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER); + let swap_chain_2: IDXGISwapChain2 = swap_chain.cast().map_err(|error| error.to_string())?; + swap_chain_2 + .SetMaximumFrameLatency(1) + .map_err(|error| error.to_string())?; + let frame_latency_waitable = swap_chain_2.GetFrameLatencyWaitableObject(); + if frame_latency_waitable.0.is_null() { + return Err("DXGI returned no frame-latency waitable object".to_owned()); + } + Ok(SwapChainResources { + swap_chain, + frame_latency_waitable, + flags, + allow_tearing, + }) + } +} + +fn supports_tearing(factory: &IDXGIFactory2) -> bool { + let Ok(factory): Result = factory.cast() else { + return false; + }; + let mut supported = BOOL::default(); + unsafe { + factory + .CheckFeatureSupport( + DXGI_FEATURE_PRESENT_ALLOW_TEARING, + (&mut supported as *mut BOOL).cast(), + size_of::() as u32, + ) + .is_ok() + && supported.as_bool() + } +} + +fn create_owned_window(window: OwnedWindow) -> Result { + register_window_class()?; + let module = unsafe { GetModuleHandleW(None).map_err(|error| error.to_string())? }; + let instance = HINSTANCE(module.0); + let parent = window.parent.map(hwnd_from_handle); + let (style, extended_style) = owned_window_styles(parent.is_some()); + let hwnd = unsafe { + CreateWindowExW( + extended_style, + WINDOW_CLASS, + w!("OpenNOW Stream"), + style, + window.bounds.x, + window.bounds.y, + window.bounds.width as i32, + window.bounds.height as i32, + parent, + None, + Some(instance), + None, + ) + .map_err(|error| error.to_string())? + }; + if let Err(error) = position_owned_window(hwnd, window) { + unsafe { + let _ = DestroyWindow(hwnd); + } + return Err(error); + } + Ok(hwnd) +} + +fn owned_window_styles(has_parent: bool) -> (WINDOW_STYLE, WINDOW_EX_STYLE) { + let style = WS_CLIPCHILDREN + | WS_CLIPSIBLINGS + | if has_parent { + WS_CHILD + } else { + WS_OVERLAPPEDWINDOW + }; + let extended_style = WS_EX_NOACTIVATE + | WS_EX_TRANSPARENT + | if has_parent { + WINDOW_EX_STYLE(0) + } else { + WS_EX_APPWINDOW + }; + (style, extended_style) +} + +fn position_owned_window(hwnd: HWND, window: OwnedWindow) -> Result<(), String> { + let visibility = if window.visible { + SWP_SHOWWINDOW + } else { + SWP_HIDEWINDOW + }; + unsafe { + SetWindowPos( + hwnd, + None, + window.bounds.x, + window.bounds.y, + window.bounds.width as i32, + window.bounds.height as i32, + SWP_NOACTIVATE | SWP_NOZORDER | visibility, + ) + .map_err(|error| error.to_string()) + } +} + +fn register_window_class() -> Result<(), String> { + let module = unsafe { GetModuleHandleW(None).map_err(|error| error.to_string())? }; + let class = WNDCLASSW { + style: CS_HREDRAW | CS_VREDRAW, + lpfnWndProc: Some(window_proc), + hInstance: HINSTANCE(module.0), + lpszClassName: WINDOW_CLASS, + ..Default::default() + }; + if unsafe { RegisterClassW(&class) } != 0 { + return Ok(()); + } + let error = unsafe { GetLastError() }; + if error == ERROR_CLASS_ALREADY_EXISTS { + Ok(()) + } else { + Err(format!("RegisterClassW failed: {error:?}")) + } +} + +unsafe extern "system" fn window_proc( + hwnd: HWND, + message: u32, + wparam: WPARAM, + lparam: LPARAM, +) -> LRESULT { + if let Some(result) = owned_window_message_result(message) { + result + } else { + unsafe { DefWindowProcW(hwnd, message, wparam, lparam) } + } +} + +fn owned_window_message_result(message: u32) -> Option { + match message { + WM_NCHITTEST => Some(LRESULT(HTTRANSPARENT as isize)), + WM_MOUSEACTIVATE => Some(LRESULT(MA_NOACTIVATE as isize)), + _ => None, + } +} + +fn hwnd_from_handle(handle: WindowHandle) -> HWND { + HWND(handle.get() as *mut c_void) +} + +fn fit_rect(input_width: u32, input_height: u32, output_width: u32, output_height: u32) -> RECT { + let input_aspect = input_width as f64 / input_height as f64; + let output_aspect = output_width as f64 / output_height as f64; + if output_aspect > input_aspect { + let width = (output_height as f64 * input_aspect).round() as i32; + let left = (output_width as i32 - width) / 2; + RECT { + left, + top: 0, + right: left + width, + bottom: output_height as i32, + } + } else { + let height = (output_width as f64 / input_aspect).round() as i32; + let top = (output_height as i32 - height) / 2; + RECT { + left: 0, + top, + right: output_width as i32, + bottom: top + height, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use ::windows::Win32::UI::WindowsAndMessaging::WS_VISIBLE; + + #[test] + fn letterboxes_wide_target() { + assert_eq!( + fit_rect(1920, 1080, 1024, 1024), + RECT { + left: 0, + top: 224, + right: 1024, + bottom: 800, + } + ); + } + + #[test] + fn owned_child_style_is_non_activating_and_input_transparent() { + let (style, extended_style) = owned_window_styles(true); + + assert_ne!(style.0 & WS_CHILD.0, 0); + assert_eq!(style.0 & WS_POPUP.0, 0); + assert_eq!(style.0 & WS_VISIBLE.0, 0); + assert_ne!(extended_style.0 & WS_EX_NOACTIVATE.0, 0); + assert_ne!(extended_style.0 & WS_EX_TRANSPARENT.0, 0); + } + + #[test] + fn owned_top_level_style_is_a_distinct_non_activating_app_window() { + let (style, extended_style) = owned_window_styles(false); + + assert_ne!(style.0 & WS_OVERLAPPEDWINDOW.0, 0); + assert_eq!(style.0 & WS_POPUP.0, 0); + assert_eq!(style.0 & WS_CHILD.0, 0); + assert_eq!(style.0 & WS_VISIBLE.0, 0); + assert_ne!(extended_style.0 & WS_EX_APPWINDOW.0, 0); + assert_ne!(extended_style.0 & WS_EX_NOACTIVATE.0, 0); + assert_ne!(extended_style.0 & WS_EX_TRANSPARENT.0, 0); + } + + #[test] + fn owned_window_rejects_hit_testing_and_mouse_activation() { + assert_eq!( + owned_window_message_result(WM_NCHITTEST), + Some(LRESULT(HTTRANSPARENT as isize)) + ); + assert_eq!( + owned_window_message_result(WM_MOUSEACTIVATE), + Some(LRESULT(MA_NOACTIVATE as isize)) + ); + assert_eq!(owned_window_message_result(0), None); + } + + #[test] + fn d3d11_on_12_exposes_video_processing_interfaces() { + Graphics::probe(WindowsGraphicsApi::D3d12) + .expect("D3D11-on-12 must support the complete graphics presentation path"); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/mod.rs b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/mod.rs new file mode 100644 index 000000000..d59e539ae --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/mod.rs @@ -0,0 +1,930 @@ +mod audio; +mod decoder; +mod graphics; + +use std::collections::VecDeque; +use std::sync::{Arc, mpsc}; +use std::thread::{self, JoinHandle}; +use std::time::{Duration, Instant}; + +use ::windows::Win32::Media::MediaFoundation::{MF_VERSION, MFSTARTUP_LITE, MFShutdown, MFStartup}; +use ::windows::Win32::Media::{TIMERR_NOERROR, timeBeginPeriod, timeEndPeriod}; +use ::windows::Win32::System::Com::{COINIT_MULTITHREADED, CoInitializeEx, CoUninitialize}; +use ::windows::Win32::System::Threading::{ + GetCurrentThread, SetThreadPriority, THREAD_PRIORITY_ABOVE_NORMAL, +}; + +use crate::{ + ADAPTIVE_VIDEO_QUEUE_CAPACITY, BackendConfig, BackendError, BackendEvent, CapabilityProbe, + Control, LifecycleState, Shared, Subsystem, VideoCodec, WindowsGraphicsApi, +}; + +use self::audio::AudioRenderer; +use self::decoder::{DecodedVideoFrame, Decoder}; +use self::graphics::Graphics; + +const RECOVERY_TIMEOUT: Duration = Duration::from_secs(5); +const AUDIO_RECOVERY_RETRY_INTERVAL: Duration = Duration::from_millis(250); +const AUDIO_RECOVERY_LOG_INTERVAL: Duration = Duration::from_secs(5); +const PRESENTATION_SPIN_THRESHOLD: Duration = Duration::from_micros(300); +const ARRIVAL_HISTORY_LENGTH: usize = 120; +const QUEUE_HISTORY_LENGTH: usize = 3; +const RENDER_HISTORY_LENGTH: usize = 60; +const PACING_OUTLIER: Duration = Duration::from_millis(75); +const PACING_DIAGNOSTIC_INTERVAL: Duration = Duration::from_secs(5); +const MAX_CATCH_UP_RATE: f64 = 0.10; + +/// Spaces decoded frames at the negotiated stream cadence without depending on +/// GFN's RTP timestamps. H.265/AV1 can assign one timestamp to a small group of +/// frames, so presenting immediately on decode makes a 120 fps stream arrive at +/// the display as visible bursts. Slower, game-driven streams remain dynamic: +/// when a frame arrives after its deadline it is presented immediately and the +/// clock is rebased instead of trying to catch up. +struct PresentationClock { + nominal_interval: Duration, + arrival_history: VecDeque, + queue_history: VecDeque, + render_history: VecDeque, + last_arrival: Option, + last_presented: Option, + next_deadline: Option, + queue_integral: f64, + last_diagnostics: Instant, +} + +impl PresentationClock { + fn new(frame_duration_100ns: i64) -> Self { + let nominal_interval = frame_interval(frame_duration_100ns); + Self { + nominal_interval, + arrival_history: VecDeque::with_capacity(ARRIVAL_HISTORY_LENGTH), + queue_history: VecDeque::with_capacity(QUEUE_HISTORY_LENGTH), + render_history: VecDeque::with_capacity(RENDER_HISTORY_LENGTH), + last_arrival: None, + last_presented: None, + next_deadline: None, + queue_integral: 0.0, + last_diagnostics: Instant::now(), + } + } + + fn reset(&mut self, frame_duration_100ns: i64) { + self.nominal_interval = frame_interval(frame_duration_100ns); + self.arrival_history.clear(); + self.queue_history.clear(); + self.render_history.clear(); + self.last_arrival = None; + self.last_presented = None; + self.next_deadline = None; + self.queue_integral = 0.0; + self.last_diagnostics = Instant::now(); + } + + fn observe_decoded_frame(&mut self, now: Instant) { + if let Some(previous) = self.last_arrival.replace(now) { + let interval = now.saturating_duration_since(previous); + if interval <= PACING_OUTLIER { + push_bounded(&mut self.arrival_history, interval, ARRIVAL_HISTORY_LENGTH); + } else { + // A loading screen or recovery gap must not pull the active + // stream cadence down for the next 120 frames. + self.arrival_history.clear(); + self.next_deadline = None; + } + } + } + + fn is_due(&self, now: Instant) -> bool { + self.next_deadline.is_none_or(|deadline| now >= deadline) + } + + fn mark_presented(&mut self, now: Instant, queued_frames: usize) { + if let Some(previous) = self.last_presented.replace(now) { + push_bounded( + &mut self.render_history, + now.saturating_duration_since(previous), + RENDER_HISTORY_LENGTH, + ); + } + push_bounded(&mut self.queue_history, queued_frames, QUEUE_HISTORY_LENGTH); + let queue_average = average_usize(&self.queue_history); + self.queue_integral = (self.queue_integral * 0.9 + queue_average).clamp(0.0, 12.0); + let interval = self.controlled_interval(queue_average); + let next = self + .next_deadline + .map_or(now + interval, |deadline| deadline + interval); + // Preserve the presentation phase while decoded frames are queued. A + // D3D11 hardware decoder commonly releases AV1/H.265 frames in small + // bursts; rebasing every slightly-late deadline to `now + interval` + // makes that harmless lateness permanent and eventually forces the + // low-latency queue to discard frames. Keeping the old phase lets the + // worker use the next DXGI-ready slot to catch up. When the queue is + // empty, rebase so a genuinely dynamic/slow game stream is never + // chased with synthetic catch-up frames. + self.next_deadline = Some(if queued_frames == 0 && next <= now { + now + interval + } else { + next + }); + + if now.duration_since(self.last_diagnostics) >= PACING_DIAGNOSTIC_INTERVAL { + let observed = average_duration(&self.render_history).unwrap_or(Duration::ZERO); + let jitter = percentile_absolute_deviation(&self.render_history, observed, 0.99); + eprintln!( + "Adaptive presentation pacing: target={:.3}ms observed={:.3}ms p99Jitter={:.3}ms queue={queue_average:.2} arrivalSamples={}", + interval.as_secs_f64() * 1_000.0, + observed.as_secs_f64() * 1_000.0, + jitter.as_secs_f64() * 1_000.0, + self.arrival_history.len(), + ); + self.last_diagnostics = now; + } + } + + fn time_until_due(&self, now: Instant) -> Duration { + self.next_deadline.map_or(Duration::ZERO, |deadline| { + deadline.saturating_duration_since(now) + }) + } + + fn controlled_interval(&self, queue_average: f64) -> Duration { + let estimated = average_duration(&self.arrival_history) + .unwrap_or(self.nominal_interval) + .clamp( + self.nominal_interval, + self.nominal_interval.saturating_mul(2), + ); + // Queue feedback is intentionally conservative. P drains a burst now; + // I prevents a small persistent backlog, while the negotiated cadence + // remains the hard upper-FPS limit. + let correction = (queue_average * 0.10 + self.queue_integral * 0.004).clamp(0.0, 0.30); + let minimum = if queue_average > 0.0 { + self.nominal_interval.as_secs_f64() * (1.0 - MAX_CATCH_UP_RATE) + } else { + self.nominal_interval.as_secs_f64() + }; + Duration::from_secs_f64((estimated.as_secs_f64() / (1.0 + correction)).max(minimum)) + } +} + +fn frame_interval(frame_duration_100ns: i64) -> Duration { + Duration::from_nanos(u64::try_from(frame_duration_100ns.max(1)).unwrap_or(1) * 100) +} + +fn push_bounded(values: &mut VecDeque, value: T, capacity: usize) { + if values.len() == capacity { + values.pop_front(); + } + values.push_back(value); +} + +fn average_duration(values: &VecDeque) -> Option { + if values.is_empty() { + return None; + } + let total_ns = values.iter().map(Duration::as_nanos).sum::(); + Some(Duration::from_nanos( + u64::try_from(total_ns / values.len() as u128).unwrap_or(u64::MAX), + )) +} + +fn average_usize(values: &VecDeque) -> f64 { + if values.is_empty() { + 0.0 + } else { + values.iter().sum::() as f64 / values.len() as f64 + } +} + +fn percentile_absolute_deviation( + values: &VecDeque, + center: Duration, + percentile: f64, +) -> Duration { + if values.is_empty() { + return Duration::ZERO; + } + let center_ns = center.as_nanos(); + let mut deviations = values + .iter() + .map(|value| value.as_nanos().abs_diff(center_ns)) + .collect::>(); + deviations.sort_unstable(); + let index = ((deviations.len() - 1) as f64 * percentile).round() as usize; + Duration::from_nanos(u64::try_from(deviations[index]).unwrap_or(u64::MAX)) +} + +/// Keeps the native media loop out of Windows' coarse default timer cadence. +/// The official GFN renderer uses an accurate-sleep pacing path and elevated +/// RTP/media threads; without this, a nominal 1 ms idle sleep can occasionally +/// become a visible multi-frame stall. +struct LowLatencyThreadGuard { + timer_resolution_active: bool, +} + +impl LowLatencyThreadGuard { + fn enter() -> Self { + let timer_resolution_active = unsafe { timeBeginPeriod(1) == TIMERR_NOERROR }; + unsafe { + let _ = SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); + } + Self { + timer_resolution_active, + } + } +} + +impl Drop for LowLatencyThreadGuard { + fn drop(&mut self) { + if self.timer_resolution_active { + unsafe { + let _ = timeEndPeriod(1); + } + } + } +} + +struct MediaRuntime; + +impl MediaRuntime { + fn initialize() -> Result { + unsafe { + CoInitializeEx(None, COINIT_MULTITHREADED) + .ok() + .map_err(|error| BackendError::Startup(format!("CoInitializeEx: {error}")))?; + if let Err(error) = MFStartup(MF_VERSION, MFSTARTUP_LITE) { + CoUninitialize(); + return Err(BackendError::Startup(format!("MFStartup: {error}"))); + } + } + Ok(Self) + } +} + +impl Drop for MediaRuntime { + fn drop(&mut self) { + unsafe { + let _ = MFShutdown(); + CoUninitialize(); + } + } +} + +pub(super) fn probe(api: WindowsGraphicsApi) -> CapabilityProbe { + let _runtime = match MediaRuntime::initialize() { + Ok(runtime) => runtime, + Err(error) => { + return CapabilityProbe { + available: false, + h264_hardware_decode: false, + h265_hardware_decode: false, + av1_hardware_decode: false, + d3d11_presentation: false, + wasapi_render: false, + reason: Some(error.to_string()), + }; + } + }; + + let graphics = Graphics::probe(api); + let h264_decoder = graphics + .as_ref() + .map_err(Clone::clone) + .and_then(|graphics| { + Decoder::probe(graphics, VideoCodec::H264).map_err(|error| error.to_string()) + }); + let h265_decoder = graphics + .as_ref() + .map_err(Clone::clone) + .and_then(|graphics| { + Decoder::probe(graphics, VideoCodec::H265).map_err(|error| error.to_string()) + }); + let av1_decoder = graphics + .as_ref() + .map_err(Clone::clone) + .and_then(|graphics| { + Decoder::probe(graphics, VideoCodec::Av1).map_err(|error| error.to_string()) + }); + let audio = AudioRenderer::probe().map_err(|error| error.to_string()); + let h264_hardware_decode = h264_decoder.is_ok(); + let h265_hardware_decode = h265_decoder.is_ok(); + let av1_hardware_decode = av1_decoder.is_ok(); + let d3d11_presentation = graphics.is_ok(); + let wasapi_render = audio.is_ok(); + let mut probe = CapabilityProbe { + available: false, + h264_hardware_decode, + h265_hardware_decode, + av1_hardware_decode, + d3d11_presentation, + wasapi_render, + reason: None, + }; + probe.available = probe.bundled_backend_available(); + if !probe.available { + probe.reason = Some( + [ + graphics.err().map(|error| format!("{api:?}: {error}")), + h264_decoder.err().map(|error| format!("H.264: {error}")), + audio.err().map(|error| format!("WASAPI: {error}")), + ] + .into_iter() + .flatten() + .collect::>() + .join("; "), + ); + } + probe +} + +pub(super) fn spawn( + api: WindowsGraphicsApi, + config: BackendConfig, + shared: Arc, + controls: mpsc::Receiver, +) -> Result, BackendError> { + let (ready_sender, ready_receiver) = mpsc::sync_channel(1); + let worker_shared = Arc::clone(&shared); + let worker = thread::Builder::new() + .name("opennow-windows-media".to_owned()) + .spawn(move || { + let runtime = match Worker::new(api, config, worker_shared, controls) { + Ok(worker) => { + let _ = ready_sender.send(Ok(())); + worker + } + Err(error) => { + let _ = ready_sender.send(Err(error)); + return; + } + }; + runtime.run(); + }) + .map_err(|error| BackendError::Startup(format!("failed to spawn media thread: {error}")))?; + + match ready_receiver.recv() { + Ok(Ok(())) => Ok(worker), + Ok(Err(error)) => { + let _ = worker.join(); + Err(error) + } + Err(_) => { + let _ = worker.join(); + Err(BackendError::Startup( + "media thread exited during initialization".to_owned(), + )) + } + } +} + +struct Worker { + api: WindowsGraphicsApi, + config: BackendConfig, + shared: Arc, + controls: mpsc::Receiver, + graphics: Graphics, + decoder: Decoder, + decoded_video: VecDeque, + presentation_clock: PresentationClock, + first_frame_presented: bool, + audio: Option, + audio_recovery: Option, + _runtime: MediaRuntime, +} + +struct AudioRecovery { + reason: String, + next_attempt: Instant, + next_log: Instant, +} + +impl Worker { + fn new( + api: WindowsGraphicsApi, + config: BackendConfig, + shared: Arc, + controls: mpsc::Receiver, + ) -> Result { + let runtime = MediaRuntime::initialize()?; + let graphics = Graphics::new(api, config.surface, config.video) + .map_err(|error| BackendError::Startup(format!("{api:?} presentation: {error}")))?; + let decoder = Decoder::new(&graphics, config.video) + .map_err(|error| BackendError::Startup(format!("Media Foundation H.264: {error}")))?; + let audio = AudioRenderer::new(config.audio) + .map_err(|error| BackendError::Startup(format!("WASAPI: {error}")))?; + let presentation_clock = PresentationClock::new(config.video.frame_duration_100ns()); + shared.set_state(LifecycleState::Running); + Ok(Self { + api, + config, + shared, + controls, + graphics, + decoder, + decoded_video: VecDeque::with_capacity(ADAPTIVE_VIDEO_QUEUE_CAPACITY), + presentation_clock, + first_frame_presented: false, + audio: Some(audio), + audio_recovery: None, + _runtime: runtime, + }) + } + + fn run(mut self) { + let _low_latency_thread = LowLatencyThreadGuard::enter(); + let mut stopping = false; + while !stopping { + let mut did_work = false; + self.graphics.pump_window_messages(); + while let Ok(control) = self.controls.try_recv() { + did_work = true; + match control { + Control::Stop => { + stopping = true; + break; + } + Control::ReconfigureVideo(format) => { + self.config.video = format; + self.shared.video.clear(); + if let Err(error) = self.rebuild_video( + Subsystem::VideoDecode, + error_label("video reconfiguration"), + ) { + self.fail(error); + return; + } + } + Control::ReconfigureAudio(format) => { + self.config.audio = format; + self.begin_audio_recovery(error_label("audio reconfiguration")); + } + Control::SetSurface(surface) => { + self.config.surface = surface; + self.decoded_video.clear(); + self.presentation_clock + .reset(self.config.video.frame_duration_100ns()); + self.first_frame_presented = false; + if let Err(error) = self.graphics.set_surface(surface, self.config.video) { + if let Err(error) = self.recover_video( + Subsystem::VideoPresentation, + format!("surface reconfiguration failed: {error}"), + ) { + self.fail(error); + return; + } + } else { + self.shared.set_state(LifecycleState::Running); + } + } + Control::SetPaused(paused) => { + self.decoded_video.clear(); + self.presentation_clock + .reset(self.config.video.frame_duration_100ns()); + self.first_frame_presented = false; + let audio_error = self + .audio + .as_mut() + .and_then(|audio| audio.set_paused(paused).err()); + if let Some(error) = audio_error { + self.begin_audio_recovery(format!( + "audio {} failed: {error}", + if paused { "pause" } else { "resume" } + )); + } + if !paused { + if let Err(error) = self + .rebuild_video(Subsystem::VideoDecode, "video resume".to_owned()) + { + self.fail(error); + return; + } + } + } + } + } + if stopping { + break; + } + let endpoint_result = self + .audio + .as_mut() + .map(AudioRenderer::default_endpoint_changed); + match endpoint_result { + Some(Ok(true)) => { + self.begin_audio_recovery("default audio endpoint changed".to_owned()); + } + Some(Ok(false)) | None => {} + Some(Err(error)) => { + self.begin_audio_recovery(format!( + "default audio endpoint check failed: {error}" + )); + } + } + self.poll_audio_recovery(); + if self + .shared + .paused + .load(std::sync::atomic::Ordering::Acquire) + { + thread::sleep(Duration::from_millis(1)); + continue; + } + + let produced = match self + .decoder + .poll_output(&mut self.decoded_video, &self.shared.events) + { + Ok(produced) => produced, + Err(error) => { + if let Err(error) = self.rebuild_video(Subsystem::VideoDecode, error) { + self.fail(error); + return; + } + continue; + } + }; + did_work |= produced > 0; + if produced > 0 { + self.presentation_clock + .observe_decoded_frame(Instant::now()); + } + let decoded_format = self.decoder.format(); + if decoded_format != self.config.video { + if let Err(error) = self.graphics.reconfigure_video(decoded_format) { + if let Err(error) = self.recover_video(Subsystem::VideoPresentation, error) { + self.fail(error); + return; + } + continue; + } + self.config.video = decoded_format; + self.presentation_clock + .reset(decoded_format.frame_duration_100ns()); + *self + .shared + .video_format + .lock() + .unwrap_or_else(|error| error.into_inner()) = decoded_format; + } + while self.decoder.wants_input() { + if let Some(frame) = self.shared.video.try_pop() { + did_work = true; + if let Err(error) = self.decoder.submit(frame) { + if let Err(error) = self.rebuild_video(Subsystem::VideoDecode, error) { + self.fail(error); + return; + } + continue; + } + } else { + break; + } + } + // DXGI's frame-latency handle behaves like an auto-reset event. + // Checking it without a frame ready would consume the signal and + // leave the swap chain waiting forever for a Present that cannot + // happen. Only consume readiness when presentation can follow. + let presentation_now = Instant::now(); + if !self.decoded_video.is_empty() && self.presentation_clock.is_due(presentation_now) { + match self.graphics.is_present_ready() { + Ok(true) => { + // Keep every decoded frame while the bounded queue has + // capacity. GFN's dynamic stream durations describe + // game output cadence, not whether an older decoded + // surface is stale; comparing them discarded normal + // AV1/H.265 decoder bursts. The phase-preserving clock + // drains bursts, while process_output's seven-surface + // cap still bounds latency during a real overload. + let frame = self.decoded_video.pop_front(); + if let Some(frame) = frame { + did_work = true; + if let Err(error) = self.graphics.present( + &frame.texture, + frame.subresource, + frame.timestamp_100ns, + frame.duration_100ns, + ) { + if let Err(error) = + self.recover_video(Subsystem::VideoPresentation, error) + { + self.fail(error); + return; + } + continue; + } + self.shared + .presented_frames + .fetch_add(1, std::sync::atomic::Ordering::Relaxed); + self.presentation_clock + .mark_presented(Instant::now(), self.decoded_video.len()); + if !self.first_frame_presented && self.graphics.is_visible() { + self.first_frame_presented = true; + let _ = self.shared.events.push(BackendEvent::FirstFramePresented); + } + } + } + Ok(false) => {} + Err(error) => { + if let Err(error) = self.recover_video(Subsystem::VideoPresentation, error) + { + self.fail(error); + return; + } + continue; + } + } + } + let audio_result = self + .audio + .as_mut() + .map(|audio| audio.render(&self.shared.audio)); + match audio_result { + Some(Ok(true)) => { + did_work = true; + let _ = self + .shared + .events + .push(BackendEvent::QueueOverflow(Subsystem::Audio)); + } + Some(Ok(false)) => {} + Some(Err(error)) => { + self.begin_audio_recovery(error); + } + None => { + // Audio remains real-time while an endpoint is unavailable. + // Discard stale PCM instead of allowing it to backpressure video. + self.shared.audio.clear(); + } + } + let presentation_wait = if self.decoded_video.is_empty() { + Duration::ZERO + } else { + self.presentation_clock.time_until_due(Instant::now()) + }; + if !presentation_wait.is_zero() && presentation_wait <= PRESENTATION_SPIN_THRESHOLD { + // Avoid handing the final fraction of an 8.33 ms interval + // back to the Windows scheduler. The bounded 300 us precision + // phase costs less than four percent of one core at 120 Hz. + while !self + .presentation_clock + .time_until_due(Instant::now()) + .is_zero() + { + std::hint::spin_loop(); + } + } else if presentation_wait > PRESENTATION_SPIN_THRESHOLD { + thread::sleep( + presentation_wait + .saturating_sub(PRESENTATION_SPIN_THRESHOLD) + .min(Duration::from_millis(1)), + ); + } else if !did_work { + thread::sleep(Duration::from_millis(1)); + } else { + thread::yield_now(); + } + } + + self.decoder.stop(); + if let Some(audio) = self.audio.as_mut() { + audio.stop(); + } + } + + fn recover_video(&mut self, subsystem: Subsystem, message: String) -> Result<(), BackendError> { + let _ = self.shared.events.push(BackendEvent::DeviceLost { + subsystem, + message: message.clone(), + }); + self.shared.set_state(LifecycleState::Recovering); + self.shared.video.clear(); + self.decoded_video.clear(); + self.presentation_clock + .reset(self.config.video.frame_duration_100ns()); + self.first_frame_presented = false; + let start = Instant::now(); + loop { + if self.shared.state() == LifecycleState::Stopping { + return Ok(()); + } + self.config.video = *self + .shared + .video_format + .lock() + .unwrap_or_else(|error| error.into_inner()); + self.config.surface = *self + .shared + .surface + .lock() + .unwrap_or_else(|error| error.into_inner()); + match Graphics::new(self.api, self.config.surface, self.config.video).and_then( + |graphics| { + Decoder::new(&graphics, self.config.video).map(|decoder| (graphics, decoder)) + }, + ) { + Ok((graphics, decoder)) => { + self.graphics = graphics; + self.decoder = decoder; + let _ = self + .shared + .events + .push(BackendEvent::DeviceRecovered(subsystem)); + let _ = self.shared.events.push(BackendEvent::KeyFrameRequired); + self.shared.set_state(LifecycleState::Running); + return Ok(()); + } + Err(error) if start.elapsed() < RECOVERY_TIMEOUT => { + let _ = error; + thread::sleep(Duration::from_millis(100)); + } + Err(error) => { + return Err(BackendError::DeviceLost { + subsystem, + message: format!("{message}; recovery timed out: {error}"), + }); + } + } + } + } + + fn rebuild_video(&mut self, subsystem: Subsystem, message: String) -> Result<(), BackendError> { + self.decoder.stop(); + self.shared.video.clear(); + self.decoded_video.clear(); + self.presentation_clock + .reset(self.config.video.frame_duration_100ns()); + self.first_frame_presented = false; + match Decoder::new(&self.graphics, self.config.video) { + Ok(decoder) => { + self.decoder = decoder; + self.graphics + .reconfigure_video(self.config.video) + .map_err(|error| { + BackendError::Reconfigure(format!("D3D11 presenter: {error}")) + })?; + let _ = self.shared.events.push(BackendEvent::KeyFrameRequired); + self.shared.set_state(LifecycleState::Running); + Ok(()) + } + Err(error) => self.recover_video(subsystem, format!("{message}: {error}")), + } + } + + fn begin_audio_recovery(&mut self, message: String) { + if self.audio_recovery.is_none() { + let _ = self.shared.events.push(BackendEvent::DeviceLost { + subsystem: Subsystem::Audio, + message: message.clone(), + }); + } + self.shared.audio.clear(); + if let Some(mut audio) = self.audio.take() { + audio.stop(); + } + let now = Instant::now(); + self.audio_recovery = Some(AudioRecovery { + reason: message, + next_attempt: now, + next_log: now + AUDIO_RECOVERY_LOG_INTERVAL, + }); + } + + fn poll_audio_recovery(&mut self) { + let Some(recovery) = self.audio_recovery.as_mut() else { + return; + }; + let now = Instant::now(); + if now < recovery.next_attempt { + return; + } + self.config.audio = *self + .shared + .audio_format + .lock() + .unwrap_or_else(|error| error.into_inner()); + let paused = self + .shared + .paused + .load(std::sync::atomic::Ordering::Acquire); + match AudioRenderer::new(self.config.audio).and_then(|mut audio| { + if paused { + audio.set_paused(true)?; + } + Ok(audio) + }) { + Ok(audio) => { + self.audio = Some(audio); + self.audio_recovery = None; + let _ = self + .shared + .events + .push(BackendEvent::DeviceRecovered(Subsystem::Audio)); + } + Err(error) => { + recovery.next_attempt = now + AUDIO_RECOVERY_RETRY_INTERVAL; + if now >= recovery.next_log { + eprintln!( + "WASAPI endpoint still unavailable after {}: {error}; video remains active", + recovery.reason + ); + recovery.next_log = now + AUDIO_RECOVERY_LOG_INTERVAL; + } + } + } + } + + fn fail(&self, error: BackendError) { + self.shared.set_state(LifecycleState::Failed); + let _ = self.shared.events.push(BackendEvent::Fatal(error)); + self.shared.video.close(); + self.shared.audio.close(); + } +} + +fn error_label(value: &str) -> String { + value.to_owned() +} + +#[cfg(test)] +mod tests { + use super::PresentationClock; + use std::time::{Duration, Instant}; + + #[test] + fn presentation_clock_spaces_a_decoded_burst() { + let start = Instant::now(); + let mut clock = PresentationClock::new(83_333); + + assert!(clock.is_due(start)); + clock.mark_presented(start, 3); + assert!(!clock.is_due(start + Duration::from_millis(4))); + assert!(clock.is_due(start + Duration::from_micros(8_334))); + } + + #[test] + fn presentation_clock_rebases_after_a_slow_frame() { + let start = Instant::now(); + let mut clock = PresentationClock::new(83_333); + clock.mark_presented(start, 0); + + let slow_arrival = start + Duration::from_millis(17); + assert!(clock.is_due(slow_arrival)); + clock.mark_presented(slow_arrival, 0); + assert!(!clock.is_due(slow_arrival + Duration::from_millis(4))); + assert!(clock.is_due(slow_arrival + Duration::from_micros(8_334))); + } + + #[test] + fn presentation_clock_preserves_phase_to_drain_a_decoder_burst() { + let start = Instant::now(); + let mut clock = PresentationClock::new(83_333); + clock.mark_presented(start, 3); + + let late = start + Duration::from_millis(18); + assert!(clock.is_due(late)); + clock.mark_presented(late, 2); + + // The next buffered frame is already due because the clock retained + // the original cadence instead of adding another full frame period to + // the late presentation time. + assert!(clock.is_due(late)); + } + + #[test] + fn presentation_clock_learns_a_dynamic_sixty_fps_source() { + let start = Instant::now(); + let mut clock = PresentationClock::new(83_333); + for frame in 0..120 { + clock.observe_decoded_frame(start + Duration::from_micros(frame * 16_667)); + } + + let interval = clock.controlled_interval(0.0); + assert!(interval >= Duration::from_micros(16_660)); + assert!(interval <= Duration::from_micros(16_670)); + } + + #[test] + fn presentation_clock_averages_grouped_frame_arrivals() { + let start = Instant::now(); + let mut clock = PresentationClock::new(83_333); + for group in 0..30 { + let group_start = start + Duration::from_millis(group * 33); + for frame in 0..4 { + clock.observe_decoded_frame(group_start + Duration::from_micros(frame * 20)); + } + } + + let interval = clock.controlled_interval(0.0); + assert!(interval >= Duration::from_micros(8_200)); + assert!(interval <= Duration::from_micros(8_500)); + } + + #[test] + fn presentation_clock_uses_a_bounded_catch_up_rate_for_backlog() { + let clock = PresentationClock::new(83_333); + let interval = clock.controlled_interval(3.0); + + assert!(interval < Duration::from_nanos(8_333_300)); + assert!(interval >= Duration::from_nanos(7_499_970)); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/Cargo.toml b/native/opennow-streamer/crates/opennow-streamer-platform/Cargo.toml new file mode 100644 index 000000000..12069540e --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "opennow-streamer-platform" +version.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true + +[features] +default = [] +linux-vaapi = ["opennow-streamer-platform-linux/vaapi"] +linux-ffmpeg = ["opennow-streamer-platform-linux/ffmpeg"] +linux-ffmpeg-bundled = ["opennow-streamer-platform-linux/ffmpeg-bundled"] + +[dependencies] +audiopus_sys.workspace = true +base64.workspace = true +image.workspace = true +openh264.workspace = true +opennow-streamer-protocol = { path = "../opennow-streamer-protocol" } +opus.workspace = true +sdl2.workspace = true + +[target.'cfg(target_os = "windows")'.dependencies] +opennow-streamer-platform-windows = { path = "../opennow-streamer-platform-windows" } +raw-window-handle = "0.6" +windows-sys = { version = "0.61", features = [ + "Win32_Foundation", + "Win32_Graphics_Gdi", + "Win32_System_LibraryLoader", + "Win32_System_Threading", + "Win32_UI_Input", + "Win32_UI_Input_KeyboardAndMouse", + "Win32_UI_WindowsAndMessaging", +] } + +[target.'cfg(target_os = "linux")'.dependencies] +opennow-streamer-platform-linux = { path = "../opennow-streamer-platform-linux" } +raw-window-handle = "0.6" +x11-dl = "2.21" + +[target.'cfg(target_os = "macos")'.dependencies] +libc = "0.2" +objc2 = "0.6" +objc2-app-kit = { version = "0.3", default-features = false, features = ["NSGraphics", "NSResponder", "NSRunningApplication", "NSView", "NSWindow", "NSWorkspace"] } +objc2-foundation = { version = "0.3", default-features = false, features = ["NSGeometry"] } +opennow-streamer-platform-macos = { path = "../opennow-streamer-platform-macos" } +raw-window-handle = "0.6" diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/lib.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/lib.rs new file mode 100644 index 000000000..de84ff198 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/lib.rs @@ -0,0 +1,312 @@ +#[cfg(target_os = "linux")] +mod linux_backend; +#[cfg(target_os = "linux")] +mod linux_frame_pacing; +#[cfg(target_os = "macos")] +mod macos_backend; +mod media; +mod native_stats_overlay; +mod native_surface; +mod output; +mod queue; +mod runtime; +#[cfg(target_os = "windows")] +mod windows_debug_overlay; +#[cfg(target_os = "windows")] +mod windows_raw_input; + +pub use media::{ + CapturedInput, CapturedInputQueue, EncodedFrame, MediaCodec, MediaControl, MediaFeedback, + MediaSession, MediaSink, MediaStreamConfig, MediaVideoCodec, PushOutcome, +}; +pub use runtime::{MainThreadHost, MediaRuntime, create_runtime}; + +/// Shows a standalone overlay window through the exact production creation path. +/// Debug-only aid for isolating window-server behavior without a streaming session. +#[cfg(target_os = "macos")] +pub fn debug_show_overlay_window() { + opennow_streamer_platform_macos::debug_show_overlay_window(); +} + +use opennow_streamer_protocol::{CodecCapability, VideoBackendCapability}; + +pub fn video_backends() -> Vec { + #[cfg(target_os = "linux")] + { + let mut backends = linux_backend::video_backends(); + backends.push(software_backend()); + backends + } + #[cfg(not(target_os = "linux"))] + { + let mut backends = Vec::new(); + #[cfg(target_os = "windows")] + { + use opennow_streamer_platform_windows::WindowsGraphicsApi; + backends.push(windows_hardware_backend( + WindowsGraphicsApi::D3d12, + "d3d12", + "d3d11on12-nv12", + )); + backends.push(windows_hardware_backend( + WindowsGraphicsApi::D3d11, + "d3d11", + "d3d11-nv12", + )); + } + #[cfg(not(target_os = "windows"))] + backends.push(hardware_backend()); + backends.push(software_backend()); + backends + } +} + +pub const fn supports_audio_decode() -> bool { + true +} + +pub const fn supports_audio_output() -> bool { + true +} + +#[cfg(target_os = "windows")] +fn windows_hardware_backend( + api: opennow_streamer_platform_windows::WindowsGraphicsApi, + backend: &'static str, + zero_copy_mode: &'static str, +) -> VideoBackendCapability { + if !runtime::backend_preference_allows(backend) { + return unavailable_backend( + backend, + "windows", + "Direct3D hardware decode was disabled by configuration", + ); + } + let probe = opennow_streamer_platform_windows::WindowsBackend::probe_for(api); + let available = probe.bundled_backend_available(); + let media_output_available = probe.d3d11_presentation && probe.wasapi_render; + let reason = if available { + None + } else { + Some("Direct3D hardware decode, presentation, or WASAPI output is unavailable") + }; + VideoBackendCapability { + backend, + platform: "windows", + codecs: vec![ + CodecCapability { + codec: "h264", + available: media_output_available && probe.h264_hardware_decode, + reason: (!(media_output_available && probe.h264_hardware_decode)).then_some( + "H.264 Media Foundation hardware decode or media output is unavailable", + ), + }, + CodecCapability { + codec: "h265", + available: media_output_available && probe.h265_hardware_decode, + reason: (!(media_output_available && probe.h265_hardware_decode)).then_some( + "H.265 Media Foundation hardware decode or media output is unavailable", + ), + }, + CodecCapability { + codec: "av1", + available: media_output_available && probe.av1_hardware_decode, + reason: (!(media_output_available && probe.av1_hardware_decode)).then_some( + "AV1 Media Foundation hardware decode or media output is unavailable", + ), + }, + ], + zero_copy_modes: available + .then_some(vec![zero_copy_mode]) + .unwrap_or_default(), + available, + reason, + } +} + +#[cfg(target_os = "macos")] +fn hardware_backend() -> VideoBackendCapability { + if !runtime::backend_preference_allows("videotoolbox") { + return unavailable_backend( + "videotoolbox", + "macos", + "VideoToolbox hardware decode was disabled by configuration", + ); + } + const UNAVAILABLE: &str = "VideoToolbox H.264 hardware decode or Metal is unavailable"; + let available = macos_backend::available(); + VideoBackendCapability { + backend: "videotoolbox", + platform: "macos", + codecs: vec![ + CodecCapability { + codec: "h264", + available, + reason: (!available).then_some(UNAVAILABLE), + }, + CodecCapability { + codec: "h265", + available: false, + reason: Some("H.265 VideoToolbox decode is not implemented"), + }, + CodecCapability { + codec: "av1", + available: false, + reason: Some("AV1 VideoToolbox decode is not implemented"), + }, + ], + zero_copy_modes: available + .then_some(vec!["cvpixelbuffer-iosurface-metal"]) + .unwrap_or_default(), + available, + reason: (!available).then_some(UNAVAILABLE), + } +} + +#[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] +fn hardware_backend() -> VideoBackendCapability { + unavailable_backend("unsupported", "other", "Unsupported operating system") +} + +fn software_backend() -> VideoBackendCapability { + VideoBackendCapability { + backend: "software", + platform: "cross-platform", + codecs: vec![ + CodecCapability { + codec: "h264", + available: true, + reason: None, + }, + CodecCapability { + codec: "h265", + available: false, + reason: Some("H.265 decoder is not built into this binary"), + }, + CodecCapability { + codec: "av1", + available: false, + reason: Some("AV1 decoder is not built into this binary"), + }, + ], + zero_copy_modes: Vec::new(), + available: true, + reason: None, + } +} + +#[cfg(not(target_os = "linux"))] +fn unavailable_backend( + backend: &'static str, + platform: &'static str, + reason: &'static str, +) -> VideoBackendCapability { + VideoBackendCapability { + backend, + platform, + codecs: ["h264", "h265", "av1"] + .into_iter() + .map(|codec| CodecCapability { + codec, + available: false, + reason: Some(reason), + }) + .collect(), + zero_copy_modes: Vec::new(), + available: false, + reason: Some(reason), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn advertises_only_the_linked_software_codec() { + let backends = video_backends(); + let software = backends + .iter() + .find(|backend| backend.backend == "software") + .expect("software backend"); + assert!(software.available); + assert!( + software + .codecs + .iter() + .find(|codec| codec.codec == "h264") + .expect("h264") + .available + ); + assert!( + software + .codecs + .iter() + .filter(|codec| codec.codec != "h264") + .all(|codec| !codec.available) + ); + #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))] + assert!( + backends + .iter() + .filter(|backend| backend.backend != "software") + .all(|backend| !backend.available) + ); + #[cfg(target_os = "windows")] + { + use opennow_streamer_platform_windows::WindowsGraphicsApi; + for (backend_name, api) in [ + ("d3d12", WindowsGraphicsApi::D3d12), + ("d3d11", WindowsGraphicsApi::D3d11), + ] { + let hardware = backends + .iter() + .find(|backend| backend.backend == backend_name) + .expect("Direct3D backend"); + let probe = opennow_streamer_platform_windows::WindowsBackend::probe_for(api); + assert_eq!(hardware.available, probe.bundled_backend_available()); + assert_eq!( + hardware + .codecs + .iter() + .find(|codec| codec.codec == "h265") + .expect("h265") + .available, + probe.h265_hardware_decode && probe.d3d11_presentation && probe.wasapi_render, + ); + assert_eq!( + hardware + .codecs + .iter() + .find(|codec| codec.codec == "av1") + .expect("av1") + .available, + probe.av1_hardware_decode && probe.d3d11_presentation && probe.wasapi_render, + ); + } + } + #[cfg(target_os = "macos")] + { + let hardware = backends + .iter() + .find(|backend| backend.backend == "videotoolbox") + .expect("VideoToolbox backend"); + assert!( + hardware + .codecs + .iter() + .filter(|codec| codec.codec != "h264") + .all(|codec| !codec.available) + ); + assert_eq!( + hardware.available, + hardware + .codecs + .iter() + .find(|codec| codec.codec == "h264") + .expect("h264") + .available + ); + } + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/linux_backend.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/linux_backend.rs new file mode 100644 index 000000000..3a8c67c64 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/linux_backend.rs @@ -0,0 +1,444 @@ +use std::sync::OnceLock; + +use opennow_streamer_platform_linux::{ + BackendCapability, DecoderPreference, PresentationCapability, probe_video_capabilities, +}; +use opennow_streamer_protocol::{CodecCapability, VideoBackendCapability}; + +const VIDEO_BACKEND_ENV: &str = "OPENNOW_NATIVE_VIDEO_BACKEND"; +const WINDOW_SYSTEM_ENV: &str = "OPENNOW_NATIVE_WINDOW_SYSTEM"; +const CODECS: [&str; 3] = ["h264", "h265", "av1"]; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum LinuxVideoPath { + Hardware(DecoderPreference), + Software, +} + +#[derive(Debug, Clone)] +pub(crate) struct LinuxVideoSelection { + pub(crate) path: LinuxVideoPath, + pub(crate) use_vulkan_output: bool, + pub(crate) fallback_reason: Option, +} + +#[derive(Debug, Clone)] +struct LinuxCapabilitySnapshot { + decoders: Vec, + presentation: PresentationCapability, +} + +impl LinuxCapabilitySnapshot { + fn probe() -> Self { + let (decoders, presentation) = probe_video_capabilities(); + Self { + decoders, + presentation, + } + } + + fn decoder(&self, name: &str) -> BackendCapability { + self.decoders + .iter() + .find(|capability| capability.name == name) + .cloned() + .unwrap_or(BackendCapability { + name: "missing-decoder-probe", + available: false, + detail: format!("capability probe did not return {name}"), + }) + } + + fn codec_decoder(&self, prefix: &str, codec: &str) -> BackendCapability { + self.decoder(&format!("{prefix}-{codec}")) + } + + fn backend_supports_all_codecs(&self, prefix: &str) -> bool { + CODECS + .iter() + .all(|codec| self.codec_decoder(prefix, codec).available) + } + + fn presentation_available(&self, window_system: &str) -> bool { + presentation_available(&self.presentation, window_system) + } +} + +fn presentation_available(presentation: &PresentationCapability, window_system: &str) -> bool { + presentation.available && presentation.window_systems.contains(&window_system) +} + +fn presentation_unavailable_reason( + presentation: &PresentationCapability, + window_system: &str, +) -> String { + if !presentation.available { + return presentation.detail.clone(); + } + format!( + "Vulkan presentation lacks {window_system} WSI required by the active Linux window system" + ) +} + +fn selected_window_system() -> &'static str { + selected_window_system_for( + std::env::var(WINDOW_SYSTEM_ENV).ok().as_deref(), + std::env::var("SDL_VIDEODRIVER").ok().as_deref(), + std::env::var_os("WAYLAND_DISPLAY").is_some(), + std::env::var_os("DISPLAY").is_some(), + ) +} + +fn selected_window_system_for( + requested: Option<&str>, + sdl_driver: Option<&str>, + has_wayland_display: bool, + has_x11_display: bool, +) -> &'static str { + for value in [requested, sdl_driver].into_iter().flatten() { + match value.trim().to_ascii_lowercase().as_str() { + "wayland" => return "wayland", + "x11" => return "x11", + _ => {} + } + } + if has_wayland_display && !has_x11_display { + "wayland" + } else { + "x11" + } +} + +fn capabilities() -> &'static LinuxCapabilitySnapshot { + static CAPABILITIES: OnceLock = OnceLock::new(); + CAPABILITIES.get_or_init(LinuxCapabilitySnapshot::probe) +} + +pub(crate) fn select_video_path() -> LinuxVideoSelection { + select_video_path_for( + std::env::var(VIDEO_BACKEND_ENV).ok().as_deref(), + capabilities(), + selected_window_system(), + ) +} + +fn select_video_path_for( + requested: Option<&str>, + capabilities: &LinuxCapabilitySnapshot, + window_system: &str, +) -> LinuxVideoSelection { + let requested = requested + .map(str::trim) + .filter(|value| !value.is_empty()) + .unwrap_or("auto") + .to_ascii_lowercase(); + let presentation = capabilities.presentation_available(window_system); + let vulkan = capabilities.backend_supports_all_codecs("vulkan-video"); + let cuda = capabilities.backend_supports_all_codecs("cuda"); + let ffmpeg = capabilities.backend_supports_all_codecs("ffmpeg-software"); + let vaapi = capabilities.decoder("vaapi-h264").available; + let v4l2 = capabilities.decoder("v4l2-h264").available; + + let preference = match requested.as_str() { + "vulkan" if vulkan => Some(DecoderPreference::VulkanOnly), + "cuda" | "nvdec" if cuda => Some(DecoderPreference::CudaOnly), + "vaapi" if vaapi => Some(DecoderPreference::VaApiOnly), + "v4l2" if v4l2 => Some(DecoderPreference::V4l2Only), + "software" | "ffmpeg" if ffmpeg => Some(DecoderPreference::SoftwareOnly), + "auto" if vulkan || cuda || vaapi || v4l2 || ffmpeg => Some(DecoderPreference::Automatic), + _ => None, + }; + if let Some(preference) = preference { + return LinuxVideoSelection { + path: LinuxVideoPath::Hardware(preference), + use_vulkan_output: presentation, + fallback_reason: (!presentation).then(|| { + format!( + "{}; using SDL NV12 presentation", + presentation_unavailable_reason(&capabilities.presentation, window_system) + ) + }), + }; + } + + let reason = match requested.as_str() { + "vulkan" => backend_unavailable_reason(capabilities, "vulkan-video"), + "cuda" | "nvdec" => backend_unavailable_reason(capabilities, "cuda"), + "vaapi" => capabilities.decoder("vaapi-h264").detail, + "v4l2" => capabilities.decoder("v4l2-h264").detail, + "software" | "ffmpeg" => backend_unavailable_reason(capabilities, "ffmpeg-software"), + "auto" => format!( + "no Linux decoder is available (Vulkan Video: {}; CUDA/NVDEC: {}; FFmpeg software: {})", + backend_unavailable_reason(capabilities, "vulkan-video"), + backend_unavailable_reason(capabilities, "cuda"), + backend_unavailable_reason(capabilities, "ffmpeg-software"), + ), + other => format!("video backend {other:?} is not supported on Linux"), + }; + LinuxVideoSelection { + path: LinuxVideoPath::Software, + use_vulkan_output: false, + fallback_reason: Some(format!("{reason}; using OpenH264/SDL fallback")), + } +} + +fn backend_unavailable_reason(capabilities: &LinuxCapabilitySnapshot, prefix: &str) -> String { + CODECS + .iter() + .filter_map(|codec| { + let capability = capabilities.codec_decoder(prefix, codec); + (!capability.available).then(|| format!("{codec}: {}", capability.detail)) + }) + .collect::>() + .join(", ") +} + +pub(crate) fn video_backends() -> Vec { + let capabilities = capabilities(); + let window_system = selected_window_system(); + vec![ + multi_codec_capability("vulkan", "vulkan-video", capabilities, window_system, false), + multi_codec_capability("cuda", "cuda", capabilities, window_system, false), + h264_capability("vaapi", "vaapi-h264", capabilities, window_system), + h264_capability("v4l2", "v4l2-h264", capabilities, window_system), + multi_codec_capability( + "ffmpeg", + "ffmpeg-software", + capabilities, + window_system, + false, + ), + ] +} + +fn multi_codec_capability( + backend: &'static str, + prefix: &str, + capabilities: &LinuxCapabilitySnapshot, + window_system: &str, + requires_presentation: bool, +) -> VideoBackendCapability { + let presentation = !requires_presentation || capabilities.presentation_available(window_system); + let codecs = CODECS + .into_iter() + .map(|codec| { + let decoder = capabilities.codec_decoder(prefix, codec); + let available = decoder.available && presentation; + let reason = if !decoder.available { + Some(static_reason(decoder.detail)) + } else if !presentation { + Some(static_reason(presentation_unavailable_reason( + &capabilities.presentation, + window_system, + ))) + } else { + None + }; + CodecCapability { + codec, + available, + reason, + } + }) + .collect::>(); + let available = codecs.iter().any(|codec| codec.available); + let reason = (!available).then(|| { + codecs + .iter() + .find_map(|codec| codec.reason) + .unwrap_or("no supported codecs") + }); + VideoBackendCapability { + backend, + platform: "linux", + codecs, + zero_copy_modes: (backend == "vulkan" + && available + && capabilities.presentation_available(window_system)) + .then_some(vec!["vulkan-video-same-device-nv12"]) + .unwrap_or_default(), + available, + reason, + } +} + +fn h264_capability( + backend: &'static str, + decoder_name: &str, + capabilities: &LinuxCapabilitySnapshot, + window_system: &str, +) -> VideoBackendCapability { + let decoder = capabilities.decoder(decoder_name); + let h264_available = decoder.available; + let h264_reason = if !decoder.available { + Some(static_reason(decoder.detail)) + } else { + None + }; + VideoBackendCapability { + backend, + platform: "linux", + codecs: vec![ + CodecCapability { + codec: "h264", + available: h264_available, + reason: h264_reason, + }, + CodecCapability { + codec: "h265", + available: false, + reason: Some("native backend currently supports H.264 only"), + }, + CodecCapability { + codec: "av1", + available: false, + reason: Some("native backend currently supports H.264 only"), + }, + ], + zero_copy_modes: (backend == "vaapi" + && h264_available + && capabilities.presentation_available(window_system)) + .then_some(vec!["vaapi-drm-prime-dmabuf-vulkan"]) + .unwrap_or_default(), + available: h264_available, + reason: h264_reason, + } +} + +fn static_reason(reason: String) -> &'static str { + Box::leak(reason.into_boxed_str()) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn capability(name: &'static str, available: bool) -> BackendCapability { + BackendCapability { + name, + available, + detail: format!("{name} probe"), + } + } + + fn snapshot( + vulkan_video: bool, + cuda: bool, + software: bool, + presentation: bool, + window_systems: Vec<&'static str>, + ) -> LinuxCapabilitySnapshot { + let mut decoders = Vec::new(); + for codec in CODECS { + decoders.push(capability( + match codec { + "h264" => "vulkan-video-h264", + "h265" => "vulkan-video-h265", + _ => "vulkan-video-av1", + }, + vulkan_video, + )); + decoders.push(capability( + match codec { + "h264" => "cuda-h264", + "h265" => "cuda-h265", + _ => "cuda-av1", + }, + cuda, + )); + decoders.push(capability( + match codec { + "h264" => "ffmpeg-software-h264", + "h265" => "ffmpeg-software-h265", + _ => "ffmpeg-software-av1", + }, + software, + )); + } + decoders.push(capability("vaapi-h264", false)); + decoders.push(capability("v4l2-h264", false)); + LinuxCapabilitySnapshot { + decoders, + presentation: PresentationCapability { + available: presentation, + api: "vulkan", + window_systems, + detail: "vulkan presentation probe".to_owned(), + }, + } + } + + #[test] + fn explicit_backends_select_distinct_decoders() { + let available = snapshot(true, true, true, true, vec!["x11"]); + assert_eq!( + select_video_path_for(Some("vulkan"), &available, "x11").path, + LinuxVideoPath::Hardware(DecoderPreference::VulkanOnly) + ); + assert_eq!( + select_video_path_for(Some("nvdec"), &available, "x11").path, + LinuxVideoPath::Hardware(DecoderPreference::CudaOnly) + ); + assert_eq!( + select_video_path_for(Some("software"), &available, "x11").path, + LinuxVideoPath::Hardware(DecoderPreference::SoftwareOnly) + ); + } + + #[test] + fn automatic_selection_uses_the_complete_codec_pipeline() { + let available = snapshot(true, true, true, true, vec!["wayland"]); + assert_eq!( + select_video_path_for(None, &available, "wayland").path, + LinuxVideoPath::Hardware(DecoderPreference::Automatic) + ); + } + + #[test] + fn presentation_must_match_the_active_window_system() { + let available = snapshot(true, true, true, true, vec!["wayland"]); + let selected = select_video_path_for(None, &available, "x11"); + assert_eq!( + selected.path, + LinuxVideoPath::Hardware(DecoderPreference::Automatic) + ); + assert!(!selected.use_vulkan_output); + assert!( + selected + .fallback_reason + .as_deref() + .is_some_and(|reason| reason.contains("lacks x11 WSI")) + ); + } + + #[test] + fn partial_codec_support_is_not_treated_as_a_complete_explicit_backend() { + let mut available = snapshot(true, true, true, true, vec!["x11"]); + available + .decoders + .iter_mut() + .find(|capability| capability.name == "vulkan-video-av1") + .unwrap() + .available = false; + let selected = select_video_path_for(Some("vulkan"), &available, "x11"); + assert_eq!(selected.path, LinuxVideoPath::Software); + assert!(selected.fallback_reason.unwrap().contains("av1")); + } + + #[test] + fn window_system_selection_prefers_explicit_runtime_contract() { + assert_eq!( + selected_window_system_for(Some("wayland"), Some("x11"), false, true), + "wayland" + ); + assert_eq!( + selected_window_system_for(None, Some("wayland"), true, true), + "wayland" + ); + assert_eq!( + selected_window_system_for(None, None, true, false), + "wayland" + ); + assert_eq!(selected_window_system_for(None, None, true, true), "x11"); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/linux_frame_pacing.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/linux_frame_pacing.rs new file mode 100644 index 000000000..3b73c5fbb --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/linux_frame_pacing.rs @@ -0,0 +1,279 @@ +use std::time::{Duration, Instant}; + +const PACING_OUTLIER: Duration = Duration::from_millis(75); +const MAX_ADAPTIVE_QUEUE_DEPTH: usize = 2; +const JITTER_QUEUE_THRESHOLD: f64 = 0.25; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum FrameSelectionPolicy { + OldestReady, + LatestReady, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) struct PacingDecision { + pub(crate) selection: FrameSelectionPolicy, + pub(crate) target_queue_depth: usize, +} + +/// Display-clocked frame scheduler modelled after the native GFN client's +/// timestamp/adaptive queue. Decode is allowed to run independently, but only +/// one selected frame is submitted to the FIFO swapchain per presentation +/// interval. Fast streams deliberately sample the newest decoded frame rather +/// than building a backlog that WSI must discard later. +#[derive(Debug)] +pub(crate) struct LinuxFramePacer { + stream_interval: Duration, + display_interval: Option, + presentation_interval: Duration, + fast_stream: bool, + vrr_enabled: bool, + last_arrival: Option<(Instant, u64)>, + jitter_ema_ns: f64, + jitter_bound_ns: f64, + next_deadline: Option, +} + +impl LinuxFramePacer { + pub(crate) fn new(stream_fps: u32, display_refresh_hz: Option, vrr_enabled: bool) -> Self { + let stream_interval = frame_interval(stream_fps); + let display_interval = display_refresh_hz.map(frame_interval); + let (presentation_interval, fast_stream) = pacing_mode(stream_interval, display_interval); + Self { + stream_interval, + display_interval, + presentation_interval, + fast_stream, + vrr_enabled, + last_arrival: None, + jitter_ema_ns: 0.0, + jitter_bound_ns: 0.0, + next_deadline: None, + } + } + + pub(crate) fn reconfigure(&mut self, stream_fps: u32, display_refresh_hz: Option) -> bool { + let stream_interval = frame_interval(stream_fps); + let display_interval = display_refresh_hz.map(frame_interval); + if self.stream_interval == stream_interval && self.display_interval == display_interval { + return false; + } + self.stream_interval = stream_interval; + self.display_interval = display_interval; + (self.presentation_interval, self.fast_stream) = + pacing_mode(stream_interval, display_interval); + self.reset(); + true + } + + pub(crate) fn reset(&mut self) { + self.last_arrival = None; + self.jitter_ema_ns = 0.0; + self.jitter_bound_ns = 0.0; + self.next_deadline = None; + } + + pub(crate) fn is_due(&self, now: Instant) -> bool { + if self.vrr_enabled { + return true; + } + self.next_deadline.is_none_or(|deadline| now >= deadline) + } + + pub(crate) fn decision(&self, now: Instant) -> PacingDecision { + // With compositor VRR enabled, submit the freshest complete server + // frame immediately. FIFO provides tear-free scanout while the output + // refresh follows server arrival timing; replaying a burst after a + // hitch would defeat Cloud G-SYNC and add input latency. + if self.vrr_enabled { + return PacingDecision { + selection: FrameSelectionPolicy::LatestReady, + target_queue_depth: 0, + }; + } + let stalled = self + .next_deadline + .is_some_and(|deadline| now.saturating_duration_since(deadline) > PACING_OUTLIER); + if self.fast_stream || stalled { + return PacingDecision { + selection: FrameSelectionPolicy::LatestReady, + target_queue_depth: 0, + }; + } + PacingDecision { + selection: FrameSelectionPolicy::OldestReady, + target_queue_depth: self.adaptive_queue_depth(), + } + } + + pub(crate) fn observe_frame(&mut self, arrived_at: Instant, timestamp_us: u64) { + let Some((previous_arrival, previous_timestamp_us)) = + self.last_arrival.replace((arrived_at, timestamp_us)) + else { + return; + }; + let arrival_interval = arrived_at.saturating_duration_since(previous_arrival); + let Some(timestamp_delta_us) = timestamp_us.checked_sub(previous_timestamp_us) else { + self.clear_timing_history(); + return; + }; + let media_interval = Duration::from_micros(timestamp_delta_us); + if arrival_interval.is_zero() + || media_interval.is_zero() + || arrival_interval > PACING_OUTLIER + || media_interval > PACING_OUTLIER + { + self.clear_timing_history(); + return; + } + + let jitter_ns = arrival_interval.abs_diff(media_interval).as_nanos() as f64; + self.jitter_ema_ns = if self.jitter_ema_ns == 0.0 { + jitter_ns + } else { + self.jitter_ema_ns * 0.90 + jitter_ns * 0.10 + }; + // Keep a decaying bound so a transient burst is absorbed, but does not + // leave the stream permanently buffered after conditions recover. + self.jitter_bound_ns = (self.jitter_bound_ns * 0.98).max(jitter_ns); + } + + pub(crate) fn mark_presented(&mut self, now: Instant) { + if self.vrr_enabled { + self.next_deadline = None; + return; + } + let next = self + .next_deadline + .map_or(now + self.presentation_interval, |deadline| { + deadline + self.presentation_interval + }); + // Never replay missed deadlines. A hitch rebases the presentation + // clock and stale frames are handled by `LatestReady` on the next tick. + self.next_deadline = Some(if next <= now { + now + self.presentation_interval + } else { + next + }); + } + + pub(crate) const fn fast_stream(&self) -> bool { + self.fast_stream + } + + pub(crate) const fn vrr_enabled(&self) -> bool { + self.vrr_enabled + } + + pub(crate) fn presentation_hz(&self) -> f64 { + 1.0 / self.presentation_interval.as_secs_f64() + } + + fn adaptive_queue_depth(&self) -> usize { + if self.jitter_bound_ns == 0.0 { + return 0; + } + let interval_ns = self.presentation_interval.as_nanos() as f64; + let target_ns = (self.jitter_ema_ns + self.jitter_bound_ns * 0.5) * 1.25; + if target_ns < interval_ns * JITTER_QUEUE_THRESHOLD { + return 0; + } + ((target_ns / interval_ns).ceil() as usize).min(MAX_ADAPTIVE_QUEUE_DEPTH) + } + + fn clear_timing_history(&mut self) { + self.last_arrival = None; + self.jitter_ema_ns = 0.0; + self.jitter_bound_ns = 0.0; + self.next_deadline = None; + } +} + +fn frame_interval(fps: u32) -> Duration { + Duration::from_secs_f64(1.0 / f64::from(fps.max(1))) +} + +fn pacing_mode(stream_interval: Duration, display_interval: Option) -> (Duration, bool) { + let Some(display_interval) = display_interval else { + return (stream_interval, false); + }; + // Matches the official client's observed mismatch boundary: a server + // interval below 75% of the display interval is treated as a fast stream. + let fast_stream = stream_interval.as_secs_f64() < display_interval.as_secs_f64() * 0.75; + (stream_interval.max(display_interval), fast_stream) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn fast_stream_samples_latest_at_display_rate() { + let pacer = LinuxFramePacer::new(240, Some(165), false); + assert!(pacer.fast_stream()); + assert_eq!( + pacer.decision(Instant::now()).selection, + FrameSelectionPolicy::LatestReady + ); + assert!((pacer.presentation_hz() - 165.0).abs() < 0.01); + } + + #[test] + fn matched_stream_uses_ordered_adaptive_queue() { + let pacer = LinuxFramePacer::new(120, Some(165), false); + assert!(!pacer.fast_stream()); + assert_eq!( + pacer.decision(Instant::now()), + PacingDecision { + selection: FrameSelectionPolicy::OldestReady, + target_queue_depth: 0, + } + ); + assert!((pacer.presentation_hz() - 120.0).abs() < 0.01); + } + + #[test] + fn missed_deadline_is_rebased_without_catch_up_burst() { + let mut pacer = LinuxFramePacer::new(120, Some(120), false); + let origin = Instant::now(); + pacer.mark_presented(origin); + let late = origin + Duration::from_millis(20); + pacer.mark_presented(late); + assert!(!pacer.is_due(late)); + assert!(pacer.is_due(late + Duration::from_millis(9))); + } + + #[test] + fn sustained_arrival_jitter_adds_bounded_queue_depth() { + let mut pacer = LinuxFramePacer::new(120, Some(165), false); + let origin = Instant::now(); + pacer.observe_frame(origin, 0); + for index in 1..20_u64 { + pacer.observe_frame( + origin + Duration::from_micros(index * 13_000), + index * 8_333, + ); + } + let decision = pacer.decision(origin + Duration::from_millis(300)); + assert_eq!(decision.selection, FrameSelectionPolicy::OldestReady); + assert!(decision.target_queue_depth > 0); + assert!(decision.target_queue_depth <= MAX_ADAPTIVE_QUEUE_DEPTH); + } + + #[test] + fn vrr_submits_latest_frame_without_a_fixed_deadline() { + let mut pacer = LinuxFramePacer::new(120, Some(165), true); + let now = Instant::now(); + assert!(pacer.is_due(now)); + assert!(pacer.vrr_enabled()); + assert_eq!( + pacer.decision(now), + PacingDecision { + selection: FrameSelectionPolicy::LatestReady, + target_queue_depth: 0, + } + ); + pacer.mark_presented(now); + assert!(pacer.is_due(now)); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/macos_backend.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/macos_backend.rs new file mode 100644 index 000000000..81011e11c --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/macos_backend.rs @@ -0,0 +1,278 @@ +use opennow_streamer_platform_macos::{ + AudioFormat, BackendConfig, H264Format, H264Framing, H264ParameterSets, MacOsBackend, + OwnedOverlayConfig, QueueLimits, ScreenRect, StreamSink, SurfaceTarget, VideoColorSpace, + probe_h264_hardware, +}; +use opennow_streamer_protocol::{RenderSurface, RenderSurfaceRect}; +use std::sync::OnceLock; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::time::{Duration, Instant}; + +const HIDDEN_SURFACE: ScreenRect = ScreenRect::new(0.0, 0.0, 2.0, 2.0); +const ORDERING_POLL_INTERVAL: Duration = Duration::from_millis(100); + +pub(crate) fn available() -> bool { + availability().load(Ordering::Acquire) +} + +pub(crate) fn disable() { + availability().store(false, Ordering::Release); +} + +fn availability() -> &'static AtomicBool { + static AVAILABLE: OnceLock = OnceLock::new(); + AVAILABLE.get_or_init(|| AtomicBool::new(probe_h264_hardware())) +} + +pub(crate) struct MacOutput { + backend: Option, + screen_rect: ScreenRect, + visible: bool, + paused: bool, + last_ordering_check: Instant, + failure_reported: bool, +} + +impl MacOutput { + pub(crate) fn initialize() -> Self { + Self { + backend: None, + screen_rect: HIDDEN_SURFACE, + visible: false, + paused: false, + last_ordering_check: Instant::now(), + failure_reported: false, + } + } + + pub(crate) fn start(&mut self, surface: Option<&RenderSurface>) -> Result<(), String> { + self.paused = false; + self.failure_reported = false; + if let Some(surface) = surface { + self.update_surface(surface)?; + } + Ok(()) + } + + pub(crate) fn configure_h264( + &mut self, + parameter_sets: H264ParameterSets, + ) -> Result { + if self.backend.is_some() { + return Err("macOS VideoToolbox backend is already configured".to_owned()); + } + let mut backend = MacOsBackend::start(BackendConfig { + surface: SurfaceTarget::OwnedOverlay(OwnedOverlayConfig::new( + self.screen_rect, + self.visible && !self.paused, + )), + video: H264Format::new(parameter_sets, VideoColorSpace::Bt709), + audio: AudioFormat::OPUS_STEREO_48KHZ, + queues: QueueLimits::default(), + }) + .map_err(|error| format!("VideoToolbox backend initialization failed: {error}"))?; + backend + .set_paused(self.paused) + .map_err(|error| format!("VideoToolbox pause state failed: {error}"))?; + let sink = backend.sink(); + self.backend = Some(backend); + Ok(sink) + } + + pub(crate) fn set_paused(&mut self, paused: bool) -> Result<(), String> { + self.paused = paused; + if let Some(backend) = self.backend.as_mut() { + backend + .set_paused(paused) + .map_err(|error| format!("macOS media pause failed: {error}"))?; + backend + .update_owned_overlay(self.screen_rect, self.visible && !paused) + .map_err(|error| format!("macOS overlay pause failed: {error}"))?; + } + Ok(()) + } + + pub(crate) fn stop(&mut self) { + if let Some(mut backend) = self.backend.take() { + backend.stop(); + } + self.paused = false; + } + + pub(crate) fn update_surface(&mut self, surface: &RenderSurface) -> Result<(), String> { + if surface.visible { + self.screen_rect = surface.screen_rect.map(screen_rect).ok_or_else(|| { + "visible macOS overlay is missing absolute screen bounds".to_owned() + })?; + } + self.visible = surface.visible && surface.screen_rect.is_some(); + if let Some(backend) = self.backend.as_mut() { + backend + .update_owned_overlay(self.screen_rect, self.visible && !self.paused) + .map_err(|error| format!("macOS overlay update failed: {error}"))?; + } + Ok(()) + } + + pub(crate) fn pump(&mut self) -> Result<(), String> { + if !self.failure_reported + && let Some(failure) = self.backend.as_ref().and_then(MacOsBackend::fatal_failure) + { + self.failure_reported = true; + return Err(format!( + "{} backend failed: {}", + failure.subsystem.name(), + failure.message + )); + } + if self.last_ordering_check.elapsed() < ORDERING_POLL_INTERVAL { + return Ok(()); + } + self.last_ordering_check = Instant::now(); + if let Some(backend) = self.backend.as_mut() { + backend + .refresh_overlay_ordering() + .map_err(|error| format!("macOS overlay ordering refresh failed: {error}"))?; + } + Ok(()) + } +} + +fn screen_rect(rect: RenderSurfaceRect) -> ScreenRect { + ScreenRect::new( + f64::from(rect.x), + f64::from(rect.y), + f64::from(rect.width), + f64::from(rect.height), + ) +} + +#[derive(Default)] +pub(crate) struct H264ParameterSetTracker { + sequence: Option>, + picture: Option>, +} + +impl H264ParameterSetTracker { + pub(crate) fn observe(&mut self, access_unit: &[u8]) -> Result { + let framing = if find_start_code(access_unit, 0).is_some() { + self.observe_annex_b(access_unit)?; + H264Framing::AnnexB + } else { + self.observe_avcc(access_unit)?; + H264Framing::Avcc + }; + Ok(framing) + } + + pub(crate) fn parameter_sets(&self) -> Result, String> { + match (&self.sequence, &self.picture) { + (Some(sequence), Some(picture)) => H264ParameterSets::new(sequence, picture) + .map(Some) + .map_err(|error| format!("invalid H.264 parameter sets: {error}")), + _ => Ok(None), + } + } + + fn observe_annex_b(&mut self, access_unit: &[u8]) -> Result<(), String> { + let Some((mut start, prefix)) = find_start_code(access_unit, 0) else { + return Err("H.264 access unit has no Annex B start code".to_owned()); + }; + if access_unit[..start].iter().any(|byte| *byte != 0) { + return Err("H.264 access unit has invalid Annex B framing".to_owned()); + } + start += prefix; + loop { + let next = find_start_code(access_unit, start); + let end = next.map_or(access_unit.len(), |(offset, _)| offset); + self.observe_nal(&access_unit[start..end])?; + let Some((next_start, next_prefix)) = next else { + return Ok(()); + }; + start = next_start + next_prefix; + } + } + + fn observe_avcc(&mut self, access_unit: &[u8]) -> Result<(), String> { + let mut offset = 0usize; + while offset < access_unit.len() { + let length_bytes = access_unit + .get(offset..offset + 4) + .ok_or_else(|| "H.264 access unit has truncated AVCC framing".to_owned())?; + let length = u32::from_be_bytes( + length_bytes + .try_into() + .expect("AVCC length was checked as four bytes"), + ) as usize; + offset += 4; + let end = offset + .checked_add(length) + .filter(|end| *end <= access_unit.len()) + .ok_or_else(|| "H.264 access unit has invalid AVCC framing".to_owned())?; + self.observe_nal(&access_unit[offset..end])?; + offset = end; + } + if offset == 0 { + return Err("H.264 access unit is empty".to_owned()); + } + Ok(()) + } + + fn observe_nal(&mut self, nal: &[u8]) -> Result<(), String> { + let header = *nal + .first() + .ok_or_else(|| "H.264 access unit contains an empty NAL unit".to_owned())?; + match header & 0x1f { + 7 => self.sequence = Some(nal.to_vec()), + 8 => self.picture = Some(nal.to_vec()), + _ => {} + } + Ok(()) + } +} + +fn find_start_code(bytes: &[u8], from: usize) -> Option<(usize, usize)> { + let mut index = from; + while index + 3 <= bytes.len() { + if bytes[index..].starts_with(&[0, 0, 0, 1]) { + return Some((index, 4)); + } + if bytes[index..].starts_with(&[0, 0, 1]) { + return Some((index, 3)); + } + index += 1; + } + None +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn extracts_parameter_sets_from_annex_b_access_unit() { + let mut tracker = H264ParameterSetTracker::default(); + let framing = tracker + .observe(&[ + 0, 0, 0, 1, 0x67, 0x64, 0, 0x29, 0, 0, 1, 0x68, 0xee, 0x3c, 0x80, 0, 0, 0, 1, 0x65, + 1, + ]) + .unwrap(); + assert_eq!(framing, H264Framing::AnnexB); + let parameters = tracker.parameter_sets().unwrap().unwrap(); + assert_eq!(parameters.sequence(), &[0x67, 0x64, 0, 0x29]); + assert_eq!(parameters.picture(), &[0x68, 0xee, 0x3c, 0x80]); + } + + #[test] + fn extracts_parameter_sets_across_avcc_access_units() { + let mut tracker = H264ParameterSetTracker::default(); + assert_eq!( + tracker.observe(&[0, 0, 0, 2, 0x67, 1]).unwrap(), + H264Framing::Avcc + ); + assert!(tracker.parameter_sets().unwrap().is_none()); + tracker.observe(&[0, 0, 0, 2, 0x68, 2]).unwrap(); + assert!(tracker.parameter_sets().unwrap().is_some()); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/media.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/media.rs new file mode 100644 index 000000000..8bfd5990d --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/media.rs @@ -0,0 +1,1877 @@ +use std::collections::VecDeque; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc::Sender; +use std::sync::{Arc, Mutex}; +use std::thread::{self, JoinHandle}; + +use openh264::OpenH264API; +use openh264::decoder::{Decoder as OpenH264Decoder, DecoderConfig}; +use openh264::formats::YUVSource; +use opus::{Channels, Decoder as OpusNativeDecoder}; + +#[cfg(target_os = "windows")] +use crate::output::WindowsBridge; +use crate::output::{DecodedVideoFrame, OutputBuffers}; +use crate::queue::{BoundedQueue, PushResult}; +use crate::runtime::HostCommand; + +#[cfg(target_os = "linux")] +use crate::linux_backend::{LinuxVideoPath, LinuxVideoSelection}; + +const VIDEO_QUEUE_CAPACITY: usize = 2; +const AUDIO_QUEUE_CAPACITY: usize = 4; +const OPUS_SAMPLE_RATE: u32 = 48_000; +const MAX_OPUS_FRAME_SAMPLES_PER_CHANNEL: usize = 5_760; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum MediaVideoCodec { + H264, + H265, + Av1, +} + +impl MediaVideoCodec { + pub const fn label(self) -> &'static str { + match self { + Self::H264 => "h264", + Self::H265 => "h265", + Self::Av1 => "av1", + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MediaStreamConfig { + pub codec: MediaVideoCodec, + pub width: u32, + pub height: u32, + pub fps: u32, + pub bitrate_bps: u32, + /// CloudMatch accepted Cloud G-SYNC and the host presentation path is VRR-capable. + pub cloud_gsync: bool, +} + +impl Default for MediaStreamConfig { + fn default() -> Self { + Self { + codec: MediaVideoCodec::H264, + width: 1920, + height: 1080, + fps: 60, + bitrate_bps: 10_000_000, + cloud_gsync: false, + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum MediaCodec { + H264, + H265, + Av1, + Opus { channels: u8 }, + Unsupported(String), +} + +#[derive(Debug, Clone)] +pub struct EncodedFrame { + pub mid: String, + pub codec: MediaCodec, + pub data: Arc<[u8]>, + pub timestamp: u64, + pub clock_rate_hz: u32, + pub keyframe: bool, + pub contiguous: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum CapturedInput { + Key { + virtual_key: u16, + modifiers: u16, + pressed: bool, + }, + MouseMove { + delta_x: i16, + delta_y: i16, + }, + MouseAbsolute { + x: u16, + y: u16, + width: u16, + height: u16, + }, + MouseButton { + button: u8, + pressed: bool, + }, + MouseWheel { + delta: i16, + }, +} + +const CAPTURED_INPUT_CAPACITY: usize = 256; + +#[derive(Debug, Default)] +pub struct CapturedInputQueue { + pending: Mutex>, + overflowed: AtomicBool, +} + +impl CapturedInputQueue { + pub fn push(&self, input: CapturedInput) { + let mut pending = self + .pending + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner); + if matches!(input, CapturedInput::MouseAbsolute { .. }) + && matches!(pending.back(), Some(CapturedInput::MouseAbsolute { .. })) + { + pending.pop_back(); + } + if pending.len() == CAPTURED_INPUT_CAPACITY { + if let Some(index) = pending.iter().position(|event| { + matches!( + event, + CapturedInput::MouseMove { .. } | CapturedInput::MouseAbsolute { .. } + ) + }) { + pending.remove(index); + } else { + self.overflowed.store(true, Ordering::Release); + return; + } + } + pending.push_back(input); + } + + pub fn take(&self) -> Option { + self.pending + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner) + .pop_front() + } + + pub fn take_overflowed(&self) -> bool { + self.overflowed.swap(false, Ordering::AcqRel) + } + + pub fn clear(&self) { + self.pending + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner) + .clear(); + self.overflowed.store(false, Ordering::Release); + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum MediaFeedback { + VideoFrameAccepted { + timestamp: u64, + bytes: u32, + keyframe: bool, + }, + PlaybackStarted { + backend: &'static str, + }, + BackendFallback { + from: &'static str, + to: &'static str, + reason: String, + }, + RequestKeyframe { + mid: String, + reason: String, + }, + DecoderError { + codec: &'static str, + message: String, + }, + QueueDropped { + media: &'static str, + count: usize, + }, + OutputError { + message: String, + }, + DeviceLost { + subsystem: &'static str, + recovered: bool, + message: Option, + }, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PushOutcome { + Queued, + DroppedOldest, + Paused, + Unsupported, + Closed, +} + +struct SharedPipeline { + video: Arc>, + audio: Arc>, + output: Arc, + feedback: Sender, + paused: AtomicBool, + video_desynced: AtomicBool, + keyframe_requested: AtomicBool, + stopped: AtomicBool, + #[cfg(target_os = "macos")] + mac_sink: Mutex>, + #[cfg(target_os = "macos")] + mac_software_fallback: AtomicBool, + #[cfg(target_os = "windows")] + windows_bridge: Arc, + #[cfg(target_os = "linux")] + linux_session: Mutex>, + #[cfg(target_os = "linux")] + linux_software_fallback: Arc, + #[cfg(target_os = "linux")] + linux_video_mid: Mutex, + #[cfg(target_os = "linux")] + linux_codec: MediaVideoCodec, +} + +#[derive(Clone)] +pub struct MediaSink { + shared: Arc, +} + +impl MediaSink { + pub fn push(&self, frame: EncodedFrame) -> PushOutcome { + if self.shared.stopped.load(Ordering::Acquire) { + return PushOutcome::Closed; + } + if self.shared.paused.load(Ordering::Acquire) { + return PushOutcome::Paused; + } + match frame.codec { + MediaCodec::H264 | MediaCodec::H265 | MediaCodec::Av1 => self.push_video(frame), + MediaCodec::Opus { .. } => self.push_audio(frame), + MediaCodec::Unsupported(_) => PushOutcome::Unsupported, + } + } + + fn push_video(&self, frame: EncodedFrame) -> PushOutcome { + #[cfg(target_os = "linux")] + self.shared + .output + .record_received_video_bytes(frame.data.len()); + if !frame.keyframe && self.shared.video_desynced.load(Ordering::Acquire) { + self.mark_video_desynced(&frame.mid, "waiting for a decodable H.264 keyframe"); + } else if !frame.contiguous { + self.mark_video_desynced(&frame.mid, "RTP video discontinuity"); + } + let mid = frame.mid.clone(); + match self.shared.video.push(frame) { + PushResult::Queued => PushOutcome::Queued, + PushResult::DroppedOldest => { + self.mark_video_desynced(&mid, "encoded video queue overflow"); + let _ = self.shared.feedback.send(MediaFeedback::QueueDropped { + media: "video", + count: 1, + }); + PushOutcome::DroppedOldest + } + PushResult::Closed => PushOutcome::Closed, + } + } + + fn push_audio(&self, frame: EncodedFrame) -> PushOutcome { + match self.shared.audio.push(frame) { + PushResult::Queued => PushOutcome::Queued, + PushResult::DroppedOldest => { + let _ = self.shared.feedback.send(MediaFeedback::QueueDropped { + media: "audio", + count: 1, + }); + PushOutcome::DroppedOldest + } + PushResult::Closed => PushOutcome::Closed, + } + } + + fn mark_video_desynced(&self, mid: &str, reason: &str) { + self.shared.video_desynced.store(true, Ordering::Release); + if !self.shared.keyframe_requested.swap(true, Ordering::AcqRel) { + let _ = self.shared.feedback.send(MediaFeedback::RequestKeyframe { + mid: mid.to_owned(), + reason: reason.to_owned(), + }); + } + } +} + +pub struct MediaSession { + sink: MediaSink, + video_worker: Option>, + audio_worker: Option>, + #[cfg(target_os = "linux")] + linux_monitor: Option>, + host_commands: Sender, +} + +#[derive(Clone)] +pub struct MediaControl { + shared: Arc, + host_commands: Sender, +} + +impl MediaSession { + pub fn captured_input(&self) -> Arc { + self.sink.shared.output.captured_input() + } + + pub(crate) fn spawn( + output: Arc, + feedback: Sender, + host_commands: Sender, + use_hardware: bool, + stream: MediaStreamConfig, + #[cfg(target_os = "windows")] windows_bridge: Arc, + #[cfg(target_os = "linux")] linux_selection: LinuxVideoSelection, + #[cfg(target_os = "linux")] linux_software_fallback: Arc, + ) -> Result { + #[cfg(not(target_os = "linux"))] + let _ = &stream; + #[cfg(target_os = "macos")] + if use_hardware { + return Self::spawn_macos(output, feedback, host_commands); + } + #[cfg(target_os = "windows")] + let use_windows_hardware = use_hardware && windows_bridge.backend().is_some(); + #[cfg(not(target_os = "windows"))] + let use_windows_hardware = false; + #[cfg(not(any(target_os = "windows", target_os = "macos")))] + let _ = use_hardware; + #[cfg(target_os = "linux")] + if !linux_software_fallback.load(Ordering::Acquire) + && let LinuxVideoPath::Hardware(decoder_preference) = linux_selection.path + { + match Self::spawn_linux( + Arc::clone(&output), + feedback.clone(), + host_commands.clone(), + stream, + decoder_preference, + Arc::clone(&linux_software_fallback), + ) { + Ok(session) => return Ok(session), + Err(reason) => { + if stream.codec != MediaVideoCodec::H264 { + return Err(format!( + "Linux {} decoder startup failed: {reason}", + stream.codec.label().to_ascii_uppercase() + )); + } + linux_software_fallback.store(true, Ordering::Release); + let _ = host_commands.send(HostCommand::FallbackLinux { + reason: format!("Linux hardware media startup failed: {reason}"), + }); + } + } + } + if !use_windows_hardware && stream.codec != MediaVideoCodec::H264 { + return Err(format!( + "{} requires the Windows hardware decoder", + stream.codec.label().to_ascii_uppercase() + )); + } + let video_decoder = (!use_windows_hardware).then(H264Decoder::new).transpose()?; + let audio_decoder = OpusDecoder::new(2)?; + let shared = Arc::new(SharedPipeline { + video: Arc::new(BoundedQueue::new(VIDEO_QUEUE_CAPACITY)), + audio: Arc::new(BoundedQueue::new(AUDIO_QUEUE_CAPACITY)), + output, + feedback, + paused: AtomicBool::new(false), + video_desynced: AtomicBool::new(true), + keyframe_requested: AtomicBool::new(false), + stopped: AtomicBool::new(false), + #[cfg(target_os = "macos")] + mac_sink: Mutex::new(None), + #[cfg(target_os = "macos")] + mac_software_fallback: AtomicBool::new(false), + #[cfg(target_os = "windows")] + windows_bridge, + #[cfg(target_os = "linux")] + linux_session: Mutex::new(None), + #[cfg(target_os = "linux")] + linux_software_fallback, + #[cfg(target_os = "linux")] + linux_video_mid: Mutex::new(String::new()), + #[cfg(target_os = "linux")] + linux_codec: stream.codec, + }); + let video_shared = Arc::clone(&shared); + let video_worker = thread::Builder::new() + .name(format!("opennow-{}-decode", stream.codec.label())) + .spawn(move || { + #[cfg(target_os = "windows")] + if use_windows_hardware { + run_windows_video(video_shared, stream.fps); + return; + } + run_video_decoder( + video_shared, + video_decoder.expect("software decoder was initialized"), + ); + }) + .map_err(|error| format!("failed to start video decoder worker: {error}"))?; + let audio_shared = Arc::clone(&shared); + let audio_worker = match thread::Builder::new() + .name("opennow-opus-decode".to_owned()) + .spawn(move || run_audio_decoder(audio_shared, audio_decoder)) + { + Ok(worker) => worker, + Err(error) => { + shared.video.close(); + let _ = video_worker.join(); + return Err(format!("failed to start Opus decoder worker: {error}")); + } + }; + Ok(Self { + sink: MediaSink { shared }, + video_worker: Some(video_worker), + audio_worker: Some(audio_worker), + #[cfg(target_os = "linux")] + linux_monitor: None, + host_commands, + }) + } + + #[cfg(target_os = "macos")] + fn spawn_macos( + output: Arc, + feedback: Sender, + host_commands: Sender, + ) -> Result { + let shared = Arc::new(SharedPipeline { + video: Arc::new(BoundedQueue::new(VIDEO_QUEUE_CAPACITY)), + audio: Arc::new(BoundedQueue::new(AUDIO_QUEUE_CAPACITY)), + output, + feedback, + paused: AtomicBool::new(false), + video_desynced: AtomicBool::new(true), + keyframe_requested: AtomicBool::new(false), + stopped: AtomicBool::new(false), + mac_sink: Mutex::new(None), + mac_software_fallback: AtomicBool::new(false), + }); + let video_shared = Arc::clone(&shared); + let video_commands = host_commands.clone(); + let video_worker = thread::Builder::new() + .name("opennow-videotoolbox-submit".to_owned()) + .spawn(move || run_macos_video(video_shared, video_commands)) + .map_err(|error| format!("failed to start VideoToolbox submit worker: {error}"))?; + let audio_shared = Arc::clone(&shared); + let audio_worker = match thread::Builder::new() + .name("opennow-coreaudio-submit".to_owned()) + .spawn(move || run_macos_audio(audio_shared)) + { + Ok(worker) => worker, + Err(error) => { + shared.video.close(); + let _ = video_worker.join(); + return Err(format!("failed to start CoreAudio submit worker: {error}")); + } + }; + Ok(Self { + sink: MediaSink { shared }, + video_worker: Some(video_worker), + audio_worker: Some(audio_worker), + #[cfg(target_os = "linux")] + linux_monitor: None, + host_commands, + }) + } + + #[cfg(target_os = "linux")] + fn spawn_linux( + output: Arc, + feedback: Sender, + host_commands: Sender, + stream: MediaStreamConfig, + decoder_preference: opennow_streamer_platform_linux::DecoderPreference, + software_fallback: Arc, + ) -> Result { + let format = opennow_streamer_platform_linux::StreamFormat::video_default( + stream.width, + stream.height, + ) + .map_err(|error| error.to_string())?; + let mut config = opennow_streamer_platform_linux::SessionConfig::new(format); + config.codec = match stream.codec { + MediaVideoCodec::H264 => opennow_streamer_platform_linux::VideoCodec::H264, + MediaVideoCodec::H265 => opennow_streamer_platform_linux::VideoCodec::H265, + MediaVideoCodec::Av1 => opennow_streamer_platform_linux::VideoCodec::Av1, + }; + config.decoder_preference = decoder_preference; + config.audio = None; + let session = opennow_streamer_platform_linux::LinuxSession::start(config) + .map_err(|error| error.to_string())?; + let shared = Arc::new(SharedPipeline { + video: Arc::new(BoundedQueue::new(VIDEO_QUEUE_CAPACITY)), + audio: Arc::new(BoundedQueue::new(AUDIO_QUEUE_CAPACITY)), + output, + feedback, + paused: AtomicBool::new(false), + video_desynced: AtomicBool::new(true), + keyframe_requested: AtomicBool::new(false), + stopped: AtomicBool::new(false), + linux_session: Mutex::new(Some(session)), + linux_software_fallback: software_fallback, + linux_video_mid: Mutex::new(String::new()), + linux_codec: stream.codec, + }); + let video_shared = Arc::clone(&shared); + let video_commands = host_commands.clone(); + let video_worker = thread::Builder::new() + .name("opennow-linux-video-submit".to_owned()) + .spawn(move || run_linux_video(video_shared, video_commands)) + .map_err(|error| format!("failed to start Linux video submit worker: {error}"))?; + let audio_decoder = OpusDecoder::new(2)?; + let audio_shared = Arc::clone(&shared); + let audio_worker = match thread::Builder::new() + .name("opennow-opus-decode".to_owned()) + .spawn(move || run_audio_decoder(audio_shared, audio_decoder)) + { + Ok(worker) => worker, + Err(error) => { + shared.video.close(); + let _ = video_worker.join(); + return Err(format!( + "failed to start Linux audio submit worker: {error}" + )); + } + }; + let monitor_shared = Arc::clone(&shared); + let monitor_commands = host_commands.clone(); + let linux_monitor = match thread::Builder::new() + .name("opennow-linux-media-events".to_owned()) + .spawn(move || run_linux_monitor(monitor_shared, monitor_commands)) + { + Ok(worker) => worker, + Err(error) => { + shared.video.close(); + shared.audio.close(); + let _ = video_worker.join(); + let _ = audio_worker.join(); + return Err(format!("failed to start Linux media monitor: {error}")); + } + }; + Ok(Self { + sink: MediaSink { shared }, + video_worker: Some(video_worker), + audio_worker: Some(audio_worker), + linux_monitor: Some(linux_monitor), + host_commands, + }) + } + + pub fn sink(&self) -> MediaSink { + self.sink.clone() + } + + pub fn control(&self) -> MediaControl { + MediaControl { + shared: Arc::clone(&self.sink.shared), + host_commands: self.host_commands.clone(), + } + } + + pub fn set_paused(&self, paused: bool) { + self.sink.shared.paused.store(paused, Ordering::Release); + self.sink.shared.video.clear(); + self.sink.shared.audio.clear(); + self.sink.shared.output.clear(); + #[cfg(target_os = "linux")] + if let Some(session) = self + .sink + .shared + .linux_session + .lock() + .unwrap_or_else(|error| error.into_inner()) + .as_ref() + { + let _ = session.set_paused(paused); + } + if !paused { + self.sink + .shared + .video_desynced + .store(true, Ordering::Release); + self.sink + .shared + .keyframe_requested + .store(false, Ordering::Release); + } + let _ = self.host_commands.send(HostCommand::Pause { + paused, + reply: None, + }); + } + + pub fn stop(mut self) { + self.stop_inner(); + } + + fn stop_inner(&mut self) { + self.control().stop(); + if let Some(worker) = self.video_worker.take() { + let _ = worker.join(); + } + if let Some(worker) = self.audio_worker.take() { + let _ = worker.join(); + } + #[cfg(target_os = "linux")] + if let Some(worker) = self.linux_monitor.take() { + let _ = worker.join(); + } + #[cfg(target_os = "macos")] + { + self.sink + .shared + .mac_sink + .lock() + .unwrap_or_else(|error| error.into_inner()) + .take(); + } + } +} + +impl MediaControl { + pub fn update_cursor(&self, bytes: Vec) { + let _ = self.host_commands.send(HostCommand::Cursor(bytes)); + } + + pub fn stop(&self) { + if self.shared.stopped.swap(true, Ordering::AcqRel) { + return; + } + self.shared.video.close(); + self.shared.audio.close(); + self.shared.output.clear(); + let _ = self.host_commands.send(HostCommand::Stop); + } +} + +#[cfg(target_os = "windows")] +fn run_windows_video(shared: Arc, maximum_fps: u32) { + use opennow_streamer_platform_windows::{ + EncodedVideoFrame, PushOutcome as WindowsPushOutcome, VideoCodec, + }; + + let mut sample_clock = AdaptiveSampleClock::new(maximum_fps); + while let Some(frame) = shared.video.pop() { + if shared.paused.load(Ordering::Acquire) { + continue; + } + if shared.windows_bridge.use_software() { + shared.video_desynced.store(true, Ordering::Release); + match H264Decoder::new() { + Ok(decoder) => run_video_decoder_from(shared, decoder, Some(frame)), + Err(message) => { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "h264", + message, + }); + } + } + return; + } + if (shared.video_desynced.load(Ordering::Acquire) + || shared.windows_bridge.keyframe_required()) + && !frame.keyframe + { + continue; + } + let Some(backend) = shared.windows_bridge.backend() else { + shared.video_desynced.store(true, Ordering::Release); + request_keyframe(&shared, &frame.mid, "D3D11 backend is unavailable"); + continue; + }; + shared.windows_bridge.set_last_video_mid(&frame.mid); + let timestamp_100ns = media_timestamp_100ns(frame.timestamp, frame.clock_rate_hz); + let duration_100ns = sample_clock.observe(timestamp_100ns); + match backend.submit_video(EncodedVideoFrame { + codec: match frame.codec { + MediaCodec::H264 => VideoCodec::H264, + MediaCodec::H265 => VideoCodec::H265, + MediaCodec::Av1 => VideoCodec::Av1, + _ => continue, + }, + data: frame.data.to_vec(), + timestamp_100ns, + duration_100ns, + key_frame: frame.keyframe, + }) { + Ok(WindowsPushOutcome::Queued) => { + report_video_frame_accepted(&shared, &frame); + if frame.keyframe { + shared.video_desynced.store(false, Ordering::Release); + shared.keyframe_requested.store(false, Ordering::Release); + shared.windows_bridge.accept_keyframe(); + } + } + Ok(WindowsPushOutcome::Paused) => {} + Ok(WindowsPushOutcome::DroppedOldest) => { + shared.video_desynced.store(true, Ordering::Release); + shared.windows_bridge.require_keyframe(); + let _ = shared.feedback.send(MediaFeedback::QueueDropped { + media: "d3d11-video", + count: 1, + }); + request_keyframe(&shared, &frame.mid, "D3D11 input queue overflow"); + } + Err(error) => { + shared.video_desynced.store(true, Ordering::Release); + shared.windows_bridge.require_keyframe(); + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: match frame.codec { + MediaCodec::H264 => "h264", + MediaCodec::H265 => "h265", + MediaCodec::Av1 => "av1", + _ => "video", + }, + message: error.to_string(), + }); + request_keyframe(&shared, &frame.mid, "D3D11 decoder rejected an access unit"); + } + } + } +} + +#[cfg(any(target_os = "windows", test))] +struct AdaptiveSampleClock { + previous_timestamp_100ns: Option, + nominal_duration_100ns: i64, + recent_durations_100ns: VecDeque, +} + +#[cfg(any(target_os = "windows", test))] +impl AdaptiveSampleClock { + const HISTORY_LENGTH: usize = 120; + + fn new(maximum_fps: u32) -> Self { + Self { + previous_timestamp_100ns: None, + nominal_duration_100ns: 10_000_000_i64 / i64::from(maximum_fps.max(1)), + recent_durations_100ns: VecDeque::with_capacity(Self::HISTORY_LENGTH), + } + } + + fn observe(&mut self, timestamp_100ns: i64) -> i64 { + let observed = self + .previous_timestamp_100ns + .replace(timestamp_100ns) + .and_then(|previous| timestamp_100ns.checked_sub(previous)) + .filter(|duration| *duration > 0); + + if let Some(duration) = observed { + if self.recent_durations_100ns.len() == Self::HISTORY_LENGTH { + self.recent_durations_100ns.pop_front(); + } + self.recent_durations_100ns.push_back(duration); + return duration; + } + + if self.recent_durations_100ns.is_empty() { + self.nominal_duration_100ns + } else { + self.recent_durations_100ns.iter().copied().sum::() + / self.recent_durations_100ns.len() as i64 + } + } +} + +#[cfg(any(target_os = "windows", test))] +fn media_timestamp_100ns(timestamp: u64, clock_rate_hz: u32) -> i64 { + if clock_rate_hz == 0 { + return 0; + } + let value = u128::from(timestamp) + .saturating_mul(10_000_000) + .checked_div(u128::from(clock_rate_hz)) + .unwrap_or(0); + i64::try_from(value).unwrap_or(i64::MAX) +} + +#[cfg(target_os = "windows")] +fn request_keyframe(shared: &SharedPipeline, mid: &str, reason: &str) { + if !shared.keyframe_requested.swap(true, Ordering::AcqRel) { + let _ = shared.feedback.send(MediaFeedback::RequestKeyframe { + mid: mid.to_owned(), + reason: reason.to_owned(), + }); + } +} + +impl Drop for MediaSession { + fn drop(&mut self) { + self.stop_inner(); + } +} + +struct H264Decoder { + decoder: OpenH264Decoder, +} + +impl H264Decoder { + fn new() -> Result { + OpenH264Decoder::with_api_config( + OpenH264API::from_source(), + DecoderConfig::new().debug(false), + ) + .map(|decoder| Self { decoder }) + .map_err(|error| format!("OpenH264 decoder initialization failed: {error}")) + } + + fn decode(&mut self, encoded: &[u8]) -> Result, String> { + let Some(yuv) = self + .decoder + .decode(encoded) + .map_err(|error| error.to_string())? + else { + return Ok(None); + }; + let (width, height) = yuv.dimensions(); + let mut rgb = vec![0; yuv.rgb8_len()]; + yuv.write_rgb8(&mut rgb); + Ok(Some(DecodedVideoFrame { + width: width as u32, + height: height as u32, + rgb, + })) + } +} + +struct OpusDecoder { + decoder: OpusNativeDecoder, + channels: u8, + scratch: Vec, +} + +impl OpusDecoder { + fn new(channels: u8) -> Result { + let opus_channels = match channels { + 1 => Channels::Mono, + 2 => Channels::Stereo, + other => return Err(format!("unsupported Opus channel count: {other}")), + }; + OpusNativeDecoder::new(OPUS_SAMPLE_RATE, opus_channels) + .map(|decoder| Self { + decoder, + channels, + scratch: vec![0.0; MAX_OPUS_FRAME_SAMPLES_PER_CHANNEL * channels as usize], + }) + .map_err(|error| format!("Opus decoder initialization failed: {error}")) + } + + fn decode(&mut self, encoded: &[u8]) -> Result<&[f32], String> { + let samples_per_channel = self + .decoder + .decode_float(encoded, &mut self.scratch, false) + .map_err(|error| error.to_string())?; + Ok(&self.scratch[..samples_per_channel * self.channels as usize]) + } +} + +fn run_video_decoder(shared: Arc, decoder: H264Decoder) { + run_video_decoder_from(shared, decoder, None); +} + +fn run_video_decoder_from( + shared: Arc, + mut decoder: H264Decoder, + mut pending: Option, +) { + loop { + let Some(frame) = pending.take().or_else(|| shared.video.pop()) else { + return; + }; + if shared.paused.load(Ordering::Acquire) { + continue; + } + if shared.video_desynced.load(Ordering::Acquire) { + if !frame.keyframe { + continue; + } + match H264Decoder::new() { + Ok(new_decoder) => decoder = new_decoder, + Err(message) => { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "h264", + message, + }); + continue; + } + } + shared.video_desynced.store(false, Ordering::Release); + shared.keyframe_requested.store(false, Ordering::Release); + } + match decoder.decode(&frame.data) { + Ok(Some(decoded)) => { + report_video_frame_accepted(&shared, &frame); + if shared.output.replace_video(decoded) { + let _ = shared.feedback.send(MediaFeedback::QueueDropped { + media: "present", + count: 1, + }); + } + } + Ok(None) => {} + Err(message) => { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "h264", + message, + }); + shared.video_desynced.store(true, Ordering::Release); + if !shared.keyframe_requested.swap(true, Ordering::AcqRel) { + let _ = shared.feedback.send(MediaFeedback::RequestKeyframe { + mid: frame.mid, + reason: "H.264 decoder rejected an access unit".to_owned(), + }); + } + } + } + } +} + +fn run_audio_decoder(shared: Arc, decoder: OpusDecoder) { + run_audio_decoder_from(shared, decoder, None); +} + +fn run_audio_decoder_from( + shared: Arc, + mut decoder: OpusDecoder, + mut pending: Option, +) { + let mut configured_channels = 2; + loop { + let Some(frame) = pending.take().or_else(|| shared.audio.pop()) else { + return; + }; + if shared.paused.load(Ordering::Acquire) { + continue; + } + let MediaCodec::Opus { channels } = frame.codec else { + continue; + }; + let channels = channels.clamp(1, 2); + if channels != configured_channels { + match OpusDecoder::new(channels) { + Ok(new_decoder) => { + decoder = new_decoder; + configured_channels = channels; + } + Err(message) => { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "opus", + message, + }); + continue; + } + } + } + match decoder.decode(&frame.data) { + Ok(samples) => { + #[cfg(target_os = "windows")] + if !shared.windows_bridge.use_software() + && let Some(backend) = shared.windows_bridge.backend() + { + use opennow_streamer_platform_windows::{ + AudioFormat, PcmFrame, PushOutcome as WindowsPushOutcome, + }; + let samples = if configured_channels == 1 { + samples + .iter() + .flat_map(|sample| [*sample, *sample]) + .collect() + } else { + samples.to_vec() + }; + match backend.submit_audio(PcmFrame { + samples, + format: AudioFormat { + sample_rate: OPUS_SAMPLE_RATE, + channels: 2, + }, + }) { + Ok(WindowsPushOutcome::DroppedOldest) => { + let _ = shared.feedback.send(MediaFeedback::QueueDropped { + media: "wasapi", + count: 1, + }); + } + Ok(WindowsPushOutcome::Queued | WindowsPushOutcome::Paused) => {} + Err(error) => { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "opus", + message: error.to_string(), + }); + } + } + continue; + } + if configured_channels == 1 { + let mut stereo = Vec::with_capacity(samples.len() * 2); + for sample in samples { + stereo.extend([*sample, *sample]); + } + let dropped = shared.output.push_audio(&stereo); + if dropped > 0 { + let _ = shared.feedback.send(MediaFeedback::QueueDropped { + media: "audio-output", + count: dropped, + }); + } + } else { + let dropped = shared.output.push_audio(samples); + if dropped > 0 { + let _ = shared.feedback.send(MediaFeedback::QueueDropped { + media: "audio-output", + count: dropped, + }); + } + } + } + Err(message) => { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "opus", + message, + }); + } + } + } +} + +#[cfg(target_os = "linux")] +fn run_linux_video(shared: Arc, host_commands: Sender) { + while let Some(frame) = shared.video.pop() { + if shared.linux_software_fallback.load(Ordering::Acquire) { + match H264Decoder::new() { + Ok(decoder) => run_video_decoder_from(shared, decoder, Some(frame)), + Err(message) => { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "h264", + message, + }); + } + } + return; + } + if shared.paused.load(Ordering::Acquire) { + continue; + } + *shared + .linux_video_mid + .lock() + .unwrap_or_else(|error| error.into_inner()) = frame.mid.clone(); + let timestamp_us = media_timestamp_us(frame.timestamp, frame.clock_rate_hz); + let encoded = match opennow_streamer_platform_linux::EncodedVideoFrame::new( + Arc::clone(&frame.data), + timestamp_us, + frame.keyframe, + ) { + Ok(encoded) => encoded, + Err(error) => { + trigger_linux_fallback( + &shared, + &host_commands, + format!("Linux decoder rejected encoded video framing: {error}"), + ); + continue; + } + }; + let result = shared + .linux_session + .lock() + .unwrap_or_else(|error| error.into_inner()) + .as_ref() + .ok_or_else(|| "Linux hardware session is unavailable".to_owned()) + .and_then(|session| { + session + .submit_video(encoded) + .map_err(|error| error.to_string()) + }); + match result { + Ok(opennow_streamer_platform_linux::PushOutcome::Queued) => { + report_video_frame_accepted(&shared, &frame); + if frame.keyframe { + shared.video_desynced.store(false, Ordering::Release); + shared.keyframe_requested.store(false, Ordering::Release); + } + } + Ok(opennow_streamer_platform_linux::PushOutcome::DroppedOldest) => { + if frame.keyframe { + shared.video_desynced.store(false, Ordering::Release); + shared.keyframe_requested.store(false, Ordering::Release); + } else { + shared.video_desynced.store(true, Ordering::Release); + } + } + Ok(opennow_streamer_platform_linux::PushOutcome::Paused) => {} + Err(reason) => trigger_linux_fallback( + &shared, + &host_commands, + format!("Linux hardware video submission failed: {reason}"), + ), + } + } +} + +#[cfg(target_os = "linux")] +fn run_linux_monitor(shared: Arc, host_commands: Sender) { + use std::time::Duration; + + while !shared.stopped.load(Ordering::Acquire) { + if shared.linux_software_fallback.load(Ordering::Acquire) { + request_linux_keyframe(&shared, "Linux decoder fallback requires a fresh keyframe"); + stop_linux_session(&shared); + return; + } + let (frames, events) = { + let session = shared + .linux_session + .lock() + .unwrap_or_else(|error| error.into_inner()); + let Some(session) = session.as_ref() else { + return; + }; + let mut frames = Vec::new(); + while let Some(frame) = session.try_recv_frame() { + frames.push(frame); + } + let mut events = Vec::new(); + while let Some(event) = session.try_recv_event() { + events.push(event); + } + (frames, events) + }; + if !shared.paused.load(Ordering::Acquire) { + for frame in frames { + if shared.output.queue_linux_video(frame) { + let _ = shared.feedback.send(MediaFeedback::QueueDropped { + media: "linux-present", + count: 1, + }); + } + } + } + for event in events { + match event { + opennow_streamer_platform_linux::BackendEvent::DecoderChanged { + from, + to, + reason, + } => { + let _ = shared.feedback.send(MediaFeedback::BackendFallback { + from: linux_decoder_name(from), + to: linux_decoder_name(to), + reason, + }); + } + opennow_streamer_platform_linux::BackendEvent::NeedKeyframe => { + request_linux_keyframe(&shared, "Linux decoder requires a fresh keyframe"); + } + opennow_streamer_platform_linux::BackendEvent::QueueOverflow { media } => { + let _ = shared + .feedback + .send(MediaFeedback::QueueDropped { media, count: 1 }); + } + opennow_streamer_platform_linux::BackendEvent::DeviceLost { subsystem, reason } => { + let _ = shared.feedback.send(MediaFeedback::DeviceLost { + subsystem: linux_subsystem_name(subsystem), + recovered: false, + message: Some(reason.clone()), + }); + trigger_linux_fallback( + &shared, + &host_commands, + format!("{subsystem:?} device was lost: {reason}"), + ); + } + opennow_streamer_platform_linux::BackendEvent::Error(reason) => { + trigger_linux_fallback(&shared, &host_commands, reason) + } + opennow_streamer_platform_linux::BackendEvent::StateChanged( + opennow_streamer_platform_linux::LifecycleState::Failed, + ) => trigger_linux_fallback( + &shared, + &host_commands, + "Linux hardware media session failed".to_owned(), + ), + opennow_streamer_platform_linux::BackendEvent::StateChanged(_) + | opennow_streamer_platform_linux::BackendEvent::DecoderSelected(_) + | opennow_streamer_platform_linux::BackendEvent::AudioSelected(_) + | opennow_streamer_platform_linux::BackendEvent::FormatChanged(_) => {} + } + } + thread::sleep(Duration::from_millis(2)); + } + stop_linux_session(&shared); +} + +#[cfg(target_os = "linux")] +fn trigger_linux_fallback( + shared: &SharedPipeline, + host_commands: &Sender, + reason: String, +) { + if shared.linux_codec != MediaVideoCodec::H264 { + shared.stopped.store(true, Ordering::Release); + shared.video.close(); + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: shared.linux_codec.label(), + message: reason, + }); + return; + } + if shared.linux_software_fallback.swap(true, Ordering::AcqRel) { + return; + } + request_linux_keyframe(shared, "Linux decoder fallback requires a fresh keyframe"); + let _ = host_commands.send(HostCommand::FallbackLinux { reason }); +} + +#[cfg(target_os = "linux")] +fn request_linux_keyframe(shared: &SharedPipeline, reason: &str) { + shared.video_desynced.store(true, Ordering::Release); + if shared.keyframe_requested.swap(true, Ordering::AcqRel) { + return; + } + let mid = shared + .linux_video_mid + .lock() + .unwrap_or_else(|error| error.into_inner()) + .clone(); + if !mid.is_empty() { + let _ = shared.feedback.send(MediaFeedback::RequestKeyframe { + mid, + reason: reason.to_owned(), + }); + } +} + +#[cfg(target_os = "linux")] +fn stop_linux_session(shared: &SharedPipeline) { + if let Some(mut session) = shared + .linux_session + .lock() + .unwrap_or_else(|error| error.into_inner()) + .take() + { + let _ = session.stop(); + } +} + +#[cfg(target_os = "linux")] +const fn linux_decoder_name( + backend: opennow_streamer_platform_linux::DecoderBackend, +) -> &'static str { + match backend { + opennow_streamer_platform_linux::DecoderBackend::Vulkan => "Vulkan Video/Vulkan", + opennow_streamer_platform_linux::DecoderBackend::Cuda => "CUDA/NVDEC/Vulkan", + opennow_streamer_platform_linux::DecoderBackend::VaApi => "VA-API/Vulkan", + opennow_streamer_platform_linux::DecoderBackend::V4l2 => "V4L2/Vulkan", + opennow_streamer_platform_linux::DecoderBackend::Ffmpeg => "FFmpeg software/Vulkan", + } +} + +#[cfg(target_os = "linux")] +const fn linux_subsystem_name( + subsystem: opennow_streamer_platform_linux::Subsystem, +) -> &'static str { + match subsystem { + opennow_streamer_platform_linux::Subsystem::VaApi => "VA-API", + opennow_streamer_platform_linux::Subsystem::V4l2 => "V4L2", + opennow_streamer_platform_linux::Subsystem::Vulkan => "Vulkan", + opennow_streamer_platform_linux::Subsystem::Ffmpeg => "FFmpeg", + opennow_streamer_platform_linux::Subsystem::Opus => "Opus", + opennow_streamer_platform_linux::Subsystem::PipeWire => "PipeWire", + opennow_streamer_platform_linux::Subsystem::Alsa => "ALSA", + opennow_streamer_platform_linux::Subsystem::Session => "Linux media session", + } +} + +#[cfg(target_os = "linux")] +fn media_timestamp_us(timestamp: u64, clock_rate_hz: u32) -> u64 { + if clock_rate_hz == 0 { + return 0; + } + timestamp.saturating_mul(1_000_000) / u64::from(clock_rate_hz) +} + +#[cfg(target_os = "macos")] +fn run_macos_video(shared: Arc, host_commands: Sender) { + use std::sync::mpsc; + use std::time::Duration; + + use opennow_streamer_platform_macos::{ + FrameTiming, H264Format, SubmitOutcome, VideoColorSpace, + }; + + use crate::runtime::MacH264Configuration; + + let mut tracker = crate::macos_backend::H264ParameterSetTracker::default(); + let mut configured_parameter_sets = None; + let mut backend_sink: Option = None; + let mut playback_started = false; + while let Some(frame) = shared.video.pop() { + if shared.paused.load(Ordering::Acquire) { + continue; + } + if let Some(sink) = backend_sink.as_ref() { + while let Some(loss) = sink.pop_video_decode_loss() { + let message = loss.status.map_or_else( + || "VideoToolbox produced no decoded pixel buffer".to_owned(), + |status| format!("VideoToolbox decode failed with OSStatus {status}"), + ); + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "h264", + message, + }); + mark_macos_video_desynced( + &shared, + &frame.mid, + "VideoToolbox lost decoder synchronization", + ); + } + if let Some(failure) = sink.fatal_failure() { + shared.mac_software_fallback.store(true, Ordering::Release); + mark_macos_video_desynced( + &shared, + &frame.mid, + &format!( + "{} failure requires software decode", + failure.subsystem.name() + ), + ); + } + } + if shared.mac_software_fallback.load(Ordering::Acquire) { + match H264Decoder::new() { + Ok(decoder) => run_video_decoder_from(shared, decoder, Some(frame)), + Err(message) => { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "h264", + message, + }); + } + } + return; + } + let framing = match tracker.observe(&frame.data) { + Ok(framing) => framing, + Err(message) => { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "h264", + message, + }); + mark_macos_video_desynced(&shared, &frame.mid, "invalid H.264 framing"); + continue; + } + }; + let parameter_sets = match tracker.parameter_sets() { + Ok(parameter_sets) => parameter_sets, + Err(message) => { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "h264", + message, + }); + mark_macos_video_desynced(&shared, &frame.mid, "invalid H.264 parameter sets"); + continue; + } + }; + if shared.video_desynced.load(Ordering::Acquire) && !frame.keyframe { + continue; + } + if backend_sink.is_none() { + let Some(parameter_sets) = parameter_sets.clone() else { + mark_macos_video_desynced( + &shared, + &frame.mid, + "VideoToolbox is waiting for H.264 SPS/PPS", + ); + continue; + }; + let (reply, response) = mpsc::channel(); + if host_commands + .send(HostCommand::ConfigureMacH264 { + parameter_sets: parameter_sets.clone(), + reply, + }) + .is_err() + { + return; + } + match response.recv_timeout(Duration::from_secs(10)) { + Ok(Ok(MacH264Configuration::Hardware(sink))) => { + *shared + .mac_sink + .lock() + .unwrap_or_else(|error| error.into_inner()) = Some(sink.clone()); + configured_parameter_sets = Some(parameter_sets); + backend_sink = Some(sink); + } + Ok(Ok(MacH264Configuration::SoftwareFallback { reason })) => { + shared.mac_software_fallback.store(true, Ordering::Release); + let _ = shared.feedback.send(MediaFeedback::BackendFallback { + from: "VideoToolbox/Metal", + to: "OpenH264/SDL", + reason, + }); + match H264Decoder::new() { + Ok(decoder) => run_video_decoder_from(shared, decoder, Some(frame)), + Err(message) => { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "h264", + message, + }); + } + } + return; + } + Ok(Err(message)) => { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "h264", + message, + }); + return; + } + Err(_) => { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "h264", + message: "VideoToolbox initialization timed out on the main thread" + .to_owned(), + }); + return; + } + } + } else if let Some(parameter_sets) = parameter_sets + && configured_parameter_sets.as_ref() != Some(¶meter_sets) + { + let format = H264Format::new(parameter_sets.clone(), VideoColorSpace::Bt709); + let Some(sink) = backend_sink.as_ref() else { + return; + }; + if let Err(error) = sink.reconfigure_h264(format) { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "h264", + message: error.to_string(), + }); + mark_macos_video_desynced( + &shared, + &frame.mid, + "VideoToolbox reconfiguration failed", + ); + continue; + } + configured_parameter_sets = Some(parameter_sets); + } + + shared.video_desynced.store(false, Ordering::Release); + shared.keyframe_requested.store(false, Ordering::Release); + let timescale = i32::try_from(frame.clock_rate_hz) + .ok() + .filter(|timescale| *timescale > 0) + .unwrap_or(90_000); + let timing = FrameTiming::new( + i64::try_from(frame.timestamp).unwrap_or(i64::MAX), + 0, + timescale, + ); + let Some(sink) = backend_sink.as_ref() else { + return; + }; + match sink.submit_h264(&frame.data, framing, timing) { + Ok(SubmitOutcome::Accepted) => report_video_frame_accepted(&shared, &frame), + Ok(SubmitOutcome::Paused) => {} + Ok(SubmitOutcome::Backpressured | SubmitOutcome::ReplacedOldest) => { + let _ = shared.feedback.send(MediaFeedback::QueueDropped { + media: "videotoolbox", + count: 1, + }); + mark_macos_video_desynced( + &shared, + &frame.mid, + "VideoToolbox decode queue backpressure", + ); + } + Err(error) => { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "h264", + message: error.to_string(), + }); + mark_macos_video_desynced( + &shared, + &frame.mid, + "VideoToolbox rejected an H.264 access unit", + ); + } + } + if !playback_started && sink.stats().video_presented > 0 { + playback_started = true; + let _ = shared.feedback.send(MediaFeedback::PlaybackStarted { + backend: "VideoToolbox/Metal", + }); + } + } +} + +fn report_video_frame_accepted(shared: &SharedPipeline, frame: &EncodedFrame) { + let _ = shared.feedback.send(MediaFeedback::VideoFrameAccepted { + timestamp: frame.timestamp, + bytes: u32::try_from(frame.data.len()).unwrap_or(u32::MAX), + keyframe: frame.keyframe, + }); +} + +#[cfg(target_os = "macos")] +fn run_macos_audio(shared: Arc) { + use opennow_streamer_platform_macos::{AudioFormat, SubmitOutcome}; + + let mut configured_channels = 2; + while let Some(frame) = shared.audio.pop() { + if shared.paused.load(Ordering::Acquire) { + continue; + } + let native_sink = shared + .mac_sink + .lock() + .unwrap_or_else(|error| error.into_inner()) + .clone(); + if native_sink + .as_ref() + .and_then(|sink| sink.fatal_failure()) + .is_some() + { + shared.mac_software_fallback.store(true, Ordering::Release); + } + if shared.mac_software_fallback.load(Ordering::Acquire) { + match OpusDecoder::new(2) { + Ok(decoder) => run_audio_decoder_from(shared, decoder, Some(frame)), + Err(message) => { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "opus", + message, + }); + } + } + return; + } + let MediaCodec::Opus { channels } = frame.codec else { + continue; + }; + let Some(sink) = native_sink else { + continue; + }; + let channels = channels.clamp(1, 2); + if channels != configured_channels { + if let Err(error) = sink.reconfigure_audio(AudioFormat::new(48_000, channels)) { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "opus", + message: error.to_string(), + }); + continue; + } + configured_channels = channels; + } + match sink.submit_opus(&frame.data) { + Ok(SubmitOutcome::Accepted | SubmitOutcome::Backpressured | SubmitOutcome::Paused) => {} + Ok(SubmitOutcome::ReplacedOldest) => { + let _ = shared.feedback.send(MediaFeedback::QueueDropped { + media: "coreaudio", + count: 1, + }); + } + Err(error) => { + if !shared.stopped.load(Ordering::Acquire) { + let _ = shared.feedback.send(MediaFeedback::DecoderError { + codec: "opus", + message: error.to_string(), + }); + } + } + } + } +} + +#[cfg(target_os = "macos")] +fn mark_macos_video_desynced(shared: &SharedPipeline, mid: &str, reason: &str) { + shared.video_desynced.store(true, Ordering::Release); + if !shared.keyframe_requested.swap(true, Ordering::AcqRel) { + let _ = shared.feedback.send(MediaFeedback::RequestKeyframe { + mid: mid.to_owned(), + reason: reason.to_owned(), + }); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use openh264::encoder::Encoder; + use openh264::formats::{RgbSliceU8, YUVBuffer}; + use opus::{Application, Encoder as OpusEncoder}; + + #[test] + fn decodes_a_synthetic_h264_keyframe() { + let width = 32; + let height = 32; + let mut rgb = vec![0_u8; width * height * 3]; + for (index, pixel) in rgb.chunks_exact_mut(3).enumerate() { + pixel.copy_from_slice(&[(index % 255) as u8, 64, 192]); + } + let yuv = YUVBuffer::from_rgb_source(RgbSliceU8::new(&rgb, (width, height))); + let mut encoder = Encoder::new().expect("encoder"); + let encoded = encoder.encode(&yuv).expect("encode").to_vec(); + let mut decoder = H264Decoder::new().expect("decoder"); + let decoded = decoder + .decode(&encoded) + .expect("decode") + .expect("decoded frame"); + assert_eq!( + (decoded.width, decoded.height), + (width as u32, height as u32) + ); + assert_eq!(decoded.rgb.len(), width * height * 3); + } + + #[test] + fn captured_input_queue_preserves_raw_motion_and_fails_closed_on_control_overflow() { + let queue = CapturedInputQueue::default(); + for _ in 0..3 { + queue.push(CapturedInput::MouseMove { + delta_x: 1, + delta_y: -1, + }); + } + for _ in 0..3 { + assert_eq!( + queue.take(), + Some(CapturedInput::MouseMove { + delta_x: 1, + delta_y: -1, + }) + ); + } + + for virtual_key in 0..=u16::try_from(CAPTURED_INPUT_CAPACITY).unwrap() { + queue.push(CapturedInput::Key { + virtual_key, + modifiers: 0, + pressed: true, + }); + } + assert!(queue.take_overflowed()); + assert_eq!( + queue.take(), + Some(CapturedInput::Key { + virtual_key: 0, + modifiers: 0, + pressed: true, + }) + ); + } + + #[test] + fn software_handoff_decodes_the_pending_h264_keyframe() { + let width = 32; + let height = 32; + let rgb = vec![96_u8; width * height * 3]; + let yuv = YUVBuffer::from_rgb_source(RgbSliceU8::new(&rgb, (width, height))); + let mut encoder = Encoder::new().expect("encoder"); + let encoded: Arc<[u8]> = encoder.encode(&yuv).expect("encode").to_vec().into(); + let output = Arc::new(OutputBuffers::new()); + let (feedback, _receiver) = std::sync::mpsc::channel(); + let shared = Arc::new(SharedPipeline { + video: Arc::new(BoundedQueue::new(VIDEO_QUEUE_CAPACITY)), + audio: Arc::new(BoundedQueue::new(AUDIO_QUEUE_CAPACITY)), + output: Arc::clone(&output), + feedback, + paused: AtomicBool::new(false), + video_desynced: AtomicBool::new(true), + keyframe_requested: AtomicBool::new(false), + stopped: AtomicBool::new(false), + #[cfg(target_os = "macos")] + mac_sink: Mutex::new(None), + #[cfg(target_os = "macos")] + mac_software_fallback: AtomicBool::new(true), + #[cfg(target_os = "windows")] + windows_bridge: Arc::new(WindowsBridge::new()), + #[cfg(target_os = "linux")] + linux_session: Mutex::new(None), + #[cfg(target_os = "linux")] + linux_software_fallback: Arc::new(AtomicBool::new(true)), + #[cfg(target_os = "linux")] + linux_video_mid: Mutex::new(String::new()), + linux_codec: MediaVideoCodec::H264, + }); + shared.video.close(); + run_video_decoder_from( + shared, + H264Decoder::new().expect("decoder"), + Some(EncodedFrame { + mid: "video".to_owned(), + codec: MediaCodec::H264, + data: encoded, + timestamp: 0, + clock_rate_hz: 90_000, + keyframe: true, + contiguous: true, + }), + ); + let decoded = output.take_video().expect("decoded pending frame"); + assert_eq!( + (decoded.width, decoded.height), + (width as u32, height as u32) + ); + } + + #[test] + fn decodes_synthetic_stereo_opus() { + let mut encoder = OpusEncoder::new(OPUS_SAMPLE_RATE, Channels::Stereo, Application::Audio) + .expect("encoder"); + let input: Vec = (0..960 * 2) + .map(|sample| ((sample as f32 / 24.0).sin()) * 0.25) + .collect(); + let mut packet = vec![0_u8; 4_000]; + let encoded_len = encoder.encode_float(&input, &mut packet).expect("encode"); + let mut decoder = OpusDecoder::new(2).expect("decoder"); + let decoded = decoder.decode(&packet[..encoded_len]).expect("decode"); + assert_eq!(decoded.len(), input.len()); + assert!(decoded.iter().any(|sample| sample.abs() > 0.001)); + } + + #[test] + fn converts_rtp_video_timestamps_to_media_foundation_time() { + assert_eq!(media_timestamp_100ns(0, 90_000), 0); + assert_eq!(media_timestamp_100ns(90_000, 90_000), 10_000_000); + assert_eq!(media_timestamp_100ns(45_000, 90_000), 5_000_000); + assert_eq!(media_timestamp_100ns(90_000, 0), 0); + } + + #[test] + fn adaptive_sample_clock_uses_the_negotiated_fps_only_as_a_ceiling() { + let mut clock = AdaptiveSampleClock::new(120); + assert_eq!(clock.observe(0), 83_333); + assert_eq!(clock.observe(83_333), 83_333); + assert_eq!(clock.observe(250_000), 166_667); + assert_eq!(clock.observe(583_334), 333_334); + } + + #[test] + fn adaptive_sample_clock_recovers_from_a_repeated_timestamp() { + let mut clock = AdaptiveSampleClock::new(120); + assert_eq!(clock.observe(0), 83_333); + assert_eq!(clock.observe(83_333), 83_333); + assert_eq!(clock.observe(83_333), 83_333); + } + + #[test] + fn paused_and_stopped_sessions_reject_frames() { + let (feedback, _receiver) = std::sync::mpsc::channel(); + let (commands, _host) = std::sync::mpsc::channel(); + let session = MediaSession::spawn( + Arc::new(OutputBuffers::new()), + feedback, + commands, + false, + MediaStreamConfig::default(), + #[cfg(target_os = "windows")] + Arc::new(WindowsBridge::new()), + #[cfg(target_os = "linux")] + LinuxVideoSelection { + path: LinuxVideoPath::Software, + use_vulkan_output: false, + fallback_reason: None, + }, + #[cfg(target_os = "linux")] + Arc::new(AtomicBool::new(true)), + ) + .expect("session"); + let sink = session.sink(); + session.set_paused(true); + assert_eq!( + sink.push(EncodedFrame { + mid: "video".to_owned(), + codec: MediaCodec::H264, + data: Arc::from([]), + timestamp: 0, + clock_rate_hz: 90_000, + keyframe: false, + contiguous: true, + }), + PushOutcome::Paused + ); + session.stop(); + assert_eq!( + sink.push(EncodedFrame { + mid: "video".to_owned(), + codec: MediaCodec::H264, + data: Arc::from([]), + timestamp: 0, + clock_rate_hz: 90_000, + keyframe: false, + contiguous: true, + }), + PushOutcome::Closed + ); + } + + #[test] + fn requests_a_keyframe_when_video_starts_mid_gop() { + let (feedback, receiver) = std::sync::mpsc::channel(); + let (commands, _host) = std::sync::mpsc::channel(); + let session = MediaSession::spawn( + Arc::new(OutputBuffers::new()), + feedback, + commands, + false, + MediaStreamConfig::default(), + #[cfg(target_os = "windows")] + Arc::new(WindowsBridge::new()), + #[cfg(target_os = "linux")] + LinuxVideoSelection { + path: LinuxVideoPath::Software, + use_vulkan_output: false, + fallback_reason: None, + }, + #[cfg(target_os = "linux")] + Arc::new(AtomicBool::new(true)), + ) + .expect("session"); + assert_eq!( + session.sink().push(EncodedFrame { + mid: "video".to_owned(), + codec: MediaCodec::H264, + data: Arc::from([0_u8, 0, 0, 1, 1]), + timestamp: 0, + clock_rate_hz: 90_000, + keyframe: false, + contiguous: true, + }), + PushOutcome::Queued + ); + assert!(matches!( + receiver.recv_timeout(std::time::Duration::from_secs(1)), + Ok(MediaFeedback::RequestKeyframe { mid, .. }) if mid == "video" + )); + session.stop(); + } + + #[cfg(target_os = "linux")] + #[test] + fn converts_rtp_timestamps_to_microseconds_without_overflow() { + assert_eq!(media_timestamp_us(180_000, 90_000), 2_000_000); + assert_eq!(media_timestamp_us(48_000, 48_000), 1_000_000); + assert_eq!(media_timestamp_us(u64::MAX, 90_000), u64::MAX / 90_000); + assert_eq!(media_timestamp_us(42, 0), 0); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/native_stats_overlay.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/native_stats_overlay.rs new file mode 100644 index 000000000..a703d0be6 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/native_stats_overlay.rs @@ -0,0 +1,720 @@ +use std::collections::VecDeque; +use std::time::{Duration, Instant}; + +use crate::media::MediaStreamConfig; + +const FULL_SIZE: (u32, u32) = (480, 470); +const MINIMAL_SIZE: (u32, u32) = (180, 40); +const EDGE_MARGIN: u32 = 24; +const SAMPLE_INTERVAL: Duration = Duration::from_millis(250); +const OVERLAY_ALPHA: u16 = 245; + +type Rgb = [u8; 3]; + +const BACKGROUND: Rgb = [3, 9, 7]; +const BORDER: Rgb = [28, 55, 40]; +const GREEN: Rgb = [47, 229, 119]; +const MUTED: Rgb = [102, 116, 108]; +const TEXT: Rgb = [216, 226, 220]; +const AMBER: Rgb = [255, 184, 0]; +const GRAPH: Rgb = [48, 111, 76]; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum OverlayMode { + Hidden, + Minimal, + Full, +} + +impl OverlayMode { + fn next(self) -> Self { + match self { + Self::Hidden => Self::Minimal, + Self::Minimal => Self::Full, + Self::Full => Self::Hidden, + } + } + + pub(crate) const fn size(self) -> Option<(u32, u32)> { + match self { + Self::Hidden => None, + Self::Minimal => Some(MINIMAL_SIZE), + Self::Full => Some(FULL_SIZE), + } + } +} + +#[derive(Debug, Clone)] +pub(crate) struct OverlayFrame { + pub(crate) width: u32, + pub(crate) height: u32, + pub(crate) rgb: Vec, +} + +pub(crate) struct NativeStatsOverlay { + mode: OverlayMode, + stream: MediaStreamConfig, + decoder: &'static str, + last_presented: u64, + last_sample: Instant, + measured_fps: f32, + last_received_video_bytes: u64, + measured_bitrate_bps: f32, + fps_history: VecDeque, + dropped_frames: u64, + presentation_skips: u64, + relative_mouse: bool, + rendered: Option, +} + +impl NativeStatsOverlay { + pub(crate) fn new(stream: MediaStreamConfig, decoder: &'static str) -> Self { + Self { + mode: OverlayMode::Hidden, + stream, + decoder, + last_presented: 0, + last_sample: Instant::now(), + measured_fps: 0.0, + last_received_video_bytes: 0, + measured_bitrate_bps: 0.0, + fps_history: VecDeque::with_capacity(18), + dropped_frames: 0, + presentation_skips: 0, + relative_mouse: false, + rendered: None, + } + } + + pub(crate) fn toggle(&mut self) { + self.mode = self.mode.next(); + self.render(); + eprintln!("Native F3 stream stats overlay: {:?}", self.mode); + } + + #[cfg(target_os = "windows")] + pub(crate) const fn mode(&self) -> OverlayMode { + self.mode + } + + pub(crate) fn update( + &mut self, + presented_frames: u64, + dropped_frames: u64, + relative_mouse: bool, + received_video_bytes: u64, + ) -> bool { + self.dropped_frames = dropped_frames; + self.relative_mouse = relative_mouse; + let now = Instant::now(); + let elapsed = now.duration_since(self.last_sample); + if elapsed < SAMPLE_INTERVAL { + return false; + } + self.measured_fps = presented_frames.saturating_sub(self.last_presented) as f32 + / elapsed.as_secs_f32().max(0.001); + let bitrate_bps = measured_bitrate_bps( + received_video_bytes.saturating_sub(self.last_received_video_bytes), + elapsed, + ); + self.measured_bitrate_bps = if self.measured_bitrate_bps <= 0.0 { + bitrate_bps + } else { + self.measured_bitrate_bps * 0.65 + bitrate_bps * 0.35 + }; + self.last_presented = presented_frames; + self.last_received_video_bytes = received_video_bytes; + self.last_sample = now; + if self.fps_history.len() == 18 { + self.fps_history.pop_front(); + } + self.fps_history.push_back(self.measured_fps); + self.render(); + true + } + + #[cfg(target_os = "linux")] + pub(crate) fn set_presentation_skips(&mut self, presentation_skips: u64) { + self.presentation_skips = presentation_skips; + } + + pub(crate) fn frame(&self) -> Option<&OverlayFrame> { + self.rendered.as_ref() + } + + pub(crate) fn composite_rgb24( + &self, + destination: &mut [u8], + width: u32, + height: u32, + stride: usize, + ) { + let Some(source) = self.frame() else { + return; + }; + let Some((origin_x, origin_y)) = overlay_origin(self.mode, width, height, source) else { + return; + }; + let copy_width = source.width.min(width.saturating_sub(origin_x)); + let copy_height = source.height.min(height.saturating_sub(origin_y)); + for row in 0..copy_height as usize { + let source_start = row * source.width as usize * 3; + let destination_start = (origin_y as usize + row) * stride + origin_x as usize * 3; + let bytes = copy_width as usize * 3; + let Some(source_row) = source.rgb.get(source_start..source_start + bytes) else { + return; + }; + let Some(destination_row) = + destination.get_mut(destination_start..destination_start + bytes) + else { + return; + }; + for (destination, source) in destination_row.iter_mut().zip(source_row) { + *destination = blend(*destination, *source); + } + } + } + + #[cfg(target_os = "linux")] + pub(crate) fn composite_linux_frame( + &self, + frame: &mut opennow_streamer_platform_linux::DecodedVideoFrame, + ) { + use opennow_streamer_platform_linux::PixelFormat; + + if frame.format.pixel_format != PixelFormat::Nv12 + || (frame.vulkan.is_none() && frame.dmabuf.is_none() && frame.planes.len() != 2) + { + return; + } + let Some(source) = self.frame() else { + return; + }; + let Some((origin_x, origin_y)) = + overlay_origin(self.mode, frame.format.width, frame.format.height, source) + else { + return; + }; + let origin_x = origin_x & !1; + let origin_y = origin_y & !1; + let copy_width = source + .width + .min(frame.format.width.saturating_sub(origin_x)) + & !1; + let copy_height = source + .height + .min(frame.format.height.saturating_sub(origin_y)) + & !1; + if frame.vulkan.is_some() || frame.dmabuf.is_some() { + let mut luma = vec![0_u8; (copy_width * copy_height) as usize]; + let mut chroma = vec![0_u8; (copy_width * copy_height / 2) as usize]; + for row in 0..copy_height as usize { + for column in 0..copy_width as usize { + let source_offset = (row * source.width as usize + column) * 3; + let rgb = &source.rgb[source_offset..source_offset + 3]; + let (y, _, _) = rgb_to_limited_bt709(rgb[0], rgb[1], rgb[2]); + luma[row * copy_width as usize + column] = y; + } + } + for row in (0..copy_height as usize).step_by(2) { + for column in (0..copy_width as usize).step_by(2) { + let mut rgb = [0_u32; 3]; + for sample_y in row..row + 2 { + for sample_x in column..column + 2 { + let offset = (sample_y * source.width as usize + sample_x) * 3; + rgb[0] += u32::from(source.rgb[offset]); + rgb[1] += u32::from(source.rgb[offset + 1]); + rgb[2] += u32::from(source.rgb[offset + 2]); + } + } + let (_, u, v) = rgb_to_limited_bt709( + (rgb[0] / 4) as u8, + (rgb[1] / 4) as u8, + (rgb[2] / 4) as u8, + ); + let offset = row / 2 * copy_width as usize + column; + chroma[offset] = u; + chroma[offset + 1] = v; + } + } + frame.overlay = Some(opennow_streamer_platform_linux::FrameOverlay { + origin_x, + origin_y, + width: copy_width, + height: copy_height, + luma: opennow_streamer_platform_linux::FramePlane { + data: std::sync::Arc::from(luma), + stride: copy_width as usize, + rows: copy_height as usize, + }, + chroma: opennow_streamer_platform_linux::FramePlane { + data: std::sync::Arc::from(chroma), + stride: copy_width as usize, + rows: copy_height as usize / 2, + }, + }); + return; + } + let (y_planes, uv_planes) = frame.planes.split_at_mut(1); + let y_stride = y_planes[0].stride; + let uv_stride = uv_planes[0].stride; + let y_plane = std::sync::Arc::make_mut(&mut y_planes[0].data); + let uv_plane = std::sync::Arc::make_mut(&mut uv_planes[0].data); + + for row in 0..copy_height as usize { + for column in 0..copy_width as usize { + let source_offset = (row * source.width as usize + column) * 3; + let Some(rgb) = source.rgb.get(source_offset..source_offset + 3) else { + return; + }; + let (y, _, _) = rgb_to_limited_bt709(rgb[0], rgb[1], rgb[2]); + let destination_offset = + (origin_y as usize + row) * y_stride + origin_x as usize + column; + let Some(destination) = y_plane.get_mut(destination_offset) else { + return; + }; + *destination = blend(*destination, y); + } + } + + for row in (0..copy_height as usize).step_by(2) { + for column in (0..copy_width as usize).step_by(2) { + let mut red = 0_u32; + let mut green = 0_u32; + let mut blue = 0_u32; + let mut samples = 0_u32; + for sample_y in row..(row + 2).min(copy_height as usize) { + for sample_x in column..(column + 2).min(copy_width as usize) { + let offset = (sample_y * source.width as usize + sample_x) * 3; + let Some(rgb) = source.rgb.get(offset..offset + 3) else { + return; + }; + red += u32::from(rgb[0]); + green += u32::from(rgb[1]); + blue += u32::from(rgb[2]); + samples += 1; + } + } + let samples = samples.max(1); + let (_, u, v) = rgb_to_limited_bt709( + (red / samples) as u8, + (green / samples) as u8, + (blue / samples) as u8, + ); + let destination_offset = + (origin_y as usize / 2 + row / 2) * uv_stride + origin_x as usize + column; + let Some(destination) = + uv_plane.get_mut(destination_offset..destination_offset + 2) + else { + return; + }; + destination[0] = blend(destination[0], u); + destination[1] = blend(destination[1], v); + } + } + } + + fn render(&mut self) { + let Some((width, height)) = self.mode.size() else { + self.rendered = None; + return; + }; + let mut canvas = Raster::new(width, height, BACKGROUND); + canvas.draw_rect(0, 0, width, height, BORDER); + match self.mode { + OverlayMode::Hidden => {} + OverlayMode::Minimal => self.draw_minimal(&mut canvas), + OverlayMode::Full => self.draw_full(&mut canvas), + } + self.rendered = Some(OverlayFrame { + width, + height, + rgb: canvas.pixels, + }); + } + + fn draw_minimal(&self, canvas: &mut Raster) { + let fps = display_fps(self.measured_fps, self.stream.fps); + canvas.draw_text(14, 10, 3, GREEN, &fps.to_string()); + canvas.draw_text(76, 15, 1, MUTED, "FPS"); + canvas.draw_text(105, 14, 2, MUTED, "|"); + let frame_time = if self.measured_fps > 1.0 { + format!("{:.1} MS/F", 1000.0 / self.measured_fps) + } else { + "-- MS/F".to_owned() + }; + canvas.draw_text(120, 15, 1, TEXT, &frame_time); + } + + fn draw_full(&self, canvas: &mut Raster) { + canvas.draw_text(20, 22, 2, GREEN, "NVST DEBUG"); + canvas.tag(328, 18, 64, "NTFK ON", GREEN); + canvas.tag(400, 18, 62, "F3 OFF", MUTED); + + let fps = display_fps(self.measured_fps, self.stream.fps); + let fps_text = fps.to_string(); + canvas.draw_text(20, 58, 7, GREEN, &fps_text); + let fps_label_x = 20 + text_width(&fps_text, 7) as i32 + 10; + canvas.draw_text(fps_label_x, 77, 2, TEXT, "FPS"); + let frame_ms = if self.measured_fps > 1.0 { + format!("{:.1} MS / FRAME", 1000.0 / self.measured_fps) + } else { + "-- MS / FRAME".to_owned() + }; + canvas.draw_text(fps_label_x, 99, 1, MUTED, &frame_ms); + self.draw_graph(canvas, 220, 58, 242, 52); + + canvas.section(20, 132, "VIDEO"); + canvas.row( + 20, + 154, + "CODEC", + 460, + &self.stream.codec.label().to_ascii_uppercase(), + TEXT, + ); + canvas.row(20, 178, "DECODER", 460, self.decoder, TEXT); + canvas.row( + 20, + 202, + "STREAM", + 460, + &format!( + "{}X{} @ {}", + self.stream.width, self.stream.height, self.stream.fps + ), + TEXT, + ); + let pacing = if self.stream.cloud_gsync { + format!("{frame_ms} / CLOUD VRR") + } else { + frame_ms.clone() + }; + canvas.row(20, 226, "FRAME PERIOD", 460, &pacing, GREEN); + canvas.row( + 20, + 250, + "DROPS / SKIPS", + 460, + &format!("{} / {}", self.dropped_frames, self.presentation_skips), + if self.dropped_frames == 0 { + TEXT + } else { + AMBER + }, + ); + canvas.row( + 20, + 274, + "CURSOR / INPUT", + 460, + if self.relative_mouse { + "LOCKED / RAW" + } else { + "ABSOLUTE / RAW" + }, + GREEN, + ); + canvas.divider(20, 299, 440); + + canvas.section(20, 317, "NETWORK"); + canvas.row(20, 339, "TRANSPORT", 460, "NVST / UDP", GREEN); + canvas.row(20, 363, "ROUND TRIP / JITTER", 460, "-- / --", MUTED); + canvas.row(20, 387, "PACKET LOSS", 460, "--", MUTED); + canvas.row( + 20, + 411, + "BITRATE NOW / MAX", + 460, + &format!( + "{:.1} / {:.1} MBPS", + self.measured_bitrate_bps / 1_000_000.0, + self.stream.bitrate_bps as f32 / 1_000_000.0, + ), + TEXT, + ); + canvas.draw_text(20, 448, 1, MUTED, "F3: MINIMAL / FULL / OFF"); + } + + fn draw_graph(&self, canvas: &mut Raster, x: i32, y: i32, width: u32, height: u32) { + canvas.fill_rect(x, y + height as i32, width, 1, BORDER); + let target = self.stream.fps.max(1) as f32; + for (index, sample) in self.fps_history.iter().enumerate() { + let bar_height = ((*sample / target).clamp(0.05, 1.2) * height as f32) as u32; + canvas.fill_rect( + x + index as i32 * 14, + y + height as i32 - bar_height as i32, + 10, + bar_height, + if *sample < target * 0.8 { AMBER } else { GRAPH }, + ); + } + } +} + +fn measured_bitrate_bps(bytes: u64, elapsed: Duration) -> f32 { + bytes as f32 * 8.0 / elapsed.as_secs_f32().max(0.001) +} + +fn overlay_origin( + mode: OverlayMode, + width: u32, + height: u32, + frame: &OverlayFrame, +) -> Option<(u32, u32)> { + mode.size()?; + let max_x = width.saturating_sub(frame.width); + let max_y = height.saturating_sub(frame.height); + Some(match mode { + OverlayMode::Hidden => return None, + OverlayMode::Minimal => (max_x.saturating_sub(EDGE_MARGIN), EDGE_MARGIN.min(max_y)), + OverlayMode::Full => (EDGE_MARGIN.min(max_x), EDGE_MARGIN.min(max_y)), + }) +} + +fn blend(destination: u8, source: u8) -> u8 { + let inverse = 255 - OVERLAY_ALPHA; + ((u16::from(source) * OVERLAY_ALPHA + u16::from(destination) * inverse + 127) / 255) as u8 +} + +#[cfg(target_os = "linux")] +fn rgb_to_limited_bt709(red: u8, green: u8, blue: u8) -> (u8, u8, u8) { + let red = i32::from(red); + let green = i32::from(green); + let blue = i32::from(blue); + let y = ((47 * red + 157 * green + 16 * blue + 128) >> 8) + 16; + let u = ((-26 * red - 87 * green + 112 * blue + 128) >> 8) + 128; + let v = ((112 * red - 102 * green - 10 * blue + 128) >> 8) + 128; + (clamp_byte(y), clamp_byte(u), clamp_byte(v)) +} + +#[cfg(target_os = "linux")] +fn clamp_byte(value: i32) -> u8 { + value.clamp(0, 255) as u8 +} + +struct Raster { + width: u32, + height: u32, + pixels: Vec, +} + +impl Raster { + fn new(width: u32, height: u32, color: Rgb) -> Self { + let mut pixels = vec![0_u8; width as usize * height as usize * 3]; + for pixel in pixels.chunks_exact_mut(3) { + pixel.copy_from_slice(&color); + } + Self { + width, + height, + pixels, + } + } + + fn fill_rect(&mut self, x: i32, y: i32, width: u32, height: u32, color: Rgb) { + let start_x = x.max(0) as u32; + let start_y = y.max(0) as u32; + let end_x = x.saturating_add_unsigned(width).max(0) as u32; + let end_y = y.saturating_add_unsigned(height).max(0) as u32; + for row in start_y.min(self.height)..end_y.min(self.height) { + for column in start_x.min(self.width)..end_x.min(self.width) { + let offset = (row as usize * self.width as usize + column as usize) * 3; + self.pixels[offset..offset + 3].copy_from_slice(&color); + } + } + } + + fn draw_rect(&mut self, x: i32, y: i32, width: u32, height: u32, color: Rgb) { + if width == 0 || height == 0 { + return; + } + self.fill_rect(x, y, width, 1, color); + self.fill_rect(x, y + height as i32 - 1, width, 1, color); + self.fill_rect(x, y, 1, height, color); + self.fill_rect(x + width as i32 - 1, y, 1, height, color); + } + + fn section(&mut self, x: i32, y: i32, label: &str) { + self.draw_text(x, y, 1, MUTED, label); + } + + fn divider(&mut self, x: i32, y: i32, width: u32) { + self.fill_rect(x, y, width, 1, BORDER); + } + + fn row(&mut self, x: i32, y: i32, label: &str, right: i32, value: &str, color: Rgb) { + self.draw_text(x, y, 2, MUTED, label); + self.draw_text(right - text_width(value, 2) as i32, y, 2, color, value); + } + + fn tag(&mut self, x: i32, y: i32, width: u32, label: &str, color: Rgb) { + self.draw_rect(x, y, width, 25, BORDER); + self.draw_text(x + 8, y + 8, 1, color, label); + } + + fn draw_text(&mut self, x: i32, y: i32, scale: u32, color: Rgb, text: &str) { + let mut cursor_x = x; + for character in text.to_ascii_uppercase().chars() { + for (row, bits) in glyph(character).iter().enumerate() { + for column in 0..5 { + if bits & (1 << (4 - column)) != 0 { + self.fill_rect( + cursor_x + column * scale as i32, + y + row as i32 * scale as i32, + scale, + scale, + color, + ); + } + } + } + cursor_x += 6 * scale as i32; + } + } +} + +fn display_fps(measured: f32, target: u32) -> u32 { + if measured > 1.0 { + measured.round() as u32 + } else { + target + } +} + +fn text_width(text: &str, scale: u32) -> u32 { + text.chars().count() as u32 * 6 * scale +} + +fn glyph(character: char) -> [u8; 7] { + match character { + 'A' => [14, 17, 17, 31, 17, 17, 17], + 'B' => [30, 17, 17, 30, 17, 17, 30], + 'C' => [14, 17, 16, 16, 16, 17, 14], + 'D' => [30, 17, 17, 17, 17, 17, 30], + 'E' => [31, 16, 16, 30, 16, 16, 31], + 'F' => [31, 16, 16, 30, 16, 16, 16], + 'G' => [14, 17, 16, 23, 17, 17, 15], + 'H' => [17, 17, 17, 31, 17, 17, 17], + 'I' => [14, 4, 4, 4, 4, 4, 14], + 'J' => [7, 2, 2, 2, 18, 18, 12], + 'K' => [17, 18, 20, 24, 20, 18, 17], + 'L' => [16, 16, 16, 16, 16, 16, 31], + 'M' => [17, 27, 21, 21, 17, 17, 17], + 'N' => [17, 25, 21, 19, 17, 17, 17], + 'O' => [14, 17, 17, 17, 17, 17, 14], + 'P' => [30, 17, 17, 30, 16, 16, 16], + 'Q' => [14, 17, 17, 17, 21, 18, 13], + 'R' => [30, 17, 17, 30, 20, 18, 17], + 'S' => [15, 16, 16, 14, 1, 1, 30], + 'T' => [31, 4, 4, 4, 4, 4, 4], + 'U' => [17, 17, 17, 17, 17, 17, 14], + 'V' => [17, 17, 17, 17, 17, 10, 4], + 'W' => [17, 17, 17, 21, 21, 21, 10], + 'X' => [17, 17, 10, 4, 10, 17, 17], + 'Y' => [17, 17, 10, 4, 4, 4, 4], + 'Z' => [31, 1, 2, 4, 8, 16, 31], + '0' => [14, 17, 19, 21, 25, 17, 14], + '1' => [4, 12, 4, 4, 4, 4, 14], + '2' => [14, 17, 1, 2, 4, 8, 31], + '3' => [30, 1, 1, 14, 1, 1, 30], + '4' => [2, 6, 10, 18, 31, 2, 2], + '5' => [31, 16, 16, 30, 1, 1, 30], + '6' => [14, 16, 16, 30, 17, 17, 14], + '7' => [31, 1, 2, 4, 8, 8, 8], + '8' => [14, 17, 17, 14, 17, 17, 14], + '9' => [14, 17, 17, 15, 1, 1, 14], + '.' => [0, 0, 0, 0, 0, 12, 12], + ':' => [0, 12, 12, 0, 12, 12, 0], + '/' => [1, 2, 2, 4, 8, 8, 16], + '-' => [0, 0, 0, 31, 0, 0, 0], + '|' => [4, 4, 4, 4, 4, 4, 4], + '@' => [14, 17, 23, 21, 23, 16, 14], + '%' => [17, 2, 4, 8, 16, 17, 0], + _ => [0; 7], + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn overlay_modes_cycle_predictably() { + assert_eq!(OverlayMode::Hidden.next(), OverlayMode::Minimal); + assert_eq!(OverlayMode::Minimal.next(), OverlayMode::Full); + assert_eq!(OverlayMode::Full.next(), OverlayMode::Hidden); + } + + #[test] + fn fps_uses_target_until_live_sample_exists() { + assert_eq!(display_fps(0.0, 120), 120); + assert_eq!(display_fps(117.4, 120), 117); + } + + #[test] + fn measured_bitrate_uses_encoded_video_bytes_over_sample_time() { + assert_eq!( + measured_bitrate_bps(1_000_000, Duration::from_secs(1)), + 8_000_000.0, + ); + assert_eq!( + measured_bitrate_bps(500_000, Duration::from_millis(250)), + 16_000_000.0, + ); + } + + #[test] + fn rgb_overlay_is_composited_in_the_expected_corner() { + let mut overlay = NativeStatsOverlay::new(MediaStreamConfig::default(), "TEST"); + overlay.toggle(); + let mut destination = vec![0_u8; 640 * 360 * 3]; + overlay.composite_rgb24(&mut destination, 640, 360, 640 * 3); + let origin = (24 * 640 + (640 - MINIMAL_SIZE.0 - EDGE_MARGIN)) as usize * 3; + assert_ne!(&destination[origin..origin + 3], &[0, 0, 0]); + assert_eq!(&destination[..3], &[0, 0, 0]); + } + + #[cfg(target_os = "linux")] + #[test] + fn nv12_overlay_updates_luma_and_chroma_without_touching_other_pixels() { + use std::sync::Arc; + + use opennow_streamer_platform_linux::{DecodedVideoFrame, FramePlane, StreamFormat}; + + let mut overlay = NativeStatsOverlay::new(MediaStreamConfig::default(), "TEST"); + overlay.toggle(); + let mut frame = DecodedVideoFrame { + format: StreamFormat::h264_default(640, 360).unwrap(), + planes: vec![ + FramePlane { + data: Arc::from(vec![16_u8; 640 * 360]), + stride: 640, + rows: 360, + }, + FramePlane { + data: Arc::from(vec![128_u8; 640 * 180]), + stride: 640, + rows: 180, + }, + ], + dmabuf: None, + vulkan: None, + overlay: None, + timestamp_us: 0, + }; + + overlay.composite_linux_frame(&mut frame); + + let origin_x = 640 - MINIMAL_SIZE.0 as usize - EDGE_MARGIN as usize; + let luma_origin = 24 * 640 + origin_x; + let chroma_origin = 12 * 640 + origin_x; + assert_ne!(frame.planes[0].data[luma_origin], 16); + assert_ne!( + &frame.planes[1].data[chroma_origin..chroma_origin + 2], + &[128, 128] + ); + assert_eq!(frame.planes[0].data[0], 16); + assert_eq!(&frame.planes[1].data[..2], &[128, 128]); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/native_surface.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/native_surface.rs new file mode 100644 index 000000000..93aaecc29 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/native_surface.rs @@ -0,0 +1,452 @@ +use opennow_streamer_protocol::RenderSurfaceRect; +use sdl2::video::Window; + +pub(crate) struct NativeSurface { + inner: platform::Surface, +} + +impl NativeSurface { + pub(crate) fn new(window: &Window) -> Result { + std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + platform::Surface::new(window) + })) + .map_err(|_| "SDL could not expose a native presentation handle".to_owned())? + .map(|inner| Self { inner }) + } + + pub(crate) fn attach_and_show( + &mut self, + parent_handle: &str, + rect: RenderSurfaceRect, + screen_rect: Option, + scale: f32, + ) -> Result<(), String> { + self.inner + .attach_and_show(parent_handle, rect, screen_rect, scale) + } + + pub(crate) fn hide(&mut self) { + self.inner.hide(); + } + + pub(crate) fn refresh_ordering(&mut self) -> Result<(), String> { + self.inner.refresh_ordering() + } + + #[cfg(target_os = "windows")] + pub(crate) fn window_handle(&self) -> isize { + self.inner.window_handle() + } +} + +#[cfg(any(target_os = "windows", target_os = "linux"))] +fn parse_handle(value: &str) -> Result { + let trimmed = value.trim(); + let parsed = if let Some(hex) = trimmed.strip_prefix("0x") { + usize::from_str_radix(hex, 16) + } else { + trimmed.parse() + }; + parsed + .ok() + .filter(|handle| *handle != 0) + .ok_or_else(|| format!("invalid Electron native window handle: {value}")) +} + +#[cfg(any(target_os = "windows", target_os = "linux"))] +fn physical_rect(rect: RenderSurfaceRect, _scale: f32) -> (i32, i32, u32, u32) { + (rect.x, rect.y, rect.width.max(2), rect.height.max(2)) +} + +#[cfg(target_os = "windows")] +mod platform { + use raw_window_handle::{HasWindowHandle, RawWindowHandle}; + use windows_sys::Win32::UI::Input::KeyboardAndMouse::SetFocus; + use windows_sys::Win32::UI::WindowsAndMessaging::{ + GWL_EXSTYLE, GWL_STYLE, GWLP_HWNDPARENT, GetWindowLongPtrW, HWND_TOP, SW_HIDE, + SWP_NOACTIVATE, SWP_SHOWWINDOW, SetForegroundWindow, SetWindowLongPtrW, SetWindowPos, + ShowWindow, WS_CHILD, WS_DISABLED, WS_EX_NOACTIVATE, WS_EX_TRANSPARENT, WS_POPUP, + WS_VISIBLE, + }; + + use super::*; + + pub(crate) struct Surface { + child: windows_sys::Win32::Foundation::HWND, + owner: windows_sys::Win32::Foundation::HWND, + shown: bool, + } + + impl Surface { + pub(crate) fn new(window: &Window) -> Result { + let child = match window + .window_handle() + .map_err(|error| format!("SDL Win32 handle unavailable: {error}"))? + .as_raw() + { + RawWindowHandle::Win32(handle) => handle.hwnd.get() as _, + _ => return Err("SDL did not create a Win32 presentation window".to_owned()), + }; + Ok(Self { + child, + owner: std::ptr::null_mut(), + shown: false, + }) + } + + pub(crate) fn window_handle(&self) -> isize { + self.child as isize + } + + pub(crate) fn attach_and_show( + &mut self, + parent_handle: &str, + rect: RenderSurfaceRect, + _screen_rect: Option, + _scale: f32, + ) -> Result<(), String> { + let owner = parse_handle(parent_handle)? as _; + let (x, y, width, height) = physical_rect(_screen_rect.unwrap_or(rect), _scale); + unsafe { + if self.owner != owner { + SetWindowLongPtrW(self.child, GWLP_HWNDPARENT, owner as isize); + self.owner = owner; + } + let style = GetWindowLongPtrW(self.child, GWL_STYLE) as u32; + SetWindowLongPtrW( + self.child, + GWL_STYLE, + ((style & !(WS_VISIBLE | WS_CHILD | WS_DISABLED)) | WS_POPUP) as isize, + ); + let extended = GetWindowLongPtrW(self.child, GWL_EXSTYLE) as u32; + SetWindowLongPtrW( + self.child, + GWL_EXSTYLE, + (extended & !(WS_EX_NOACTIVATE | WS_EX_TRANSPARENT)) as isize, + ); + if SetWindowPos( + self.child, + HWND_TOP, + x, + y, + width as i32, + height as i32, + SWP_NOACTIVATE | SWP_SHOWWINDOW, + ) == 0 + { + return Err("failed to position external SDL video surface".to_owned()); + } + if !self.shown { + let _ = SetForegroundWindow(self.child); + let _ = SetFocus(self.child); + self.shown = true; + } + } + Ok(()) + } + + pub(crate) fn hide(&mut self) { + unsafe { + ShowWindow(self.child, SW_HIDE); + } + self.shown = false; + } + + pub(crate) fn refresh_ordering(&mut self) -> Result<(), String> { + Ok(()) + } + } +} + +#[cfg(all(test, any(target_os = "windows", target_os = "linux")))] +mod tests { + use super::*; + + #[test] + fn renderer_rect_is_already_physical_at_common_dpi_scales() { + let rect = RenderSurfaceRect { + x: 120, + y: 80, + width: 1280, + height: 720, + }; + + for scale in [1.0, 1.5, 2.0] { + assert_eq!(physical_rect(rect, scale), (120, 80, 1280, 720)); + } + } + + #[test] + fn physical_rect_only_clamps_empty_dimensions() { + let rect = RenderSurfaceRect { + x: -10, + y: 20, + width: 0, + height: 1, + }; + + assert_eq!(physical_rect(rect, 2.0), (-10, 20, 2, 2)); + } +} + +#[cfg(target_os = "linux")] +mod platform { + use std::sync::atomic::{AtomicI32, Ordering}; + + use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle}; + use x11_dl::xlib; + + use super::*; + + static X11_ERROR_CODE: AtomicI32 = AtomicI32::new(0); + + unsafe extern "C" fn record_x11_error( + _display: *mut xlib::Display, + event: *mut xlib::XErrorEvent, + ) -> i32 { + if !event.is_null() { + X11_ERROR_CODE.store(unsafe { (*event).error_code.into() }, Ordering::Release); + } + 0 + } + + pub(crate) struct Surface { + xlib: xlib::Xlib, + display: *mut xlib::Display, + child: xlib::Window, + parent: xlib::Window, + } + + impl Surface { + pub(crate) fn new(window: &Window) -> Result { + let child = match window + .window_handle() + .map_err(|error| format!("SDL X11 window handle unavailable: {error}"))? + .as_raw() + { + RawWindowHandle::Xlib(handle) => handle.window, + RawWindowHandle::Wayland(_) => { + return Err( + "native Electron surface embedding requires an X11/XWayland session" + .to_owned(), + ); + } + _ => return Err("SDL did not create an X11 presentation window".to_owned()), + }; + let display = match window + .display_handle() + .map_err(|error| format!("SDL X11 display handle unavailable: {error}"))? + .as_raw() + { + RawDisplayHandle::Xlib(handle) => handle + .display + .map(|display| display.as_ptr()) + .unwrap_or(std::ptr::null_mut()), + _ => std::ptr::null_mut(), + }; + if display.is_null() { + return Err("SDL X11 display pointer is null".to_owned()); + } + Ok(Self { + xlib: xlib::Xlib::open() + .map_err(|error| format!("failed to load X11 embedding API: {error}"))?, + display: display.cast(), + child, + parent: 0, + }) + } + + pub(crate) fn attach_and_show( + &mut self, + parent_handle: &str, + rect: RenderSurfaceRect, + _screen_rect: Option, + _scale: f32, + ) -> Result<(), String> { + let parent = parse_handle(parent_handle)? as xlib::Window; + let (x, y, width, height) = physical_rect(rect, _scale); + let error_code = unsafe { + (self.xlib.XSync)(self.display, xlib::False); + X11_ERROR_CODE.store(0, Ordering::Release); + let previous = (self.xlib.XSetErrorHandler)(Some(record_x11_error)); + if self.parent != parent { + (self.xlib.XUnmapWindow)(self.display, self.child); + (self.xlib.XReparentWindow)(self.display, self.child, parent, x, y); + (self.xlib.XSelectInput)(self.display, self.child, xlib::StructureNotifyMask); + self.parent = parent; + } + (self.xlib.XMoveResizeWindow)(self.display, self.child, x, y, width, height); + (self.xlib.XLowerWindow)(self.display, self.child); + (self.xlib.XMapWindow)(self.display, self.child); + (self.xlib.XSync)(self.display, xlib::False); + (self.xlib.XSetErrorHandler)(previous); + X11_ERROR_CODE.load(Ordering::Acquire) + }; + if error_code != 0 { + self.parent = 0; + return Err(format!( + "X11 could not attach the native child surface (error {error_code})" + )); + } + Ok(()) + } + + pub(crate) fn hide(&mut self) { + unsafe { + (self.xlib.XSync)(self.display, xlib::False); + X11_ERROR_CODE.store(0, Ordering::Release); + let previous = (self.xlib.XSetErrorHandler)(Some(record_x11_error)); + (self.xlib.XUnmapWindow)(self.display, self.child); + (self.xlib.XSync)(self.display, xlib::False); + (self.xlib.XSetErrorHandler)(previous); + } + } + + pub(crate) fn refresh_ordering(&mut self) -> Result<(), String> { + Ok(()) + } + } +} + +#[cfg(target_os = "macos")] +mod platform { + use std::time::{Duration, Instant}; + + use objc2::rc::Retained; + use objc2_app_kit::{NSView, NSWindow, NSWorkspace}; + use raw_window_handle::{HasWindowHandle, RawWindowHandle}; + + use super::*; + + const ORDERING_POLL_INTERVAL: Duration = Duration::from_millis(100); + + pub(crate) struct Surface { + child: Retained, + raw_window: *mut sdl2::sys::SDL_Window, + parent_pid: libc::pid_t, + requested_visible: bool, + ordered: bool, + last_ordering_check: Option, + } + + impl Surface { + pub(crate) fn new(window: &Window) -> Result { + let child_view = match window + .window_handle() + .map_err(|error| format!("SDL AppKit handle unavailable: {error}"))? + .as_raw() + { + RawWindowHandle::AppKit(handle) => unsafe { + &*handle.ns_view.as_ptr().cast::() + }, + _ => return Err("SDL did not create an AppKit presentation window".to_owned()), + }; + let child = child_view + .window() + .ok_or_else(|| "SDL AppKit view has no window".to_owned())?; + child.setIgnoresMouseEvents(true); + Ok(Self { + child, + raw_window: window.raw(), + parent_pid: unsafe { libc::getppid() }, + requested_visible: false, + ordered: false, + last_ordering_check: None, + }) + } + + pub(crate) fn attach_and_show( + &mut self, + _parent_handle: &str, + _rect: RenderSurfaceRect, + screen_rect: Option, + _scale: f32, + ) -> Result<(), String> { + let screen_rect = screen_rect.ok_or_else(|| { + "macOS native surface is missing absolute screen bounds".to_owned() + })?; + let width = i32::try_from(screen_rect.width) + .map_err(|_| "macOS native surface width is out of range".to_owned())?; + let height = i32::try_from(screen_rect.height) + .map_err(|_| "macOS native surface height is out of range".to_owned())?; + unsafe { + sdl2::sys::SDL_SetWindowPosition(self.raw_window, screen_rect.x, screen_rect.y); + sdl2::sys::SDL_SetWindowSize(self.raw_window, width, height); + } + self.requested_visible = true; + self.last_ordering_check = None; + self.refresh_ordering() + } + + pub(crate) fn hide(&mut self) { + self.requested_visible = false; + if self.ordered { + unsafe { + sdl2::sys::SDL_HideWindow(self.raw_window); + } + self.ordered = false; + } + } + + pub(crate) fn refresh_ordering(&mut self) -> Result<(), String> { + if self + .last_ordering_check + .is_some_and(|last| last.elapsed() < ORDERING_POLL_INTERVAL) + { + return Ok(()); + } + self.last_ordering_check = Some(Instant::now()); + let should_order = self.requested_visible && self.parent_is_frontmost(); + if should_order == self.ordered { + return Ok(()); + } + unsafe { + if should_order { + sdl2::sys::SDL_ShowWindow(self.raw_window); + } else { + sdl2::sys::SDL_HideWindow(self.raw_window); + } + } + if should_order { + self.child.orderFrontRegardless(); + } + self.ordered = should_order; + Ok(()) + } + + fn parent_is_frontmost(&self) -> bool { + NSWorkspace::sharedWorkspace() + .frontmostApplication() + .is_some_and(|application| application.processIdentifier() == self.parent_pid) + } + } +} + +#[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))] +mod platform { + use super::*; + + pub(crate) struct Surface; + + impl Surface { + pub(crate) fn new(_window: &Window) -> Result { + Err("native presentation is unsupported on this operating system".to_owned()) + } + + pub(crate) fn attach_and_show( + &mut self, + _parent_handle: &str, + _rect: RenderSurfaceRect, + _screen_rect: Option, + _scale: f32, + ) -> Result<(), String> { + Err("native presentation is unsupported on this operating system".to_owned()) + } + + pub(crate) fn hide(&mut self) {} + + pub(crate) fn refresh_ordering(&mut self) -> Result<(), String> { + Ok(()) + } + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/output.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/output.rs new file mode 100644 index 000000000..4d360b582 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/output.rs @@ -0,0 +1,2870 @@ +use std::collections::{HashMap, HashSet, VecDeque}; +use std::io::Cursor as IoCursor; +#[cfg(target_os = "windows")] +use std::sync::atomic::AtomicBool; +#[cfg(target_os = "linux")] +use std::sync::atomic::AtomicU64; +#[cfg(any(target_os = "windows", target_os = "linux"))] +use std::sync::atomic::Ordering; +use std::sync::{Arc, Mutex}; +#[cfg(target_os = "linux")] +use std::time::Instant; + +use base64::Engine as _; +use base64::engine::general_purpose::STANDARD as BASE64; +use image::ImageReader; +use opennow_streamer_protocol::RenderSurface; +use sdl2::audio::{AudioCallback, AudioDevice, AudioSpecDesired}; +use sdl2::pixels::{Color, PixelFormatEnum}; +use sdl2::rect::Rect; +use sdl2::render::{Texture, WindowCanvas}; + +#[cfg(target_os = "linux")] +use crate::linux_frame_pacing::{FrameSelectionPolicy, LinuxFramePacer}; +use crate::media::{CapturedInput, CapturedInputQueue, MediaStreamConfig}; +#[cfg(target_os = "linux")] +use crate::native_stats_overlay::NativeStatsOverlay; +use crate::native_surface::NativeSurface; +#[cfg(target_os = "windows")] +use crate::windows_debug_overlay::NativeDebugOverlay; +#[cfg(target_os = "windows")] +use crate::windows_raw_input::WindowsRawInputController; + +#[cfg(target_os = "linux")] +use opennow_streamer_platform_linux::DecodedVideoFrame as LinuxDecodedVideoFrame; +#[cfg(target_os = "windows")] +use opennow_streamer_platform_windows::{ + AudioFormat, BackendConfig, BackendEvent, Bounds, ExistingWindow, OwnedWindow, Subsystem, + SurfaceTarget, VideoCodec, VideoFormat, WindowHandle, WindowsBackend, WindowsGraphicsApi, +}; + +const AUDIO_SAMPLE_RATE: i32 = 48_000; +const AUDIO_CHANNELS: u8 = 2; +const AUDIO_BUFFER_FRAMES: u16 = 480; +const MAX_AUDIO_LATENCY_MS: usize = 120; +#[cfg(target_os = "linux")] +const LINUX_VIDEO_QUEUE_CAPACITY: usize = 6; + +#[derive(Debug)] +pub(crate) struct DecodedVideoFrame { + pub(crate) width: u32, + pub(crate) height: u32, + pub(crate) rgb: Vec, +} + +#[cfg(target_os = "linux")] +#[derive(Debug)] +struct QueuedLinuxVideoFrame { + frame: LinuxDecodedVideoFrame, + arrived_at: Instant, +} + +#[derive(Debug)] +pub(crate) struct OutputBuffers { + video: Mutex>, + #[cfg(target_os = "linux")] + linux_video: Mutex>, + #[cfg(target_os = "linux")] + software_video_drops: AtomicU64, + #[cfg(target_os = "linux")] + hardware_video_drops: AtomicU64, + #[cfg(target_os = "linux")] + display_video_skips: AtomicU64, + #[cfg(target_os = "linux")] + received_video_bytes: AtomicU64, + audio: Mutex>, + audio_capacity: usize, + captured_input: Arc, +} + +#[cfg(target_os = "windows")] +pub(crate) struct WindowsBridge { + backend: Mutex>>, + software_fallback: AtomicBool, + keyframe_required: AtomicBool, + last_video_mid: Mutex, +} + +#[cfg(target_os = "windows")] +impl WindowsBridge { + pub(crate) fn new() -> Self { + Self { + backend: Mutex::new(None), + software_fallback: AtomicBool::new(false), + keyframe_required: AtomicBool::new(true), + last_video_mid: Mutex::new("video".to_owned()), + } + } + + pub(crate) fn backend(&self) -> Option> { + self.backend + .lock() + .unwrap_or_else(|error| error.into_inner()) + .clone() + } + + fn replace_backend(&self, backend: Option>) { + *self + .backend + .lock() + .unwrap_or_else(|error| error.into_inner()) = backend; + } + + pub(crate) fn use_software(&self) -> bool { + self.software_fallback.load(Ordering::Acquire) + } + + pub(crate) fn fall_back_to_software(&self) { + self.software_fallback.store(true, Ordering::Release); + self.keyframe_required.store(true, Ordering::Release); + self.replace_backend(None); + } + + pub(crate) fn reset(&self) { + self.software_fallback.store(false, Ordering::Release); + self.keyframe_required.store(true, Ordering::Release); + self.replace_backend(None); + } + + pub(crate) fn set_last_video_mid(&self, mid: &str) { + *self + .last_video_mid + .lock() + .unwrap_or_else(|error| error.into_inner()) = mid.to_owned(); + } + + pub(crate) fn last_video_mid(&self) -> String { + self.last_video_mid + .lock() + .unwrap_or_else(|error| error.into_inner()) + .clone() + } + + pub(crate) fn keyframe_required(&self) -> bool { + self.keyframe_required.load(Ordering::Acquire) + } + + pub(crate) fn require_keyframe(&self) { + self.keyframe_required.store(true, Ordering::Release); + } + + pub(crate) fn accept_keyframe(&self) { + self.keyframe_required.store(false, Ordering::Release); + } +} + +impl OutputBuffers { + pub(crate) fn new() -> Self { + Self { + video: Mutex::new(None), + #[cfg(target_os = "linux")] + linux_video: Mutex::new(VecDeque::with_capacity(LINUX_VIDEO_QUEUE_CAPACITY)), + #[cfg(target_os = "linux")] + software_video_drops: AtomicU64::new(0), + #[cfg(target_os = "linux")] + hardware_video_drops: AtomicU64::new(0), + #[cfg(target_os = "linux")] + display_video_skips: AtomicU64::new(0), + #[cfg(target_os = "linux")] + received_video_bytes: AtomicU64::new(0), + audio: Mutex::new(VecDeque::with_capacity( + AUDIO_SAMPLE_RATE as usize * AUDIO_CHANNELS as usize * MAX_AUDIO_LATENCY_MS / 1_000, + )), + audio_capacity: AUDIO_SAMPLE_RATE as usize + * AUDIO_CHANNELS as usize + * MAX_AUDIO_LATENCY_MS + / 1_000, + captured_input: Arc::new(CapturedInputQueue::default()), + } + } + + pub(crate) fn captured_input(&self) -> Arc { + Arc::clone(&self.captured_input) + } + + pub(crate) fn replace_video(&self, frame: DecodedVideoFrame) -> bool { + let dropped = self + .video + .lock() + .unwrap_or_else(|error| error.into_inner()) + .replace(frame) + .is_some(); + #[cfg(target_os = "linux")] + if dropped { + self.software_video_drops.fetch_add(1, Ordering::Relaxed); + } + dropped + } + + pub(crate) fn take_video(&self) -> Option { + self.video + .lock() + .unwrap_or_else(|error| error.into_inner()) + .take() + } + + #[cfg(target_os = "linux")] + pub(crate) fn queue_linux_video(&self, frame: LinuxDecodedVideoFrame) -> bool { + let mut queue = self + .linux_video + .lock() + .unwrap_or_else(|error| error.into_inner()); + let dropped = if queue.len() == LINUX_VIDEO_QUEUE_CAPACITY { + queue.pop_front(); + true + } else { + false + }; + queue.push_back(QueuedLinuxVideoFrame { + frame, + arrived_at: Instant::now(), + }); + if dropped { + self.hardware_video_drops.fetch_add(1, Ordering::Relaxed); + } + dropped + } + + #[cfg(target_os = "linux")] + fn take_linux_video(&self) -> Option { + self.linux_video + .lock() + .unwrap_or_else(|error| error.into_inner()) + .pop_front() + } + + #[cfg(target_os = "linux")] + fn take_linux_video_for_presentation( + &self, + selection: FrameSelectionPolicy, + target_queue_depth: usize, + ) -> Option { + let mut queue = self + .linux_video + .lock() + .unwrap_or_else(|error| error.into_inner()); + if queue.len() <= target_queue_depth { + return None; + } + let (frame, skipped) = match selection { + FrameSelectionPolicy::OldestReady => (queue.pop_front(), 0), + FrameSelectionPolicy::LatestReady => { + let frame = queue.pop_back(); + let skipped = queue.len(); + queue.clear(); + (frame, skipped) + } + }; + if skipped > 0 { + self.display_video_skips.fetch_add( + u64::try_from(skipped).unwrap_or(u64::MAX), + Ordering::Relaxed, + ); + } + frame + } + + #[cfg(target_os = "linux")] + fn clear_linux_video(&self) { + self.linux_video + .lock() + .unwrap_or_else(|error| error.into_inner()) + .clear(); + } + + #[cfg(target_os = "linux")] + fn software_video_drops(&self) -> u64 { + self.software_video_drops.load(Ordering::Relaxed) + } + + #[cfg(target_os = "linux")] + fn hardware_video_drops(&self) -> u64 { + self.hardware_video_drops.load(Ordering::Relaxed) + } + + #[cfg(target_os = "linux")] + fn display_video_skips(&self) -> u64 { + self.display_video_skips.load(Ordering::Relaxed) + } + + #[cfg(target_os = "linux")] + pub(crate) fn record_received_video_bytes(&self, bytes: usize) { + self.received_video_bytes + .fetch_add(u64::try_from(bytes).unwrap_or(u64::MAX), Ordering::Relaxed); + } + + #[cfg(target_os = "linux")] + fn received_video_bytes(&self) -> u64 { + self.received_video_bytes.load(Ordering::Relaxed) + } + + pub(crate) fn push_audio(&self, samples: &[f32]) -> usize { + let mut audio = self.audio.lock().unwrap_or_else(|error| error.into_inner()); + let overflow = audio + .len() + .saturating_add(samples.len()) + .saturating_sub(self.audio_capacity); + if overflow > 0 { + let drain_count = overflow.min(audio.len()); + audio.drain(..drain_count); + } + if samples.len() >= self.audio_capacity { + audio.clear(); + audio.extend( + samples[samples.len() - self.audio_capacity..] + .iter() + .copied(), + ); + } else { + audio.extend(samples.iter().copied()); + } + overflow + } + + pub(crate) fn clear(&self) { + self.take_video(); + #[cfg(target_os = "linux")] + { + self.clear_linux_video(); + self.software_video_drops.store(0, Ordering::Relaxed); + self.hardware_video_drops.store(0, Ordering::Relaxed); + self.display_video_skips.store(0, Ordering::Relaxed); + } + self.audio + .lock() + .unwrap_or_else(|error| error.into_inner()) + .clear(); + } + + fn fill_audio(&self, destination: &mut [f32]) { + let mut audio = self.audio.lock().unwrap_or_else(|error| error.into_inner()); + for sample in destination { + *sample = audio.pop_front().unwrap_or(0.0); + } + } +} + +#[cfg(target_os = "linux")] +pub(crate) struct LinuxHardwareOutput { + // These fields own resources derived from the SDL Wayland/X11 display. + // Rust drops fields in declaration order, so keep the presenter and + // window ahead of the SDL root to preserve their native lifetimes even + // when normal stop handling is bypassed during unwinding. + presenter: Option, + native_surface: Result, + input_capture: SdlInputCapture, + window: sdl2::video::Window, + video: sdl2::VideoSubsystem, + event_pump: sdl2::EventPump, + audio: AudioDevice, + output: Arc, + external_renderer: bool, + stream_size: (u32, u32), + surface_size: Option<(u32, u32)>, + stream_fps: u32, + debug_overlay: NativeStatsOverlay, + presented_frames: u64, + frame_pacer: LinuxFramePacer, + vrr_fullscreen_initialized: bool, + visible: bool, + paused: bool, + _sdl: sdl2::Sdl, +} + +#[cfg(target_os = "linux")] +impl LinuxHardwareOutput { + fn initialize(output: Arc, stream: MediaStreamConfig) -> Result { + let sdl = sdl2::init().map_err(|error| format!("SDL initialization failed: {error}"))?; + let video = sdl + .video() + .map_err(|error| format!("SDL video initialization failed: {error}"))?; + let audio_subsystem = sdl + .audio() + .map_err(|error| format!("SDL audio initialization failed: {error}"))?; + let video_driver = video.current_video_driver(); + if !matches!(video_driver, "x11" | "wayland") { + return Err(format!( + "Linux Vulkan presentation requires X11 or Wayland, but SDL selected {video_driver}", + )); + } + let external_renderer = external_renderer_enabled(); + if video_driver == "wayland" && !external_renderer { + return Err( + "Wayland presentation must use a compositor-managed top-level window".to_owned(), + ); + } + let mut window_builder = video.window("OpenNOW Stream", 1280, 720); + window_builder + .position_centered() + .resizable() + .allow_highdpi() + .hidden() + .vulkan(); + if !external_renderer { + window_builder.borderless(); + } + let window = window_builder + .build() + .map_err(|error| format!("native Vulkan window creation failed: {error}"))?; + let display_refresh_hz = linux_display_refresh_hz(&video, &window); + let frame_pacer = LinuxFramePacer::new(stream.fps, display_refresh_hz, stream.cloud_gsync); + eprintln!( + "Linux presentation pacing: stream={}fps display={} output={:.1}Hz mode={}", + stream.fps, + display_refresh_hz.map_or_else(|| "unknown".to_owned(), |value| format!("{value}Hz")), + frame_pacer.presentation_hz(), + if frame_pacer.vrr_enabled() { + "cloud-gsync-vrr" + } else if frame_pacer.fast_stream() { + "nonblocking-fast-stream" + } else { + "adaptive-timestamp" + }, + ); + let native_surface = if external_renderer { + Err("external Linux output does not use child-window embedding".to_owned()) + } else { + NativeSurface::new(&window) + }; + let desired = AudioSpecDesired { + freq: Some(AUDIO_SAMPLE_RATE), + channels: Some(AUDIO_CHANNELS), + samples: Some(AUDIO_BUFFER_FRAMES), + }; + let callback_output = Arc::clone(&output); + let audio = audio_subsystem + .open_playback(None, &desired, move |_| StreamAudioCallback { + output: callback_output, + }) + .map_err(|error| format!("native audio output creation failed: {error}"))?; + let event_pump = sdl + .event_pump() + .map_err(|error| format!("native window event pump creation failed: {error}"))?; + Ok(Self { + presenter: None, + native_surface, + input_capture: SdlInputCapture::new( + external_renderer && native_input_capture_enabled(), + false, + ), + window, + video, + event_pump, + audio, + output, + external_renderer, + stream_size: (stream.width.max(1), stream.height.max(1)), + surface_size: None, + stream_fps: stream.fps.max(1), + debug_overlay: NativeStatsOverlay::new( + stream, + if stream.cloud_gsync { + "LINUX / VULKAN VRR" + } else { + "LINUX / VULKAN" + }, + ), + presented_frames: 0, + frame_pacer, + vrr_fullscreen_initialized: false, + visible: false, + paused: false, + _sdl: sdl, + }) + } + + fn start(&mut self, surface: Option<&RenderSurface>) -> Result<(), String> { + self.paused = false; + self.presented_frames = 0; + self.frame_pacer.reset(); + self.vrr_fullscreen_initialized = false; + self.output.clear(); + self.audio.resume(); + if let Some(surface) = surface { + self.update_surface(surface)?; + } + Ok(()) + } + + fn set_paused(&mut self, paused: bool) { + self.paused = paused; + self.frame_pacer.reset(); + self.vrr_fullscreen_initialized = false; + if paused { + self.input_capture.release(&self._sdl, &mut self.window); + self.audio.pause(); + self.output.clear(); + } else { + self.audio.resume(); + } + } + + fn stop(&mut self) { + self.input_capture.release(&self._sdl, &mut self.window); + self.output.clear(); + self.audio.pause(); + self.presenter = None; + self.surface_size = None; + if let Ok(surface) = self.native_surface.as_mut() { + surface.hide(); + } + if self.external_renderer { + self.window.hide(); + } + self.visible = false; + self.paused = false; + self.frame_pacer.reset(); + self.vrr_fullscreen_initialized = false; + } + + fn update_surface(&mut self, surface: &RenderSurface) -> Result<(), String> { + let Some(rect) = surface.rect.filter(|_| surface.visible) else { + self.input_capture.release(&self._sdl, &mut self.window); + if let Ok(native_surface) = self.native_surface.as_mut() { + native_surface.hide(); + } + if self.external_renderer { + self.window.hide(); + } + self.presenter = None; + self.surface_size = None; + self.visible = false; + return Ok(()); + }; + if self.external_renderer { + let bounds = surface.screen_rect.unwrap_or(rect); + self.window.set_position( + sdl2::video::WindowPos::Positioned(bounds.x), + sdl2::video::WindowPos::Positioned(bounds.y), + ); + self.window + .set_size(bounds.width.max(2), bounds.height.max(2)) + .map_err(|error| format!("failed to resize external Vulkan surface: {error}"))?; + self.window.show(); + if !self.visible { + self.window.raise(); + } + if self.frame_pacer.vrr_enabled() && !self.vrr_fullscreen_initialized { + use sdl2::video::FullscreenType; + + self.window + .set_fullscreen(FullscreenType::Desktop) + .map_err(|error| { + format!("Cloud G-SYNC could not enter compositor fullscreen: {error}") + })?; + self.vrr_fullscreen_initialized = true; + eprintln!( + "Linux Cloud G-SYNC presentation requested compositor fullscreen for VRR" + ); + } + } else { + let parent_handle = surface.window_handle.as_deref().ok_or_else(|| { + "visible native surface is missing Electron windowHandle".to_owned() + })?; + self.native_surface + .as_mut() + .map_err(|error| error.clone())? + .attach_and_show( + parent_handle, + rect, + surface.screen_rect, + surface.device_scale_factor, + )?; + } + let display_refresh_hz = linux_display_refresh_hz(&self.video, &self.window); + if self + .frame_pacer + .reconfigure(self.stream_fps, display_refresh_hz) + { + eprintln!( + "Linux presentation pacing changed: stream={}fps display={} output={:.1}Hz mode={}", + self.stream_fps, + display_refresh_hz + .map_or_else(|| "unknown".to_owned(), |value| format!("{value}Hz")), + self.frame_pacer.presentation_hz(), + if self.frame_pacer.vrr_enabled() { + "cloud-gsync-vrr" + } else if self.frame_pacer.fast_stream() { + "nonblocking-fast-stream" + } else { + "adaptive-timestamp" + }, + ); + self.output.clear_linux_video(); + } + let size = if self.external_renderer { + let (width, height) = self.window.vulkan_drawable_size(); + (width.max(2), height.max(2)) + } else { + (rect.width.max(2), rect.height.max(2)) + }; + if self.presenter.is_some() && self.surface_size != Some(size) { + if let Some(presenter) = self.presenter.as_mut() { + presenter + .reconfigure(size.0, size.1) + .map_err(|error| error.to_string())?; + } + } + self.surface_size = Some(size); + self.visible = true; + Ok(()) + } + + fn pump(&mut self) -> Result { + if !self.external_renderer + && let Ok(surface) = self.native_surface.as_mut() + { + surface.refresh_ordering()?; + } + for event in self.event_pump.poll_iter().collect::>() { + if matches!(event, sdl2::event::Event::Quit { .. }) { + self.input_capture.release(&self._sdl, &mut self.window); + if let Ok(surface) = self.native_surface.as_mut() { + surface.hide(); + } + if self.external_renderer { + self.window.hide(); + } + self.presenter = None; + self.visible = false; + } else if handle_linux_stats_shortcut(&mut self.debug_overlay, &event) + || (self.external_renderer + && handle_native_window_shortcut(&mut self.window, &event)) + { + continue; + } else { + self.input_capture.handle_event( + &self._sdl, + &mut self.window, + self.stream_size, + event, + ); + } + } + if self.paused || !self.visible { + self.output.clear_linux_video(); + return Ok(false); + } + if self.external_renderer { + let (width, height) = self.window.vulkan_drawable_size(); + let drawable_size = (width.max(2), height.max(2)); + if self.surface_size != Some(drawable_size) { + if let Some(presenter) = self.presenter.as_mut() { + presenter + .reconfigure(drawable_size.0, drawable_size.1) + .map_err(|error| error.to_string())?; + } + self.surface_size = Some(drawable_size); + } + } + self.debug_overlay + .set_presentation_skips(self.output.display_video_skips()); + self.debug_overlay.update( + self.presented_frames, + self.output.hardware_video_drops(), + self.input_capture.relative_mouse, + self.output.received_video_bytes(), + ); + let now = Instant::now(); + if !self.frame_pacer.is_due(now) { + return Ok(false); + } + let decision = self.frame_pacer.decision(now); + let frame = self + .output + .take_linux_video_for_presentation(decision.selection, decision.target_queue_depth); + let Some(queued_frame) = frame else { + return Ok(false); + }; + self.frame_pacer + .observe_frame(queued_frame.arrived_at, queued_frame.frame.timestamp_us); + let mut frame = queued_frame.frame; + self.stream_size = (frame.format.width.max(1), frame.format.height.max(1)); + self.debug_overlay.composite_linux_frame(&mut frame); + if frame.vulkan.as_ref().is_some_and(|vulkan| { + self.presenter + .as_ref() + .is_some_and(|presenter| !presenter.matches_vulkan_video_device(vulkan)) + }) { + // Decoder recovery can replace the FFmpeg Vulkan device. Rebuild + // the surface resources on the new device before touching it. + self.presenter = None; + } + if self.presenter.is_none() { + let size = self + .surface_size + .ok_or_else(|| "Linux Vulkan presenter has no visible surface extent".to_owned())?; + self.presenter = Some(create_linux_presenter( + &self.window, + size.0, + size.1, + frame.vulkan.as_deref(), + )?); + } + let presented = self + .presenter + .as_mut() + .ok_or_else(|| { + "Linux Vulkan presenter is not attached to a visible surface".to_owned() + })? + .present(&frame) + .map_err(|error| error.to_string())?; + if presented { + self.presented_frames = self.presented_frames.saturating_add(1); + self.frame_pacer.mark_presented(Instant::now()); + } + Ok(presented) + } + + fn take_captured_input(&mut self) -> Vec { + self.input_capture.take() + } + + fn update_cursor(&mut self, bytes: &[u8]) { + if self.external_renderer { + self.input_capture + .apply_cursor(&self._sdl, &mut self.window, self.stream_size, bytes); + } + } +} + +#[cfg(target_os = "linux")] +impl Drop for LinuxHardwareOutput { + fn drop(&mut self) { + self.stop(); + } +} + +#[cfg(target_os = "linux")] +fn create_linux_presenter( + window: &sdl2::video::Window, + width: u32, + height: u32, + vulkan_video: Option<&opennow_streamer_platform_linux::VulkanVideoFrame>, +) -> Result { + use std::ffi::c_void; + use std::num::NonZeroU64; + use std::ptr::NonNull; + + use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle}; + + let display_handle = window + .display_handle() + .map_err(|error| format!("SDL display handle unavailable: {error}"))?; + let window_handle = window + .window_handle() + .map_err(|error| format!("SDL window handle unavailable: {error}"))?; + let surface = match (display_handle.as_raw(), window_handle.as_raw()) { + (RawDisplayHandle::Xlib(display), RawWindowHandle::Xlib(window)) => { + let screen = display.screen; + let display = display + .display + .ok_or_else(|| "SDL X11 display pointer is null".to_owned())?; + let window = NonZeroU64::new(window.window) + .ok_or_else(|| "SDL returned an empty X11 window handle".to_owned())?; + let display = NonNull::::new(display.as_ptr().cast()) + .ok_or_else(|| "SDL X11 display pointer is null".to_owned())?; + unsafe { + opennow_streamer_platform_linux::NativeSurface::borrow_x11(display, window, screen) + } + } + (RawDisplayHandle::Wayland(display), RawWindowHandle::Wayland(window)) => unsafe { + opennow_streamer_platform_linux::NativeSurface::borrow_wayland( + display.display, + window.surface, + ) + }, + _ => { + return Err( + "SDL returned mismatched or unsupported Linux handles for Vulkan presentation" + .to_owned(), + ); + } + }; + match vulkan_video { + Some(frame) => opennow_streamer_platform_linux::VulkanPresenter::new_for_vulkan_video( + &surface, width, height, frame, + ), + None => opennow_streamer_platform_linux::VulkanPresenter::new(&surface, width, height), + } + .map_err(|error| error.to_string()) +} + +#[cfg(target_os = "linux")] +fn linux_display_refresh_hz( + video: &sdl2::VideoSubsystem, + window: &sdl2::video::Window, +) -> Option { + let display_index = window.display_index().ok()?; + let refresh_rate = video.current_display_mode(display_index).ok()?.refresh_rate; + u32::try_from(refresh_rate).ok().filter(|value| *value > 0) +} + +#[cfg(target_os = "linux")] +struct StreamAudioCallback { + output: Arc, +} + +impl AudioCallback for StreamAudioCallback { + type Channel = f32; + + fn callback(&mut self, output: &mut [f32]) { + self.output.fill_audio(output); + } +} + +struct SdlInputCapture { + captured: Vec, + pressed_keys: HashMap, + pressed_buttons: HashSet, + enabled: bool, + focused: bool, + relative_mouse: bool, + external_relative_motion: bool, + cursor_state: RemoteCursorState, + cursors: HashMap<(u8, u8), sdl2::mouse::Cursor>, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum RemoteCursorState { + Unknown, + Hidden, + Visible, +} + +impl SdlInputCapture { + fn new(enabled: bool, external_relative_motion: bool) -> Self { + Self { + captured: Vec::new(), + pressed_keys: HashMap::new(), + pressed_buttons: HashSet::new(), + enabled, + focused: false, + relative_mouse: false, + external_relative_motion, + // Do not infer hidden-cursor gameplay before the first server + // update. GFN sends a distinct predefined cursor ID 0 when the + // game actually wants locked relative input. + cursor_state: RemoteCursorState::Unknown, + cursors: HashMap::new(), + } + } + + fn handle_event( + &mut self, + sdl: &sdl2::Sdl, + window: &mut sdl2::video::Window, + stream_size: (u32, u32), + event: sdl2::event::Event, + ) { + use sdl2::event::{Event, WindowEvent}; + + if !self.enabled { + return; + } + let window_size = window.size(); + match event { + Event::KeyDown { + scancode: Some(scancode), + keymod, + repeat: false, + .. + } => { + let Some(virtual_key) = sdl_virtual_key(scancode) else { + return; + }; + if self.pressed_keys.insert(scancode, virtual_key).is_none() { + self.captured.push(CapturedInput::Key { + virtual_key, + modifiers: sdl_modifiers(scancode, keymod), + pressed: true, + }); + } + } + Event::KeyUp { + scancode: Some(scancode), + keymod, + .. + } => { + if let Some(virtual_key) = self.pressed_keys.remove(&scancode) { + self.captured.push(CapturedInput::Key { + virtual_key, + modifiers: sdl_modifiers(scancode, keymod), + pressed: false, + }); + } + } + Event::MouseMotion { .. } if self.relative_mouse && self.external_relative_motion => {} + Event::MouseMotion { xrel, yrel, .. } if self.relative_mouse => { + push_mouse_motion(&mut self.captured, xrel, yrel); + } + Event::MouseMotion { x, y, .. } if self.cursor_state != RemoteCursorState::Hidden => { + let absolute = + map_window_point_to_stream_viewport((x, y), stream_size, window_size); + self.captured.push(CapturedInput::MouseAbsolute { + x: absolute.x, + y: absolute.y, + width: absolute.width, + height: absolute.height, + }); + } + Event::MouseButtonDown { .. } | Event::MouseButtonUp { .. } + if self.relative_mouse && self.external_relative_motion => {} + Event::MouseButtonDown { mouse_btn, .. } => { + // A button event proves this window owns foreground input even + // if SDL delivered FocusGained later in the same pump batch. + self.focused = true; + if self.cursor_state == RemoteCursorState::Hidden { + self.enable_relative_mouse(sdl, window); + } + if let Some(button) = sdl_mouse_button(mouse_btn) + && self.pressed_buttons.insert(button) + { + self.captured.push(CapturedInput::MouseButton { + button, + pressed: true, + }); + } + } + Event::MouseButtonUp { mouse_btn, .. } => { + if let Some(button) = sdl_mouse_button(mouse_btn) + && self.pressed_buttons.remove(&button) + { + self.captured.push(CapturedInput::MouseButton { + button, + pressed: false, + }); + } + } + Event::MouseWheel { .. } if self.relative_mouse && self.external_relative_motion => {} + Event::MouseWheel { y, direction, .. } if y != 0 => { + let direction = if direction == sdl2::mouse::MouseWheelDirection::Flipped { + -1 + } else { + 1 + }; + self.captured.push(CapturedInput::MouseWheel { + delta: clamp_i16(y.saturating_mul(120).saturating_mul(direction)), + }); + } + Event::Window { + win_event: WindowEvent::FocusGained, + .. + } => { + self.focused = true; + if self.cursor_state == RemoteCursorState::Hidden { + self.enable_relative_mouse(sdl, window); + } + } + Event::Window { + win_event: WindowEvent::FocusLost, + .. + } => { + self.focused = false; + self.release(sdl, window); + } + _ => {} + } + } + + fn enable_relative_mouse(&mut self, sdl: &sdl2::Sdl, window: &mut sdl2::video::Window) { + if self.focused && !self.relative_mouse { + window.set_mouse_grab(true); + sdl.mouse().set_relative_mouse_mode(true); + sdl.mouse().show_cursor(false); + self.relative_mouse = true; + eprintln!("External SDL mouse control mode: locked relative"); + } + } + + fn disable_relative_mouse(&mut self, sdl: &sdl2::Sdl, window: &mut sdl2::video::Window) { + if self.relative_mouse { + sdl.mouse().set_relative_mouse_mode(false); + window.set_mouse_grab(false); + self.relative_mouse = false; + eprintln!("External SDL mouse control mode: absolute cursor"); + } + } + + fn apply_cursor( + &mut self, + sdl: &sdl2::Sdl, + window: &mut sdl2::video::Window, + stream_size: (u32, u32), + bytes: &[u8], + ) { + let Some((&message_type, remainder)) = bytes.split_first() else { + return; + }; + if !matches!(message_type, 0 | 1) { + return; + } + let Some(&cursor_id) = remainder.first() else { + return; + }; + let was_cursor_visible = self.cursor_state == RemoteCursorState::Visible; + self.cursor_state = cursor_state_for_message(message_type, cursor_id); + eprintln!( + "GFN cursor applied: sourceType={message_type} cursorId={cursor_id} state={:?} bytes={}", + self.cursor_state, + bytes.len(), + ); + if self.cursor_state == RemoteCursorState::Hidden { + self.enable_relative_mouse(sdl, window); + return; + } + self.disable_relative_mouse(sdl, window); + let cursor_key = (message_type, cursor_id); + if message_type == 1 { + match custom_sdl_cursor(bytes) { + Ok(cursor) => { + self.cursors.insert(cursor_key, cursor); + } + Err(error) => { + eprintln!("GFN custom cursor {cursor_id} could not be decoded: {error}"); + } + } + } else if let std::collections::hash_map::Entry::Vacant(entry) = + self.cursors.entry(cursor_key) + { + let system_cursor = match cursor_id { + 2 => sdl2::mouse::SystemCursor::IBeam, + 3 => sdl2::mouse::SystemCursor::Wait, + 4 => sdl2::mouse::SystemCursor::Crosshair, + 5 => sdl2::mouse::SystemCursor::WaitArrow, + 6 => sdl2::mouse::SystemCursor::SizeNWSE, + 7 => sdl2::mouse::SystemCursor::SizeNESW, + 8 => sdl2::mouse::SystemCursor::SizeWE, + 9 => sdl2::mouse::SystemCursor::SizeNS, + 10 => sdl2::mouse::SystemCursor::SizeAll, + 12 => sdl2::mouse::SystemCursor::Hand, + _ => sdl2::mouse::SystemCursor::Arrow, + }; + if let Ok(cursor) = sdl2::mouse::Cursor::from_system(system_cursor) { + entry.insert(cursor); + } + } + if let Some(cursor) = self.cursors.get(&cursor_key) { + cursor.set(); + } else if let Ok(cursor) = + sdl2::mouse::Cursor::from_system(sdl2::mouse::SystemCursor::Arrow) + { + cursor.set(); + self.cursors.insert(cursor_key, cursor); + } + sdl.mouse().show_cursor(true); + if !was_cursor_visible && let Some(position) = parse_cursor_position(bytes) { + let viewport = aspect_fit( + stream_size.0.max(1), + stream_size.1.max(1), + window.size().0.max(1), + window.size().1.max(1), + ); + let x = viewport.x() + normalized_cursor_coordinate(position.0, viewport.width()); + let y = viewport.y() + normalized_cursor_coordinate(position.1, viewport.height()); + sdl.mouse().warp_mouse_in_window(window, x, y); + } + } + + fn release(&mut self, sdl: &sdl2::Sdl, window: &mut sdl2::video::Window) { + for (_, virtual_key) in self.pressed_keys.drain() { + self.captured.push(CapturedInput::Key { + virtual_key, + modifiers: 0, + pressed: false, + }); + } + for button in self.pressed_buttons.drain() { + self.captured.push(CapturedInput::MouseButton { + button, + pressed: false, + }); + } + self.disable_relative_mouse(sdl, window); + window.set_mouse_grab(false); + sdl.mouse().show_cursor(true); + } + + fn take(&mut self) -> Vec { + std::mem::take(&mut self.captured) + } +} + +pub(crate) struct SoftwareOutput { + // Texture and window-owned resources must be released before the SDL + // renderer/window, and SDL itself must outlive every derived resource. + texture: Option, + native_surface: Result, + input_capture: SdlInputCapture, + canvas: WindowCanvas, + texture_size: Option<(u32, u32)>, + texture_format: Option, + event_pump: sdl2::EventPump, + audio: AudioDevice, + output: Arc, + external_renderer: bool, + #[cfg(target_os = "linux")] + debug_overlay: NativeStatsOverlay, + #[cfg(target_os = "linux")] + presented_frames: u64, + #[cfg(target_os = "linux")] + presented_linux_frame: bool, + visible: bool, + paused: bool, + _sdl: sdl2::Sdl, +} + +impl SoftwareOutput { + fn initialize(output: Arc, stream: MediaStreamConfig) -> Result { + let sdl = sdl2::init().map_err(|error| format!("SDL initialization failed: {error}"))?; + let video = sdl + .video() + .map_err(|error| format!("SDL video initialization failed: {error}"))?; + let audio_subsystem = sdl + .audio() + .map_err(|error| format!("SDL audio initialization failed: {error}"))?; + let external_renderer = external_renderer_enabled(); + let mut window_builder = video.window("OpenNOW Stream", 1280, 720); + window_builder + .position_centered() + .resizable() + .hidden() + .metal_view(); + if external_renderer && cfg!(target_os = "linux") { + window_builder.allow_highdpi(); + } + if !external_renderer { + window_builder.borderless(); + } + let window = window_builder + .build() + .map_err(|error| format!("native video window creation failed: {error}"))?; + let mut canvas = window + .into_canvas() + .build() + .map_err(|error| format!("native video renderer creation failed: {error}"))?; + canvas.set_draw_color(Color::BLACK); + canvas.clear(); + canvas.present(); + + let desired = AudioSpecDesired { + freq: Some(AUDIO_SAMPLE_RATE), + channels: Some(AUDIO_CHANNELS), + samples: Some(AUDIO_BUFFER_FRAMES), + }; + let callback_output = Arc::clone(&output); + let audio = audio_subsystem + .open_playback(None, &desired, move |_| StreamAudioCallback { + output: callback_output, + }) + .map_err(|error| format!("native audio output creation failed: {error}"))?; + if audio.spec().freq != AUDIO_SAMPLE_RATE || audio.spec().channels != AUDIO_CHANNELS { + return Err(format!( + "native audio output returned unsupported format: {} Hz, {} channels", + audio.spec().freq, + audio.spec().channels + )); + } + let event_pump = sdl + .event_pump() + .map_err(|error| format!("native window event pump creation failed: {error}"))?; + let native_surface = if video.current_video_driver() == "dummy" { + Err("dummy SDL video driver has no native presentation handle".to_owned()) + } else { + NativeSurface::new(canvas.window()) + }; + + Ok(Self { + texture: None, + native_surface, + input_capture: SdlInputCapture::new( + cfg!(any(target_os = "windows", target_os = "linux")) + && external_renderer + && native_input_capture_enabled(), + false, + ), + canvas, + texture_size: None, + texture_format: None, + event_pump, + audio, + output, + external_renderer, + #[cfg(target_os = "linux")] + debug_overlay: NativeStatsOverlay::new(stream, "LINUX / SDL"), + #[cfg(target_os = "linux")] + presented_frames: 0, + #[cfg(target_os = "linux")] + presented_linux_frame: false, + visible: false, + paused: false, + _sdl: sdl, + }) + } + + fn start(&mut self, surface: Option<&RenderSurface>) -> Result<(), String> { + self.paused = false; + #[cfg(target_os = "linux")] + { + self.presented_frames = 0; + self.presented_linux_frame = false; + } + self.output.clear(); + self.audio.resume(); + if let Some(surface) = surface { + self.update_surface(surface)?; + } + Ok(()) + } + + fn set_paused(&mut self, paused: bool) { + self.paused = paused; + if paused { + self.input_capture + .release(&self._sdl, self.canvas.window_mut()); + self.audio.pause(); + self.output.clear(); + } else { + self.audio.resume(); + } + } + + fn stop(&mut self) { + self.input_capture + .release(&self._sdl, self.canvas.window_mut()); + self.flush_captured_input(); + self.audio.pause(); + self.output.clear(); + if let Ok(surface) = self.native_surface.as_mut() { + surface.hide(); + } + if self.external_renderer { + self.canvas.window_mut().hide(); + } + self.visible = false; + self.paused = false; + self.texture = None; + self.texture_size = None; + self.texture_format = None; + #[cfg(target_os = "linux")] + { + self.presented_linux_frame = false; + } + } + + fn update_surface(&mut self, surface: &RenderSurface) -> Result<(), String> { + let Some(rect) = surface.rect.filter(|_| surface.visible) else { + if let Ok(native_surface) = self.native_surface.as_mut() { + native_surface.hide(); + } + if self.external_renderer { + self.canvas.window_mut().hide(); + } + self.visible = false; + return Ok(()); + }; + if self.external_renderer { + let bounds = surface.screen_rect.unwrap_or(rect); + let window = self.canvas.window_mut(); + window.set_position( + sdl2::video::WindowPos::Positioned(bounds.x), + sdl2::video::WindowPos::Positioned(bounds.y), + ); + window + .set_size(bounds.width.max(2), bounds.height.max(2)) + .map_err(|error| format!("failed to resize external SDL video surface: {error}"))?; + window.show(); + window.raise(); + self.visible = true; + return Ok(()); + } + let parent_handle = surface + .window_handle + .as_deref() + .ok_or_else(|| "visible native surface is missing Electron windowHandle".to_owned())?; + self.native_surface + .as_mut() + .map_err(|error| error.clone())? + .attach_and_show( + parent_handle, + rect, + surface.screen_rect, + surface.device_scale_factor, + )?; + self.visible = true; + Ok(()) + } + + fn pump(&mut self) -> Result { + if !self.external_renderer + && let Ok(surface) = self.native_surface.as_mut() + { + surface.refresh_ordering()?; + } + let events = self.event_pump.poll_iter().collect::>(); + for event in events { + if matches!(event, sdl2::event::Event::Quit { .. }) { + self.input_capture + .release(&self._sdl, self.canvas.window_mut()); + if let Ok(surface) = self.native_surface.as_mut() { + surface.hide(); + } + if self.external_renderer { + self.canvas.window_mut().hide(); + } + self.visible = false; + continue; + } + #[cfg(target_os = "linux")] + if handle_linux_stats_shortcut(&mut self.debug_overlay, &event) { + continue; + } + if self.external_renderer + && handle_native_window_shortcut(self.canvas.window_mut(), &event) + { + continue; + } + let window_size = self.canvas.window().size(); + let stream_size = self.texture_size.unwrap_or(window_size); + self.input_capture.handle_event( + &self._sdl, + self.canvas.window_mut(), + stream_size, + event, + ); + } + if self.paused || !self.visible { + self.output.take_video(); + #[cfg(target_os = "linux")] + self.output.clear_linux_video(); + return Ok(false); + } + #[cfg(target_os = "linux")] + if let Some(frame) = self.output.take_linux_video() { + return self.present_linux_frame(frame.frame); + } + let Some(mut frame) = self.output.take_video() else { + return Ok(false); + }; + #[cfg(target_os = "linux")] + { + self.presented_linux_frame = false; + self.debug_overlay.update( + self.presented_frames, + self.output.software_video_drops(), + self.input_capture.relative_mouse, + self.output.received_video_bytes(), + ); + self.debug_overlay.composite_rgb24( + &mut frame.rgb, + frame.width, + frame.height, + frame.width as usize * 3, + ); + } + if self.texture_size != Some((frame.width, frame.height)) + || self.texture_format != Some(PixelFormatEnum::RGB24) + { + self.texture = Some( + self.canvas + .texture_creator() + .create_texture_streaming(PixelFormatEnum::RGB24, frame.width, frame.height) + .map_err(|error| format!("video texture creation failed: {error}"))?, + ); + self.texture_size = Some((frame.width, frame.height)); + self.texture_format = Some(PixelFormatEnum::RGB24); + } + let texture = self.texture.as_mut().expect("texture was just created"); + texture + .update(None, &frame.rgb, frame.width as usize * 3) + .map_err(|error| format!("video texture upload failed: {error}"))?; + let (output_width, output_height) = self.canvas.output_size()?; + let target = aspect_fit(frame.width, frame.height, output_width, output_height); + self.canvas.set_draw_color(Color::BLACK); + self.canvas.clear(); + self.canvas.copy(texture, None, target)?; + self.canvas.present(); + #[cfg(target_os = "linux")] + { + self.presented_frames = self.presented_frames.saturating_add(1); + } + Ok(true) + } + + #[cfg(target_os = "linux")] + fn present_linux_frame(&mut self, mut frame: LinuxDecodedVideoFrame) -> Result { + use opennow_streamer_platform_linux::PixelFormat; + + if frame.format.pixel_format != PixelFormat::Nv12 || frame.planes.len() != 2 { + return Err(format!( + "SDL Linux presentation requires NV12 with two planes, received {:?}", + frame.format.pixel_format + )); + } + let width = frame.format.width; + let height = frame.format.height; + self.debug_overlay + .set_presentation_skips(self.output.display_video_skips()); + self.debug_overlay.update( + self.presented_frames, + self.output.hardware_video_drops(), + self.input_capture.relative_mouse, + self.output.received_video_bytes(), + ); + self.debug_overlay.composite_linux_frame(&mut frame); + if self.texture_size != Some((width, height)) + || self.texture_format != Some(PixelFormatEnum::NV12) + { + self.texture = Some( + self.canvas + .texture_creator() + .create_texture_streaming(PixelFormatEnum::NV12, width, height) + .map_err(|error| format!("NV12 texture creation failed: {error}"))?, + ); + self.texture_size = Some((width, height)); + self.texture_format = Some(PixelFormatEnum::NV12); + } + let y_plane = &frame.planes[0]; + let uv_plane = &frame.planes[1]; + self.texture + .as_mut() + .expect("NV12 texture was just created") + .with_lock(None, |destination, pitch| { + for row in 0..height as usize { + let source_start = row * y_plane.stride; + let destination_start = row * pitch; + destination[destination_start..destination_start + width as usize] + .copy_from_slice( + &y_plane.data[source_start..source_start + width as usize], + ); + } + let uv_base = pitch * height as usize; + for row in 0..height as usize / 2 { + let source_start = row * uv_plane.stride; + let destination_start = uv_base + row * pitch; + destination[destination_start..destination_start + width as usize] + .copy_from_slice( + &uv_plane.data[source_start..source_start + width as usize], + ); + } + }) + .map_err(|error| format!("NV12 texture upload failed: {error}"))?; + let (output_width, output_height) = self.canvas.output_size()?; + let target = aspect_fit(width, height, output_width, output_height); + self.canvas.set_draw_color(Color::BLACK); + self.canvas.clear(); + self.canvas.copy( + self.texture.as_ref().expect("NV12 texture exists"), + None, + target, + )?; + self.canvas.present(); + self.presented_frames = self.presented_frames.saturating_add(1); + self.presented_linux_frame = true; + Ok(true) + } + + fn backend_label(&self) -> &'static str { + #[cfg(target_os = "linux")] + if self.presented_linux_frame { + return "Linux decoder/SDL NV12"; + } + "OpenH264/SDL" + } + + fn take_captured_input(&mut self) -> Vec { + self.input_capture.take() + } + + fn update_cursor(&mut self, bytes: &[u8]) { + if self.external_renderer { + let stream_size = self + .texture_size + .unwrap_or_else(|| self.canvas.window().size()); + self.input_capture.apply_cursor( + &self._sdl, + self.canvas.window_mut(), + stream_size, + bytes, + ); + } + } + + fn flush_captured_input(&mut self) { + let captured_input = self.output.captured_input(); + for input in self.take_captured_input() { + captured_input.push(input); + } + } +} + +impl Drop for SoftwareOutput { + fn drop(&mut self) { + self.stop(); + } +} + +fn sdl_virtual_key(scancode: sdl2::keyboard::Scancode) -> Option { + use sdl2::keyboard::Scancode; + + Some(match scancode { + Scancode::A => 0x41, + Scancode::B => 0x42, + Scancode::C => 0x43, + Scancode::D => 0x44, + Scancode::E => 0x45, + Scancode::F => 0x46, + Scancode::G => 0x47, + Scancode::H => 0x48, + Scancode::I => 0x49, + Scancode::J => 0x4a, + Scancode::K => 0x4b, + Scancode::L => 0x4c, + Scancode::M => 0x4d, + Scancode::N => 0x4e, + Scancode::O => 0x4f, + Scancode::P => 0x50, + Scancode::Q => 0x51, + Scancode::R => 0x52, + Scancode::S => 0x53, + Scancode::T => 0x54, + Scancode::U => 0x55, + Scancode::V => 0x56, + Scancode::W => 0x57, + Scancode::X => 0x58, + Scancode::Y => 0x59, + Scancode::Z => 0x5a, + Scancode::Num0 => 0x30, + Scancode::Num1 => 0x31, + Scancode::Num2 => 0x32, + Scancode::Num3 => 0x33, + Scancode::Num4 => 0x34, + Scancode::Num5 => 0x35, + Scancode::Num6 => 0x36, + Scancode::Num7 => 0x37, + Scancode::Num8 => 0x38, + Scancode::Num9 => 0x39, + Scancode::Return | Scancode::KpEnter => 0x0d, + Scancode::Escape => 0x1b, + Scancode::Backspace => 0x08, + Scancode::Tab => 0x09, + Scancode::Space => 0x20, + Scancode::Minus => 0xbd, + Scancode::Equals | Scancode::KpEquals => 0xbb, + Scancode::LeftBracket => 0xdb, + Scancode::RightBracket => 0xdd, + Scancode::Backslash => 0xdc, + Scancode::NonUsBackslash => 0xe2, + Scancode::Semicolon => 0xba, + Scancode::Apostrophe => 0xde, + Scancode::Grave => 0xc0, + Scancode::Comma => 0xbc, + Scancode::Period => 0xbe, + Scancode::Slash => 0xbf, + Scancode::F1 => 0x70, + Scancode::F2 => 0x71, + Scancode::F3 => 0x72, + Scancode::F4 => 0x73, + Scancode::F5 => 0x74, + Scancode::F6 => 0x75, + Scancode::F7 => 0x76, + Scancode::F8 => 0x77, + Scancode::F9 => 0x78, + Scancode::F10 => 0x79, + Scancode::F11 => 0x7a, + Scancode::F12 => 0x7b, + Scancode::F13 => 0x7c, + Scancode::F14 => 0x7d, + Scancode::F15 => 0x7e, + Scancode::F16 => 0x7f, + Scancode::F17 => 0x80, + Scancode::F18 => 0x81, + Scancode::F19 => 0x82, + Scancode::F20 => 0x83, + Scancode::F21 => 0x84, + Scancode::F22 => 0x85, + Scancode::F23 => 0x86, + Scancode::F24 => 0x87, + Scancode::Right => 0x27, + Scancode::Left => 0x25, + Scancode::Down => 0x28, + Scancode::Up => 0x26, + Scancode::LCtrl => 0xa2, + Scancode::LShift => 0xa0, + Scancode::LAlt => 0xa4, + Scancode::LGui => 0x5b, + Scancode::RCtrl => 0xa3, + Scancode::RShift => 0xa1, + Scancode::RAlt => 0xa5, + Scancode::RGui => 0x5c, + Scancode::CapsLock => 0x14, + Scancode::NumLockClear => 0x90, + Scancode::Insert => 0x2d, + Scancode::Delete => 0x2e, + Scancode::Home => 0x24, + Scancode::End => 0x23, + Scancode::PageUp => 0x21, + Scancode::PageDown => 0x22, + Scancode::PrintScreen => 0x2a, + Scancode::ScrollLock => 0x91, + Scancode::Pause => 0x13, + Scancode::Application => 0x5d, + Scancode::Kp0 => 0x60, + Scancode::Kp1 => 0x61, + Scancode::Kp2 => 0x62, + Scancode::Kp3 => 0x63, + Scancode::Kp4 => 0x64, + Scancode::Kp5 => 0x65, + Scancode::Kp6 => 0x66, + Scancode::Kp7 => 0x67, + Scancode::Kp8 => 0x68, + Scancode::Kp9 => 0x69, + Scancode::KpPlus => 0x6b, + Scancode::KpMinus => 0x6d, + Scancode::KpMultiply => 0x6a, + Scancode::KpDivide => 0x6f, + Scancode::KpPeriod => 0x6e, + _ => return None, + }) +} + +fn sdl_modifiers(scancode: sdl2::keyboard::Scancode, modifiers: sdl2::keyboard::Mod) -> u16 { + use sdl2::keyboard::{Mod, Scancode}; + + let mut flags = 0; + if !matches!(scancode, Scancode::LShift | Scancode::RShift) + && modifiers.intersects(Mod::LSHIFTMOD | Mod::RSHIFTMOD) + { + flags |= 0x01; + } + if !matches!(scancode, Scancode::LCtrl | Scancode::RCtrl) + && modifiers.intersects(Mod::LCTRLMOD | Mod::RCTRLMOD) + { + flags |= 0x02; + } + if !matches!(scancode, Scancode::LAlt | Scancode::RAlt) + && modifiers.intersects(Mod::LALTMOD | Mod::RALTMOD) + { + flags |= 0x04; + } + if !matches!(scancode, Scancode::LGui | Scancode::RGui) + && modifiers.intersects(Mod::LGUIMOD | Mod::RGUIMOD) + { + flags |= 0x08; + } + flags +} + +fn sdl_mouse_button(button: sdl2::mouse::MouseButton) -> Option { + use sdl2::mouse::MouseButton; + + match button { + MouseButton::Left => Some(1), + MouseButton::Middle => Some(2), + MouseButton::Right => Some(3), + MouseButton::X1 => Some(4), + MouseButton::X2 => Some(5), + MouseButton::Unknown => None, + } +} + +fn push_mouse_motion(input: &mut Vec, delta_x: i32, delta_y: i32) { + if delta_x == 0 && delta_y == 0 { + return; + } + input.push(CapturedInput::MouseMove { + delta_x: clamp_i16(delta_x), + delta_y: clamp_i16(delta_y), + }); +} + +fn clamp_i16(value: i32) -> i16 { + value.clamp(i32::from(i16::MIN), i32::from(i16::MAX)) as i16 +} + +fn clamp_i32_u16(value: i32) -> u16 { + value.clamp(0, i32::from(u16::MAX)) as u16 +} + +fn clamp_u32_u16(value: u32) -> u16 { + value.min(u32::from(u16::MAX)) as u16 +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct AbsoluteMouseViewport { + x: u16, + y: u16, + width: u16, + height: u16, +} + +struct CustomCursorPayload<'a> { + hotspot_x: u8, + hotspot_y: u8, + image_base64: &'a [u8], + scale: f32, +} + +fn cursor_state_for_message(message_type: u8, cursor_id: u8) -> RemoteCursorState { + if message_type == 0 && cursor_id == 0 { + RemoteCursorState::Hidden + } else { + // Custom cursor ID 0 is still a visible bitmap. Only predefined ID 0 + // is the protocol's hidden/raw-input cursor. + RemoteCursorState::Visible + } +} + +fn parse_custom_cursor_payload(bytes: &[u8]) -> Result, String> { + if bytes.first() != Some(&1) || bytes.len() < 7 { + return Err("not a complete custom cursor message".to_owned()); + } + let mime_length = usize::from(bytes[4]); + let mime_end = 5_usize + .checked_add(mime_length) + .ok_or_else(|| "custom cursor MIME length overflow".to_owned())?; + let image_length_bytes = bytes + .get(mime_end..mime_end + 2) + .ok_or_else(|| "custom cursor is missing its image length".to_owned())?; + let image_length = usize::from(u16::from_le_bytes([ + image_length_bytes[0], + image_length_bytes[1], + ])); + let image_start = mime_end + 2; + let image_end = image_start + .checked_add(image_length) + .ok_or_else(|| "custom cursor image length overflow".to_owned())?; + let image_base64 = bytes + .get(image_start..image_end) + .ok_or_else(|| "custom cursor image is truncated".to_owned())?; + let position_end = image_end.saturating_add(4); + let scale = bytes + .get(position_end..position_end + 2) + .map(|raw| f32::from(u16::from_le_bytes([raw[0], raw[1]])) / 100.0) + .filter(|scale| scale.is_finite() && *scale > 0.0) + .unwrap_or(1.0); + Ok(CustomCursorPayload { + hotspot_x: bytes[2], + hotspot_y: bytes[3], + image_base64, + scale, + }) +} + +fn custom_sdl_cursor(bytes: &[u8]) -> Result { + const MAX_CURSOR_EXTENT: u32 = 256; + let payload = parse_custom_cursor_payload(bytes)?; + let encoded = std::str::from_utf8(payload.image_base64) + .map_err(|error| format!("cursor image base64 is not UTF-8: {error}"))?; + let compressed = BASE64 + .decode(encoded) + .map_err(|error| format!("cursor image base64 is invalid: {error}"))?; + let image = ImageReader::new(IoCursor::new(compressed)) + .with_guessed_format() + .map_err(|error| format!("cursor image format is unknown: {error}"))? + .decode() + .map_err(|error| format!("cursor image decode failed: {error}"))? + .to_rgba8(); + let (source_width, source_height) = image.dimensions(); + if source_width == 0 + || source_height == 0 + || source_width > MAX_CURSOR_EXTENT + || source_height > MAX_CURSOR_EXTENT + { + return Err(format!( + "cursor image dimensions are outside 1..={MAX_CURSOR_EXTENT}: {source_width}x{source_height}" + )); + } + let width = ((source_width as f32 / payload.scale).round() as u32).clamp(1, MAX_CURSOR_EXTENT); + let height = + ((source_height as f32 / payload.scale).round() as u32).clamp(1, MAX_CURSOR_EXTENT); + let rgba = if (width, height) == (source_width, source_height) { + image + } else { + image::imageops::resize(&image, width, height, image::imageops::FilterType::Triangle) + }; + let row_bytes = width as usize * 4; + let mut surface = sdl2::surface::Surface::new(width, height, PixelFormatEnum::RGBA32)?; + let pitch = surface.pitch() as usize; + surface.with_lock_mut(|destination| { + for (source, destination) in rgba + .as_raw() + .chunks_exact(row_bytes) + .zip(destination.chunks_mut(pitch)) + { + destination[..row_bytes].copy_from_slice(source); + } + }); + let hotspot_x = ((f32::from(payload.hotspot_x) / payload.scale).round() as i32) + .clamp(0, width.saturating_sub(1) as i32); + let hotspot_y = ((f32::from(payload.hotspot_y) / payload.scale).round() as i32) + .clamp(0, height.saturating_sub(1) as i32); + sdl2::mouse::Cursor::from_surface(surface, hotspot_x, hotspot_y) +} + +fn map_window_point_to_stream_viewport( + point: (i32, i32), + stream_size: (u32, u32), + window_size: (u32, u32), +) -> AbsoluteMouseViewport { + let viewport = aspect_fit( + stream_size.0.max(1), + stream_size.1.max(1), + window_size.0.max(1), + window_size.1.max(1), + ); + let width = viewport.width().max(1); + let height = viewport.height().max(1); + AbsoluteMouseViewport { + x: clamp_i32_u16((point.0 - viewport.x()).clamp(0, width.saturating_sub(1) as i32)), + y: clamp_i32_u16((point.1 - viewport.y()).clamp(0, height.saturating_sub(1) as i32)), + width: clamp_u32_u16(width), + height: clamp_u32_u16(height), + } +} + +fn parse_cursor_position(bytes: &[u8]) -> Option<(u16, u16)> { + if bytes.len() < 7 || !matches!(bytes[0], 0 | 1) { + return None; + } + let mime_length = usize::from(bytes[4]); + let image_length_offset = 5_usize.checked_add(mime_length)?; + let image_length_bytes = bytes.get(image_length_offset..image_length_offset + 2)?; + let image_length = usize::from(u16::from_le_bytes([ + image_length_bytes[0], + image_length_bytes[1], + ])); + let position_offset = image_length_offset + .checked_add(2)? + .checked_add(image_length)?; + let position = bytes.get(position_offset..position_offset + 4)?; + Some(( + u16::from_le_bytes([position[0], position[1]]), + u16::from_le_bytes([position[2], position[3]]), + )) +} + +fn normalized_cursor_coordinate(value: u16, viewport_extent: u32) -> i32 { + let extent = viewport_extent.max(1); + let coordinate = (u64::from(value) * u64::from(extent) / u64::from(u16::MAX)) as u32; + coordinate.min(extent.saturating_sub(1)) as i32 +} + +#[cfg(target_os = "linux")] +fn handle_linux_stats_shortcut( + overlay: &mut NativeStatsOverlay, + event: &sdl2::event::Event, +) -> bool { + use sdl2::event::Event; + use sdl2::keyboard::Scancode; + + match event { + Event::KeyDown { + scancode: Some(Scancode::F3), + repeat: false, + .. + } => { + overlay.toggle(); + true + } + Event::KeyUp { + scancode: Some(Scancode::F3), + .. + } => true, + _ => false, + } +} + +fn handle_native_window_shortcut( + window: &mut sdl2::video::Window, + event: &sdl2::event::Event, +) -> bool { + use sdl2::event::Event; + use sdl2::keyboard::Scancode; + use sdl2::video::FullscreenType; + + match event { + Event::KeyDown { + scancode: Some(Scancode::F11), + repeat: false, + .. + } => { + let next = if window.fullscreen_state() == FullscreenType::Off { + FullscreenType::Desktop + } else { + FullscreenType::Off + }; + match window.set_fullscreen(next) { + Ok(()) => eprintln!( + "External SDL fullscreen changed: {}", + if next == FullscreenType::Off { + "off" + } else { + "desktop" + } + ), + Err(error) => eprintln!("External SDL fullscreen toggle failed: {error}"), + } + true + } + Event::KeyUp { + scancode: Some(Scancode::F11), + .. + } => true, + _ => false, + } +} + +fn native_input_capture_enabled() -> bool { + native_input_capture_enabled_value(std::env::var("OPENNOW_NATIVE_INPUT_OWNER").ok().as_deref()) +} + +fn native_input_capture_enabled_value(owner: Option<&str>) -> bool { + owner.is_some_and(|owner| owner.trim().eq_ignore_ascii_case("native")) +} + +pub(crate) enum ActiveOutput { + Software(Box), + #[cfg(target_os = "windows")] + Windows(WindowsOutput), + #[cfg(target_os = "linux")] + LinuxHardware(Box), + #[cfg(target_os = "macos")] + Mac(crate::macos_backend::MacOutput), +} + +impl ActiveOutput { + #[cfg(target_os = "macos")] + pub(crate) fn is_macos_hardware(&self) -> bool { + matches!(self, Self::Mac(_)) + } + + #[cfg(target_os = "linux")] + pub(crate) fn is_linux_hardware(&self) -> bool { + matches!(self, Self::LinuxHardware(_)) + } + + pub(crate) fn initialize( + output: Arc, + use_hardware: bool, + stream: MediaStreamConfig, + #[cfg(target_os = "windows")] windows_bridge: Arc, + use_linux_hardware: bool, + ) -> Result { + #[cfg(target_os = "macos")] + if use_hardware { + return Ok(Self::Mac(crate::macos_backend::MacOutput::initialize())); + } + #[cfg(target_os = "windows")] + if use_hardware { + return WindowsOutput::initialize(windows_bridge, output, stream).map(Self::Windows); + } + #[cfg(target_os = "linux")] + if use_linux_hardware { + return LinuxHardwareOutput::initialize(output, stream) + .map(Box::new) + .map(Self::LinuxHardware); + } + let _ = use_hardware; + let _ = use_linux_hardware; + SoftwareOutput::initialize(output, stream) + .map(Box::new) + .map(Self::Software) + } + + pub(crate) fn start(&mut self, surface: Option<&RenderSurface>) -> Result<(), String> { + match self { + Self::Software(output) => output.start(surface), + #[cfg(target_os = "windows")] + Self::Windows(output) => output.start(surface), + #[cfg(target_os = "linux")] + Self::LinuxHardware(output) => output.start(surface), + #[cfg(target_os = "macos")] + Self::Mac(output) => output.start(surface), + } + } + + pub(crate) fn set_paused(&mut self, paused: bool) -> Result<(), String> { + match self { + Self::Software(output) => { + output.set_paused(paused); + Ok(()) + } + #[cfg(target_os = "windows")] + Self::Windows(output) => output.set_paused(paused), + #[cfg(target_os = "linux")] + Self::LinuxHardware(output) => { + output.set_paused(paused); + Ok(()) + } + #[cfg(target_os = "macos")] + Self::Mac(output) => output.set_paused(paused), + } + } + + pub(crate) fn stop(&mut self) { + match self { + Self::Software(output) => output.stop(), + #[cfg(target_os = "windows")] + Self::Windows(output) => output.stop(), + #[cfg(target_os = "linux")] + Self::LinuxHardware(output) => output.stop(), + #[cfg(target_os = "macos")] + Self::Mac(output) => output.stop(), + } + } + + pub(crate) fn update_surface(&mut self, surface: &RenderSurface) -> Result<(), String> { + match self { + Self::Software(output) => output.update_surface(surface), + #[cfg(target_os = "windows")] + Self::Windows(output) => output.update_surface(surface), + #[cfg(target_os = "linux")] + Self::LinuxHardware(output) => output.update_surface(surface), + #[cfg(target_os = "macos")] + Self::Mac(output) => output.update_surface(surface), + } + } + + pub(crate) fn pump(&mut self) -> Result { + match self { + Self::Software(output) => { + let presented = output.pump()?; + Ok(if presented { + OutputEvent::Presented(output.backend_label()) + } else { + OutputEvent::None + }) + } + #[cfg(target_os = "windows")] + Self::Windows(output) => output.pump(), + #[cfg(target_os = "linux")] + Self::LinuxHardware(output) => output.pump().map(|presented| { + if presented { + OutputEvent::Presented("Linux decoder/Vulkan") + } else { + OutputEvent::None + } + }), + #[cfg(target_os = "macos")] + Self::Mac(output) => output.pump().map(|_| OutputEvent::None), + } + } + + pub(crate) fn take_captured_input(&mut self) -> Vec { + match self { + Self::Software(output) => output.take_captured_input(), + #[cfg(target_os = "windows")] + Self::Windows(output) => output.take_captured_input(), + #[cfg(target_os = "linux")] + Self::LinuxHardware(output) => output.take_captured_input(), + #[cfg(target_os = "macos")] + Self::Mac(_) => Vec::new(), + } + } + + pub(crate) fn update_cursor(&mut self, bytes: &[u8]) { + match self { + Self::Software(output) => output.update_cursor(bytes), + #[cfg(target_os = "windows")] + Self::Windows(output) => output.update_cursor(bytes), + #[cfg(target_os = "linux")] + Self::LinuxHardware(output) => output.update_cursor(bytes), + #[cfg(target_os = "macos")] + Self::Mac(_) => {} + } + } + + #[cfg(target_os = "macos")] + pub(crate) fn configure_macos_h264( + &mut self, + parameter_sets: opennow_streamer_platform_macos::H264ParameterSets, + ) -> Result { + match self { + Self::Mac(output) => output.configure_h264(parameter_sets), + Self::Software(_) => Err("VideoToolbox is not the selected media backend".to_owned()), + } + } +} + +pub(crate) enum OutputEvent { + None, + Presented(&'static str), + #[cfg(target_os = "windows")] + RequestKeyframe, + #[cfg(target_os = "windows")] + DeviceLost { + subsystem: &'static str, + recovered: bool, + message: Option, + }, + #[cfg(target_os = "windows")] + QueueDropped(&'static str), + #[cfg(target_os = "windows")] + Fatal(String), +} + +#[cfg(target_os = "windows")] +struct WindowsExternalSdlSurface { + sdl: sdl2::Sdl, + window: sdl2::video::Window, + event_pump: sdl2::EventPump, + native_surface: NativeSurface, + input_capture: SdlInputCapture, + raw_input: Option, + debug_overlay: NativeDebugOverlay, + stream_size: (u32, u32), + visible: bool, + focused: bool, +} + +#[cfg(target_os = "windows")] +impl WindowsExternalSdlSurface { + fn initialize( + stream: MediaStreamConfig, + graphics_api: WindowsGraphicsApi, + captured_input: Arc, + ) -> Result { + // Force the Windows RawInput path. Warp-relative motion is quantized by + // cursor recentering and Windows pointer scaling, which is particularly + // noticeable in 120 FPS first-person games. + sdl2::hint::set("SDL_MOUSE_RELATIVE_MODE_WARP", "0"); + sdl2::hint::set("SDL_MOUSE_RELATIVE_SCALING", "0"); + let sdl = sdl2::init().map_err(|error| format!("SDL initialization failed: {error}"))?; + let video = sdl + .video() + .map_err(|error| format!("SDL video initialization failed: {error}"))?; + let window = video + .window("OpenNOW Stream", 1280, 720) + .position_centered() + .resizable() + .hidden() + .build() + .map_err(|error| format!("external SDL video window creation failed: {error}"))?; + let native_surface = NativeSurface::new(&window)?; + let debug_overlay = NativeDebugOverlay::new( + &video, + native_surface.window_handle(), + stream, + match graphics_api { + WindowsGraphicsApi::D3d12 => "D3D11VA / D3D12", + WindowsGraphicsApi::D3d11 => "D3D11VA ZERO-COPY", + }, + )?; + let event_pump = sdl + .event_pump() + .map_err(|error| format!("external SDL event pump creation failed: {error}"))?; + let capture_input = native_input_capture_enabled(); + let raw_input = if capture_input { + match WindowsRawInputController::start(native_surface.window_handle(), captured_input) { + Ok(controller) => { + eprintln!("Dedicated Windows Raw Input mouse thread ready"); + Some(controller) + } + Err(error) => { + eprintln!( + "Dedicated Windows Raw Input unavailable; retaining SDL motion: {error}" + ); + None + } + } + } else { + None + }; + eprintln!( + "External SDL stream window ready (native keyboard/mouse capture: {capture_input})" + ); + let external_relative_motion = raw_input.is_some(); + Ok(Self { + sdl, + window, + event_pump, + native_surface, + input_capture: SdlInputCapture::new(capture_input, external_relative_motion), + raw_input, + debug_overlay, + stream_size: (stream.width, stream.height), + visible: false, + focused: false, + }) + } + + fn target(&self) -> Result { + let handle = WindowHandle::new(self.native_surface.window_handle()) + .ok_or_else(|| "external SDL window returned an empty HWND".to_owned())?; + Ok(SurfaceTarget::Existing(ExistingWindow { hwnd: handle })) + } + + fn update(&mut self, surface: &RenderSurface) -> Result<(), String> { + let Some(rect) = surface.rect.filter(|_| surface.visible) else { + self.input_capture.release(&self.sdl, &mut self.window); + if let Some(raw_input) = self.raw_input.as_ref() { + raw_input.set_enabled(false); + } + self.debug_overlay.hide(); + self.window.hide(); + self.visible = false; + return Ok(()); + }; + let bounds = surface.screen_rect.unwrap_or(rect); + self.window.set_position( + sdl2::video::WindowPos::Positioned(bounds.x), + sdl2::video::WindowPos::Positioned(bounds.y), + ); + self.window + .set_size(bounds.width.max(2), bounds.height.max(2)) + .map_err(|error| format!("failed to resize external SDL video surface: {error}"))?; + self.window.show(); + if !self.visible { + self.window.raise(); + } + self.visible = true; + self.focused = self.window.has_input_focus(); + if let Some(raw_input) = self.raw_input.as_ref() { + raw_input.set_target(self.native_surface.window_handle()); + } + if self.focused { + self.debug_overlay.show_if_enabled(); + } + Ok(()) + } + + fn pump(&mut self, presented_frames: u64, dropped_frames: u64) { + let stream_window_id = self.window.id(); + for event in self.event_pump.poll_iter().collect::>() { + if matches!(event, sdl2::event::Event::Quit { .. }) { + self.input_capture.release(&self.sdl, &mut self.window); + self.window.hide(); + self.debug_overlay.hide(); + self.visible = false; + self.focused = false; + } else if matches!( + event, + sdl2::event::Event::Window { + window_id, + win_event: sdl2::event::WindowEvent::FocusLost, + .. + } if window_id == stream_window_id + ) { + self.focused = false; + self.debug_overlay.hide(); + } else if matches!( + event, + sdl2::event::Event::Window { + window_id, + win_event: sdl2::event::WindowEvent::FocusGained, + .. + } if window_id == stream_window_id + ) { + self.focused = true; + self.debug_overlay.show_if_enabled(); + } else if matches!( + event, + sdl2::event::Event::KeyDown { + scancode: Some(sdl2::keyboard::Scancode::F3), + repeat: false, + .. + } + ) { + self.debug_overlay.toggle(); + continue; + } else if matches!( + event, + sdl2::event::Event::KeyUp { + scancode: Some(sdl2::keyboard::Scancode::F3), + .. + } + ) { + continue; + } else if handle_native_window_shortcut(&mut self.window, &event) { + continue; + } else { + self.input_capture.handle_event( + &self.sdl, + &mut self.window, + self.stream_size, + event, + ); + } + } + if let Some(raw_input) = self.raw_input.as_ref() { + raw_input + .set_enabled(self.visible && self.focused && self.input_capture.relative_mouse); + } + self.debug_overlay.update( + presented_frames, + dropped_frames, + self.input_capture.relative_mouse, + ); + } + + fn release(&mut self) { + self.input_capture.release(&self.sdl, &mut self.window); + if let Some(raw_input) = self.raw_input.as_ref() { + raw_input.set_enabled(false); + } + self.debug_overlay.hide(); + self.window.hide(); + self.visible = false; + self.focused = false; + } + + fn take_captured_input(&mut self) -> Vec { + self.input_capture.take() + } + + fn update_cursor(&mut self, bytes: &[u8]) { + self.input_capture + .apply_cursor(&self.sdl, &mut self.window, self.stream_size, bytes); + } +} + +#[cfg(target_os = "windows")] +pub(crate) struct WindowsOutput { + backend: Arc, + graphics_api: WindowsGraphicsApi, + bridge: Arc, + output: Arc, + external_surface: Option, + dropped_video_frames: u64, + stopped: bool, +} + +#[cfg(target_os = "windows")] +impl WindowsOutput { + fn initialize( + bridge: Arc, + output: Arc, + stream: MediaStreamConfig, + ) -> Result { + bridge.reset(); + let external_renderer = external_renderer_enabled(); + let graphics_api = selected_windows_graphics_api(stream.codec); + let external_surface = if external_renderer { + Some(WindowsExternalSdlSurface::initialize( + stream, + graphics_api, + output.captured_input(), + )?) + } else { + None + }; + let initial_surface = match external_surface.as_ref() { + Some(surface) => surface.target()?, + None => hidden_windows_surface(), + }; + let backend = Arc::new( + WindowsBackend::start_for( + graphics_api, + BackendConfig { + video: VideoFormat { + codec: match stream.codec { + crate::media::MediaVideoCodec::H264 => VideoCodec::H264, + crate::media::MediaVideoCodec::H265 => VideoCodec::H265, + crate::media::MediaVideoCodec::Av1 => VideoCodec::Av1, + }, + width: stream.width, + height: stream.height, + frame_rate_numerator: std::num::NonZeroU32::new(stream.fps.max(1)) + .expect("fps is clamped non-zero"), + frame_rate_denominator: std::num::NonZeroU32::new(1) + .expect("one is non-zero"), + average_bitrate: stream.bitrate_bps.max(1), + }, + audio: AudioFormat { + sample_rate: AUDIO_SAMPLE_RATE as u32, + channels: AUDIO_CHANNELS as u16, + }, + surface: initial_surface, + video_queue_capacity: + opennow_streamer_platform_windows::ADAPTIVE_VIDEO_QUEUE_CAPACITY, + audio_queue_capacity: 4, + }, + ) + .map_err(|error| error.to_string())?, + ); + bridge.replace_backend(Some(Arc::clone(&backend))); + Ok(Self { + backend, + graphics_api, + bridge, + output, + external_surface, + dropped_video_frames: 0, + stopped: false, + }) + } + + fn start(&mut self, surface: Option<&RenderSurface>) -> Result<(), String> { + if let Some(surface) = surface { + self.update_surface(surface)?; + } + Ok(()) + } + + fn set_paused(&mut self, paused: bool) -> Result<(), String> { + if paused && let Some(surface) = self.external_surface.as_mut() { + surface + .input_capture + .release(&surface.sdl, &mut surface.window); + } + self.backend + .set_paused(paused) + .map_err(|error| error.to_string()) + } + + fn update_surface(&mut self, surface: &RenderSurface) -> Result<(), String> { + if let Some(external_surface) = self.external_surface.as_mut() { + external_surface.update(surface)?; + return self + .backend + .set_surface(external_surface.target()?) + .map_err(|error| error.to_string()); + } + self.backend + .set_surface(windows_surface(surface)?) + .map_err(|error| error.to_string()) + } + + fn pump(&mut self) -> Result { + if let Some(surface) = self.external_surface.as_mut() { + surface.pump(self.backend.presented_frames(), self.dropped_video_frames); + } + let Some(event) = self.backend.try_event() else { + return Ok(OutputEvent::None); + }; + Ok(match event { + BackendEvent::FirstFramePresented => OutputEvent::Presented(match self.graphics_api { + WindowsGraphicsApi::D3d12 => "Media Foundation/D3D11-on-12/D3D12/WASAPI", + WindowsGraphicsApi::D3d11 => "Media Foundation/D3D11/WASAPI", + }), + BackendEvent::KeyFrameRequired => { + self.bridge.require_keyframe(); + OutputEvent::RequestKeyframe + } + BackendEvent::DeviceLost { subsystem, message } => OutputEvent::DeviceLost { + subsystem: subsystem_label(subsystem), + recovered: false, + message: Some(message), + }, + BackendEvent::DeviceRecovered(subsystem) => OutputEvent::DeviceLost { + subsystem: subsystem_label(subsystem), + recovered: true, + message: None, + }, + BackendEvent::Fatal(error) => OutputEvent::Fatal(error.to_string()), + BackendEvent::QueueOverflow(subsystem) => { + if matches!( + subsystem, + Subsystem::VideoDecode | Subsystem::VideoPresentation + ) { + self.dropped_video_frames = self.dropped_video_frames.saturating_add(1); + } + if subsystem == Subsystem::VideoDecode { + self.bridge.require_keyframe(); + } + OutputEvent::QueueDropped(subsystem_label(subsystem)) + } + BackendEvent::StateChanged(_) | BackendEvent::VideoFormatChanged(_) => { + OutputEvent::None + } + }) + } + + fn stop(&mut self) { + if self.stopped { + return; + } + self.bridge.replace_backend(None); + if let Some(surface) = self.external_surface.as_mut() { + surface.release(); + let captured_input = self.output.captured_input(); + for input in surface.take_captured_input() { + captured_input.push(input); + } + } + self.backend.stop(); + self.stopped = true; + } + + fn take_captured_input(&mut self) -> Vec { + self.external_surface + .as_mut() + .map(WindowsExternalSdlSurface::take_captured_input) + .unwrap_or_default() + } + + fn update_cursor(&mut self, bytes: &[u8]) { + if let Some(surface) = self.external_surface.as_mut() { + surface.update_cursor(bytes); + } + } +} + +#[cfg(target_os = "windows")] +fn selected_windows_graphics_api(codec: crate::media::MediaVideoCodec) -> WindowsGraphicsApi { + let d3d12_allowed = crate::runtime::backend_preference_allows("d3d12"); + let d3d11_allowed = crate::runtime::backend_preference_allows("d3d11"); + select_windows_graphics_api( + codec, + d3d12_allowed, + d3d11_allowed, + WindowsBackend::probe_for(WindowsGraphicsApi::D3d12).bundled_backend_available(), + ) +} + +#[cfg(target_os = "windows")] +fn select_windows_graphics_api( + codec: crate::media::MediaVideoCodec, + d3d12_allowed: bool, + d3d11_allowed: bool, + d3d12_available: bool, +) -> WindowsGraphicsApi { + // Media Foundation exposes AV1 decode surfaces through D3D11. Under Auto, + // keep those surfaces on D3D11 instead of synchronizing and flushing them + // through D3D11-on-12 for every 120 Hz frame. An explicit D3D12 selection + // remains authoritative for diagnostics and user preference. + if d3d12_allowed + && (!d3d11_allowed || (codec != crate::media::MediaVideoCodec::Av1 && d3d12_available)) + { + WindowsGraphicsApi::D3d12 + } else { + WindowsGraphicsApi::D3d11 + } +} + +#[cfg(target_os = "windows")] +impl Drop for WindowsOutput { + fn drop(&mut self) { + self.stop(); + } +} + +#[cfg(target_os = "windows")] +fn hidden_windows_surface() -> SurfaceTarget { + SurfaceTarget::Owned(OwnedWindow { + parent: None, + bounds: Bounds { + x: 0, + y: 0, + width: 2, + height: 2, + }, + visible: false, + }) +} + +#[cfg(target_os = "windows")] +fn windows_surface(surface: &RenderSurface) -> Result { + let Some(rect) = surface.rect.filter(|_| surface.visible) else { + return Ok(hidden_windows_surface()); + }; + let parent = surface + .window_handle + .as_deref() + .ok_or_else(|| "visible native surface is missing Electron windowHandle".to_owned())?; + let parent = parse_windows_handle(parent)?; + Ok(SurfaceTarget::Owned(OwnedWindow { + parent: Some(parent), + bounds: Bounds { + x: rect.x, + y: rect.y, + width: rect.width.max(2), + height: rect.height.max(2), + }, + visible: true, + })) +} + +fn external_renderer_enabled() -> bool { + external_renderer_enabled_value( + std::env::var("OPENNOW_NATIVE_EXTERNAL_RENDERER") + .ok() + .as_deref(), + ) +} + +fn external_renderer_enabled_value(value: Option<&str>) -> bool { + value.is_some_and(|value| { + matches!( + value.trim().to_ascii_lowercase().as_str(), + "1" | "true" | "yes" | "on" + ) + }) +} + +#[cfg(target_os = "windows")] +fn parse_windows_handle(value: &str) -> Result { + let trimmed = value.trim(); + let raw = if let Some(hex) = trimmed + .strip_prefix("0x") + .or_else(|| trimmed.strip_prefix("0X")) + { + isize::from_str_radix(hex, 16) + } else { + trimmed.parse::() + } + .map_err(|error| format!("invalid Electron HWND {value:?}: {error}"))?; + WindowHandle::new(raw).ok_or_else(|| "Electron HWND must be non-zero".to_owned()) +} + +#[cfg(target_os = "windows")] +fn subsystem_label(subsystem: Subsystem) -> &'static str { + match subsystem { + Subsystem::VideoDecode => "video-decode", + Subsystem::VideoPresentation => "video-presentation", + Subsystem::Audio => "audio", + } +} + +fn aspect_fit(source_width: u32, source_height: u32, width: u32, height: u32) -> Rect { + let scale = (width as f64 / source_width as f64).min(height as f64 / source_height as f64); + let target_width = (source_width as f64 * scale).round() as u32; + let target_height = (source_height as f64 * scale).round() as u32; + Rect::new( + ((width - target_width) / 2) as i32, + ((height - target_height) / 2) as i32, + target_width, + target_height, + ) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(target_os = "windows")] + #[test] + fn automatic_av1_uses_direct_d3d11_but_explicit_d3d12_is_preserved() { + use crate::media::MediaVideoCodec; + + assert_eq!( + select_windows_graphics_api(MediaVideoCodec::Av1, true, true, true), + WindowsGraphicsApi::D3d11 + ); + assert_eq!( + select_windows_graphics_api(MediaVideoCodec::Av1, true, false, true), + WindowsGraphicsApi::D3d12 + ); + assert_eq!( + select_windows_graphics_api(MediaVideoCodec::H265, true, true, true), + WindowsGraphicsApi::D3d12 + ); + } + + #[test] + fn audio_buffer_drops_oldest_samples() { + let output = OutputBuffers { + video: Mutex::new(None), + #[cfg(target_os = "linux")] + linux_video: Mutex::new(VecDeque::with_capacity(LINUX_VIDEO_QUEUE_CAPACITY)), + #[cfg(target_os = "linux")] + software_video_drops: AtomicU64::new(0), + #[cfg(target_os = "linux")] + hardware_video_drops: AtomicU64::new(0), + #[cfg(target_os = "linux")] + display_video_skips: AtomicU64::new(0), + #[cfg(target_os = "linux")] + received_video_bytes: AtomicU64::new(0), + audio: Mutex::new(VecDeque::new()), + audio_capacity: 4, + captured_input: Arc::new(CapturedInputQueue::default()), + }; + assert_eq!(output.push_audio(&[1.0, 2.0, 3.0]), 0); + assert_eq!(output.push_audio(&[4.0, 5.0, 6.0]), 2); + let mut values = [0.0; 4]; + output.fill_audio(&mut values); + assert_eq!(values, [3.0, 4.0, 5.0, 6.0]); + } + + #[test] + fn video_slot_keeps_only_the_latest_frame() { + let output = OutputBuffers::new(); + assert!(!output.replace_video(DecodedVideoFrame { + width: 1, + height: 1, + rgb: vec![1, 2, 3], + })); + assert!(output.replace_video(DecodedVideoFrame { + width: 2, + height: 1, + rgb: vec![4; 6], + })); + assert_eq!(output.take_video().expect("frame").width, 2); + } + + #[cfg(target_os = "linux")] + #[test] + fn linux_video_queue_smooths_bursts_and_bounds_recovery_latency() { + use opennow_streamer_platform_linux::StreamFormat; + + let frame = |timestamp_us| LinuxDecodedVideoFrame { + format: StreamFormat::video_default(2, 2).expect("format"), + planes: Vec::new(), + dmabuf: None, + vulkan: None, + overlay: None, + timestamp_us, + }; + let output = OutputBuffers::new(); + for timestamp_us in 0..LINUX_VIDEO_QUEUE_CAPACITY as u64 { + assert!(!output.queue_linux_video(frame(timestamp_us))); + } + assert!(output.queue_linux_video(frame(LINUX_VIDEO_QUEUE_CAPACITY as u64))); + assert_eq!(output.hardware_video_drops(), 1); + assert_eq!( + output + .take_linux_video() + .expect("oldest frame") + .frame + .timestamp_us, + 1 + ); + assert_eq!( + output + .take_linux_video() + .expect("next frame") + .frame + .timestamp_us, + 2 + ); + + let recovery = OutputBuffers::new(); + for timestamp_us in 10..12 { + assert!(!recovery.queue_linux_video(frame(timestamp_us))); + } + assert_eq!( + recovery + .take_linux_video_for_presentation(FrameSelectionPolicy::LatestReady, 0) + .expect("latest recovery frame") + .frame + .timestamp_us, + 11, + ); + assert_eq!(recovery.hardware_video_drops(), 0); + assert_eq!(recovery.display_video_skips(), 1); + assert!(recovery.take_linux_video().is_none()); + } + + #[test] + fn aspect_fit_letterboxes_without_stretching() { + assert_eq!( + aspect_fit(1920, 1080, 1000, 1000), + Rect::new(0, 218, 1000, 563) + ); + } + + #[test] + fn absolute_mouse_coordinates_exclude_letterbox_bars() { + assert_eq!( + map_window_point_to_stream_viewport((500, 500), (1920, 1080), (1000, 1000)), + AbsoluteMouseViewport { + x: 500, + y: 282, + width: 1000, + height: 563, + } + ); + assert_eq!( + map_window_point_to_stream_viewport((500, 0), (1920, 1080), (1000, 1000)), + AbsoluteMouseViewport { + x: 500, + y: 0, + width: 1000, + height: 563, + } + ); + } + + #[test] + fn cursor_channel_position_uses_normalized_stream_coordinates() { + let message = [0, 12, 0, 0, 0, 0, 0, 0x00, 0x80, 0xff, 0xff]; + assert_eq!(parse_cursor_position(&message), Some((32768, 65535))); + assert_eq!(normalized_cursor_coordinate(32768, 2560), 1280); + assert_eq!(normalized_cursor_coordinate(65535, 1440), 1439); + } + + #[test] + fn sdl_keys_map_to_windows_virtual_keys_and_gfn_modifiers() { + use sdl2::keyboard::{Mod, Scancode}; + + assert_eq!(sdl_virtual_key(Scancode::W), Some(0x57)); + assert_eq!(sdl_virtual_key(Scancode::Escape), Some(0x1b)); + assert_eq!(sdl_virtual_key(Scancode::LCtrl), Some(0xa2)); + assert_eq!( + sdl_modifiers(Scancode::W, Mod::LSHIFTMOD | Mod::LCTRLMOD), + 0x03 + ); + assert_eq!(sdl_modifiers(Scancode::LShift, Mod::LSHIFTMOD), 0); + } + + #[test] + fn adjacent_sdl_mouse_motion_is_preserved_and_clamped() { + let mut input = Vec::new(); + push_mouse_motion(&mut input, 10, -20); + push_mouse_motion(&mut input, i32::MAX, -30); + + assert_eq!( + input, + vec![ + CapturedInput::MouseMove { + delta_x: 10, + delta_y: -20, + }, + CapturedInput::MouseMove { + delta_x: i16::MAX, + delta_y: -30, + }, + ] + ); + } + + #[test] + fn native_input_capture_requires_explicit_ownership() { + assert!(!native_input_capture_enabled_value(None)); + assert!(!native_input_capture_enabled_value(Some("electron"))); + assert!(native_input_capture_enabled_value(Some(" native "))); + } + + #[test] + fn native_input_capture_waits_for_the_first_server_cursor_mode() { + let capture = SdlInputCapture::new(true, false); + assert!(!capture.focused); + assert!(!capture.relative_mouse); + assert_eq!(capture.cursor_state, RemoteCursorState::Unknown); + } + + #[test] + fn only_predefined_cursor_zero_enters_relative_mouse_mode() { + assert_eq!(cursor_state_for_message(0, 0), RemoteCursorState::Hidden); + assert_eq!(cursor_state_for_message(0, 1), RemoteCursorState::Visible); + assert_eq!(cursor_state_for_message(1, 0), RemoteCursorState::Visible); + } + + #[test] + fn custom_cursor_parser_preserves_bitmap_hotspot_and_scale() { + let mime = b"image/png"; + let image = b"AAAA"; + let mut bytes = vec![1, 0, 3, 4, mime.len() as u8]; + bytes.extend_from_slice(mime); + bytes.extend_from_slice(&(image.len() as u16).to_le_bytes()); + bytes.extend_from_slice(image); + bytes.extend_from_slice(&10_u16.to_le_bytes()); + bytes.extend_from_slice(&20_u16.to_le_bytes()); + bytes.extend_from_slice(&150_u16.to_le_bytes()); + + let cursor = parse_custom_cursor_payload(&bytes).expect("custom cursor"); + assert_eq!(cursor.hotspot_x, 3); + assert_eq!(cursor.hotspot_y, 4); + assert_eq!(cursor.image_base64, image); + assert_eq!(cursor.scale, 1.5); + } + + #[test] + fn external_renderer_environment_values_are_explicit() { + assert!(external_renderer_enabled_value(Some("1"))); + assert!(external_renderer_enabled_value(Some(" TRUE "))); + assert!(!external_renderer_enabled_value(Some("0"))); + assert!(!external_renderer_enabled_value(None)); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/queue.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/queue.rs new file mode 100644 index 000000000..89cd6a4a0 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/queue.rs @@ -0,0 +1,107 @@ +use std::collections::VecDeque; +use std::sync::{Condvar, Mutex}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum PushResult { + Queued, + DroppedOldest, + Closed, +} + +#[derive(Debug)] +struct QueueState { + values: VecDeque, + closed: bool, +} + +#[derive(Debug)] +pub(crate) struct BoundedQueue { + capacity: usize, + state: Mutex>, + ready: Condvar, +} + +impl BoundedQueue { + pub(crate) fn new(capacity: usize) -> Self { + assert!(capacity > 0, "bounded queue capacity must be non-zero"); + Self { + capacity, + state: Mutex::new(QueueState { + values: VecDeque::with_capacity(capacity), + closed: false, + }), + ready: Condvar::new(), + } + } + + pub(crate) fn push(&self, value: T) -> PushResult { + let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner()); + if state.closed { + return PushResult::Closed; + } + let result = if state.values.len() == self.capacity { + state.values.pop_front(); + PushResult::DroppedOldest + } else { + PushResult::Queued + }; + state.values.push_back(value); + self.ready.notify_one(); + result + } + + pub(crate) fn pop(&self) -> Option { + let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner()); + loop { + if let Some(value) = state.values.pop_front() { + return Some(value); + } + if state.closed { + return None; + } + state = self + .ready + .wait(state) + .unwrap_or_else(|error| error.into_inner()); + } + } + + pub(crate) fn clear(&self) { + self.state + .lock() + .unwrap_or_else(|error| error.into_inner()) + .values + .clear(); + } + + pub(crate) fn close(&self) { + let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner()); + state.closed = true; + state.values.clear(); + self.ready.notify_all(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn drops_the_oldest_value_at_capacity() { + let queue = BoundedQueue::new(2); + assert_eq!(queue.push(1), PushResult::Queued); + assert_eq!(queue.push(2), PushResult::Queued); + assert_eq!(queue.push(3), PushResult::DroppedOldest); + assert_eq!(queue.pop(), Some(2)); + assert_eq!(queue.pop(), Some(3)); + } + + #[test] + fn close_wakes_and_rejects_producers() { + let queue = BoundedQueue::new(1); + queue.push(1); + queue.close(); + assert_eq!(queue.pop(), None); + assert_eq!(queue.push(2), PushResult::Closed); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/runtime.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/runtime.rs new file mode 100644 index 000000000..8bed16164 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/runtime.rs @@ -0,0 +1,790 @@ +use std::marker::PhantomData; +use std::rc::Rc; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::mpsc::{self, Receiver, Sender}; +use std::time::Duration; + +use opennow_streamer_protocol::RenderSurface; + +use crate::media::{MediaFeedback, MediaSession, MediaStreamConfig}; +#[cfg(target_os = "windows")] +use crate::output::WindowsBridge; +use crate::output::{ActiveOutput, OutputBuffers, OutputEvent}; + +#[cfg(target_os = "linux")] +use crate::linux_backend::{LinuxVideoPath, LinuxVideoSelection}; + +// Keep native input sampling below one rendered frame even at 120 Hz. SDL can +// coalesce the individual raw-input events, so this improves delivery cadence +// without allowing the queue to grow with redundant motion packets. +const HOST_POLL_INTERVAL: Duration = Duration::from_micros(250); +const HOST_START_TIMEOUT: Duration = Duration::from_secs(10); +const HOST_CONTROL_TIMEOUT: Duration = Duration::from_secs(2); + +#[cfg(target_os = "macos")] +pub(crate) enum MacH264Configuration { + Hardware(opennow_streamer_platform_macos::StreamSink), + SoftwareFallback { reason: String }, +} + +pub(crate) enum HostCommand { + Start { + reply: Sender>, + feedback: Sender, + stream: MediaStreamConfig, + }, + Pause { + paused: bool, + reply: Option>>, + }, + Surface { + surface: RenderSurface, + reply: Sender>, + }, + Cursor(Vec), + #[cfg(target_os = "macos")] + ConfigureMacH264 { + parameter_sets: opennow_streamer_platform_macos::H264ParameterSets, + reply: Sender>, + }, + #[cfg(target_os = "linux")] + FallbackLinux { + reason: String, + }, + Stop, + Shutdown, +} + +#[derive(Clone)] +pub struct MediaRuntime { + commands: Sender, + output: Arc, + paused: Arc, + use_hardware: Arc, + #[cfg(target_os = "windows")] + windows_bridge: Arc, + #[cfg(target_os = "linux")] + linux_selection: LinuxVideoSelection, + #[cfg(target_os = "linux")] + linux_software_fallback: Arc, +} + +impl MediaRuntime { + pub fn start( + &self, + feedback: Sender, + stream: MediaStreamConfig, + ) -> Result { + let (reply, response) = mpsc::channel(); + self.commands + .send(HostCommand::Start { + reply, + feedback: feedback.clone(), + stream, + }) + .map_err(|_| "native media host is no longer running".to_owned())?; + response + .recv_timeout(HOST_START_TIMEOUT) + .map_err(|_| "native media host did not start on the UI thread".to_owned())??; + #[cfg(target_os = "linux")] + if let Some(reason) = self.linux_selection.fallback_reason.clone() { + let _ = feedback.send(MediaFeedback::BackendFallback { + from: "Linux Vulkan presentation", + to: if matches!(self.linux_selection.path, LinuxVideoPath::Hardware(_)) { + "Linux decoder/SDL NV12" + } else { + "OpenH264/SDL" + }, + reason, + }); + } + match MediaSession::spawn( + Arc::clone(&self.output), + feedback, + self.commands.clone(), + self.use_hardware.load(Ordering::Acquire), + stream, + #[cfg(target_os = "windows")] + Arc::clone(&self.windows_bridge), + #[cfg(target_os = "linux")] + self.linux_selection.clone(), + #[cfg(target_os = "linux")] + Arc::clone(&self.linux_software_fallback), + ) { + Ok(session) => { + if self.paused.load(Ordering::Acquire) { + session.set_paused(true); + } + Ok(session) + } + Err(error) => { + let _ = self.commands.send(HostCommand::Stop); + Err(error) + } + } + } + + pub fn update_surface(&self, surface: RenderSurface) -> Result<(), String> { + let (reply, response) = mpsc::channel(); + self.commands + .send(HostCommand::Surface { surface, reply }) + .map_err(|_| "native media host is no longer running".to_owned())?; + response + .recv_timeout(HOST_CONTROL_TIMEOUT) + .map_err(|_| "native media host did not apply the Electron surface update".to_owned())? + } + + pub fn set_paused(&self, paused: bool) -> Result<(), String> { + self.paused.store(paused, Ordering::Release); + let (reply, response) = mpsc::channel(); + self.commands + .send(HostCommand::Pause { + paused, + reply: Some(reply), + }) + .map_err(|_| "native media host is no longer running".to_owned())?; + response + .recv_timeout(HOST_CONTROL_TIMEOUT) + .map_err(|_| "native media host did not apply the pause update".to_owned())? + } + + pub fn shutdown(&self) { + let _ = self.commands.send(HostCommand::Shutdown); + } +} + +pub struct MainThreadHost { + commands: Receiver, + output: Arc, + _not_send: PhantomData>, + use_macos_hardware: Arc, + #[cfg(target_os = "windows")] + windows_bridge: Arc, + #[cfg(target_os = "linux")] + linux_selection: LinuxVideoSelection, + #[cfg(target_os = "linux")] + linux_software_fallback: Arc, +} + +impl MainThreadHost { + pub fn run(self) { + let mut active: Option = None; + let mut surface: Option = None; + let mut paused = false; + let mut feedback: Option> = None; + let mut software_playback_started = false; + let mut active_stream = MediaStreamConfig::default(); + loop { + match self.commands.recv_timeout(HOST_POLL_INTERVAL) { + Ok(HostCommand::Start { + reply, + feedback: session_feedback, + stream, + }) => { + active_stream = stream; + if let Some(output) = active.as_mut() { + output.stop(); + } + let requested_hardware = self.use_macos_hardware.load(Ordering::Acquire); + #[cfg(target_os = "linux")] + let requested_linux_hardware = self.linux_selection.use_vulkan_output + && matches!(self.linux_selection.path, LinuxVideoPath::Hardware(_)) + && !self.linux_software_fallback.load(Ordering::Acquire); + #[cfg(not(target_os = "linux"))] + let requested_linux_hardware = false; + let mut startup_fallback = None; + let initialized = match initialize_output( + Arc::clone(&self.output), + surface.as_ref(), + paused, + requested_hardware, + stream, + requested_linux_hardware, + #[cfg(target_os = "windows")] + Arc::clone(&self.windows_bridge), + ) { + Ok(output) => Ok(output), + Err(hardware_error) if requested_hardware || requested_linux_hardware => { + self.use_macos_hardware.store(false, Ordering::Release); + #[cfg(target_os = "windows")] + self.windows_bridge.fall_back_to_software(); + startup_fallback = Some(hardware_error); + initialize_output( + Arc::clone(&self.output), + surface.as_ref(), + paused, + false, + stream, + false, + #[cfg(target_os = "windows")] + Arc::clone(&self.windows_bridge), + ) + } + Err(error) => Err(error), + }; + match initialized { + Ok(output) => { + active = Some(output); + feedback = Some(session_feedback); + software_playback_started = false; + if let (Some(reason), Some(feedback)) = + (startup_fallback, feedback.as_ref()) + { + let _ = feedback.send(MediaFeedback::BackendFallback { + from: hardware_backend_label(), + to: if requested_linux_hardware { + "Linux decoder/SDL NV12" + } else { + "OpenH264/SDL" + }, + reason, + }); + } + let _ = reply.send(Ok(())); + } + Err(error) => { + active = None; + feedback = None; + let _ = reply.send(Err(error)); + } + } + } + Ok(HostCommand::Pause { + paused: new_paused, + reply, + }) => { + let result = active + .as_mut() + .map_or(Ok(()), |output| output.set_paused(new_paused)); + if result.is_ok() { + paused = new_paused; + } + if let Some(reply) = reply { + let _ = reply.send(result); + } + } + Ok(HostCommand::Surface { + surface: new_surface, + reply, + }) => { + static SURFACE_LOG_REMAINING: AtomicU64 = AtomicU64::new(12); + if SURFACE_LOG_REMAINING + .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |remaining| { + remaining.checked_sub(1) + }) + .is_ok() + { + eprintln!( + "NVST surface-update visible={} rect={:?}", + new_surface.visible, new_surface.screen_rect + ); + } + #[cfg(target_os = "linux")] + let linux_hardware = + active.as_ref().is_some_and(ActiveOutput::is_linux_hardware); + let result = if let Some(output) = active.as_mut() { + output.update_surface(&new_surface) + } else { + Ok(()) + }; + #[cfg(target_os = "linux")] + let mut result = result; + #[cfg(target_os = "linux")] + if linux_hardware && let Err(reason) = &result { + match initialize_output( + Arc::clone(&self.output), + Some(&new_surface), + paused, + false, + active_stream, + false, + ) { + Ok(output) => { + if let Some(current) = active.as_mut() { + current.stop(); + } + active = Some(output); + software_playback_started = false; + if let Some(feedback) = feedback.as_ref() { + let _ = feedback.send(MediaFeedback::BackendFallback { + from: "Linux decoder/Vulkan", + to: "Linux decoder/SDL NV12", + reason: format!( + "Linux surface reconfiguration failed: {reason}" + ), + }); + } + result = Ok(()); + } + Err(error) => result = Err(error), + } + } + if let Err(message) = &result { + if let Some(output) = active.as_mut() { + if let Some(feedback) = feedback.as_ref() { + let _ = feedback.send(MediaFeedback::OutputError { + message: message.clone(), + }); + } + output.stop(); + active = None; + feedback = None; + } + } + surface = Some(new_surface); + let _ = reply.send(result); + } + #[cfg(target_os = "macos")] + Ok(HostCommand::ConfigureMacH264 { + parameter_sets, + reply, + }) => { + let hardware_result = active + .as_mut() + .ok_or_else(|| "native media output is not active".to_owned()) + .and_then(|output| output.configure_macos_h264(parameter_sets)); + match hardware_result { + Ok(sink) => { + let _ = reply.send(Ok(MacH264Configuration::Hardware(sink))); + } + Err(hardware_error) => { + self.use_macos_hardware.store(false, Ordering::Release); + crate::macos_backend::disable(); + if let Some(output) = active.as_mut() { + output.stop(); + } + let fallback = ActiveOutput::initialize( + Arc::clone(&self.output), + false, + MediaStreamConfig::default(), + false, + ) + .and_then(|mut output| { + output.start(surface.as_ref())?; + output.set_paused(paused)?; + Ok(output) + }); + match fallback { + Ok(output) => { + active = Some(output); + let _ = + reply.send(Ok(MacH264Configuration::SoftwareFallback { + reason: hardware_error, + })); + } + Err(fallback_error) => { + active = None; + let _ = reply.send(Err(format!( + "VideoToolbox startup failed ({hardware_error}); software output fallback also failed: {fallback_error}" + ))); + } + } + } + } + } + Ok(HostCommand::Cursor(bytes)) => { + if let Some(output) = active.as_mut() { + output.update_cursor(&bytes); + } + } + #[cfg(target_os = "linux")] + Ok(HostCommand::FallbackLinux { reason }) => { + self.linux_software_fallback.store(true, Ordering::Release); + let replacement = initialize_output( + Arc::clone(&self.output), + surface.as_ref(), + paused, + false, + active_stream, + false, + ); + match replacement { + Ok(output) => { + if let Some(current) = active.as_mut() { + current.stop(); + } + active = Some(output); + software_playback_started = false; + if let Some(feedback) = feedback.as_ref() { + let _ = feedback.send(MediaFeedback::BackendFallback { + from: "Linux decoder pipeline", + to: "OpenH264/SDL", + reason, + }); + } + } + Err(fallback_error) => { + if let Some(feedback) = feedback.as_ref() { + let _ = feedback.send(MediaFeedback::OutputError { + message: format!( + "Linux hardware fallback failed: {fallback_error}" + ), + }); + } + active = None; + feedback = None; + } + } + } + Ok(HostCommand::Stop) => { + if let Some(output) = active.as_mut() { + output.stop(); + } + active = None; + feedback = None; + software_playback_started = false; + } + Ok(HostCommand::Shutdown) | Err(mpsc::RecvTimeoutError::Disconnected) => { + if let Some(output) = active.as_mut() { + output.stop(); + } + return; + } + Err(mpsc::RecvTimeoutError::Timeout) => {} + } + if let Some(output) = active.as_mut() { + let output_event = output.pump(); + let captured_input = self.output.captured_input(); + for input in output.take_captured_input() { + captured_input.push(input); + } + match output_event { + Ok(OutputEvent::Presented(backend)) if !software_playback_started => { + software_playback_started = true; + if let Some(feedback) = feedback.as_ref() { + let _ = feedback.send(MediaFeedback::PlaybackStarted { backend }); + } + } + #[cfg(target_os = "windows")] + Ok(OutputEvent::RequestKeyframe) => { + if let Some(feedback) = feedback.as_ref() { + let _ = feedback.send(MediaFeedback::RequestKeyframe { + mid: current_video_mid( + #[cfg(target_os = "windows")] + &self.windows_bridge, + ), + reason: "D3D11 decoder recovery requires a fresh keyframe" + .to_owned(), + }); + } + } + #[cfg(target_os = "windows")] + Ok(OutputEvent::DeviceLost { + subsystem, + recovered, + message, + }) => { + if let Some(feedback) = feedback.as_ref() { + let _ = feedback.send(MediaFeedback::DeviceLost { + subsystem, + recovered, + message, + }); + } + } + #[cfg(target_os = "windows")] + Ok(OutputEvent::QueueDropped(media)) => { + if let Some(feedback) = feedback.as_ref() { + let _ = feedback.send(MediaFeedback::QueueDropped { media, count: 1 }); + } + } + #[cfg(target_os = "windows")] + Ok(OutputEvent::Fatal(message)) => { + let fallback = (|| { + output.stop(); + self.use_macos_hardware.store(false, Ordering::Release); + #[cfg(target_os = "windows")] + self.windows_bridge.fall_back_to_software(); + let mut replacement = ActiveOutput::initialize( + Arc::clone(&self.output), + false, + MediaStreamConfig::default(), + #[cfg(target_os = "windows")] + Arc::clone(&self.windows_bridge), + false, + )?; + replacement.start(surface.as_ref())?; + replacement.set_paused(paused)?; + Ok::<_, String>(replacement) + })(); + match fallback { + Ok(replacement) => { + *output = replacement; + software_playback_started = false; + if let Some(feedback) = feedback.as_ref() { + let _ = feedback.send(MediaFeedback::BackendFallback { + from: "Media Foundation/D3D11/WASAPI", + to: "OpenH264/SDL", + reason: message, + }); + let _ = feedback.send(MediaFeedback::RequestKeyframe { + mid: current_video_mid( + #[cfg(target_os = "windows")] + &self.windows_bridge, + ), + reason: "D3D11 device recovery failed".to_owned(), + }); + } + } + Err(fallback_error) => { + if let Some(feedback) = feedback.as_ref() { + let _ = feedback.send(MediaFeedback::OutputError { + message: format!( + "D3D11 output failed ({message}); software fallback failed: {fallback_error}" + ), + }); + } + active = None; + feedback = None; + software_playback_started = false; + } + } + } + Ok(OutputEvent::None | OutputEvent::Presented(_)) => {} + Err(message) => { + #[cfg(target_os = "macos")] + if output.is_macos_hardware() { + self.use_macos_hardware.store(false, Ordering::Release); + crate::macos_backend::disable(); + output.stop(); + let fallback = initialize_output( + Arc::clone(&self.output), + surface.as_ref(), + paused, + false, + MediaStreamConfig::default(), + false, + ); + match fallback { + Ok(replacement) => { + *output = replacement; + software_playback_started = false; + if let Some(feedback) = feedback.as_ref() { + let _ = feedback.send(MediaFeedback::BackendFallback { + from: "VideoToolbox/Metal/CoreAudio", + to: "OpenH264/SDL", + reason: message, + }); + } + continue; + } + Err(fallback_error) => { + if let Some(feedback) = feedback.as_ref() { + let _ = feedback.send(MediaFeedback::OutputError { + message: format!( + "macOS hardware output failed ({message}); software fallback failed: {fallback_error}" + ), + }); + } + active = None; + feedback = None; + software_playback_started = false; + continue; + } + } + } + #[cfg(target_os = "linux")] + if output.is_linux_hardware() { + output.stop(); + let fallback = initialize_output( + Arc::clone(&self.output), + surface.as_ref(), + paused, + false, + active_stream, + false, + ); + if let Ok(replacement) = fallback { + *output = replacement; + software_playback_started = false; + if let Some(feedback) = feedback.as_ref() { + let _ = feedback.send(MediaFeedback::BackendFallback { + from: "Linux decoder/Vulkan", + to: "Linux decoder/SDL NV12", + reason: format!( + "Linux Vulkan presentation failed: {message}" + ), + }); + } + continue; + } + } + if let Some(feedback) = feedback.as_ref() { + let _ = feedback.send(MediaFeedback::OutputError { message }); + } + output.stop(); + active = None; + feedback = None; + software_playback_started = false; + } + } + } + // The host loop replaces `NSApplication.run()`; without draining AppKit's queue the + // overlay window never finishes ordering in and its controls stay dead. + #[cfg(target_os = "macos")] + opennow_streamer_platform_macos::pump_app_events(); + } + } +} + +pub fn create_runtime() -> Result<(MainThreadHost, MediaRuntime), String> { + ensure_macos_main_thread()?; + let use_macos_hardware = Arc::new(AtomicBool::new(use_hardware_backend())); + #[cfg(target_os = "linux")] + let linux_selection = crate::linux_backend::select_video_path(); + #[cfg(target_os = "linux")] + let linux_software_fallback = Arc::new(AtomicBool::new(matches!( + linux_selection.path, + LinuxVideoPath::Software + ))); + let (commands, receiver) = mpsc::channel(); + let output = Arc::new(OutputBuffers::new()); + let paused = Arc::new(AtomicBool::new(false)); + #[cfg(target_os = "windows")] + let windows_bridge = Arc::new(WindowsBridge::new()); + Ok(( + MainThreadHost { + commands: receiver, + output: Arc::clone(&output), + _not_send: PhantomData, + use_macos_hardware: Arc::clone(&use_macos_hardware), + #[cfg(target_os = "windows")] + windows_bridge: Arc::clone(&windows_bridge), + #[cfg(target_os = "linux")] + linux_selection: linux_selection.clone(), + #[cfg(target_os = "linux")] + linux_software_fallback: Arc::clone(&linux_software_fallback), + }, + MediaRuntime { + commands, + output, + paused, + use_hardware: use_macos_hardware, + #[cfg(target_os = "windows")] + windows_bridge, + #[cfg(target_os = "linux")] + linux_selection, + #[cfg(target_os = "linux")] + linux_software_fallback, + }, + )) +} + +fn initialize_output( + output: Arc, + surface: Option<&RenderSurface>, + paused: bool, + use_hardware: bool, + stream: MediaStreamConfig, + use_linux_hardware: bool, + #[cfg(target_os = "windows")] windows_bridge: Arc, +) -> Result { + let mut output = ActiveOutput::initialize( + output, + use_hardware, + stream, + #[cfg(target_os = "windows")] + windows_bridge, + use_linux_hardware, + )?; + if let Err(error) = output.start(surface) { + output.stop(); + return Err(error); + } + if let Err(error) = output.set_paused(paused) { + output.stop(); + return Err(error); + } + Ok(output) +} + +#[cfg(target_os = "macos")] +fn use_hardware_backend() -> bool { + backend_preference_allows("videotoolbox") && crate::macos_backend::available() +} + +#[cfg(target_os = "windows")] +fn use_hardware_backend() -> bool { + backend_preference_allows("d3d12") || backend_preference_allows("d3d11") +} + +#[cfg(not(any(target_os = "macos", target_os = "windows")))] +const fn use_hardware_backend() -> bool { + false +} + +#[cfg(any(target_os = "windows", target_os = "macos"))] +pub(crate) fn backend_preference_allows(hardware_backend: &str) -> bool { + backend_preference_allows_value( + std::env::var("OPENNOW_NATIVE_VIDEO_BACKEND") + .ok() + .as_deref(), + hardware_backend, + ) +} + +#[cfg(any(target_os = "windows", target_os = "macos", test))] +fn backend_preference_allows_value(value: Option<&str>, hardware_backend: &str) -> bool { + value + .map(str::trim) + .filter(|value| !value.is_empty()) + .is_none_or(|value| { + let value = value.to_ascii_lowercase(); + value == "auto" || value == hardware_backend + }) +} + +#[cfg(target_os = "windows")] +fn current_video_mid(bridge: &WindowsBridge) -> String { + bridge.last_video_mid() +} + +#[cfg(target_os = "windows")] +const fn hardware_backend_label() -> &'static str { + "Media Foundation/Direct3D/WASAPI" +} + +#[cfg(target_os = "macos")] +const fn hardware_backend_label() -> &'static str { + "VideoToolbox/Metal/CoreAudio" +} + +#[cfg(not(any(target_os = "windows", target_os = "macos")))] +const fn hardware_backend_label() -> &'static str { + "Linux decoder/Vulkan" +} + +#[cfg(target_os = "macos")] +fn ensure_macos_main_thread() -> Result<(), String> { + if unsafe { libc::pthread_main_np() } == 1 { + Ok(()) + } else { + Err( + "the macOS native media host must be created and run on the process main thread" + .to_owned(), + ) + } +} + +#[cfg(not(target_os = "macos"))] +fn ensure_macos_main_thread() -> Result<(), String> { + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::backend_preference_allows_value; + + #[test] + fn video_backend_preference_selects_only_auto_or_the_requested_hardware() { + assert!(backend_preference_allows_value(None, "d3d11")); + assert!(backend_preference_allows_value(Some(""), "d3d11")); + assert!(backend_preference_allows_value(Some("AUTO"), "d3d11")); + assert!(backend_preference_allows_value(Some("d3d11"), "d3d11")); + assert!(!backend_preference_allows_value(Some("software"), "d3d11")); + assert!(!backend_preference_allows_value(Some("d3d12"), "d3d11")); + assert!(backend_preference_allows_value(Some("d3d12"), "d3d12")); + assert!(!backend_preference_allows_value(Some("d3d11"), "d3d12")); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/windows_debug_overlay.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/windows_debug_overlay.rs new file mode 100644 index 000000000..bb804b6d6 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/windows_debug_overlay.rs @@ -0,0 +1,181 @@ +use raw_window_handle::{HasWindowHandle, RawWindowHandle}; +use sdl2::pixels::{Color, PixelFormatEnum}; +use sdl2::render::WindowCanvas; +use sdl2::video::{Window, WindowPos}; +use windows_sys::Win32::Foundation::{HWND, POINT, RECT}; +use windows_sys::Win32::Graphics::Gdi::ClientToScreen; +use windows_sys::Win32::UI::WindowsAndMessaging::{ + GWL_EXSTYLE, GWLP_HWNDPARENT, GetClientRect, GetWindowLongPtrW, SetWindowLongPtrW, + WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT, +}; + +use crate::media::MediaStreamConfig; +use crate::native_stats_overlay::{NativeStatsOverlay, OverlayMode}; + +const EDGE_MARGIN: i32 = 24; + +pub(crate) struct NativeDebugOverlay { + canvas: WindowCanvas, + parent: HWND, + stats: NativeStatsOverlay, +} + +impl NativeDebugOverlay { + pub(crate) fn new( + video: &sdl2::VideoSubsystem, + parent: isize, + stream: MediaStreamConfig, + decoder: &'static str, + ) -> Result { + let (width, height) = OverlayMode::Minimal + .size() + .expect("minimal overlay has a size"); + let window = video + .window("OpenNOW Stream Stats", width, height) + .position(0, 0) + .borderless() + .hidden() + .build() + .map_err(|error| format!("native stats overlay creation failed: {error}"))?; + let overlay_handle = hwnd(&window)?; + let parent = parent as HWND; + unsafe { + SetWindowLongPtrW(overlay_handle, GWLP_HWNDPARENT, parent as isize); + let extended = GetWindowLongPtrW(overlay_handle, GWL_EXSTYLE) as u32; + SetWindowLongPtrW( + overlay_handle, + GWL_EXSTYLE, + (extended | WS_EX_NOACTIVATE | WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW) as isize, + ); + } + let mut canvas = window + .into_canvas() + .software() + .build() + .map_err(|error| format!("native stats overlay renderer failed: {error}"))?; + let _ = canvas.window_mut().set_opacity(0.96); + Ok(Self { + canvas, + parent, + stats: NativeStatsOverlay::new(stream, decoder), + }) + } + + pub(crate) fn toggle(&mut self) { + self.stats.toggle(); + if self.stats.mode() == OverlayMode::Hidden { + self.canvas.window_mut().hide(); + } else { + self.refresh_position(); + self.draw(); + self.canvas.window_mut().show(); + self.canvas.window_mut().raise(); + } + } + + pub(crate) fn hide(&mut self) { + self.canvas.window_mut().hide(); + } + + pub(crate) fn show_if_enabled(&mut self) { + if self.stats.mode() != OverlayMode::Hidden { + self.refresh_position(); + self.draw(); + self.canvas.window_mut().show(); + } + } + + pub(crate) fn update( + &mut self, + presented_frames: u64, + dropped_frames: u64, + relative_mouse: bool, + ) { + if self + .stats + .update(presented_frames, dropped_frames, relative_mouse) + && self.stats.mode() != OverlayMode::Hidden + { + self.refresh_position(); + self.draw(); + } + } + + fn refresh_position(&mut self) { + let Some((client_x, client_y, client_width, _)) = client_bounds(self.parent) else { + return; + }; + let Some((requested_width, requested_height)) = self.stats.mode().size() else { + return; + }; + let width = match self.stats.mode() { + OverlayMode::Full => { + requested_width.min(client_width.saturating_sub(EDGE_MARGIN as u32 * 2).max(320)) + } + OverlayMode::Minimal => requested_width, + OverlayMode::Hidden => return, + }; + let x = match self.stats.mode() { + OverlayMode::Minimal => client_x + client_width as i32 - width as i32 - EDGE_MARGIN, + OverlayMode::Full => client_x + EDGE_MARGIN, + OverlayMode::Hidden => return, + }; + let window = self.canvas.window_mut(); + let _ = window.set_size(width, requested_height); + window.set_position( + WindowPos::Positioned(x), + WindowPos::Positioned(client_y + EDGE_MARGIN), + ); + } + + fn draw(&mut self) { + let Some(frame) = self.stats.frame() else { + return; + }; + self.canvas.set_draw_color(Color::RGB(3, 9, 7)); + self.canvas.clear(); + let texture_creator = self.canvas.texture_creator(); + let Ok(mut texture) = texture_creator.create_texture_streaming( + PixelFormatEnum::RGB24, + frame.width, + frame.height, + ) else { + return; + }; + if texture + .update(None, &frame.rgb, frame.width as usize * 3) + .is_err() + { + return; + } + let _ = self.canvas.copy(&texture, None, None); + self.canvas.present(); + } +} + +fn hwnd(window: &Window) -> Result { + match window + .window_handle() + .map_err(|error| format!("stats overlay Win32 handle unavailable: {error}"))? + .as_raw() + { + RawWindowHandle::Win32(handle) => Ok(handle.hwnd.get() as HWND), + _ => Err("stats overlay did not create a Win32 window".to_owned()), + } +} + +fn client_bounds(parent: HWND) -> Option<(i32, i32, u32, u32)> { + let mut rect = RECT::default(); + let mut origin = POINT { x: 0, y: 0 }; + unsafe { + if GetClientRect(parent, &mut rect) == 0 || ClientToScreen(parent, &mut origin) == 0 { + return None; + } + } + Some(( + origin.x, + origin.y, + (rect.right - rect.left).max(1) as u32, + (rect.bottom - rect.top).max(1) as u32, + )) +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/windows_raw_input.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/windows_raw_input.rs new file mode 100644 index 000000000..579b141c0 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/windows_raw_input.rs @@ -0,0 +1,425 @@ +use std::collections::HashSet; +use std::ffi::c_void; +use std::mem::{MaybeUninit, size_of}; +use std::ptr::{null, null_mut}; +use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering}; +use std::sync::{Arc, Mutex, mpsc}; +use std::thread::{self, JoinHandle}; + +use windows_sys::Win32::Foundation::{HWND, LPARAM, LRESULT, WPARAM}; +use windows_sys::Win32::System::LibraryLoader::GetModuleHandleW; +use windows_sys::Win32::System::Threading::{ + GetCurrentThread, SetThreadPriority, THREAD_PRIORITY_ABOVE_NORMAL, +}; +use windows_sys::Win32::UI::Input::{ + GetRawInputData, HRAWINPUT, MOUSE_MOVE_ABSOLUTE, RAWINPUT, RAWINPUTDEVICE, RAWINPUTHEADER, + RID_INPUT, RIDEV_INPUTSINK, RIDEV_REMOVE, RIM_TYPEMOUSE, RegisterRawInputDevices, +}; +use windows_sys::Win32::UI::WindowsAndMessaging::{ + CREATESTRUCTW, CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW, GWLP_USERDATA, + GetForegroundWindow, GetMessageW, GetWindowLongPtrW, HWND_MESSAGE, MSG, PostMessageW, + PostQuitMessage, RI_MOUSE_BUTTON_4_DOWN, RI_MOUSE_BUTTON_4_UP, RI_MOUSE_BUTTON_5_DOWN, + RI_MOUSE_BUTTON_5_UP, RI_MOUSE_LEFT_BUTTON_DOWN, RI_MOUSE_LEFT_BUTTON_UP, + RI_MOUSE_MIDDLE_BUTTON_DOWN, RI_MOUSE_MIDDLE_BUTTON_UP, RI_MOUSE_RIGHT_BUTTON_DOWN, + RI_MOUSE_RIGHT_BUTTON_UP, RI_MOUSE_WHEEL, RegisterClassW, SetWindowLongPtrW, TranslateMessage, + WM_APP, WM_CLOSE, WM_INPUT, WM_NCCREATE, WM_NCDESTROY, WNDCLASSW, +}; + +use crate::media::{CapturedInput, CapturedInputQueue}; + +const RAW_INPUT_CLASS: &[u16] = &[ + b'O' as u16, + b'p' as u16, + b'e' as u16, + b'n' as u16, + b'N' as u16, + b'O' as u16, + b'W' as u16, + b'R' as u16, + b'a' as u16, + b'w' as u16, + b'I' as u16, + b'n' as u16, + b'p' as u16, + b'u' as u16, + b't' as u16, + 0, +]; +const WM_RAW_INPUT_REREGISTER: u32 = WM_APP + 1; + +struct RawInputState { + target: AtomicIsize, + enabled: AtomicBool, + pressed_buttons: Mutex>, + captured_input: Arc, +} + +pub(crate) struct WindowsRawInputController { + state: Arc, + message_window: isize, + worker: Option>, +} + +impl WindowsRawInputController { + pub(crate) fn start( + target: isize, + captured_input: Arc, + ) -> Result { + let state = Arc::new(RawInputState { + target: AtomicIsize::new(target), + enabled: AtomicBool::new(false), + pressed_buttons: Mutex::new(HashSet::new()), + captured_input, + }); + let thread_state = Arc::clone(&state); + let (ready_sender, ready_receiver) = mpsc::sync_channel(1); + let worker = thread::Builder::new() + .name("opennow-raw-input".to_owned()) + .spawn(move || run_raw_input_thread(thread_state, ready_sender)) + .map_err(|error| format!("failed to spawn Raw Input thread: {error}"))?; + let message_window = match ready_receiver.recv() { + Ok(Ok(hwnd)) => hwnd, + Ok(Err(error)) => { + let _ = worker.join(); + return Err(error); + } + Err(_) => { + let _ = worker.join(); + return Err("Raw Input thread exited during initialization".to_owned()); + } + }; + Ok(Self { + state, + message_window, + worker: Some(worker), + }) + } + + pub(crate) fn set_target(&self, target: isize) { + self.state.target.store(target, Ordering::Release); + } + + pub(crate) fn set_enabled(&self, enabled: bool) { + let changed = self.state.enabled.swap(enabled, Ordering::AcqRel) != enabled; + if changed && enabled { + // SDL also uses Raw Input for relative mode. Register our dedicated + // message window after SDL toggles the mode so motion is delivered + // directly to this thread rather than SDL's event pump. + unsafe { + let _ = PostMessageW(self.message_window as HWND, WM_RAW_INPUT_REREGISTER, 0, 0); + } + } else if changed { + release_pressed_buttons(&self.state); + } + } +} + +impl Drop for WindowsRawInputController { + fn drop(&mut self) { + self.state.enabled.store(false, Ordering::Release); + release_pressed_buttons(&self.state); + unsafe { + let _ = PostMessageW(self.message_window as HWND, WM_CLOSE, 0, 0); + } + if let Some(worker) = self.worker.take() { + let _ = worker.join(); + } + } +} + +fn run_raw_input_thread(state: Arc, ready: mpsc::SyncSender>) { + unsafe { + let _ = SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); + let instance = GetModuleHandleW(null()); + let window_class = WNDCLASSW { + lpfnWndProc: Some(raw_input_window_proc), + hInstance: instance, + lpszClassName: RAW_INPUT_CLASS.as_ptr(), + ..Default::default() + }; + let _ = RegisterClassW(&window_class); + let state_pointer = Arc::as_ptr(&state); + let hwnd = CreateWindowExW( + 0, + RAW_INPUT_CLASS.as_ptr(), + RAW_INPUT_CLASS.as_ptr(), + 0, + 0, + 0, + 0, + 0, + HWND_MESSAGE, + null_mut(), + instance, + state_pointer.cast::(), + ); + if hwnd.is_null() { + let _ = ready.send(Err("failed to create Raw Input message window".to_owned())); + return; + } + if !register_raw_mouse(hwnd) { + let _ = DestroyWindow(hwnd); + let _ = ready.send(Err("failed to register the Raw Input mouse".to_owned())); + return; + } + let _ = ready.send(Ok(hwnd as isize)); + let mut message = MSG::default(); + while GetMessageW(&mut message, null_mut(), 0, 0) > 0 { + let _ = TranslateMessage(&message); + DispatchMessageW(&message); + } + } +} + +unsafe extern "system" fn raw_input_window_proc( + hwnd: HWND, + message: u32, + wparam: WPARAM, + lparam: LPARAM, +) -> LRESULT { + if message == WM_NCCREATE { + let create = unsafe { &*(lparam as *const CREATESTRUCTW) }; + unsafe { + SetWindowLongPtrW(hwnd, GWLP_USERDATA, create.lpCreateParams as isize); + } + return 1; + } + + let state_pointer = unsafe { GetWindowLongPtrW(hwnd, GWLP_USERDATA) } as *const RawInputState; + match message { + WM_RAW_INPUT_REREGISTER => { + // Internal wake after SDL changes relative mode: reclaim the raw + // mouse registration for this dedicated message thread. + unsafe { + let _ = register_raw_mouse(hwnd); + } + 0 + } + WM_INPUT => { + if !state_pointer.is_null() { + unsafe { + process_raw_input(&*state_pointer, lparam as HRAWINPUT); + } + } + 0 + } + WM_CLOSE => { + unsafe { + unregister_raw_mouse(); + let _ = DestroyWindow(hwnd); + } + 0 + } + WM_NCDESTROY => { + unsafe { + SetWindowLongPtrW(hwnd, GWLP_USERDATA, 0); + PostQuitMessage(0); + } + 0 + } + _ => unsafe { DefWindowProcW(hwnd, message, wparam, lparam) }, + } +} + +unsafe fn register_raw_mouse(hwnd: HWND) -> bool { + let device = RAWINPUTDEVICE { + usUsagePage: 0x01, + usUsage: 0x02, + dwFlags: RIDEV_INPUTSINK, + hwndTarget: hwnd, + }; + unsafe { RegisterRawInputDevices(&device, 1, size_of::() as u32) != 0 } +} + +unsafe fn unregister_raw_mouse() { + let device = RAWINPUTDEVICE { + usUsagePage: 0x01, + usUsage: 0x02, + dwFlags: RIDEV_REMOVE, + hwndTarget: null_mut(), + }; + unsafe { + let _ = RegisterRawInputDevices(&device, 1, size_of::() as u32); + } +} + +unsafe fn process_raw_input(state: &RawInputState, handle: HRAWINPUT) { + if !state.enabled.load(Ordering::Acquire) + || unsafe { GetForegroundWindow() } as isize != state.target.load(Ordering::Acquire) + { + return; + } + let mut raw = MaybeUninit::::uninit(); + let mut size = size_of::() as u32; + let copied = unsafe { + GetRawInputData( + handle, + RID_INPUT, + raw.as_mut_ptr().cast::(), + &mut size, + size_of::() as u32, + ) + }; + if copied == u32::MAX || copied < size_of::() as u32 { + return; + } + let raw = unsafe { raw.assume_init() }; + if raw.header.dwType != RIM_TYPEMOUSE { + return; + } + let mouse = unsafe { raw.data.mouse }; + if mouse.usFlags & MOUSE_MOVE_ABSOLUTE == 0 { + push_mouse_delta(&state.captured_input, mouse.lLastX, mouse.lLastY); + } + + let buttons = unsafe { mouse.Anonymous.Anonymous }; + push_raw_mouse_buttons(state, buttons.usButtonFlags); + if u32::from(buttons.usButtonFlags) & RI_MOUSE_WHEEL != 0 { + state.captured_input.push(CapturedInput::MouseWheel { + delta: buttons.usButtonData as i16, + }); + } +} + +fn push_raw_mouse_buttons(state: &RawInputState, flags: u16) { + const BUTTON_FLAGS: &[(u32, u32, u8)] = &[ + (RI_MOUSE_LEFT_BUTTON_DOWN, RI_MOUSE_LEFT_BUTTON_UP, 1), + (RI_MOUSE_MIDDLE_BUTTON_DOWN, RI_MOUSE_MIDDLE_BUTTON_UP, 2), + (RI_MOUSE_RIGHT_BUTTON_DOWN, RI_MOUSE_RIGHT_BUTTON_UP, 3), + (RI_MOUSE_BUTTON_4_DOWN, RI_MOUSE_BUTTON_4_UP, 4), + (RI_MOUSE_BUTTON_5_DOWN, RI_MOUSE_BUTTON_5_UP, 5), + ]; + let flags = u32::from(flags); + for &(down, up, button) in BUTTON_FLAGS { + if flags & down != 0 { + push_mouse_button(state, button, true); + } + if flags & up != 0 { + push_mouse_button(state, button, false); + } + } +} + +fn push_mouse_button(state: &RawInputState, button: u8, pressed: bool) { + let mut pressed_buttons = state + .pressed_buttons + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()); + if !state.enabled.load(Ordering::Acquire) { + return; + } + let changed = if pressed { + pressed_buttons.insert(button) + } else { + pressed_buttons.remove(&button) + }; + if changed { + state + .captured_input + .push(CapturedInput::MouseButton { button, pressed }); + } +} + +fn release_pressed_buttons(state: &RawInputState) { + let mut pressed_buttons = state + .pressed_buttons + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()); + for button in pressed_buttons.drain() { + state.captured_input.push(CapturedInput::MouseButton { + button, + pressed: false, + }); + } +} + +fn push_mouse_delta(queue: &CapturedInputQueue, mut delta_x: i32, mut delta_y: i32) { + while delta_x != 0 || delta_y != 0 { + let x = delta_x.clamp(i32::from(i16::MIN), i32::from(i16::MAX)) as i16; + let y = delta_y.clamp(i32::from(i16::MIN), i32::from(i16::MAX)) as i16; + queue.push(CapturedInput::MouseMove { + delta_x: x, + delta_y: y, + }); + delta_x -= i32::from(x); + delta_y -= i32::from(y); + } +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + use std::sync::atomic::Ordering; + + use super::{RawInputState, push_mouse_delta, push_raw_mouse_buttons, release_pressed_buttons}; + use crate::media::{CapturedInput, CapturedInputQueue}; + use windows_sys::Win32::UI::WindowsAndMessaging::{ + RI_MOUSE_LEFT_BUTTON_DOWN, RI_MOUSE_LEFT_BUTTON_UP, RI_MOUSE_RIGHT_BUTTON_DOWN, + }; + + fn state() -> RawInputState { + RawInputState { + target: Default::default(), + enabled: true.into(), + pressed_buttons: Default::default(), + captured_input: Arc::new(CapturedInputQueue::default()), + } + } + + #[test] + fn large_raw_mouse_deltas_are_split_without_loss() { + let queue = CapturedInputQueue::default(); + push_mouse_delta(&queue, 40_000, -40_000); + + let mut total_x = 0_i32; + let mut total_y = 0_i32; + while let Some(CapturedInput::MouseMove { delta_x, delta_y }) = queue.take() { + total_x += i32::from(delta_x); + total_y += i32::from(delta_y); + } + assert_eq!((total_x, total_y), (40_000, -40_000)); + } + + #[test] + fn raw_button_flags_are_forwarded_once_and_released() { + let state = state(); + push_raw_mouse_buttons( + &state, + (RI_MOUSE_LEFT_BUTTON_DOWN | RI_MOUSE_RIGHT_BUTTON_DOWN) as u16, + ); + push_raw_mouse_buttons(&state, RI_MOUSE_LEFT_BUTTON_DOWN as u16); + push_raw_mouse_buttons(&state, RI_MOUSE_LEFT_BUTTON_UP as u16); + + assert_eq!( + state.captured_input.take(), + Some(CapturedInput::MouseButton { + button: 1, + pressed: true, + }) + ); + assert_eq!( + state.captured_input.take(), + Some(CapturedInput::MouseButton { + button: 3, + pressed: true, + }) + ); + assert_eq!( + state.captured_input.take(), + Some(CapturedInput::MouseButton { + button: 1, + pressed: false, + }) + ); + + state.enabled.store(false, Ordering::Release); + release_pressed_buttons(&state); + assert_eq!( + state.captured_input.take(), + Some(CapturedInput::MouseButton { + button: 3, + pressed: false, + }) + ); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-protocol/Cargo.toml b/native/opennow-streamer/crates/opennow-streamer-protocol/Cargo.toml new file mode 100644 index 000000000..1a1670cbe --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-protocol/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "opennow-streamer-protocol" +version.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true + +[dependencies] +serde.workspace = true +serde_json.workspace = true diff --git a/native/opennow-streamer/crates/opennow-streamer-protocol/src/lib.rs b/native/opennow-streamer/crates/opennow-streamer-protocol/src/lib.rs new file mode 100644 index 000000000..c6c5c7612 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-protocol/src/lib.rs @@ -0,0 +1,312 @@ +use serde::{Deserialize, Serialize}; +use serde_json::{Map, Value}; + +pub const PROTOCOL_VERSION: u64 = 4; + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Command { + pub id: String, + #[serde(rename = "type")] + pub kind: String, + #[serde(default)] + pub protocol_version: Option, + #[serde(default)] + pub context: Option, + #[serde(default)] + pub sdp: Option, + #[serde(default)] + pub candidate: Option, + #[serde(default)] + pub input: Option, + #[serde(default)] + pub paused: Option, + #[serde(default)] + pub surface: Option, + #[serde(default)] + pub max_bitrate_kbps: Option, + #[serde(default)] + pub reason: Option, + #[serde(default)] + pub shortcuts: Option, + #[serde(default)] + pub host: Option, + #[serde(default)] + pub port: Option, + #[serde(default)] + pub payload_base64: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct IceCandidate { + pub candidate: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub sdp_mid: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub sdp_m_line_index: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub username_fragment: Option, +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct NativeInput { + #[serde(default)] + pub payload_base64: String, + #[serde(default)] + pub partially_reliable: bool, +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderSurface { + #[serde(default)] + pub rect: Option, + #[serde(default)] + pub visible: bool, + #[serde(default = "default_device_scale_factor")] + pub device_scale_factor: f32, + #[serde(default)] + pub window_handle: Option, + #[serde(default)] + pub screen_rect: Option, +} + +impl Default for RenderSurface { + fn default() -> Self { + Self { + rect: None, + visible: false, + device_scale_factor: default_device_scale_factor(), + window_handle: None, + screen_rect: None, + } + } +} + +fn default_device_scale_factor() -> f32 { + 1.0 +} + +#[derive(Debug, Clone, Copy, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RenderSurfaceRect { + pub x: i32, + pub y: i32, + pub width: u32, + pub height: u32, +} + +#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SessionContext { + pub session: Session, + pub settings: Value, + pub shortcuts: Value, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub nvst_video: Option, + #[serde(flatten)] + pub extra: Map, +} + +#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Session { + pub session_id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub sub_session_id: Option, + pub server_ip: String, + #[serde(default)] + pub ice_servers: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub media_connection_info: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub connection_info: Option>, + #[serde(flatten)] + pub extra: Map, +} + +#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ConnectionInfo { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub ip: Option, + pub port: u32, + pub usage: u32, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub protocol: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub app_level_protocol: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub resource_path: Option, + #[serde(flatten)] + pub extra: Map, +} + +#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct IceServer { + pub urls: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub username: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub credential: Option, + #[serde(flatten)] + pub extra: Map, +} + +#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct MediaConnectionInfo { + pub ip: String, + pub port: u32, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub usage: Option, + #[serde(flatten)] + pub extra: Map, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Capabilities { + pub protocol_version: u64, + pub backend: &'static str, + #[serde(skip_serializing_if = "Option::is_none")] + pub fallback_reason: Option<&'static str>, + pub supports_offer_answer: bool, + pub supports_remote_ice: bool, + pub supports_local_ice: bool, + pub supports_input: bool, + pub supports_video_decode: bool, + pub supports_video_present: bool, + pub supports_audio_decode: bool, + pub supports_audio_output: bool, + pub video_backends: Vec, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct VideoBackendCapability { + pub backend: &'static str, + pub platform: &'static str, + pub codecs: Vec, + pub zero_copy_modes: Vec<&'static str>, + pub available: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub reason: Option<&'static str>, +} + +#[derive(Debug, Clone, Serialize)] +pub struct CodecCapability { + pub codec: &'static str, + pub available: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub reason: Option<&'static str>, +} + +pub fn response(id: impl Into, kind: &str) -> Value { + serde_json::json!({ "id": id.into(), "type": kind }) +} + +pub fn error(id: Option<&str>, code: &str, message: impl Into) -> Value { + let mut value = serde_json::json!({ + "type": "error", + "code": code, + "message": message.into(), + }); + if let Some(id) = id { + value["id"] = Value::String(id.to_owned()); + } + value +} + +pub fn event(kind: &str, fields: Value) -> Value { + let mut object = fields.as_object().cloned().unwrap_or_default(); + object.insert("type".to_owned(), Value::String(kind.to_owned())); + Value::Object(object) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parses_forward_compatible_commands() { + let command: Command = serde_json::from_value(serde_json::json!({ + "id": "1", + "type": "start", + "context": { "session": { "sessionId": "session" } }, + "futureField": true + })) + .expect("command"); + assert_eq!(command.kind, "start"); + assert!(command.context.is_some()); + } + + #[test] + fn serializes_candidate_for_app_contract() { + let candidate = IceCandidate { + candidate: "candidate:1 1 udp 1 127.0.0.1 5000 typ host".to_owned(), + sdp_mid: Some("0".to_owned()), + sdp_m_line_index: Some(0), + username_fragment: None, + }; + let value = serde_json::to_value(candidate).expect("candidate"); + assert_eq!(value["sdpMLineIndex"], 0); + } + + #[test] + fn unsolicited_errors_do_not_serialize_a_null_request_id() { + let value = error(None, "invalid-command", "bad JSON"); + assert!(value.get("id").is_none()); + assert_eq!(value["type"], "error"); + } + + #[test] + fn session_context_round_trips_required_and_forward_compatible_fields() { + let fixture = serde_json::json!({ + "session": { + "sessionId": "synthetic-session", + "subSessionId": "synthetic-subsession", + "serverIp": "127-0-0-1.synthetic.invalid", + "iceServers": [], + "mediaConnectionInfo": { + "ip": "198.51.100.20", + "port": 18_784, + "usage": 17, + "futureEndpointField": true + }, + "connectionInfo": [ + { + "ip": "198.51.100.10", + "port": 443, + "usage": 14, + "protocol": 1, + "resourcePath": "/nvst/" + }, + { + "ip": "198.51.100.20", + "port": 48322, + "usage": 16, + "protocol": 1, + "appLevelProtocol": 6, + "resourcePath": "rtsps://198.51.100.20:48322/session", + "futureConnectionField": true + } + ], + "futureSessionField": "preserved" + }, + "settings": { "codec": "H264", "fps": 60 }, + "shortcuts": { "stopStream": "Ctrl+Shift+Q" }, + "futureContextField": 42 + }); + + let context: SessionContext = serde_json::from_value(fixture.clone()).expect("context"); + assert_eq!(context.session.session_id, "synthetic-session"); + assert_eq!( + serde_json::to_value(context).expect("serializable context"), + fixture + ); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-transport/Cargo.toml b/native/opennow-streamer/crates/opennow-streamer-transport/Cargo.toml new file mode 100644 index 000000000..ca2e3bc81 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-transport/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "opennow-streamer-transport" +version.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true + +[dependencies] +aes.workspace = true +ctr.workspace = true +crc32fast.workspace = true +getrandom.workspace = true +ghash.workspace = true +hmac.workspace = true +opennow-streamer-protocol = { path = "../opennow-streamer-protocol" } +serde_json.workspace = true +sha1.workspace = true +socket2.workspace = true +subtle.workspace = true +thiserror.workspace = true + +[target.'cfg(windows)'.dependencies] +str0m = { workspace = true, features = ["wincrypto-dimpl"] } + +[target.'cfg(target_os = "macos")'.dependencies] +str0m = { workspace = true, features = ["apple-crypto"] } + +[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies] +str0m = { workspace = true, features = ["rust-crypto"] } + +[dev-dependencies] +serde_json.workspace = true diff --git a/native/opennow-streamer/crates/opennow-streamer-transport/src/input.rs b/native/opennow-streamer/crates/opennow-streamer-transport/src/input.rs new file mode 100644 index 000000000..b5e7830ed --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-transport/src/input.rs @@ -0,0 +1,176 @@ +use std::time::{Duration, Instant}; + +use str0m::Rtc; +use str0m::channel::{ChannelConfig, ChannelId, Reliability}; + +pub(crate) const INPUT_HEARTBEAT_INTERVAL: Duration = Duration::from_secs(2); + +const RELIABLE_INPUT_LABEL: &str = "input_channel_v1"; +const PARTIAL_INPUT_LABEL: &str = "input_channel_partially_reliable"; +const STATS_LABEL: &str = "stats_channel"; +const INPUT_HEARTBEAT: &[u8] = &[2, 0, 0, 0]; + +#[derive(Debug, Clone, Copy)] +pub(crate) struct InputChannels { + pub(crate) reliable: ChannelId, + pub(crate) partial: ChannelId, + pub(crate) stats: ChannelId, +} + +impl InputChannels { + pub(crate) fn create(rtc: &mut Rtc, partial_reliable_lifetime_ms: u16) -> Self { + let stats = rtc.direct_api().create_data_channel(ChannelConfig { + label: STATS_LABEL.to_owned(), + ordered: false, + reliability: Reliability::MaxRetransmits { retransmits: 0 }, + ..Default::default() + }); + let reliable = rtc.direct_api().create_data_channel(ChannelConfig { + label: RELIABLE_INPUT_LABEL.to_owned(), + ..Default::default() + }); + let partial = rtc.direct_api().create_data_channel(ChannelConfig { + label: PARTIAL_INPUT_LABEL.to_owned(), + ordered: false, + reliability: Reliability::MaxPacketLifetime { + lifetime: partial_reliable_lifetime_ms, + }, + ..Default::default() + }); + Self { + reliable, + partial, + stats, + } + } + + pub(crate) fn send(self, rtc: &mut Rtc, bytes: &[u8], partially_reliable: bool) -> bool { + let id = if partially_reliable { + self.partial + } else { + self.reliable + }; + rtc.channel(id) + .is_some_and(|mut channel| channel.write(true, bytes).unwrap_or(false)) + } + + pub(crate) fn send_heartbeat(self, rtc: &mut Rtc) -> bool { + self.send(rtc, INPUT_HEARTBEAT, false) + } +} + +#[derive(Debug, Default)] +pub(crate) struct InputChannelState { + reliable_open: bool, + partial_open: bool, + negotiated_version: Option, + ready_reported: bool, +} + +impl InputChannelState { + pub(crate) fn channel_opened(&mut self, channels: InputChannels, id: ChannelId) -> Option { + if id == channels.reliable { + self.reliable_open = true; + } else if id == channels.partial { + self.partial_open = true; + } + self.take_new_ready_version() + } + + pub(crate) fn channel_data( + &mut self, + channels: InputChannels, + id: ChannelId, + bytes: &[u8], + ) -> Option { + if id == channels.stats { + return None; + } + if id == channels.reliable + && let Some(version) = input_protocol_version(bytes) + { + self.negotiated_version = Some(version); + } + self.take_new_ready_version() + } + + pub(crate) fn is_ready(&self) -> bool { + self.reliable_open && self.partial_open && self.negotiated_version.is_some() + } + + pub(crate) fn channel_closed(&mut self, channels: InputChannels, id: ChannelId) -> bool { + let was_ready = self.is_ready(); + if id == channels.reliable { + self.reliable_open = false; + self.negotiated_version = None; + } else if id == channels.partial { + self.partial_open = false; + } else { + return false; + } + self.ready_reported = false; + was_ready + } + + fn take_new_ready_version(&mut self) -> Option { + if self.ready_reported || !self.is_ready() { + return None; + } + self.ready_reported = true; + self.negotiated_version + } +} + +pub(crate) fn next_input_heartbeat(now: Instant) -> Instant { + now + INPUT_HEARTBEAT_INTERVAL +} + +fn input_protocol_version(bytes: &[u8]) -> Option { + if bytes.len() < 2 { + return None; + } + let first = u16::from_le_bytes([bytes[0], bytes[1]]); + if first == 526 { + return Some(if bytes.len() >= 4 { + u16::from_le_bytes([bytes[2], bytes[3]]) + } else { + 2 + }); + } + (bytes[0] == 0x0e).then_some(first) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn channels() -> InputChannels { + let mut rtc = Rtc::new(Instant::now()); + InputChannels::create(&mut rtc, 300) + } + + #[test] + fn parses_both_input_handshake_layouts() { + assert_eq!(input_protocol_version(&[0x0e, 0x02, 0x03, 0x00]), Some(3)); + assert_eq!(input_protocol_version(&[0x0e, 0x03]), Some(0x030e)); + assert_eq!(input_protocol_version(&[1]), None); + } + + #[test] + fn input_is_ready_only_after_both_channels_and_handshake() { + let channels = channels(); + let mut state = InputChannelState::default(); + + assert_eq!(state.channel_opened(channels, channels.reliable), None); + assert_eq!( + state.channel_data(channels, channels.reliable, &[0x0e, 0x02, 0x03, 0x00]), + None + ); + assert!(!state.is_ready()); + assert_eq!(state.channel_opened(channels, channels.partial), Some(3)); + assert!(state.is_ready()); + assert!(state.channel_closed(channels, channels.partial)); + assert!(!state.is_ready()); + assert!(!state.channel_closed(channels, channels.stats)); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-transport/src/lib.rs b/native/opennow-streamer/crates/opennow-streamer-transport/src/lib.rs new file mode 100644 index 000000000..a0bdfb819 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-transport/src/lib.rs @@ -0,0 +1,947 @@ +use std::io::ErrorKind; +use std::net::{IpAddr, SocketAddr, ToSocketAddrs, UdpSocket}; +use std::ops::Range; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc::{self, Receiver, Sender, SyncSender, TryRecvError, TrySendError}; +use std::sync::{Arc, Once}; +use std::thread::{self, JoinHandle}; +use std::time::{Duration, Instant}; + +use opennow_streamer_protocol::{IceCandidate, IceServer, MediaConnectionInfo, Session}; +use str0m::change::SdpOffer; +use str0m::crypto::from_feature_flags; +use str0m::media::{KeyframeRequestKind, Mid}; +use str0m::net::{Protocol, Receive}; +use str0m::{Candidate, Event, IceConnectionState, Input, Output, Rtc, RtcConfig}; +use thiserror::Error; + +mod input; +pub mod nvst; +mod nvst_control; +mod nvst_input; + +use input::{InputChannelState, InputChannels, next_input_heartbeat}; + +pub use nvst::{ + BoundedFrameQueue, EncodedVideoAccessUnit, NvstBundleIdentity, NvstConfigError, NvstDropReason, + NvstFallbackReason, NvstReceiveEvent, NvstReceiverState, NvstRecovery, NvstSrtpProfile, + NvstUdpReceiverControl, NvstUdpReceiverError, NvstUdpReceiverSession, NvstUnsupportedFeature, + NvstVideoCodec, NvstVideoConfig, NvstVideoReceiver, PreferredVideoTransport, + ReservedNvstBundle, SharedNvstFeedback, advertised_nvst_ipv4, parse_nvst_video_handoff, + reserve_nvst_mjolnir_udp_socket, reserve_nvst_udp_socket, select_preferred_video_transport, + spawn_nvst_mjolnir_receiver, spawn_nvst_udp_receiver, spawn_nvst_udp_receiver_with_socket, +}; + +static INSTALL_CRYPTO: Once = Once::new(); + +#[derive(Debug, Error)] +pub enum TransportError { + #[error("invalid server endpoint: {0}")] + InvalidServerEndpoint(String), + #[error("failed to resolve server endpoint {endpoint}: {source}")] + ResolveServerEndpoint { + endpoint: String, + #[source] + source: std::io::Error, + }, + #[error("invalid WebRTC media endpoint: {0}")] + InvalidMediaEndpoint(String), + #[error("failed to resolve WebRTC media endpoint {endpoint}: {source}")] + ResolveMediaEndpoint { + endpoint: String, + #[source] + source: std::io::Error, + }, + #[error("failed to bind media UDP socket: {0}")] + Bind(#[source] std::io::Error), + #[error("invalid WebRTC offer: {0}")] + Offer(String), + #[error("failed to configure local ICE candidate: {0}")] + LocalCandidate(String), + #[error("invalid remote ICE candidate: {0}")] + RemoteCandidate(String), + #[error("input channel is not ready")] + InputNotReady, + #[error("encoded media consumer is no longer running")] + MediaConsumerClosed, + #[error("encoded media consumer is backpressured")] + MediaConsumerBackpressured, + #[error("transport worker is no longer running")] + Closed, +} + +impl TransportError { + pub const fn code(&self) -> &'static str { + match self { + Self::InvalidServerEndpoint(_) | Self::ResolveServerEndpoint { .. } => { + "invalid-server-endpoint" + } + Self::InvalidMediaEndpoint(_) | Self::ResolveMediaEndpoint { .. } => { + "invalid-media-endpoint" + } + Self::Bind(_) | Self::LocalCandidate(_) => "local-transport-failed", + Self::Offer(_) => "invalid-offer", + Self::RemoteCandidate(_) => "invalid-remote-candidate", + Self::InputNotReady => "input-not-ready", + Self::MediaConsumerClosed => "media-consumer-closed", + Self::MediaConsumerBackpressured => "media-consumer-backpressured", + Self::Closed => "transport-closed", + } + } +} + +#[derive(Debug)] +pub enum TransportEvent { + Connected, + Disconnected(String), + InputReady(u16), + InputUnavailable(String), + Log(String), +} + +#[derive(Debug, Clone)] +pub struct EncodedMediaFrame { + pub mid: String, + pub codec: String, + pub payload: Arc<[u8]>, + pub rtp_timestamp: u64, + pub clock_rate_hz: u32, + pub channels: Option, + pub received_at_us: u64, + pub keyframe: bool, + pub contiguous: bool, +} + +pub type MediaConsumer = SyncSender; + +pub fn install_crypto() { + INSTALL_CRYPTO.call_once(|| from_feature_flags().install_process_default()); +} + +fn deliver_media_frame( + consumer: &MediaConsumer, + frame: EncodedMediaFrame, +) -> Result<(), TransportError> { + consumer.try_send(frame).map_err(|error| match error { + TrySendError::Full(_) => TransportError::MediaConsumerBackpressured, + TrySendError::Disconnected(_) => TransportError::MediaConsumerClosed, + }) +} + +enum TransportCommand { + AddRemoteCandidate(Candidate), + SendInput { + bytes: Vec, + partially_reliable: bool, + }, + RequestKeyframe { + mid: String, + }, + Stop, +} + +pub struct NegotiatedTransport { + pub answer_sdp: String, + pub local_candidate: IceCandidate, + pub session: TransportSession, +} + +pub struct TransportSession { + commands: Sender, + join: Option>, + media_endpoint: Option, + input_ready: Arc, +} + +#[derive(Clone)] +pub struct TransportControl { + commands: Sender, +} + +impl TransportSession { + pub fn control(&self) -> TransportControl { + TransportControl { + commands: self.commands.clone(), + } + } + + pub fn add_remote_candidate(&self, candidate: &IceCandidate) -> Result<(), TransportError> { + let candidate = normalize_remote_candidate(&candidate.candidate, self.media_endpoint); + let candidate = candidate.strip_prefix("a=").unwrap_or(&candidate); + let candidate = Candidate::from_sdp_string(candidate) + .map_err(|error| TransportError::RemoteCandidate(error.to_string()))?; + self.commands + .send(TransportCommand::AddRemoteCandidate(candidate)) + .map_err(|_| TransportError::Closed) + } + + pub fn send_input( + &self, + bytes: Vec, + partially_reliable: bool, + ) -> Result<(), TransportError> { + if !self.input_ready.load(Ordering::Acquire) { + return Err(TransportError::InputNotReady); + } + self.commands + .send(TransportCommand::SendInput { + bytes, + partially_reliable, + }) + .map_err(|_| TransportError::Closed) + } + + pub fn stop(mut self) { + let _ = self.commands.send(TransportCommand::Stop); + if let Some(join) = self.join.take() { + let _ = join.join(); + } + } +} + +impl TransportControl { + pub fn request_keyframe(&self, mid: impl Into) -> Result<(), TransportError> { + self.commands + .send(TransportCommand::RequestKeyframe { mid: mid.into() }) + .map_err(|_| TransportError::Closed) + } +} + +impl Drop for TransportSession { + fn drop(&mut self) { + let _ = self.commands.send(TransportCommand::Stop); + } +} + +pub fn negotiate( + offer_sdp: &str, + session: &Session, + partial_reliable_lifetime_ms: u16, + events: Sender, + media_consumer: MediaConsumer, +) -> Result { + install_crypto(); + + if let Some(schemes) = configured_ice_schemes(&session.ice_servers) { + let _ = events.send(TransportEvent::Log(format!( + "Configured ICE services ({schemes}) are not gathered locally; continuing with a direct host candidate for the ICE-lite GFN peer" + ))); + } + let normalized_offer = normalize_offer_endpoints(offer_sdp, session)?; + let server_ip = match normalized_offer.media_endpoint { + Some(endpoint) => endpoint.ip(), + None => resolve_server_endpoint(&session.server_ip)?, + }; + let socket = bind_routed_socket(server_ip).map_err(TransportError::Bind)?; + let local_addr = socket.local_addr().map_err(TransportError::Bind)?; + let local_candidate = Candidate::host(local_addr, "udp") + .map_err(|error| TransportError::LocalCandidate(error.to_string()))?; + + // Advertise only media formats that the native pipeline can actually + // consume. str0m enables several video codecs by default, which made the + // answer claim AV1/H.265 support even though the decoder is H.264-only. + let mut rtc = RtcConfig::new() + .clear_codecs() + .enable_opus(true) + .enable_h264(true) + .build(Instant::now()); + rtc.add_local_candidate(local_candidate.clone()); + let offer = SdpOffer::from_sdp_string(&normalized_offer.sdp) + .map_err(|error| TransportError::Offer(error.to_string()))?; + let answer = rtc + .sdp_api() + .accept_offer(offer) + .map_err(|error| TransportError::Offer(error.to_string()))?; + + let channels = InputChannels::create(&mut rtc, partial_reliable_lifetime_ms); + + let answer_sdp = answer.to_sdp_string(); + let candidate_text = local_candidate.to_sdp_string(); + let (command_tx, command_rx) = mpsc::channel(); + let input_ready = Arc::new(AtomicBool::new(false)); + let worker_input_ready = input_ready.clone(); + let transport_origin = Instant::now(); + let join = thread::Builder::new() + .name("opennow-webrtc".to_owned()) + .spawn(move || { + run_transport( + rtc, + socket, + command_rx, + TransportOutputs { + events, + media_consumer, + }, + channels, + worker_input_ready, + transport_origin, + ); + }) + .map_err(TransportError::Bind)?; + + Ok(NegotiatedTransport { + answer_sdp, + local_candidate: IceCandidate { + candidate: candidate_text, + sdp_mid: Some("0".to_owned()), + sdp_m_line_index: Some(0), + username_fragment: None, + }, + session: TransportSession { + commands: command_tx, + join: Some(join), + media_endpoint: normalized_offer.media_endpoint, + input_ready, + }, + }) +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct NormalizedOffer { + pub sdp: String, + pub replacements: usize, + pub media_endpoint: Option, +} + +pub fn normalize_offer_endpoints( + offer_sdp: &str, + session: &Session, +) -> Result { + let media_endpoint = resolve_media_endpoint(session.media_connection_info.as_ref())?; + let Some(endpoint) = media_endpoint else { + return Ok(NormalizedOffer { + sdp: offer_sdp.to_owned(), + replacements: 0, + media_endpoint: None, + }); + }; + + let mut sdp = String::with_capacity(offer_sdp.len()); + let mut replacements = 0; + for chunk in offer_sdp.split_inclusive('\n') { + let (line, ending) = chunk + .strip_suffix("\r\n") + .map(|line| (line, "\r\n")) + .or_else(|| chunk.strip_suffix('\n').map(|line| (line, "\n"))) + .unwrap_or((chunk, "")); + let rewritten = rewrite_candidate_endpoint(line, endpoint); + replacements += usize::from(rewritten != line); + sdp.push_str(&rewritten); + sdp.push_str(ending); + } + + Ok(NormalizedOffer { + sdp, + replacements, + media_endpoint: Some(endpoint), + }) +} + +pub fn resolve_server_endpoint(endpoint: &str) -> Result { + resolve_host(endpoint, 9).map_err(|source| { + if endpoint.trim().is_empty() { + TransportError::InvalidServerEndpoint("endpoint is empty".to_owned()) + } else { + TransportError::ResolveServerEndpoint { + endpoint: endpoint.to_owned(), + source, + } + } + }) +} + +fn resolve_media_endpoint( + endpoint: Option<&MediaConnectionInfo>, +) -> Result, TransportError> { + let Some(endpoint) = endpoint.filter(|endpoint| matches!(endpoint.usage, Some(2 | 17))) else { + return Ok(None); + }; + let port = u16::try_from(endpoint.port) + .ok() + .filter(|port| *port != 0) + .ok_or_else(|| { + TransportError::InvalidMediaEndpoint(format!( + "port {} is outside 1..=65535", + endpoint.port + )) + })?; + if endpoint.ip.trim().is_empty() { + return Err(TransportError::InvalidMediaEndpoint( + "hostname is empty".to_owned(), + )); + } + resolve_host(&endpoint.ip, port) + .map(|ip| Some(SocketAddr::new(ip, port))) + .map_err(|source| TransportError::ResolveMediaEndpoint { + endpoint: format!("{}:{port}", endpoint.ip), + source, + }) +} + +fn resolve_host(host: &str, port: u16) -> std::io::Result { + let host = host.trim(); + if host.is_empty() { + return Err(std::io::Error::new( + ErrorKind::InvalidInput, + "endpoint is empty", + )); + } + if let Ok(ip) = host.parse() { + return Ok(ip); + } + if let Some(ip) = dashed_ipv4_prefix(host) { + return Ok(IpAddr::V4(ip)); + } + (host, port) + .to_socket_addrs()? + .next() + .map(|address| address.ip()) + .ok_or_else(|| std::io::Error::new(ErrorKind::AddrNotAvailable, "no addresses resolved")) +} + +fn dashed_ipv4_prefix(host: &str) -> Option { + let first_label = host.split('.').next()?; + let octets = first_label + .split('-') + .map(str::parse::) + .collect::, _>>() + .ok()?; + let octets: [u8; 4] = octets.try_into().ok()?; + Some(octets.into()) +} + +fn configured_ice_schemes(servers: &[IceServer]) -> Option { + let mut schemes = servers + .iter() + .flat_map(|server| &server.urls) + .map(|url| { + url.split_once(':') + .map_or("unknown", |(scheme, _)| scheme) + .to_ascii_lowercase() + }) + .collect::>(); + if schemes.is_empty() { + return None; + } + schemes.sort_unstable(); + schemes.dedup(); + Some(schemes.join(", ")) +} + +fn normalize_remote_candidate(candidate: &str, endpoint: Option) -> String { + endpoint.map_or_else( + || candidate.to_owned(), + |endpoint| rewrite_candidate_endpoint(candidate, endpoint), + ) +} + +fn rewrite_candidate_endpoint(candidate: &str, endpoint: SocketAddr) -> String { + let candidate_body = candidate.strip_prefix("a=").unwrap_or(candidate); + if !candidate_body.starts_with("candidate:") { + return candidate.to_owned(); + } + let Some(address_range) = token_range(candidate, 4) else { + return candidate.to_owned(); + }; + let Some(port_range) = token_range(candidate, 5) else { + return candidate.to_owned(); + }; + let address = endpoint.ip().to_string(); + let port = endpoint.port().to_string(); + if candidate[address_range.clone()] == address && candidate[port_range.clone()] == port { + return candidate.to_owned(); + } + + let mut rewritten = candidate.to_owned(); + rewritten.replace_range(port_range, &port); + rewritten.replace_range(address_range, &address); + rewritten +} + +fn token_range(value: &str, target: usize) -> Option> { + let mut token = 0; + let mut start = None; + for (index, character) in value.char_indices() { + if character.is_ascii_whitespace() { + if let Some(start) = start.take() { + if token == target { + return Some(start..index); + } + token += 1; + } + } else if start.is_none() { + start = Some(index); + } + } + start + .filter(|_| token == target) + .map(|start| start..value.len()) +} + +fn bind_routed_socket(server_ip: IpAddr) -> std::io::Result { + let unspecified = match server_ip { + IpAddr::V4(_) => "0.0.0.0:0", + IpAddr::V6(_) => "[::]:0", + }; + let route_probe = UdpSocket::bind(unspecified)?; + route_probe.connect(SocketAddr::new(server_ip, 9))?; + let local_ip = route_probe.local_addr()?.ip(); + UdpSocket::bind(SocketAddr::new(local_ip, 0)) +} + +struct TransportOutputs { + events: Sender, + media_consumer: MediaConsumer, +} + +fn run_transport( + mut rtc: Rtc, + socket: UdpSocket, + commands: Receiver, + outputs: TransportOutputs, + channels: InputChannels, + input_ready_state: Arc, + transport_origin: Instant, +) { + struct ResetInputReady(Arc); + + impl Drop for ResetInputReady { + fn drop(&mut self) { + self.0.store(false, Ordering::Release); + } + } + + let _reset_input_ready = ResetInputReady(input_ready_state.clone()); + let mut receive_buffer = vec![0_u8; 65_536]; + let mut input_state = InputChannelState::default(); + let mut next_heartbeat = next_input_heartbeat(Instant::now()); + let mut input_handshake_started_at = None; + let mut input_timeout_reported = false; + + loop { + loop { + match commands.try_recv() { + Ok(TransportCommand::AddRemoteCandidate(candidate)) => { + rtc.add_remote_candidate(candidate); + } + Ok(TransportCommand::SendInput { + bytes, + partially_reliable, + }) => { + if input_state.is_ready() + && !channels.send(&mut rtc, &bytes, partially_reliable) + { + input_ready_state.store(false, Ordering::Release); + let _ = outputs.events.send(TransportEvent::InputUnavailable( + "input packet could not be queued".to_owned(), + )); + } + } + Ok(TransportCommand::RequestKeyframe { mid }) => { + let mid = Mid::from(mid.as_str()); + let Some(mut writer) = rtc.writer(mid) else { + let _ = outputs.events.send(TransportEvent::Log(format!( + "Unable to request keyframe for unknown media id {mid}" + ))); + continue; + }; + let kind = if writer.is_request_keyframe_possible(KeyframeRequestKind::Pli) { + Some(KeyframeRequestKind::Pli) + } else if writer.is_request_keyframe_possible(KeyframeRequestKind::Fir) { + Some(KeyframeRequestKind::Fir) + } else { + None + }; + if let Some(kind) = kind + && let Err(error) = writer.request_keyframe(None, kind) + { + let _ = outputs.events.send(TransportEvent::Log(format!( + "Failed to request keyframe for {mid}: {error}" + ))); + } + } + Ok(TransportCommand::Stop) | Err(TryRecvError::Disconnected) => { + rtc.disconnect(); + let _ = outputs + .events + .send(TransportEvent::Disconnected("stopped".to_owned())); + return; + } + Err(TryRecvError::Empty) => break, + } + } + + if input_state.is_ready() && Instant::now() >= next_heartbeat { + if !channels.send_heartbeat(&mut rtc) { + input_ready_state.store(false, Ordering::Release); + let _ = outputs.events.send(TransportEvent::InputUnavailable( + "input heartbeat could not be queued".to_owned(), + )); + } + next_heartbeat = next_input_heartbeat(Instant::now()); + } + if !input_timeout_reported + && !input_state.is_ready() + && input_handshake_started_at.is_some_and(|started| { + Instant::now().duration_since(started) >= Duration::from_secs(5) + }) + { + input_timeout_reported = true; + let _ = outputs.events.send(TransportEvent::InputUnavailable( + "input handshake timed out".to_owned(), + )); + } + + let timeout = loop { + match rtc.poll_output() { + Ok(Output::Timeout(timeout)) => break timeout, + Ok(Output::Transmit(transmit)) => { + if let Err(error) = socket.send_to(&transmit.contents, transmit.destination) { + let _ = outputs.events.send(TransportEvent::Disconnected(format!( + "UDP send failed: {error}" + ))); + return; + } + } + Ok(Output::Event(event)) => match event { + Event::IceConnectionStateChange(IceConnectionState::Connected) => { + input_handshake_started_at.get_or_insert_with(Instant::now); + let _ = outputs.events.send(TransportEvent::Connected); + } + Event::IceConnectionStateChange(IceConnectionState::Disconnected) => { + let _ = outputs + .events + .send(TransportEvent::Disconnected("ICE disconnected".to_owned())); + return; + } + Event::ChannelOpen(id, _) => { + if let Some(version) = input_state.channel_opened(channels, id) { + input_ready_state.store(true, Ordering::Release); + let _ = outputs.events.send(TransportEvent::InputReady(version)); + } + } + Event::ChannelData(data) => { + if let Some(version) = + input_state.channel_data(channels, data.id, &data.data) + { + input_ready_state.store(true, Ordering::Release); + let _ = outputs.events.send(TransportEvent::InputReady(version)); + } + } + Event::ChannelClose(id) => { + if input_state.channel_closed(channels, id) { + input_ready_state.store(false, Ordering::Release); + let _ = outputs.events.send(TransportEvent::InputUnavailable( + "input data channel closed".to_owned(), + )); + } + } + Event::MediaData(data) => { + let keyframe = data.is_keyframe(); + let received_at_us = data + .network_time + .saturating_duration_since(transport_origin) + .as_micros() + .try_into() + .unwrap_or(u64::MAX); + let frame = EncodedMediaFrame { + mid: data.mid.to_string(), + codec: format!("{:?}", data.params.spec().codec), + payload: data.data, + rtp_timestamp: data.time.numer(), + clock_rate_hz: data.time.denom(), + channels: data.params.spec().channels, + received_at_us, + keyframe, + contiguous: data.contiguous, + }; + if let Err(error) = deliver_media_frame(&outputs.media_consumer, frame) { + let _ = outputs + .events + .send(TransportEvent::Disconnected(error.to_string())); + return; + } + } + _ => {} + }, + Err(error) => { + let _ = outputs + .events + .send(TransportEvent::Disconnected(error.to_string())); + return; + } + } + }; + + let wait = timeout + .saturating_duration_since(Instant::now()) + .min(Duration::from_millis(10)); + if wait.is_zero() { + if let Err(error) = rtc.handle_input(Input::Timeout(Instant::now())) { + let _ = outputs.events.send(TransportEvent::Disconnected(format!( + "RTC timer failed: {error}" + ))); + return; + } + continue; + } + + if let Err(error) = socket.set_read_timeout(Some(wait)) { + let _ = outputs.events.send(TransportEvent::Disconnected(format!( + "UDP timeout configuration failed: {error}" + ))); + return; + } + let input = match socket.recv_from(&mut receive_buffer) { + Ok((length, source)) => { + let destination = match socket.local_addr() { + Ok(value) => value, + Err(error) => { + let _ = outputs + .events + .send(TransportEvent::Disconnected(error.to_string())); + return; + } + }; + let contents = match receive_buffer[..length].try_into() { + Ok(value) => value, + Err(error) => { + let _ = outputs.events.send(TransportEvent::Log(format!( + "Dropping oversized UDP packet: {error}" + ))); + continue; + } + }; + Input::Receive( + Instant::now(), + Receive { + proto: Protocol::Udp, + source, + destination, + contents, + }, + ) + } + Err(error) if matches!(error.kind(), ErrorKind::WouldBlock | ErrorKind::TimedOut) => { + Input::Timeout(Instant::now()) + } + Err(error) => { + let _ = outputs + .events + .send(TransportEvent::Disconnected(error.to_string())); + return; + } + }; + if let Err(error) = rtc.handle_input(input) { + let _ = outputs + .events + .send(TransportEvent::Disconnected(error.to_string())); + return; + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use opennow_streamer_protocol::Session; + use serde_json::json; + use str0m::media::{Direction, MediaKind}; + + fn synthetic_session(media_connection_info: serde_json::Value) -> Session { + serde_json::from_value(json!({ + "sessionId": "synthetic-session", + "serverIp": "127-0-0-1.session.synthetic.invalid", + "iceServers": [], + "mediaConnectionInfo": media_connection_info, + })) + .expect("synthetic session") + } + + #[test] + fn normalizes_synthetic_gfn_media_endpoint_candidates() { + let session = synthetic_session(json!({ + "ip": "198-51-100-42.media.synthetic.invalid", + "port": 18_784, + "usage": 17, + })); + let offer = [ + "v=0", + "c=IN IP4 0.0.0.0", + "a=candidate:udp 1 udp 2122260223 0.0.0.0 47998 typ host", + "a=candidate:tcp 1 tcp 1518214911 203.0.113.9 9 typ host tcptype active", + ] + .join("\r\n"); + + let normalized = normalize_offer_endpoints(&offer, &session).expect("normalized offer"); + + assert_eq!(normalized.replacements, 2); + assert_eq!( + normalized.media_endpoint, + Some("198.51.100.42:18784".parse().expect("socket address")) + ); + assert!(normalized.sdp.contains("c=IN IP4 0.0.0.0")); + assert!( + normalized + .sdp + .contains("a=candidate:udp 1 udp 2122260223 198.51.100.42 18784 typ host") + ); + assert!(normalized.sdp.contains( + "a=candidate:tcp 1 tcp 1518214911 198.51.100.42 18784 typ host tcptype active" + )); + assert!(normalized.sdp.contains("\r\n")); + } + + #[test] + fn rewrites_trickled_candidate_to_the_normalized_media_endpoint() { + let endpoint = Some("198.51.100.42:18784".parse().expect("socket address")); + let candidate = "candidate:remote 1 udp 2122260223 203.0.113.9 47998 typ host"; + + assert_eq!( + normalize_remote_candidate(candidate, endpoint), + "candidate:remote 1 udp 2122260223 198.51.100.42 18784 typ host" + ); + assert_eq!( + normalize_remote_candidate("candidate:malformed", endpoint), + "candidate:malformed" + ); + } + + #[test] + fn skips_non_webrtc_media_endpoint_usage() { + let session = synthetic_session(json!({ + "ip": "198.51.100.42", + "port": 18_784, + "usage": 14, + })); + let offer = "v=0\na=candidate:udp 1 udp 1 203.0.113.9 47998 typ host\n"; + + let normalized = normalize_offer_endpoints(offer, &session).expect("normalized offer"); + + assert_eq!(normalized.sdp, offer); + assert_eq!(normalized.replacements, 0); + assert_eq!(normalized.media_endpoint, None); + } + + #[test] + fn accepts_ip_encoded_and_dns_hostnames_as_server_endpoints() { + assert_eq!( + resolve_server_endpoint("127-0-0-1.session.synthetic.invalid") + .expect("encoded hostname"), + "127.0.0.1".parse::().expect("IP address") + ); + assert!( + resolve_server_endpoint("localhost") + .expect("DNS hostname") + .is_loopback() + ); + } + + #[test] + fn rejects_invalid_media_endpoint_port() { + let session = synthetic_session(json!({ + "ip": "198.51.100.42", + "port": 70_000, + "usage": 2, + })); + + let error = normalize_offer_endpoints("v=0\n", &session).expect_err("invalid endpoint"); + + assert_eq!(error.code(), "invalid-media-endpoint"); + assert!(error.to_string().contains("1..=65535")); + } + + #[test] + fn summarizes_configured_ice_schemes_without_credentials() { + let servers: Vec = serde_json::from_value(json!([ + { + "urls": ["stun:stun.synthetic.invalid:3478"], + }, + { + "urls": ["turns:turn.synthetic.invalid:5349"], + "username": "synthetic-user", + "credential": "synthetic-secret" + } + ])) + .expect("ICE servers"); + + let schemes = configured_ice_schemes(&servers).expect("configured schemes"); + + assert_eq!(schemes, "stun, turns"); + assert!(!schemes.contains("synthetic-secret")); + } + + #[test] + fn negotiates_a_synthetic_offer_with_a_hostname_server_endpoint() { + install_crypto(); + let mut offerer = RtcConfig::new().build(Instant::now()); + offerer.add_local_candidate( + Candidate::host("127.0.0.1:49152".parse().expect("candidate address"), "udp") + .expect("local candidate"), + ); + let mut change = offerer.sdp_api(); + change.add_media(MediaKind::Video, Direction::SendOnly, None, None, None); + let (offer, _pending) = change.apply().expect("offer"); + let offer_sdp = offer.to_sdp_string(); + let session = synthetic_session(serde_json::Value::Null); + let (events, _receiver) = mpsc::channel(); + let (media_consumer, _media_receiver) = mpsc::sync_channel(4); + + let negotiated = negotiate(&offer_sdp, &session, 300, events, media_consumer) + .expect("negotiated answer"); + + assert!(negotiated.answer_sdp.contains("m=video")); + assert!(!negotiated.answer_sdp.contains("m=video 0")); + assert!(negotiated.answer_sdp.contains("H264/90000")); + assert!(!negotiated.answer_sdp.contains("AV1/90000")); + assert!(!negotiated.answer_sdp.contains("H265/90000")); + negotiated.session.stop(); + } + + #[test] + fn delivers_encoded_payload_to_typed_consumer_without_copying_arc() { + let (consumer, receiver) = mpsc::sync_channel(1); + let payload: Arc<[u8]> = Arc::from([1_u8, 2, 3, 4]); + let frame = EncodedMediaFrame { + mid: "video-0".to_owned(), + codec: "H264".to_owned(), + payload: payload.clone(), + rtp_timestamp: 180_000, + clock_rate_hz: 90_000, + channels: None, + received_at_us: 2_500, + keyframe: true, + contiguous: true, + }; + + deliver_media_frame(&consumer, frame).expect("frame delivery"); + + let delivered = receiver.recv().expect("delivered frame"); + assert!(Arc::ptr_eq(&delivered.payload, &payload)); + assert_eq!(delivered.rtp_timestamp, 180_000); + assert_eq!(delivered.clock_rate_hz, 90_000); + assert_eq!(delivered.channels, None); + assert_eq!(delivered.received_at_us, 2_500); + } + + #[test] + fn reports_media_consumer_backpressure_instead_of_growing_an_unbounded_queue() { + let (consumer, _receiver) = mpsc::sync_channel(1); + let frame = || EncodedMediaFrame { + mid: "video-0".to_owned(), + codec: "H264".to_owned(), + payload: Arc::from([1_u8, 2, 3, 4]), + rtp_timestamp: 180_000, + clock_rate_hz: 90_000, + channels: None, + received_at_us: 2_500, + keyframe: true, + contiguous: true, + }; + deliver_media_frame(&consumer, frame()).expect("first frame delivery"); + + let error = deliver_media_frame(&consumer, frame()).expect_err("bounded queue is full"); + + assert_eq!(error.code(), "media-consumer-backpressured"); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-transport/src/nvst.rs b/native/opennow-streamer/crates/opennow-streamer-transport/src/nvst.rs new file mode 100644 index 000000000..5f3120075 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-transport/src/nvst.rs @@ -0,0 +1,6546 @@ +//! Independently authored NVST video receive transport. +//! +//! This module only implements the receive side of the classic NVST video handoff: +//! authenticated SRTP video datagrams from the negotiated peer become bounded H.264 +//! Annex-B access units. Standard Opus RTP and the existing input data-channel contract +//! use the negotiated DTLS bundle. Proprietary FEC repair remains deliberately unsupported. + +use std::collections::{BTreeMap, HashSet, VecDeque}; +use std::fmt; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, UdpSocket}; +use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering}; +use std::sync::mpsc::{self, Receiver, Sender, TryRecvError}; +use std::sync::{Arc, Mutex, OnceLock}; +use std::thread::{self, JoinHandle}; +use std::time::{Duration, Instant}; + +use aes::cipher::{BlockEncrypt, KeyIvInit, StreamCipher}; +use aes::{Aes128, Aes256}; +use crc32fast::hash as crc32; +use ctr::{Ctr32BE, Ctr128BE}; +use ghash::{GHash, universal_hash::UniversalHash}; +use hmac::{Hmac, Mac}; +use serde_json::Value; +use sha1::Sha1; +use socket2::{Domain, Protocol, Socket, Type}; +use subtle::ConstantTimeEq; +use thiserror::Error; + +use str0m::channel::ChannelId; +use str0m::config::Fingerprint; +use str0m::format::{Codec, FormatParams}; +use str0m::media::{Frequency, MediaKind, Mid}; +use str0m::net::{Protocol as RtcProtocol, Receive}; +use str0m::rtp::Ssrc; +use str0m::{Candidate, Event, IceCreds, Input, Output, Rtc, RtcConfig}; + +use super::nvst_control::{ + DEFAULT_FRAME_TIME_US, FRAMES_PER_PACING_REPORT, QOS_REPORT_INTERVAL, QOS_WARM_UP, QosReport, + frame_ack, frame_pacing_report, idr_request, +}; +use super::nvst_input::{ + NvstInputChannelState, NvstInputChannels, NvstInputCodec, native_input_type_is_motion, + native_input_type_name, native_input_types, next_control_keepalive, server_cursor_messages, +}; +use super::{ + EncodedMediaFrame, MediaConsumer, TransportError, deliver_media_frame, install_crypto, +}; + +const RTP_FIXED_HEADER_LEN: usize = 12; +const SRTP_AES_CM_HMAC_SHA1_80_TAG_LEN: usize = 10; +/// RFC 7714 `AEAD_AES_*_GCM` profiles carry a 16-byte authentication tag. +const SRTP_AEAD_AES_GCM_TAG_LEN: usize = 16; +/// NVIDIA's `SecureRtp` (libBifrost2) maps `sec_serv_conf_and_auth` + 256-bit keys +/// to `srtp_crypto_policy_set_aes_gcm_256_8_auth` — an 8-byte tag, not RFC 7714's 16. +const SRTP_AEAD_AES_GCM_8_TAG_LEN: usize = 8; + +/// RFC 3711 / libsrtp SRTP labels. Hook captures of 0x03/0x05 were SRTCP (same +/// master key, separate session keys). Mjolnir video is RTP, so use 0x00/0x02. +const GFN_SRTP_KEY_LABEL: u8 = 0x00; +const GFN_SRTP_SALT_LABEL: u8 = 0x02; +/// RFC 3711 SRTCP KDF labels (same master key, separate session keys). +const GFN_SRTCP_KEY_LABEL: u8 = 0x03; +const GFN_SRTCP_SALT_LABEL: u8 = 0x05; +const SRTCP_ENCRYPTED_FLAG: u32 = 0x8000_0000; +const RTCP_SENDER_SSRC: u32 = 0x4f4e_4f57; // "ONOW" +const SRTCP_RR_INTERVAL: Duration = Duration::from_secs(1); +// GFN's Windows client starts RTP loss recovery after 1 ms. Waiting for the +// old 20 ms cadence allowed a 120 fps / high-bitrate stream to exhaust the +// reorder queue before the first NACK was even transmitted. +const RTCP_RECOVERY_INTERVAL: Duration = Duration::from_millis(1); +const MAX_PENDING_NACK_RANGES: usize = 16; +const MAX_PENDING_FRAME_ACKS: usize = 512; + +fn verbose_diagnostics_enabled() -> bool { + static ENABLED: OnceLock = OnceLock::new(); + *ENABLED.get_or_init(|| { + std::env::var("OPENNOW_NVST_TRACE") + .ok() + .is_some_and(|value| matches!(value.trim(), "1" | "true" | "TRUE" | "yes" | "on")) + }) +} +const MAX_NACK_PACKET_COUNT: usize = 64; +const MAX_NACK_FCI_ENTRIES: usize = MAX_NACK_PACKET_COUNT.div_ceil(17); +const NV_VIDEO_PACKET_LEN: usize = 16; +// Match the official client's bounded NACK/dejitter envelope: it keeps up to +// 1,024 RTP packets available for late or retransmitted packets and permits a +// 2,048-entry NACK queue. A 32-packet window is only a few milliseconds at +// 150 Mbps and turns recoverable reordering into visible keyframe hitches. +const DEFAULT_REORDER_WINDOW: usize = 1_024; +const MAX_REORDER_WINDOW: usize = 2_048; +// NVIDIA's Mjolnir receiver uses an 8 ms dequeue deadline. Keep the large +// packet store for retransmissions, but never let one missing packet hold an +// entire high-refresh stream until the store fills (roughly 300 ms at 120 fps). +const MJOLNIR_REORDER_DEQUEUE_TIMEOUT: Duration = Duration::from_millis(8); +const NVST_UDP_RECEIVE_BUFFER_BYTES: usize = 8 * 1024 * 1024; +const DEFAULT_MAX_ACCESS_UNIT_BYTES: usize = 2 * 1024 * 1024; +const MAX_ACCESS_UNIT_BYTES: usize = 16 * 1024 * 1024; +const DEFAULT_TIMEOUT: Duration = Duration::from_secs(5); +const MIN_TIMEOUT: Duration = Duration::from_millis(250); +const MAX_TIMEOUT: Duration = Duration::from_secs(90); +const MAX_PING_BYTES: usize = 512; +const PING_INTERVAL_BEFORE_CONNECTION: Duration = Duration::from_millis(20); +const PING_INTERVAL_AFTER_CONNECTION: Duration = Duration::from_millis(100); +const CURSOR_CAPTURE_RETRY_INTERVAL: Duration = Duration::from_millis(250); +const MAX_CURSOR_CAPTURE_ATTEMPTS: u8 = 8; +const UDP_RECEIVE_POLL_INTERVAL: Duration = Duration::from_millis(10); +// The WebRTC bundle owns the SCTP input channels. A 10 ms socket wait batches +// raw mouse reports and makes high-refresh streams feel closer to 100 Hz. +const CONTROL_RECEIVE_POLL_INTERVAL: Duration = Duration::from_millis(1); +const STUN_HEADER_LEN: usize = 20; +const STUN_MAGIC_COOKIE: u32 = 0x2112_a442; +const STUN_BINDING_REQUEST: u16 = 0x0001; +const STUN_BINDING_SUCCESS_RESPONSE: u16 = 0x0101; +const STUN_ATTR_USERNAME: u16 = 0x0006; +const STUN_ATTR_MESSAGE_INTEGRITY: u16 = 0x0008; +const STUN_ATTR_XOR_MAPPED_ADDRESS: u16 = 0x0020; +const STUN_ATTR_FINGERPRINT: u16 = 0x8028; +const STUN_FINGERPRINT_XOR: u32 = 0x5354_554e; +const MAX_ICE_CREDENTIAL_BYTES: usize = 256; + +/// The independently documented `NV_VIDEO_PACKET` flag values used by an earlier OpenNOW +/// implementation. This module does not borrow code or binaries from NVIDIA. +#[cfg(test)] +const FLAG_CONTAINS_PIC_DATA: u8 = 0x01; +const FLAG_EOF: u8 = 0x02; +const FLAG_SOF: u8 = 0x04; +const STREAM_PACKET_INDEX_MASK: u32 = 0x00ff_ffff; +/// Mjolnir video RTP packets carry the per-packet video metadata in a fixed +/// 16-byte RTP extension block with profile `0x4753` ("GS"), not in the payload. +const GS_VIDEO_EXTENSION_PROFILE: u16 = 0x4753; +const MAX_GS_FRAME_HEADER_BYTES: usize = 64; +const GS_SHORT_FRAME_HEADER_BYTES: usize = 8; +// GFN's current cloud NVST protocol uses a compact extended frame header. It +// is not the 44-byte extended header used by current consumer GameStream. +const GFN_EXTENDED_FRAME_HEADER_BYTES: usize = 20; +const GFN_RED_PAYLOAD_TYPE: u8 = 63; +const GFN_OPUS_PAYLOAD_TYPE: u8 = 111; +const MAX_REDUNDANT_AUDIO_BLOCKS: usize = 8; +const MAX_OPUS_PACKET_BYTES: usize = 1_275; + +fn diagnostic_hex(bytes: &[u8], limit: usize) -> String { + let mut value = bytes + .iter() + .take(limit) + .map(|byte| format!("{byte:02x}")) + .collect::(); + if bytes.len() > limit { + value.push_str("..."); + } + value +} + +type Aes256Ctr = Ctr128BE; +type Aes128Ctr = Ctr128BE; +type HmacSha1 = Hmac; + +/// The SRTP profile must come from negotiated metadata. The legacy `nvstVideo` handoff has no +/// profile field; Bifrost's Mjolnir video path hardcodes `aes_gcm_256_8_auth`, so the legacy +/// default selects the 8-byte-tag GCM variant. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum NvstSrtpProfile { + AeadAes128Gcm, + AeadAes256Gcm, + AeadAes128Gcm8, + AeadAes256Gcm8, + AesCm128HmacSha1_32, + AesCm128HmacSha1_80, + AesCm256HmacSha1_32, + AesCm256HmacSha1_80, +} + +impl NvstSrtpProfile { + fn parse(value: &str) -> Result { + match value.trim().to_ascii_uppercase().as_str() { + "AEAD_AES_128_GCM" | "SRTP_AEAD_AES_128_GCM" => Ok(Self::AeadAes128Gcm), + "AEAD_AES_256_GCM" | "SRTP_AEAD_AES_256_GCM" => Ok(Self::AeadAes256Gcm), + "AEAD_AES_128_GCM_8" | "SRTP_AEAD_AES_128_GCM_8" => Ok(Self::AeadAes128Gcm8), + "AEAD_AES_256_GCM_8" | "SRTP_AEAD_AES_256_GCM_8" => Ok(Self::AeadAes256Gcm8), + "AES_CM_128_HMAC_SHA1_32" | "SRTP_AES_CM_128_HMAC_SHA1_32" => { + Ok(Self::AesCm128HmacSha1_32) + } + "AES_CM_128_HMAC_SHA1_80" | "SRTP_AES_CM_128_HMAC_SHA1_80" => { + Ok(Self::AesCm128HmacSha1_80) + } + "AES_CM_256_HMAC_SHA1_32" | "SRTP_AES_CM_256_HMAC_SHA1_32" => { + Ok(Self::AesCm256HmacSha1_32) + } + "AES_CM_256_HMAC_SHA1_80" | "SRTP_AES_CM_256_HMAC_SHA1_80" => { + Ok(Self::AesCm256HmacSha1_80) + } + other => Err(NvstConfigError::UnsupportedSrtpProfile(other.to_owned())), + } + } +} + +/// Video codecs accepted by the native NVST receive path. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum NvstVideoCodec { + H264, + H265, + Av1, +} + +impl NvstVideoCodec { + fn parse(value: &str) -> Result { + match value.trim().to_ascii_uppercase().as_str() { + "H264" | "AVC" => Ok(Self::H264), + "H265" | "HEVC" => Ok(Self::H265), + "AV1" => Ok(Self::Av1), + other => Err(NvstConfigError::UnsupportedCodec(other.to_owned())), + } + } + + pub const fn label(self) -> &'static str { + match self { + Self::H264 => "H264", + Self::H265 => "H265", + Self::Av1 => "AV1", + } + } +} + +/// Why an NVST handoff cannot be selected. Callers should retain their WebRTC fallback. +#[derive(Debug, Error)] +pub enum NvstConfigError { + #[error("nvstVideo must be an object")] + HandoffNotObject, + #[error("nvstVideo is missing {0}")] + MissingField(&'static str), + #[error("nvstVideo.{field} must be a {expected}")] + InvalidFieldType { + field: &'static str, + expected: &'static str, + }, + #[error("nvstVideo.{field} is out of range")] + OutOfRange { field: &'static str }, + #[error("nvstVideo.videoPeerIp is not a routable unicast IP address: {0}")] + InvalidPeerIp(String), + #[error("nvstVideo.srtpAesKeyHex is invalid for the selected SRTP profile")] + InvalidAesKey, + #[error("nvstVideo.srtpSaltHex is invalid for the selected SRTP profile")] + InvalidSrtpSalt, + #[error("nvstVideo.srtpProfile {0} is not implemented")] + UnsupportedSrtpProfile(String), + #[error("NVST video codec {0} is not implemented; supported codecs are H264, H265, and AV1")] + UnsupportedCodec(String), + #[error("nvstVideo.audioTrack must contain standard negotiated Opus RTP metadata")] + InvalidAudioTrack, + #[error("nvstTransport cannot be used without the required nvstVideo handoff")] + MissingNvstVideoHandoff, +} + +/// Explicitly records transport features that cannot be sent correctly from current wire data. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum NvstUnsupportedFeature { + FecRepair, +} + +impl fmt::Display for NvstUnsupportedFeature { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + let name = match self { + Self::FecRepair => "FEC repair", + }; + formatter.write_str(name) + } +} + +/// Feedback plane shared between the Mjolnir video receiver (which learns the +/// stream SSRC/sequence and detects unrecoverable loss) and the ICE/DTLS bundle +/// (which owns the `rtcp1` SCTP data channel used for RTCP feedback). +/// +/// The official client sends RTCP Receiver Reports / PLI over an SCTP data +/// channel on the bundle ("RTCP over SCTP is a must for One SDK video to +/// function"). Without it the server stops video after a short provisional +/// window. This state lets the bundle build accurate reports for the stream the +/// Mjolnir receiver is actually seeing. +#[derive(Debug, Default)] +struct ReceptionTiming { + first_arrival: Option, + first_rtp_timestamp: u32, + last_rtp_timestamp: u32, + last_transit: i64, + jitter: f64, +} + +#[derive(Debug, Clone, Copy)] +struct RtcpReportBlock { + media_ssrc: u32, + fraction_lost: u8, + cumulative_lost: i32, + highest_sequence: u32, + jitter: u32, +} + +#[derive(Debug, Clone, Copy)] +struct CompletedFrameFeedback { + frame_number: u32, + bytes: u32, + accepted_at: Instant, +} + +#[derive(Debug)] +pub struct NvstFeedbackState { + /// Bound video stream SSRC (0 until the first packet is authenticated). + video_ssrc: AtomicU32, + /// Highest extended sequence number received on the video stream. + highest_sequence: AtomicU32, + base_sequence: AtomicU32, + received_packets: AtomicU32, + report_prior: Mutex<(u32, u32)>, + reception_timing: Mutex, + /// Set when the receiver hits unrecoverable loss and needs a fresh keyframe. + keyframe_needed: AtomicBool, + /// Missing extended RTP sequence ranges awaiting RFC 4585 generic NACK. + pending_nacks: Mutex>, + completed_frames: AtomicU32, + completed_frame_bytes: AtomicU64, + last_completed_rtp_timestamp: AtomicU32, + accepted_frame_sequence: AtomicU32, + pending_frame_acks: Mutex>, +} + +impl Default for NvstFeedbackState { + fn default() -> Self { + Self { + video_ssrc: AtomicU32::new(0), + highest_sequence: AtomicU32::new(0), + base_sequence: AtomicU32::new(u32::MAX), + received_packets: AtomicU32::new(0), + report_prior: Mutex::new((0, 0)), + reception_timing: Mutex::new(ReceptionTiming::default()), + keyframe_needed: AtomicBool::new(false), + pending_nacks: Mutex::new(VecDeque::new()), + completed_frames: AtomicU32::new(0), + completed_frame_bytes: AtomicU64::new(0), + last_completed_rtp_timestamp: AtomicU32::new(0), + accepted_frame_sequence: AtomicU32::new(0), + pending_frame_acks: Mutex::new(VecDeque::new()), + } + } +} + +impl NvstFeedbackState { + fn publish_stream(&self, ssrc: u32, highest_sequence: u32, rtp_timestamp: u32, now: Instant) { + self.video_ssrc.store(ssrc, Ordering::Release); + let _ = self.base_sequence.compare_exchange( + u32::MAX, + highest_sequence, + Ordering::AcqRel, + Ordering::Acquire, + ); + self.highest_sequence + .fetch_max(highest_sequence, Ordering::AcqRel); + self.received_packets.fetch_add(1, Ordering::AcqRel); + + let mut timing = self + .reception_timing + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner); + let Some(first_arrival) = timing.first_arrival else { + timing.first_arrival = Some(now); + timing.first_rtp_timestamp = rtp_timestamp; + timing.last_rtp_timestamp = rtp_timestamp; + return; + }; + if timing.last_rtp_timestamp == rtp_timestamp { + return; + } + let arrival_ticks = now + .saturating_duration_since(first_arrival) + .as_secs_f64() + .mul_add(90_000.0, 0.0) as i64; + let rtp_ticks = i64::from(rtp_timestamp.wrapping_sub(timing.first_rtp_timestamp)); + let transit = arrival_ticks - rtp_ticks; + let delta = transit.abs_diff(timing.last_transit) as f64; + timing.last_rtp_timestamp = rtp_timestamp; + timing.last_transit = transit; + timing.jitter += (delta - timing.jitter) / 16.0; + } + + pub fn request_keyframe(&self) { + self.keyframe_needed.store(true, Ordering::Release); + } + + fn request_nack(&self, first_missing_index: u64, last_missing_index: u64) { + if first_missing_index > last_missing_index { + return; + } + let mut pending = self + .pending_nacks + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner); + if let Some((_, queued_last)) = pending.back_mut() + && first_missing_index <= queued_last.saturating_add(1) + { + *queued_last = (*queued_last).max(last_missing_index); + return; + } + if pending.len() == MAX_PENDING_NACK_RANGES { + pending.pop_front(); + } + pending.push_back((first_missing_index, last_missing_index)); + } + + fn resolve_nack(&self, received_index: u64) { + let mut pending = self + .pending_nacks + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner); + let mut updated = VecDeque::with_capacity(pending.len().saturating_add(1)); + while let Some((first, last)) = pending.pop_front() { + if received_index < first || received_index > last { + updated.push_back((first, last)); + continue; + } + if first < received_index { + updated.push_back((first, received_index - 1)); + } + if received_index < last { + updated.push_back((received_index + 1, last)); + } + } + *pending = updated; + } + + fn publish_completed_frame(&self, frame: &EncodedVideoAccessUnit) { + self.completed_frames.fetch_add(1, Ordering::AcqRel); + self.completed_frame_bytes.fetch_add( + u64::try_from(frame.bytes.len()).unwrap_or(u64::MAX), + Ordering::AcqRel, + ); + self.last_completed_rtp_timestamp + .store(frame.timestamp, Ordering::Release); + } + + pub fn publish_accepted_frame(&self, bytes: u32, accepted_at: Instant) { + let frame_number = self + .accepted_frame_sequence + .fetch_add(1, Ordering::AcqRel) + .wrapping_add(1); + let mut pending = self + .pending_frame_acks + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner); + if pending.len() == MAX_PENDING_FRAME_ACKS { + pending.pop_front(); + } + pending.push_back(CompletedFrameFeedback { + frame_number, + bytes, + accepted_at, + }); + } + + fn take_completed_frame(&self) -> Option { + self.pending_frame_acks + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner) + .pop_front() + } + + fn completed_frame_snapshot(&self) -> (u32, u32, u32) { + ( + self.completed_frames.load(Ordering::Acquire), + self.completed_frame_bytes.load(Ordering::Acquire) as u32, + self.last_completed_rtp_timestamp.load(Ordering::Acquire), + ) + } + + /// SSRC + highest sequence for the next Receiver Report, if a stream is bound. + fn stream_snapshot(&self) -> Option<(u32, u32)> { + let ssrc = self.video_ssrc.load(Ordering::Acquire); + (ssrc != 0).then(|| (ssrc, self.highest_sequence.load(Ordering::Acquire))) + } + + fn report_snapshot(&self, update_interval: bool) -> Option { + let media_ssrc = self.video_ssrc.load(Ordering::Acquire); + let base = self.base_sequence.load(Ordering::Acquire); + if media_ssrc == 0 || base == u32::MAX { + return None; + } + let highest_sequence = self.highest_sequence.load(Ordering::Acquire); + let received = self.received_packets.load(Ordering::Acquire); + let expected = highest_sequence.wrapping_sub(base).wrapping_add(1); + let cumulative_lost = i64::from(expected) - i64::from(received); + let cumulative_lost = cumulative_lost.clamp(-0x80_0000, 0x7f_ffff) as i32; + let fraction_lost = if update_interval { + let mut prior = self + .report_prior + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner); + let expected_interval = expected.wrapping_sub(prior.0); + let received_interval = received.wrapping_sub(prior.1); + *prior = (expected, received); + let lost_interval = expected_interval.saturating_sub(received_interval); + if expected_interval == 0 { + 0 + } else { + ((u64::from(lost_interval) << 8) / u64::from(expected_interval)).min(255) as u8 + } + } else { + 0 + }; + let jitter = self + .reception_timing + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner) + .jitter + .clamp(0.0, f64::from(u32::MAX)) as u32; + Some(RtcpReportBlock { + media_ssrc, + fraction_lost, + cumulative_lost, + highest_sequence, + jitter, + }) + } + + /// Atomically takes the pending keyframe request, returning true if one was set. + fn take_keyframe_request(&self) -> bool { + self.keyframe_needed.swap(false, Ordering::AcqRel) + } + + fn take_nack(&self) -> Option<(u64, u64)> { + let mut pending = self + .pending_nacks + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner); + let (first, last) = pending.pop_front()?; + let send_last = + last.min(first.saturating_add((MAX_NACK_PACKET_COUNT.saturating_sub(1)) as u64)); + if send_last < last { + pending.push_front((send_last + 1, last)); + } + Some((first, send_last)) + } +} + +/// Shared handle to the NVST feedback plane (cheap to clone, shared across threads). +pub type SharedNvstFeedback = Arc; + +/// Legacy `nvstVideo` configuration normalized into the bounded receive transport. +/// +/// Secret material is never exposed through `Debug`. The legacy `nvstVideo` handoff defaults to +/// `AEAD_AES_256_GCM`; every SRTP profile requires an explicit `srtpSaltHex`. +#[derive(Clone)] +pub struct NvstVideoConfig { + client_udp_port: u16, + video_peer: SocketAddr, + bundle_peer: Option, + srtp: NvstSrtpMaterial, + ping_payload: Vec, + ping_version: Option, + stun_credentials: Option, + remote_dtls_fingerprint: Option, + /// Dedicated NATT-only video (Mjolnir) socket port in the official two-socket + /// cloud model. When set, video RTP/SRTP arrives on this socket while the + /// ICE/DTLS bundle socket only carries control/audio keepalive traffic. + mjolnir_udp_port: Option, + codec: NvstVideoCodec, + audio_track: Option, + expected_payload_type: Option, + expected_ssrc: Option, + reorder_window_packets: usize, + max_access_unit_bytes: usize, + timeout: Duration, + frame_time_us: u32, + /// Feedback plane shared with the ICE/DTLS bundle (cloned configs share it). + feedback: SharedNvstFeedback, +} + +impl fmt::Debug for NvstVideoConfig { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("NvstVideoConfig") + .field("client_udp_port", &self.client_udp_port) + .field("video_peer", &self.video_peer) + .field("bundle_peer", &self.bundle_peer) + .field("srtp", &self.srtp) + .field("ping_payload_len", &self.ping_payload.len()) + .field("ping_version", &self.ping_version) + .field("stun_credentials", &self.stun_credentials) + .field( + "remote_dtls_fingerprint_bytes", + &self.remote_dtls_fingerprint.as_ref().map(String::len), + ) + .field("mjolnir_udp_port", &self.mjolnir_udp_port) + .field("codec", &self.codec) + .field("audio_track", &self.audio_track) + .field("expected_payload_type", &self.expected_payload_type) + .field("expected_ssrc", &self.expected_ssrc) + .field("reorder_window_packets", &self.reorder_window_packets) + .field("max_access_unit_bytes", &self.max_access_unit_bytes) + .field("timeout", &self.timeout) + .field("frame_time_us", &self.frame_time_us) + .finish() + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct NvstAudioTrack { + pub payload_type: u8, + pub clock_rate_hz: u32, + pub channels: u8, + pub mid: String, + pub ssrc: Option, +} + +#[derive(Clone)] +struct NvstStunCredentials { + local_username_fragment: String, + local_password: String, + remote_username_fragment: String, + remote_password: String, +} + +impl fmt::Debug for NvstStunCredentials { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("NvstStunCredentials") + .field("local_username_fragment", &"[redacted]") + .field("local_password", &"[redacted]") + .field("remote_username_fragment", &"[redacted]") + .field("remote_password", &"[redacted]") + .finish() + } +} + +#[derive(Clone)] +enum NvstSrtpMaterial { + AeadAes128Gcm { + master_key: [u8; 16], + master_salt: [u8; 12], + authentication_tag_len: usize, + }, + AeadAes256Gcm { + master_key: [u8; 32], + master_salt: [u8; 12], + authentication_tag_len: usize, + }, + AesCm128HmacSha1 { + master_key: [u8; 16], + master_salt: [u8; 14], + authentication_tag_len: usize, + }, + AesCm256HmacSha1 { + master_key: [u8; 32], + master_salt: [u8; 14], + authentication_tag_len: usize, + }, +} + +impl fmt::Debug for NvstSrtpMaterial { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("NvstSrtpMaterial") + .field("profile", &self.profile()) + .field("master_key", &"[redacted]") + .field("master_salt", &"[redacted]") + .finish() + } +} + +impl NvstSrtpMaterial { + fn profile(&self) -> NvstSrtpProfile { + match self { + Self::AeadAes128Gcm { + authentication_tag_len: SRTP_AEAD_AES_GCM_8_TAG_LEN, + .. + } => NvstSrtpProfile::AeadAes128Gcm8, + Self::AeadAes128Gcm { .. } => NvstSrtpProfile::AeadAes128Gcm, + Self::AeadAes256Gcm { + authentication_tag_len: SRTP_AEAD_AES_GCM_8_TAG_LEN, + .. + } => NvstSrtpProfile::AeadAes256Gcm8, + Self::AeadAes256Gcm { .. } => NvstSrtpProfile::AeadAes256Gcm, + Self::AesCm128HmacSha1 { + authentication_tag_len: SRTP_AES_CM_HMAC_SHA1_80_TAG_LEN, + .. + } => NvstSrtpProfile::AesCm128HmacSha1_80, + Self::AesCm128HmacSha1 { .. } => NvstSrtpProfile::AesCm128HmacSha1_32, + Self::AesCm256HmacSha1 { + authentication_tag_len: SRTP_AES_CM_HMAC_SHA1_80_TAG_LEN, + .. + } => NvstSrtpProfile::AesCm256HmacSha1_80, + Self::AesCm256HmacSha1 { .. } => NvstSrtpProfile::AesCm256HmacSha1_32, + } + } +} + +impl NvstVideoConfig { + /// Parses the stable `nvstVideo` handoff supplied by the RTSP probe. + pub fn from_legacy_handoff( + handoff: &Value, + settings_codec: Option<&str>, + ) -> Result { + let object = handoff + .as_object() + .ok_or(NvstConfigError::HandoffNotObject)?; + let client_udp_port = required_u16(object, "clientUdpPort")?; + if client_udp_port == 0 { + return Err(NvstConfigError::OutOfRange { + field: "clientUdpPort", + }); + } + + let peer_ip_text = required_string(object, "videoPeerIp")?; + let peer_ip: IpAddr = peer_ip_text + .parse() + .map_err(|_| NvstConfigError::InvalidPeerIp(peer_ip_text.to_owned()))?; + if !is_unicast_peer(peer_ip) { + return Err(NvstConfigError::InvalidPeerIp(peer_ip_text.to_owned())); + } + let video_peer_port = required_u16(object, "videoPeerPort")?; + if video_peer_port == 0 { + return Err(NvstConfigError::OutOfRange { + field: "videoPeerPort", + }); + } + let bundle_peer = + if object.contains_key("bundlePeerIp") || object.contains_key("bundlePeerPort") { + let bundle_ip_text = required_string(object, "bundlePeerIp")?; + let bundle_ip: IpAddr = bundle_ip_text + .parse() + .map_err(|_| NvstConfigError::InvalidPeerIp(bundle_ip_text.to_owned()))?; + if !is_unicast_peer(bundle_ip) { + return Err(NvstConfigError::InvalidPeerIp(bundle_ip_text.to_owned())); + } + let bundle_port = required_u16(object, "bundlePeerPort")?; + if bundle_port == 0 { + return Err(NvstConfigError::OutOfRange { + field: "bundlePeerPort", + }); + } + Some(SocketAddr::new(bundle_ip, bundle_port)) + } else { + None + }; + + let master_key = required_string(object, "srtpAesKeyHex")?; + // Bifrost's SignalingHandler initializes Mjolnir video as + // sec_serv_conf_and_auth + 256-bit keys → AES-256-GCM with an 8-byte tag. + let srtp_profile = optional_string(object, "srtpProfile")? + .map(NvstSrtpProfile::parse) + .transpose()? + .unwrap_or(NvstSrtpProfile::AeadAes256Gcm8); + let srtp = match srtp_profile { + NvstSrtpProfile::AeadAes128Gcm | NvstSrtpProfile::AeadAes128Gcm8 => { + let master_salt = required_string(object, "srtpSaltHex").and_then(|salt| { + decode_fixed_hex::<12>(salt, NvstConfigError::InvalidSrtpSalt) + })?; + NvstSrtpMaterial::AeadAes128Gcm { + master_key: decode_fixed_hex::<16>(master_key, NvstConfigError::InvalidAesKey)?, + master_salt, + authentication_tag_len: match srtp_profile { + NvstSrtpProfile::AeadAes128Gcm8 => SRTP_AEAD_AES_GCM_8_TAG_LEN, + _ => SRTP_AEAD_AES_GCM_TAG_LEN, + }, + } + } + NvstSrtpProfile::AeadAes256Gcm | NvstSrtpProfile::AeadAes256Gcm8 => { + let master_salt = required_string(object, "srtpSaltHex").and_then(|salt| { + decode_fixed_hex::<12>(salt, NvstConfigError::InvalidSrtpSalt) + })?; + NvstSrtpMaterial::AeadAes256Gcm { + master_key: decode_fixed_hex::<32>(master_key, NvstConfigError::InvalidAesKey)?, + master_salt, + authentication_tag_len: match srtp_profile { + NvstSrtpProfile::AeadAes256Gcm8 => SRTP_AEAD_AES_GCM_8_TAG_LEN, + _ => SRTP_AEAD_AES_GCM_TAG_LEN, + }, + } + } + NvstSrtpProfile::AesCm128HmacSha1_32 | NvstSrtpProfile::AesCm128HmacSha1_80 => { + let master_salt = required_string(object, "srtpSaltHex").and_then(|salt| { + decode_salt_hex::<14>(salt, NvstConfigError::InvalidSrtpSalt) + })?; + NvstSrtpMaterial::AesCm128HmacSha1 { + master_key: decode_fixed_hex::<16>(master_key, NvstConfigError::InvalidAesKey)?, + master_salt, + authentication_tag_len: match srtp_profile { + NvstSrtpProfile::AesCm128HmacSha1_32 => 4, + NvstSrtpProfile::AesCm128HmacSha1_80 => SRTP_AES_CM_HMAC_SHA1_80_TAG_LEN, + _ => unreachable!("AES-CM profile selected above"), + }, + } + } + NvstSrtpProfile::AesCm256HmacSha1_32 | NvstSrtpProfile::AesCm256HmacSha1_80 => { + let master_salt = required_string(object, "srtpSaltHex").and_then(|salt| { + decode_salt_hex::<14>(salt, NvstConfigError::InvalidSrtpSalt) + })?; + NvstSrtpMaterial::AesCm256HmacSha1 { + master_key: decode_fixed_hex::<32>(master_key, NvstConfigError::InvalidAesKey)?, + master_salt, + authentication_tag_len: match srtp_profile { + NvstSrtpProfile::AesCm256HmacSha1_32 => 4, + NvstSrtpProfile::AesCm256HmacSha1_80 => SRTP_AES_CM_HMAC_SHA1_80_TAG_LEN, + _ => unreachable!("AES-CM profile selected above"), + }, + } + } + }; + + let codec_name = optional_string(object, "codec")? + .or(settings_codec) + .ok_or(NvstConfigError::MissingField("codec"))?; + let codec = NvstVideoCodec::parse(codec_name)?; + let audio_track = object + .get("audioTrack") + .map(parse_audio_track) + .transpose()?; + let ping_payload = optional_string(object, "pingPayload")? + .map_or_else(|| b"PING".to_vec(), |payload| payload.as_bytes().to_vec()); + if ping_payload.is_empty() || ping_payload.len() > MAX_PING_BYTES { + return Err(NvstConfigError::OutOfRange { + field: "pingPayload", + }); + } + let ping_version = optional_u8(object, "pingVersion")?; + let remote_dtls_fingerprint = + optional_string(object, "remoteDtlsFingerprint")?.map(str::to_owned); + let mjolnir_udp_port = optional_u16(object, "mjolnirUdpPort")?; + if mjolnir_udp_port == Some(0) { + return Err(NvstConfigError::OutOfRange { + field: "mjolnirUdpPort", + }); + } + let stun_credentials = if ping_version == Some(6) || remote_dtls_fingerprint.is_some() { + Some(NvstStunCredentials { + local_username_fragment: required_ice_credential( + object, + "localIceUsernameFragment", + )?, + local_password: required_ice_credential(object, "localIcePassword")?, + remote_username_fragment: required_ice_credential( + object, + "remoteIceUsernameFragment", + )?, + remote_password: required_ice_credential(object, "remoteIcePassword")?, + }) + } else { + None + }; + + let expected_payload_type = optional_u8(object, "rtpPayloadType")?; + let expected_ssrc = optional_u32(object, "rtpSsrc")?; + let reorder_window_packets = + optional_usize(object, "reorderWindowPackets")?.unwrap_or(DEFAULT_REORDER_WINDOW); + if !(1..=MAX_REORDER_WINDOW).contains(&reorder_window_packets) { + return Err(NvstConfigError::OutOfRange { + field: "reorderWindowPackets", + }); + } + let max_access_unit_bytes = + optional_usize(object, "maxAccessUnitBytes")?.unwrap_or(DEFAULT_MAX_ACCESS_UNIT_BYTES); + if !(1..=MAX_ACCESS_UNIT_BYTES).contains(&max_access_unit_bytes) { + return Err(NvstConfigError::OutOfRange { + field: "maxAccessUnitBytes", + }); + } + let timeout_ms = optional_u64(object, "timeoutMs")?; + let timeout = timeout_ms + .map(Duration::from_millis) + .unwrap_or(DEFAULT_TIMEOUT); + if !(MIN_TIMEOUT..=MAX_TIMEOUT).contains(&timeout) { + return Err(NvstConfigError::OutOfRange { field: "timeoutMs" }); + } + + Ok(Self { + client_udp_port, + video_peer: SocketAddr::new(peer_ip, video_peer_port), + bundle_peer, + srtp, + ping_payload, + ping_version, + stun_credentials, + remote_dtls_fingerprint, + mjolnir_udp_port, + codec, + audio_track, + expected_payload_type, + expected_ssrc, + reorder_window_packets, + max_access_unit_bytes, + timeout, + frame_time_us: DEFAULT_FRAME_TIME_US, + feedback: Arc::new(NvstFeedbackState::default()), + }) + } + + pub fn client_udp_port(&self) -> u16 { + self.client_udp_port + } + + /// Shared feedback plane (RTCP-over-SCTP state) for this session. + pub fn feedback(&self) -> SharedNvstFeedback { + self.feedback.clone() + } + + pub fn video_peer(&self) -> SocketAddr { + self.video_peer + } + + pub fn bundle_peer(&self) -> SocketAddr { + self.bundle_peer.unwrap_or(self.video_peer) + } + + pub fn codec(&self) -> NvstVideoCodec { + self.codec + } + + pub fn audio_track(&self) -> Option<&NvstAudioTrack> { + self.audio_track.as_ref() + } + + pub fn srtp_profile(&self) -> NvstSrtpProfile { + self.srtp.profile() + } + + pub fn timeout(&self) -> Duration { + self.timeout + } + + pub fn remote_dtls_fingerprint(&self) -> Option<&str> { + self.remote_dtls_fingerprint.as_deref() + } + + pub fn mjolnir_udp_port(&self) -> Option { + self.mjolnir_udp_port + } +} + +fn parse_audio_track(value: &Value) -> Result { + let object = value + .as_object() + .ok_or(NvstConfigError::InvalidAudioTrack)?; + let payload_type = object + .get("payloadType") + .and_then(Value::as_u64) + .and_then(|value| u8::try_from(value).ok()) + .filter(|value| *value <= 127) + .ok_or(NvstConfigError::InvalidAudioTrack)?; + object + .get("codec") + .and_then(Value::as_str) + .filter(|value| value.eq_ignore_ascii_case("opus")) + .ok_or(NvstConfigError::InvalidAudioTrack)?; + let clock_rate_hz = object + .get("clockRateHz") + .and_then(Value::as_u64) + .and_then(|value| u32::try_from(value).ok()) + .filter(|value| *value == 48_000) + .ok_or(NvstConfigError::InvalidAudioTrack)?; + let channels = object + .get("channels") + .and_then(Value::as_u64) + .and_then(|value| u8::try_from(value).ok()) + .filter(|value| matches!(*value, 1 | 2)) + .ok_or(NvstConfigError::InvalidAudioTrack)?; + let mid = match object.get("mid") { + Some(Value::String(value)) if !value.is_empty() && value.len() <= 64 => value.clone(), + Some(_) => return Err(NvstConfigError::InvalidAudioTrack), + None => "audio".to_owned(), + }; + let ssrc = match object.get("ssrc") { + Some(value) => Some( + value + .as_u64() + .and_then(|value| u32::try_from(value).ok()) + .filter(|value| *value != 0) + .ok_or(NvstConfigError::InvalidAudioTrack)?, + ), + None => None, + }; + Ok(NvstAudioTrack { + payload_type, + clock_rate_hz, + channels, + mid, + ssrc, + }) +} + +fn required_ice_credential( + object: &serde_json::Map, + field: &'static str, +) -> Result { + let value = required_string(object, field)?; + if value.is_empty() || value.len() > MAX_ICE_CREDENTIAL_BYTES { + return Err(NvstConfigError::OutOfRange { field }); + } + Ok(value.to_owned()) +} + +/// Parses `context.nvstVideo` without tying the rest of the transport to JSON field names. +/// `None` means the legacy handoff was not supplied, which is a normal WebRTC fallback case. +pub fn parse_nvst_video_handoff( + context: &Value, +) -> Result, NvstConfigError> { + let Some(handoff) = context.get("nvstVideo") else { + if context.get("nvstTransport").is_some() { + return Err(NvstConfigError::MissingNvstVideoHandoff); + } + return Ok(None); + }; + let settings_codec = context.pointer("/settings/codec").and_then(Value::as_str); + let mut config = NvstVideoConfig::from_legacy_handoff(handoff, settings_codec)?; + if let Some(fps) = context + .pointer("/session/negotiatedStreamProfile/fps") + .or_else(|| context.pointer("/settings/fps")) + .and_then(Value::as_u64) + .and_then(|value| u32::try_from(value).ok()) + .map(|value| value.clamp(1, 240)) + { + config.frame_time_us = 1_000_000 / fps; + } + Ok(Some(config)) +} + +/// The transport selector always prefers a valid NVST video handoff, while making every +/// incomplete or unsupported handoff a typed WebRTC fallback instead of an optimistic start. +#[derive(Debug)] +pub enum PreferredVideoTransport { + Nvst(Box), + WebRtcFallback(NvstFallbackReason), +} + +#[derive(Debug)] +pub enum NvstFallbackReason { + NoNvstHandoff, + InvalidNvstHandoff(NvstConfigError), +} + +pub fn select_preferred_video_transport(context: &Value) -> PreferredVideoTransport { + match parse_nvst_video_handoff(context) { + Ok(Some(config)) => PreferredVideoTransport::Nvst(Box::new(config)), + Ok(None) => PreferredVideoTransport::WebRtcFallback(NvstFallbackReason::NoNvstHandoff), + Err(error) => { + PreferredVideoTransport::WebRtcFallback(NvstFallbackReason::InvalidNvstHandoff(error)) + } + } +} + +fn required_string<'a>( + object: &'a serde_json::Map, + field: &'static str, +) -> Result<&'a str, NvstConfigError> { + let value = object + .get(field) + .ok_or(NvstConfigError::MissingField(field))?; + value.as_str().ok_or(NvstConfigError::InvalidFieldType { + field, + expected: "string", + }) +} + +fn optional_string<'a>( + object: &'a serde_json::Map, + field: &'static str, +) -> Result, NvstConfigError> { + match object.get(field) { + None | Some(Value::Null) => Ok(None), + Some(value) => value + .as_str() + .map(Some) + .ok_or(NvstConfigError::InvalidFieldType { + field, + expected: "string", + }), + } +} + +fn required_u16( + object: &serde_json::Map, + field: &'static str, +) -> Result { + let value = required_u64(object, field)?; + u16::try_from(value).map_err(|_| NvstConfigError::OutOfRange { field }) +} + +fn required_u64( + object: &serde_json::Map, + field: &'static str, +) -> Result { + let value = object + .get(field) + .ok_or(NvstConfigError::MissingField(field))?; + value.as_u64().ok_or(NvstConfigError::InvalidFieldType { + field, + expected: "unsigned integer", + }) +} + +fn optional_u64( + object: &serde_json::Map, + field: &'static str, +) -> Result, NvstConfigError> { + match object.get(field) { + None | Some(Value::Null) => Ok(None), + Some(value) => value + .as_u64() + .map(Some) + .ok_or(NvstConfigError::InvalidFieldType { + field, + expected: "unsigned integer", + }), + } +} + +fn optional_u16( + object: &serde_json::Map, + field: &'static str, +) -> Result, NvstConfigError> { + optional_u64(object, field)?.map_or(Ok(None), |value| { + u16::try_from(value) + .map(Some) + .map_err(|_| NvstConfigError::OutOfRange { field }) + }) +} + +fn optional_u8( + object: &serde_json::Map, + field: &'static str, +) -> Result, NvstConfigError> { + optional_u64(object, field)?.map_or(Ok(None), |value| { + u8::try_from(value) + .map(Some) + .map_err(|_| NvstConfigError::OutOfRange { field }) + }) +} + +fn optional_u32( + object: &serde_json::Map, + field: &'static str, +) -> Result, NvstConfigError> { + optional_u64(object, field)?.map_or(Ok(None), |value| { + u32::try_from(value) + .map(Some) + .map_err(|_| NvstConfigError::OutOfRange { field }) + }) +} + +fn optional_usize( + object: &serde_json::Map, + field: &'static str, +) -> Result, NvstConfigError> { + optional_u64(object, field)?.map_or(Ok(None), |value| { + usize::try_from(value) + .map(Some) + .map_err(|_| NvstConfigError::OutOfRange { field }) + }) +} + +fn decode_fixed_hex( + value: &str, + error: NvstConfigError, +) -> Result<[u8; N], NvstConfigError> { + if value.len() != N * 2 { + return Err(error); + } + let mut decoded = [0_u8; N]; + for (index, output) in decoded.iter_mut().enumerate() { + let offset = index * 2; + let pair = match value.get(offset..offset + 2) { + Some(pair) => pair, + None => return Err(error), + }; + *output = match u8::from_str_radix(pair, 16) { + Ok(byte) => byte, + Err(_) => return Err(error), + }; + } + Ok(decoded) +} + +/// GFN packs the keyId into the low 4 bytes of a 12-byte salt; libsrtp right-pads the +/// AES-CM master salt to 14 bytes. Accept the 12-byte probe form and right-pad with zeros. +fn decode_salt_hex( + value: &str, + error: NvstConfigError, +) -> Result<[u8; N], NvstConfigError> { + if value.len() % 2 != 0 || value.len() > N * 2 { + return Err(error); + } + let mut decoded = [0_u8; N]; + for (index, output) in decoded.iter_mut().take(value.len() / 2).enumerate() { + let offset = index * 2; + let pair = match value.get(offset..offset + 2) { + Some(pair) => pair, + None => return Err(error), + }; + *output = match u8::from_str_radix(pair, 16) { + Ok(byte) => byte, + Err(_) => return Err(error), + }; + } + Ok(decoded) +} + +fn is_unicast_peer(ip: IpAddr) -> bool { + match ip { + IpAddr::V4(ip) => !ip.is_unspecified() && !ip.is_multicast() && ip != Ipv4Addr::BROADCAST, + IpAddr::V6(ip) => !ip.is_unspecified() && !ip.is_multicast() && ip != Ipv6Addr::UNSPECIFIED, + } +} + +/// A received encoded video access unit ready for a decoder queue. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EncodedVideoAccessUnit { + pub codec: NvstVideoCodec, + pub timestamp: u32, + pub frame_index: u32, + pub first_stream_packet_index: u32, + pub keyframe: bool, + pub contiguous: bool, + pub bytes: Vec, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum NvstReceiverState { + Running, + Paused, + RecoveryRequired, + Stopped, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum NvstDropReason { + UnexpectedSource { + expected: SocketAddr, + actual: SocketAddr, + }, + Paused, + Stopped, + RecoveryRequired, + MalformedRtp(RtpParseError), + AuthenticationFailed, + ReplayRejected, + UnexpectedPayloadType { + expected: u8, + actual: u8, + }, + UnexpectedSsrc { + expected: u32, + actual: u32, + }, + StaleRtpPacket { + index: u64, + }, + DuplicateRtpPacket { + index: u64, + }, + Unsupported(NvstUnsupportedFeature), + AwaitingStartOfFrame, + FrameDiscontinuity, + MissingAnnexBStartCode, + InvalidLastPacketPayloadLength { + reported: usize, + frame_header_size: usize, + available: usize, + }, + AccessUnitTooLarge { + limit: usize, + }, + MalformedRedAudio, + MediaConsumerBackpressured, + MediaConsumerClosed, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum RtpParseError { + TooShort, + InvalidVersion, + InvalidCsrcLength, + InvalidExtensionLength, + MissingAuthenticationTag, + InvalidPadding, + MissingNvVideoHeader, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum NvstRecovery { + PacketGap { + first_missing_index: u64, + last_missing_index: u64, + }, + Timeout { + idle_for: Duration, + }, +} + +/// All receive decisions are explicit so callers can collect operational metrics without +/// treating malformed network traffic as a fatal thread error. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum NvstReceiveEvent { + Frame(EncodedVideoAccessUnit), + TransportReady(&'static str), + InputReady(u16), + InputUnavailable(String), + Cursor(Vec), + Dropped(NvstDropReason), + RecoveryNeeded(NvstRecovery), + Lifecycle(NvstReceiverState), +} + +#[derive(Debug, Clone, Copy)] +struct RtpHeader { + payload_type: u8, + sequence_number: u16, + timestamp: u32, + ssrc: u32, + payload_offset: usize, + has_padding: bool, + gs_video_header: Option<[u8; NV_VIDEO_PACKET_LEN]>, +} + +impl RtpHeader { + fn parse(packet: &[u8]) -> Result { + if packet.len() < RTP_FIXED_HEADER_LEN { + return Err(RtpParseError::TooShort); + } + let first = packet[0]; + if first >> 6 != 2 { + return Err(RtpParseError::InvalidVersion); + } + let csrc_count = usize::from(first & 0x0f); + let mut payload_offset = RTP_FIXED_HEADER_LEN + .checked_add(csrc_count.saturating_mul(4)) + .ok_or(RtpParseError::InvalidCsrcLength)?; + if packet.len() < payload_offset { + return Err(RtpParseError::InvalidCsrcLength); + } + let mut gs_video_header = None; + if first & 0x10 != 0 { + if packet.len() < payload_offset + 4 { + return Err(RtpParseError::InvalidExtensionLength); + } + let profile = u16::from_be_bytes([packet[payload_offset], packet[payload_offset + 1]]); + let words = + u16::from_be_bytes([packet[payload_offset + 2], packet[payload_offset + 3]]); + let extension_len = usize::from(words) + .checked_mul(4) + .and_then(|length| length.checked_add(4)) + .ok_or(RtpParseError::InvalidExtensionLength)?; + let extension_end = payload_offset + .checked_add(extension_len) + .ok_or(RtpParseError::InvalidExtensionLength)?; + if packet.len() < extension_end { + return Err(RtpParseError::InvalidExtensionLength); + } + if profile == GS_VIDEO_EXTENSION_PROFILE { + if usize::from(words) * 4 != NV_VIDEO_PACKET_LEN { + return Err(RtpParseError::InvalidExtensionLength); + } + let body = &packet[payload_offset + 4..extension_end]; + gs_video_header = Some( + body[..NV_VIDEO_PACKET_LEN] + .try_into() + .expect("length checked"), + ); + } + payload_offset = extension_end; + } + Ok(Self { + payload_type: packet[1] & 0x7f, + sequence_number: u16::from_be_bytes([packet[2], packet[3]]), + timestamp: u32::from_be_bytes([packet[4], packet[5], packet[6], packet[7]]), + ssrc: u32::from_be_bytes([packet[8], packet[9], packet[10], packet[11]]), + payload_offset, + has_padding: first & 0x20 != 0, + gs_video_header, + }) + } + + fn payload<'a>(&self, packet: &'a [u8]) -> Result<&'a [u8], RtpParseError> { + if packet.len() < self.payload_offset { + return Err(RtpParseError::TooShort); + } + let mut end = packet.len(); + if self.has_padding { + let padding = usize::from(*packet.last().ok_or(RtpParseError::InvalidPadding)?); + if padding == 0 || padding > end.saturating_sub(self.payload_offset) { + return Err(RtpParseError::InvalidPadding); + } + end -= padding; + } + Ok(&packet[self.payload_offset..end]) + } +} + +#[derive(Debug)] +struct RtpPacket { + index: u64, + header: RtpHeader, + plaintext: Vec, +} + +#[derive(Clone)] +struct SrtpReceiver { + cipher: SrtpCipher, + replay: ReplayWindow, +} + +#[derive(Clone)] +enum SrtpCipher { + AeadAes128Gcm { + encryption_key: [u8; 16], + session_salt: [u8; 12], + authentication_tag_len: usize, + }, + AeadAes256Gcm { + encryption_key: [u8; 32], + session_salt: [u8; 12], + authentication_tag_len: usize, + }, + AesCm128HmacSha1 { + encryption_key: [u8; 16], + authentication_key: [u8; 20], + session_salt: [u8; 14], + authentication_tag_len: usize, + }, + AesCm256HmacSha1 { + encryption_key: [u8; 32], + authentication_key: [u8; 20], + session_salt: [u8; 14], + authentication_tag_len: usize, + }, +} + +impl SrtpReceiver { + fn from_material(material: &NvstSrtpMaterial) -> Self { + let cipher = match material { + NvstSrtpMaterial::AeadAes128Gcm { + master_key, + master_salt, + authentication_tag_len, + } => SrtpCipher::AeadAes128Gcm { + encryption_key: derive_aes128_cm_key::<16>( + master_key, + master_salt, + GFN_SRTP_KEY_LABEL, + ), + session_salt: derive_aes128_cm_key::<12>( + master_key, + master_salt, + GFN_SRTP_SALT_LABEL, + ), + authentication_tag_len: *authentication_tag_len, + }, + NvstSrtpMaterial::AeadAes256Gcm { + master_key, + master_salt, + authentication_tag_len, + } => SrtpCipher::AeadAes256Gcm { + encryption_key: derive_aes_cm_key::<32>( + master_key, + master_salt, + GFN_SRTP_KEY_LABEL, + ), + session_salt: derive_aes_cm_key::<12>(master_key, master_salt, GFN_SRTP_SALT_LABEL), + authentication_tag_len: *authentication_tag_len, + }, + NvstSrtpMaterial::AesCm128HmacSha1 { + master_key, + master_salt, + authentication_tag_len, + } => SrtpCipher::AesCm128HmacSha1 { + encryption_key: derive_aes128_cm_key::<16>(master_key, master_salt, 0x00), + authentication_key: derive_aes128_cm_key::<20>(master_key, master_salt, 0x01), + session_salt: derive_aes128_cm_key::<14>(master_key, master_salt, 0x02), + authentication_tag_len: *authentication_tag_len, + }, + NvstSrtpMaterial::AesCm256HmacSha1 { + master_key, + master_salt, + authentication_tag_len, + } => SrtpCipher::AesCm256HmacSha1 { + encryption_key: derive_aes_cm_key::<32>(master_key, master_salt, 0x00), + authentication_key: derive_aes_cm_key::<20>(master_key, master_salt, 0x01), + session_salt: derive_aes_cm_key::<14>(master_key, master_salt, 0x02), + authentication_tag_len: *authentication_tag_len, + }, + }; + Self { + cipher, + replay: ReplayWindow::default(), + } + } + + fn unprotect(&mut self, datagram: &[u8]) -> Result { + let header = RtpHeader::parse(datagram).map_err(NvstDropReason::MalformedRtp)?; + let packet_index = self.replay.guess_packet_index(header.sequence_number)?; + let roc = u32::try_from(packet_index >> 16).map_err(|_| NvstDropReason::ReplayRejected)?; + let plaintext = match &self.cipher { + SrtpCipher::AeadAes128Gcm { + encryption_key, + session_salt, + authentication_tag_len, + } => unprotect_aes_gcm( + datagram, + header, + roc, + encryption_key, + session_salt, + *authentication_tag_len, + )?, + SrtpCipher::AeadAes256Gcm { + encryption_key, + session_salt, + authentication_tag_len, + } => unprotect_aes_gcm( + datagram, + header, + roc, + encryption_key, + session_salt, + *authentication_tag_len, + )?, + SrtpCipher::AesCm128HmacSha1 { + encryption_key, + authentication_key, + session_salt, + authentication_tag_len, + } => unprotect_aes_cm_hmac_sha1( + datagram, + header, + packet_index, + roc, + encryption_key, + authentication_key, + session_salt, + *authentication_tag_len, + )?, + SrtpCipher::AesCm256HmacSha1 { + encryption_key, + authentication_key, + session_salt, + authentication_tag_len, + } => unprotect_aes_cm_hmac_sha1( + datagram, + header, + packet_index, + roc, + encryption_key, + authentication_key, + session_salt, + *authentication_tag_len, + )?, + }; + self.replay.check(packet_index)?; + header + .payload(&plaintext) + .map_err(NvstDropReason::MalformedRtp)?; + self.replay.commit(packet_index); + Ok(RtpPacket { + index: packet_index, + header, + plaintext, + }) + } +} + +/// AES-GCM with a truncated tag. `aes-gcm` 0.10 only seals 12–16 byte tags; +/// NVIDIA's Mjolnir path uses the 8-byte `aes_gcm_*_8_auth` libsrtp policy. +fn unprotect_aes_gcm( + datagram: &[u8], + header: RtpHeader, + roc: u32, + encryption_key: &[u8], + session_salt: &[u8; 12], + tag_len: usize, +) -> Result, NvstDropReason> { + let ciphertext_end = + datagram + .len() + .checked_sub(tag_len) + .ok_or(NvstDropReason::MalformedRtp( + RtpParseError::MissingAuthenticationTag, + ))?; + if ciphertext_end < header.payload_offset { + return Err(NvstDropReason::MalformedRtp( + RtpParseError::MissingAuthenticationTag, + )); + } + let iv = srtp_gcm_iv(*session_salt, header.ssrc, roc, header.sequence_number); + let aad = &datagram[..header.payload_offset]; + let ciphertext = &datagram[header.payload_offset..ciphertext_end]; + let received_tag = &datagram[ciphertext_end..]; + let (expected_tag, mut ctr) = aes_gcm_tag_and_ctr(encryption_key, &iv, aad, ciphertext); + if expected_tag[..tag_len].ct_eq(received_tag).unwrap_u8() != 1 { + return Err(NvstDropReason::AuthenticationFailed); + } + let mut plaintext = datagram[..ciphertext_end].to_vec(); + ctr.apply_keystream(&mut plaintext[header.payload_offset..]); + Ok(plaintext) +} + +enum GcmCtr { + Aes128(Box>), + Aes256(Box>), +} + +impl GcmCtr { + fn apply_keystream(&mut self, buffer: &mut [u8]) { + match self { + Self::Aes128(cipher) => cipher.apply_keystream(buffer), + Self::Aes256(cipher) => cipher.apply_keystream(buffer), + } + } +} + +fn aes_gcm_tag_and_ctr( + encryption_key: &[u8], + iv: &[u8; 12], + aad: &[u8], + ciphertext: &[u8], +) -> ([u8; 16], GcmCtr) { + let mut j0 = [0_u8; 16]; + j0[..12].copy_from_slice(iv); + j0[15] = 1; + let mut hash_key = [0_u8; 16]; + let mut tag_mask = [0_u8; 16]; + let ctr = match encryption_key.len() { + 16 => { + let key: &[u8; 16] = encryption_key.try_into().expect("16-byte GCM key"); + let aes = ::new(key.into()); + aes.encrypt_block((&mut hash_key).into()); + let mut ctr = Ctr32BE::::new(key.into(), (&j0).into()); + ctr.apply_keystream(&mut tag_mask); + GcmCtr::Aes128(Box::new(ctr)) + } + 32 => { + let key: &[u8; 32] = encryption_key.try_into().expect("32-byte GCM key"); + let aes = ::new(key.into()); + aes.encrypt_block((&mut hash_key).into()); + let mut ctr = Ctr32BE::::new(key.into(), (&j0).into()); + ctr.apply_keystream(&mut tag_mask); + GcmCtr::Aes256(Box::new(ctr)) + } + _ => unreachable!("AES-GCM key is 16 or 32 bytes"), + }; + let mut hasher = ::new((&hash_key).into()); + hasher.update_padded(aad); + hasher.update_padded(ciphertext); + let mut len_block = ghash::Block::default(); + len_block[..8].copy_from_slice(&((aad.len() as u64) * 8).to_be_bytes()); + len_block[8..].copy_from_slice(&((ciphertext.len() as u64) * 8).to_be_bytes()); + hasher.update(&[len_block]); + let mut tag = hasher.finalize(); + for (byte, mask) in tag.iter_mut().zip(tag_mask) { + *byte ^= mask; + } + let mut expected = [0_u8; 16]; + expected.copy_from_slice(&tag); + (expected, ctr) +} + +#[cfg(test)] +fn protect_aes_gcm( + packet: &mut Vec, + payload_offset: usize, + encryption_key: &[u8], + iv: &[u8; 12], + tag_len: usize, +) { + let aad_owned = packet[..payload_offset].to_vec(); + let (_, mut ctr) = aes_gcm_tag_and_ctr(encryption_key, iv, &aad_owned, &[]); + ctr.apply_keystream(&mut packet[payload_offset..]); + let (tag, _) = aes_gcm_tag_and_ctr(encryption_key, iv, &aad_owned, &packet[payload_offset..]); + packet.extend_from_slice(&tag[..tag_len]); +} + +#[allow(clippy::too_many_arguments)] +fn unprotect_aes_cm_hmac_sha1( + datagram: &[u8], + header: RtpHeader, + packet_index: u64, + roc: u32, + encryption_key: &[u8], + authentication_key: &[u8; 20], + session_salt: &[u8; 14], + authentication_tag_len: usize, +) -> Result, NvstDropReason> { + let authenticated_len = + datagram + .len() + .checked_sub(authentication_tag_len) + .ok_or(NvstDropReason::MalformedRtp( + RtpParseError::MissingAuthenticationTag, + ))?; + if authenticated_len < header.payload_offset { + return Err(NvstDropReason::MalformedRtp( + RtpParseError::MissingAuthenticationTag, + )); + } + let mut mac = + HmacSha1::new_from_slice(authentication_key).expect("HMAC-SHA1 accepts a fixed-size key"); + mac.update(&datagram[..authenticated_len]); + mac.update(&roc.to_be_bytes()); + let expected_tag = mac.finalize().into_bytes(); + let received_tag = &datagram[authenticated_len..]; + if expected_tag[..authentication_tag_len] + .ct_eq(received_tag) + .unwrap_u8() + != 1 + { + return Err(NvstDropReason::AuthenticationFailed); + } + let mut plaintext = datagram[..authenticated_len].to_vec(); + let iv = srtp_aes_cm_iv(session_salt, header.ssrc, packet_index); + match encryption_key.len() { + 16 => { + let key: &[u8; 16] = encryption_key.try_into().expect("16-byte AES-CM key"); + let mut cipher = Aes128Ctr::new(key.into(), (&iv).into()); + cipher.apply_keystream(&mut plaintext[header.payload_offset..]); + } + 32 => { + let key: &[u8; 32] = encryption_key.try_into().expect("32-byte AES-CM key"); + let mut cipher = Aes256Ctr::new(key.into(), (&iv).into()); + cipher.apply_keystream(&mut plaintext[header.payload_offset..]); + } + _ => unreachable!("AES-CM key is 16 or 32 bytes"), + } + Ok(plaintext) +} + +fn derive_aes_cm_key( + master_key: &[u8; 32], + master_salt: &[u8], + label: u8, +) -> [u8; N] { + let mut iv = [0_u8; 16]; + iv[..master_salt.len()].copy_from_slice(master_salt); + // RFC 3711 key_id = label * 2^48, then x = master_salt * 2^16 XOR key_id * 2^16. + iv[7] ^= label; + let mut output = [0_u8; N]; + let mut cipher = Aes256Ctr::new(master_key.into(), (&iv).into()); + cipher.apply_keystream(&mut output); + output +} + +fn derive_aes128_cm_key( + master_key: &[u8; 16], + master_salt: &[u8], + label: u8, +) -> [u8; N] { + let mut iv = [0_u8; 16]; + iv[..master_salt.len()].copy_from_slice(master_salt); + iv[7] ^= label; + let mut output = [0_u8; N]; + let mut cipher = Aes128Ctr::new(master_key.into(), (&iv).into()); + cipher.apply_keystream(&mut output); + output +} + +fn srtp_aes_cm_iv(session_salt: &[u8; 14], ssrc: u32, packet_index: u64) -> [u8; 16] { + let mut iv = [0_u8; 16]; + iv[..14].copy_from_slice(session_salt); + for (target, source) in iv[4..8].iter_mut().zip(ssrc.to_be_bytes()) { + *target ^= source; + } + let index_bytes = packet_index.to_be_bytes(); + for (target, source) in iv[8..14].iter_mut().zip(&index_bytes[2..]) { + *target ^= source; + } + iv +} + +fn srtp_gcm_iv(session_salt: [u8; 12], ssrc: u32, roc: u32, sequence_number: u16) -> [u8; 12] { + let mut iv = session_salt; + for (target, source) in iv[2..6].iter_mut().zip(ssrc.to_be_bytes()) { + *target ^= source; + } + for (target, source) in iv[6..10].iter_mut().zip(roc.to_be_bytes()) { + *target ^= source; + } + for (target, source) in iv[10..].iter_mut().zip(sequence_number.to_be_bytes()) { + *target ^= source; + } + iv +} + +/// RFC 7714 §9.2 SRTCP GCM IV: salt XOR (SSRC at bytes 2..6, SRTCP index at 6..10). +fn srtcp_gcm_iv(session_salt: [u8; 12], ssrc: u32, srtcp_index: u32) -> [u8; 12] { + let mut iv = session_salt; + for (target, source) in iv[2..6].iter_mut().zip(ssrc.to_be_bytes()) { + *target ^= source; + } + for (target, source) in iv[6..10].iter_mut().zip(srtcp_index.to_be_bytes()) { + *target ^= source; + } + iv +} + +/// Builds and SRTCP-protects an RTCP Receiver Report carrying one report block. +/// The raw Mjolnir transport keeps the fixed eight-byte ONOW receiver header clear, +/// sets the report payload E/S bit before encryption, and appends the eight-byte GCM +/// tag before E|index. AAD is the clear header followed by the first eight ciphertext +/// bytes; the sender SSRC in that clear header selects the nonce context. +#[allow(clippy::too_many_arguments)] +fn protect_srtcp_receiver_report_gcm( + report: RtcpReportBlock, + srtcp_index: u32, + encryption_key: &[u8], + session_salt: &[u8; 12], + tag_len: usize, +) -> Vec { + let mut packet = Vec::with_capacity(32 + 4 + tag_len); + packet.push(0x81); // V=2, P=0, RC=1 (one report block) + packet.push(201); // PT=RR + packet.extend_from_slice(&7_u16.to_be_bytes()); // length: 8 words - 1 + packet.extend_from_slice(&RTCP_SENDER_SSRC.to_be_bytes()); + packet.extend_from_slice(&report.media_ssrc.to_be_bytes()); + packet.push(report.fraction_lost); + packet.extend_from_slice(&(report.cumulative_lost as u32).to_be_bytes()[1..]); + packet.extend_from_slice(&report.highest_sequence.to_be_bytes()); + packet.extend_from_slice(&report.jitter.to_be_bytes()); + packet.extend_from_slice(&0_u32.to_be_bytes()); // LSR + packet.extend_from_slice(&0_u32.to_be_bytes()); // DLSR + + let e_index = SRTCP_ENCRYPTED_FLAG | (srtcp_index & !SRTCP_ENCRYPTED_FLAG); + let iv = srtcp_gcm_iv(*session_salt, RTCP_SENDER_SSRC, srtcp_index); + packet[8] |= 0x80; + let (_, mut ctr) = aes_gcm_tag_and_ctr(encryption_key, &iv, &[], &[]); + ctr.apply_keystream(&mut packet[8..]); + let mut aad = packet[..8].to_vec(); + aad.extend_from_slice(&packet[8..16]); + let (tag, _) = aes_gcm_tag_and_ctr(encryption_key, &iv, &aad, &packet[8..]); + packet.extend_from_slice(&tag[..tag_len]); + packet.extend_from_slice(&e_index.to_be_bytes()); + packet +} + +/// Builds a plain (unencrypted) RTCP Receiver Report (RFC 3550 §6.4.1) with one +/// report block for `media_ssrc`. Sent over the `rtcp1` SCTP data channel, which +/// is already encrypted by DTLS, so no SRTCP layer is applied. +fn build_rtcp_receiver_report(sender_ssrc: u32, report: RtcpReportBlock) -> Vec { + let mut packet = Vec::with_capacity(32); + packet.push(0x81); // V=2, P=0, RC=1 (one report block) + packet.push(201); // PT=RR + packet.extend_from_slice(&7_u16.to_be_bytes()); // length: 8 words - 1 + packet.extend_from_slice(&sender_ssrc.to_be_bytes()); + packet.extend_from_slice(&report.media_ssrc.to_be_bytes()); + packet.push(report.fraction_lost); + packet.extend_from_slice(&(report.cumulative_lost as u32).to_be_bytes()[1..]); + packet.extend_from_slice(&report.highest_sequence.to_be_bytes()); + packet.extend_from_slice(&report.jitter.to_be_bytes()); + packet.extend_from_slice(&0_u32.to_be_bytes()); // LSR + packet.extend_from_slice(&0_u32.to_be_bytes()); // DLSR + packet +} + +/// Builds a plain RTCP Picture Loss Indication (RFC 4585 §6.3.1) asking the +/// sender of `media_ssrc` for a fresh keyframe. +fn build_rtcp_pli(sender_ssrc: u32, media_ssrc: u32) -> Vec { + let mut packet = Vec::with_capacity(12); + packet.push(0x81); // V=2, P=0, FMT=1 (PLI) + packet.push(206); // PT=PSFB (payload-specific feedback) + packet.extend_from_slice(&2_u16.to_be_bytes()); // length: 3 words - 1 + packet.extend_from_slice(&sender_ssrc.to_be_bytes()); + packet.extend_from_slice(&media_ssrc.to_be_bytes()); + packet +} + +/// Builds an RFC 4585 §6.2.1 generic NACK for a continuous range of missing +/// extended RTP sequence numbers. Each FCI entry represents its PID plus up to +/// 16 following packets in the bitmask; the packet is bounded to avoid turning +/// a malicious sequence jump into an unbounded control message. +fn build_rtcp_nack( + sender_ssrc: u32, + media_ssrc: u32, + first_missing_index: u64, + last_missing_index: u64, +) -> Vec { + let mut entries = Vec::with_capacity(MAX_NACK_FCI_ENTRIES); + let mut current = first_missing_index; + let effective_last = last_missing_index + .min(first_missing_index.saturating_add((MAX_NACK_PACKET_COUNT.saturating_sub(1)) as u64)); + while current <= effective_last && entries.len() < MAX_NACK_FCI_ENTRIES { + let pid = current as u16; + let represented_following = (effective_last - current).min(16) as u16; + let blp = if represented_following == 16 { + u16::MAX + } else { + ((1_u32 << represented_following) - 1) as u16 + }; + entries.push((pid, blp)); + current = current.saturating_add(17); + } + + let mut packet = Vec::with_capacity(12 + entries.len() * 4); + packet.push(0x81); // V=2, P=0, FMT=1 (generic NACK) + packet.push(205); // PT=RTPFB (transport-layer feedback) + packet.extend_from_slice(&(2_u16 + entries.len() as u16).to_be_bytes()); + packet.extend_from_slice(&sender_ssrc.to_be_bytes()); + packet.extend_from_slice(&media_ssrc.to_be_bytes()); + for (pid, blp) in entries { + packet.extend_from_slice(&pid.to_be_bytes()); + packet.extend_from_slice(&blp.to_be_bytes()); + } + packet +} + +#[derive(Clone, Default)] +struct ReplayWindow { + highest_index: Option, + seen: u64, +} + +impl ReplayWindow { + fn guess_packet_index(&self, sequence_number: u16) -> Result { + let Some(highest_index) = self.highest_index else { + return Ok(u64::from(sequence_number)); + }; + let roc = highest_index >> 16; + let highest_sequence = (highest_index & 0xffff) as u16; + let delta = i32::from(sequence_number) - i32::from(highest_sequence); + let guessed_roc = if delta < -32_768 { + roc.checked_add(1).ok_or(NvstDropReason::ReplayRejected)? + } else if delta > 32_768 { + roc.checked_sub(1).ok_or(NvstDropReason::ReplayRejected)? + } else { + roc + }; + Ok((guessed_roc << 16) | u64::from(sequence_number)) + } + + fn check(&self, index: u64) -> Result<(), NvstDropReason> { + let Some(highest_index) = self.highest_index else { + return Ok(()); + }; + if index > highest_index { + return Ok(()); + } + let age = highest_index - index; + if age >= 64 || self.seen & (1_u64 << age) != 0 { + return Err(NvstDropReason::ReplayRejected); + } + Ok(()) + } + + fn commit(&mut self, index: u64) { + match self.highest_index { + None => { + self.highest_index = Some(index); + self.seen = 1; + } + Some(highest_index) if index > highest_index => { + let advance = index - highest_index; + self.seen = if advance >= 64 { + 1 + } else { + (self.seen << advance) | 1 + }; + self.highest_index = Some(index); + } + Some(highest_index) => { + self.seen |= 1_u64 << (highest_index - index); + } + } + } +} + +#[derive(Debug, Clone, Copy)] +struct NvVideoPacket { + stream_packet_index: u32, + frame_index: u32, + flags: u8, + fec_current_block: u8, + fec_last_block: u8, + is_fec: bool, +} + +impl NvVideoPacket { + /// Reads the Mjolnir video metadata from the `0x4753` ("GS") RTP extension: + /// a 16-byte little-endian block holding the stream packet index, frame index, + /// the packet-type nibble (picture data / SOF / EOF), and FEC group + /// coordinates. The RTP payload starts with the GameStream frame header on an + /// SOF packet and otherwise continues the H.264 access-unit data directly. + fn parse<'a>(header: &RtpHeader, payload: &'a [u8]) -> Result<(Self, &'a [u8]), RtpParseError> { + let Some(extension) = header.gs_video_header else { + return Err(RtpParseError::MissingNvVideoHeader); + }; + let packet_word = u32::from_le_bytes(extension[0..4].try_into().expect("length checked")); + let flags_word = u32::from_le_bytes(extension[8..12].try_into().expect("length checked")); + let fec_word = u32::from_le_bytes(extension[12..16].try_into().expect("length checked")); + let multi_fec_blocks = extension[11]; + let fec_percentage = (fec_word >> 4) & 0xff; + let fec_index = (fec_word >> 12) & 0x3ff; + let fec_source_packets = (fec_word >> 22) & 0x3ff; + let packet = Self { + stream_packet_index: (packet_word >> 8) & STREAM_PACKET_INDEX_MASK, + frame_index: u32::from_le_bytes(extension[4..8].try_into().expect("length checked")), + flags: (flags_word & 0x0f) as u8, + fec_current_block: (multi_fec_blocks >> 4) & 0x03, + fec_last_block: (multi_fec_blocks >> 6) & 0x03, + is_fec: fec_percentage != 0 && fec_index >= fec_source_packets, + }; + Ok((packet, payload)) + } + + fn is_start_of_frame(self) -> bool { + self.flags & FLAG_SOF != 0 && self.fec_current_block == 0 + } + + fn is_end_of_frame(self) -> bool { + self.flags & FLAG_EOF != 0 && self.fec_current_block == self.fec_last_block + } +} + +struct VideoAccessUnitAssembler { + codec: NvstVideoCodec, + current_frame: Option, + first_stream_packet_index: Option, + keyframe_hint: bool, + last_packet_payload_length: Option, + expected_access_unit_length: Option, + invalid_av1_length_logged: bool, + first_start_payload_logged: bool, + first_access_unit_logged: bool, + bytes: Vec, + max_access_unit_bytes: usize, +} + +impl VideoAccessUnitAssembler { + fn new(codec: NvstVideoCodec, max_access_unit_bytes: usize) -> Self { + Self { + codec, + current_frame: None, + first_stream_packet_index: None, + keyframe_hint: false, + last_packet_payload_length: None, + expected_access_unit_length: None, + invalid_av1_length_logged: false, + first_start_payload_logged: false, + first_access_unit_logged: false, + bytes: Vec::new(), + max_access_unit_bytes, + } + } + + fn reset(&mut self) { + self.current_frame = None; + self.first_stream_packet_index = None; + self.keyframe_hint = false; + self.last_packet_payload_length = None; + self.expected_access_unit_length = None; + self.bytes.clear(); + } + + fn push( + &mut self, + header: NvVideoPacket, + timestamp: u32, + payload: &[u8], + ) -> Result, NvstDropReason> { + if header.is_fec { + return Err(NvstDropReason::Unsupported( + NvstUnsupportedFeature::FecRepair, + )); + } + let mut frame_header_size = 0; + let mut picture_payload = payload; + if header.is_start_of_frame() { + self.reset(); + self.keyframe_hint = payload.get(3).is_some_and(|value| *value == 2); + picture_payload = video_picture_payload(self.codec, payload) + .ok_or(NvstDropReason::MissingAnnexBStartCode)?; + frame_header_size = payload.len() - picture_payload.len(); + if !self.first_start_payload_logged { + self.first_start_payload_logged = true; + eprintln!( + "NVST first {} start payload: frame={} bytes={} frameHeader={} raw={}", + self.codec.label(), + header.frame_index, + payload.len(), + frame_header_size, + diagnostic_hex(payload, 64), + ); + } + if self.codec == NvstVideoCodec::Av1 { + match payload.first() { + Some(0x01) => { + self.last_packet_payload_length = payload + .get(4..6) + .map(|length| usize::from(u16::from_le_bytes([length[0], length[1]]))); + } + Some(0x81) => { + self.expected_access_unit_length = payload.get(16..20).map(|length| { + u32::from_le_bytes([length[0], length[1], length[2], length[3]]) + as usize + }); + } + _ => {} + } + } + self.current_frame = Some(header.frame_index); + self.first_stream_packet_index = Some(header.stream_packet_index); + } else if self.current_frame != Some(header.frame_index) { + self.reset(); + return Err(NvstDropReason::AwaitingStartOfFrame); + } + + // GFN pads the final packet to its FEC block size. AVC/HEVC Annex B + // decoders tolerate those trailing zeroes, while AV1 decoders require + // exact access units. The short header's bytes 4..6 describe the final + // packet; the cloud 0x81 header instead advertises the complete AV1 + // access-unit size in bytes 16..20 and is handled after assembly below. + if self.codec == NvstVideoCodec::Av1 + && header.is_end_of_frame() + && let Some(reported) = self.last_packet_payload_length + { + let exact_payload_length = reported.checked_sub(frame_header_size); + if let Some(exact_payload_length) = exact_payload_length + && exact_payload_length > 0 + && exact_payload_length <= picture_payload.len() + { + picture_payload = &picture_payload[..exact_payload_length]; + } else if !self.invalid_av1_length_logged { + self.invalid_av1_length_logged = true; + eprintln!( + "NVST AV1 final-packet length hint ignored: reported={reported} frameHeader={frame_header_size} available={}", + picture_payload.len() + ); + } + } + + let remaining = self.max_access_unit_bytes.saturating_sub(self.bytes.len()); + if picture_payload.len() > remaining { + self.reset(); + return Err(NvstDropReason::AccessUnitTooLarge { + limit: self.max_access_unit_bytes, + }); + } + self.bytes.extend_from_slice(picture_payload); + if !header.is_end_of_frame() { + return Ok(None); + } + + let mut bytes = std::mem::take(&mut self.bytes); + if self.codec == NvstVideoCodec::Av1 + && let Some(reported) = self.expected_access_unit_length + { + if reported > 0 && reported <= bytes.len() { + bytes.truncate(reported); + } else { + let available = bytes.len(); + self.reset(); + return Err(NvstDropReason::InvalidLastPacketPayloadLength { + reported, + frame_header_size, + available, + }); + } + } + strip_trailing_access_unit_delimiter(self.codec, &mut bytes); + if !self.first_access_unit_logged { + self.first_access_unit_logged = true; + eprintln!( + "NVST first {} access unit: frame={} bytes={} keyframeHint={} raw={}", + self.codec.label(), + header.frame_index, + bytes.len(), + self.keyframe_hint, + diagnostic_hex(&bytes, 64), + ); + } + self.current_frame = None; + let first_stream_packet_index = self + .first_stream_packet_index + .take() + .expect("start-of-frame initializes the packet index"); + Ok(Some(EncodedVideoAccessUnit { + codec: self.codec, + timestamp, + frame_index: header.frame_index, + first_stream_packet_index, + keyframe: video_access_unit_is_keyframe(self.codec, &bytes, self.keyframe_hint), + contiguous: true, + bytes, + })) + } +} + +fn strip_trailing_access_unit_delimiter(codec: NvstVideoCodec, bytes: &mut Vec) { + if codec == NvstVideoCodec::Av1 { + return; + } + let mut offset = 0; + let mut last_nal = None; + while let Some((start, prefix_len)) = find_annex_b_start_code(&bytes[offset..]) { + let start = offset + start; + let nal_start = start + prefix_len; + last_nal = Some((start, nal_start)); + offset = nal_start + 1; + } + if let Some((start, nal_start)) = last_nal + && bytes.get(nal_start).is_some_and(|header| match codec { + NvstVideoCodec::H264 => header & 0x1f == 9, + NvstVideoCodec::H265 => (header >> 1) & 0x3f == 35, + NvstVideoCodec::Av1 => false, + }) + { + bytes.truncate(start); + } +} + +fn video_picture_payload(codec: NvstVideoCodec, payload: &[u8]) -> Option<&[u8]> { + match codec { + NvstVideoCodec::H264 | NvstVideoCodec::H265 => { + let search_len = payload.len().min(MAX_GS_FRAME_HEADER_BYTES + 4); + let (offset, _) = find_annex_b_start_code(&payload[..search_len])?; + Some(&payload[offset..]) + } + NvstVideoCodec::Av1 => match payload.first()? { + // Unlike AVC/HEVC, AV1 has no Annex-B start code that can be used + // to discover this boundary. Use the GFN cloud header sizes seen + // on the same NVST video track instead of the similarly named but + // different consumer GameStream extended-header layout. + 0x01 => payload.get(GS_SHORT_FRAME_HEADER_BYTES..), + 0x81 => payload.get(GFN_EXTENDED_FRAME_HEADER_BYTES..), + _ => None, + }, + } +} + +fn video_access_unit_is_keyframe( + codec: NvstVideoCodec, + bytes: &[u8], + frame_header_hint: bool, +) -> bool { + if codec == NvstVideoCodec::Av1 { + return frame_header_hint; + } + let mut offset = 0; + while let Some((start, prefix_len)) = find_annex_b_start_code(&bytes[offset..]) { + let nal_start = offset + start + prefix_len; + if let Some(nal_header) = bytes.get(nal_start) + && match codec { + NvstVideoCodec::H264 => nal_header & 0x1f == 5, + NvstVideoCodec::H265 => matches!((nal_header >> 1) & 0x3f, 16..=21), + NvstVideoCodec::Av1 => false, + } + { + return true; + } + offset = nal_start; + } + false +} + +fn find_annex_b_start_code(bytes: &[u8]) -> Option<(usize, usize)> { + let four_byte = bytes.windows(4).position(|window| window == [0, 0, 0, 1]); + let three_byte = bytes.windows(3).position(|window| window == [0, 0, 1]); + match (four_byte, three_byte) { + (Some(four_byte), Some(three_byte)) if four_byte <= three_byte => Some((four_byte, 4)), + (_, Some(three_byte)) => Some((three_byte, 3)), + (Some(four_byte), None) => Some((four_byte, 4)), + (None, None) => None, + } +} + +struct RtpReorderBuffer { + next_index: Option, + packets: BTreeMap, + max_packets: usize, + gap_wait: Option<(u64, Instant)>, +} + +struct ReorderResult { + ready: Vec, + nack: Option<(u64, u64)>, + recovery: Option, + dropped: Option, +} + +impl RtpReorderBuffer { + fn new(max_packets: usize) -> Self { + Self { + next_index: None, + packets: BTreeMap::new(), + max_packets, + gap_wait: None, + } + } + + fn reset(&mut self) { + self.next_index = None; + self.packets.clear(); + self.gap_wait = None; + } + + fn push(&mut self, packet: RtpPacket, now: Instant) -> ReorderResult { + let index = packet.index; + let next_index = *self.next_index.get_or_insert(index); + if index < next_index { + return ReorderResult { + ready: Vec::new(), + nack: None, + recovery: None, + dropped: Some(NvstDropReason::StaleRtpPacket { index }), + }; + } + if self.packets.contains_key(&index) { + return ReorderResult { + ready: Vec::new(), + nack: None, + recovery: None, + dropped: Some(NvstDropReason::DuplicateRtpPacket { index }), + }; + } + + let buffered_before = self.packets.len(); + let mut recovery = None; + if buffered_before == 0 && index.saturating_sub(next_index) >= self.max_packets as u64 { + recovery = Some(NvstRecovery::PacketGap { + first_missing_index: next_index, + last_missing_index: index - 1, + }); + self.next_index = Some(index); + self.gap_wait = None; + } + self.packets.insert(index, packet); + let mut ready = Vec::new(); + let mut nack = None; + loop { + while let Some(next) = self.next_index { + let Some(packet) = self.packets.remove(&next) else { + break; + }; + ready.push(packet); + self.next_index = Some(next + 1); + } + + let Some((&first_available, _)) = self.packets.first_key_value() else { + self.gap_wait = None; + break; + }; + let expected = self.next_index.expect("next index remains initialized"); + debug_assert!(first_available > expected); + + // Only NACK sequence numbers that are genuinely absent. Using the + // newest packet index as the range end also requested every packet + // already held in the reorder map, causing duplicate retransmission + // bursts that competed with live video traffic. + nack = Some((expected, first_available.saturating_sub(1))); + let gap_started = match self.gap_wait { + Some((waiting_for, started)) if waiting_for == expected => started, + _ => { + self.gap_wait = Some((expected, now)); + now + } + }; + let gap_exceeded_window = first_available.saturating_sub(expected) + >= self.max_packets as u64 + || self.packets.len() >= self.max_packets; + let gap_timed_out = + now.saturating_duration_since(gap_started) >= MJOLNIR_REORDER_DEQUEUE_TIMEOUT; + if !gap_exceeded_window && !gap_timed_out { + break; + } + + recovery = Some(NvstRecovery::PacketGap { + first_missing_index: expected, + last_missing_index: first_available - 1, + }); + self.next_index = Some(first_available); + self.gap_wait = None; + nack = None; + } + ReorderResult { + ready, + nack, + recovery, + dropped: None, + } + } +} + +/// Sends periodic SRTCP Receiver Reports so the peer keeps the video flowing. +/// The official client maintains an SRTCP session (hook captures show the 0x03/0x05 +/// KDF labels); without any receiver feedback the server stops video after an +/// initial burst. Only the GCM profiles are supported (the active Mjolnir policy). +struct SrtcpSender { + encryption_key: SrtcpKey, + session_salt: [u8; 12], + tag_len: usize, + next_index: u32, + last_sent: Option, +} + +enum SrtcpKey { + Aes128([u8; 16]), + Aes256([u8; 32]), +} + +impl SrtcpKey { + fn as_bytes(&self) -> &[u8] { + match self { + Self::Aes128(key) => key, + Self::Aes256(key) => key, + } + } +} + +impl SrtcpSender { + fn from_material(material: &NvstSrtpMaterial) -> Option { + let (encryption_key, session_salt, tag_len) = match material { + NvstSrtpMaterial::AeadAes128Gcm { + master_key, + master_salt, + authentication_tag_len, + } => ( + SrtcpKey::Aes128(derive_aes128_cm_key::<16>( + master_key, + master_salt, + GFN_SRTCP_KEY_LABEL, + )), + derive_aes128_cm_key::<12>(master_key, master_salt, GFN_SRTCP_SALT_LABEL), + *authentication_tag_len, + ), + NvstSrtpMaterial::AeadAes256Gcm { + master_key, + master_salt, + authentication_tag_len, + } => ( + SrtcpKey::Aes256(derive_aes_cm_key::<32>( + master_key, + master_salt, + GFN_SRTCP_KEY_LABEL, + )), + derive_aes_cm_key::<12>(master_key, master_salt, GFN_SRTCP_SALT_LABEL), + *authentication_tag_len, + ), + _ => return None, + }; + Some(Self { + encryption_key, + session_salt, + tag_len, + next_index: 0, + last_sent: None, + }) + } + + /// Returns an SRTCP Receiver Report to send once per interval, after the media + /// SSRC is known. Returns `None` when it is not yet time or nothing to report on. + fn poll_receiver_report( + &mut self, + report: Option, + now: Instant, + ) -> Option> { + let report = report?; + if let Some(last) = self.last_sent + && now.duration_since(last) < SRTCP_RR_INTERVAL + { + return None; + } + self.last_sent = Some(now); + let index = self.next_index; + self.next_index = self.next_index.wrapping_add(1); + Some(protect_srtcp_receiver_report_gcm( + report, + index, + self.encryption_key.as_bytes(), + &self.session_salt, + self.tag_len, + )) + } +} + +/// Stateful, non-blocking NVST video receiver. `process_datagram` is deterministic and testable; +/// `spawn_nvst_udp_receiver` below is a thin UDP/thread wrapper for the production path. +pub struct NvstVideoReceiver { + config: NvstVideoConfig, + srtp: SrtpReceiver, + srtcp: Option, + reorder: RtpReorderBuffer, + assembler: VideoAccessUnitAssembler, + last_stream_packet_index: Option, + next_frame_contiguous: bool, + state: NvstReceiverState, + bound_ssrc: Option, + highest_sequence_received: u32, + authenticated_packets: u64, + fec_packets: u64, + frames_emitted: u64, + timeout_origin: Instant, + last_authenticated_packet: Option, +} + +impl NvstVideoReceiver { + pub fn new(config: NvstVideoConfig) -> Self { + let srtp = SrtpReceiver::from_material(&config.srtp); + let srtcp = SrtcpSender::from_material(&config.srtp); + let reorder = RtpReorderBuffer::new(config.reorder_window_packets); + let assembler = VideoAccessUnitAssembler::new(config.codec, config.max_access_unit_bytes); + Self { + config, + srtp, + srtcp, + reorder, + assembler, + last_stream_packet_index: None, + next_frame_contiguous: true, + state: NvstReceiverState::Running, + bound_ssrc: None, + highest_sequence_received: 0, + authenticated_packets: 0, + fec_packets: 0, + frames_emitted: 0, + timeout_origin: Instant::now(), + last_authenticated_packet: None, + } + } + + pub fn state(&self) -> NvstReceiverState { + self.state + } + + pub fn pause(&mut self) -> Option { + if self.state != NvstReceiverState::Running { + return None; + } + self.reset_media_state(); + self.state = NvstReceiverState::Paused; + Some(NvstReceiveEvent::Lifecycle(self.state)) + } + + pub fn resume(&mut self) -> Option { + if self.state != NvstReceiverState::Paused { + return None; + } + self.reset_media_state(); + self.timeout_origin = Instant::now(); + self.state = NvstReceiverState::Running; + Some(NvstReceiveEvent::Lifecycle(self.state)) + } + + pub fn recover(&mut self) -> Option { + if self.state != NvstReceiverState::RecoveryRequired { + return None; + } + self.reset_media_state(); + self.timeout_origin = Instant::now(); + self.state = NvstReceiverState::Running; + Some(NvstReceiveEvent::Lifecycle(self.state)) + } + + pub fn stop(&mut self) -> Option { + if self.state == NvstReceiverState::Stopped { + return None; + } + self.reset_media_state(); + self.state = NvstReceiverState::Stopped; + Some(NvstReceiveEvent::Lifecycle(self.state)) + } + + /// Returns a typed timeout only once. The caller must deliberately call `recover` before + /// more media is accepted, preventing a stale stream from silently resuming. + pub fn poll_timeout(&mut self, now: Instant) -> Option { + if self.state != NvstReceiverState::Running { + return None; + } + let last_packet = self + .last_authenticated_packet + .unwrap_or(self.timeout_origin); + let idle_for = now.saturating_duration_since(last_packet); + if idle_for < self.config.timeout { + return None; + } + self.reset_media_state(); + self.state = NvstReceiverState::RecoveryRequired; + Some(NvstReceiveEvent::RecoveryNeeded(NvstRecovery::Timeout { + idle_for, + })) + } + + pub fn process_datagram( + &mut self, + source: SocketAddr, + datagram: &[u8], + now: Instant, + ) -> Vec { + if source != self.config.video_peer { + return vec![NvstReceiveEvent::Dropped( + NvstDropReason::UnexpectedSource { + expected: self.config.video_peer, + actual: source, + }, + )]; + } + match self.state { + NvstReceiverState::Paused => { + return vec![NvstReceiveEvent::Dropped(NvstDropReason::Paused)]; + } + NvstReceiverState::Stopped => { + return vec![NvstReceiveEvent::Dropped(NvstDropReason::Stopped)]; + } + NvstReceiverState::RecoveryRequired => { + return vec![NvstReceiveEvent::Dropped(NvstDropReason::RecoveryRequired)]; + } + NvstReceiverState::Running => {} + } + let packet = match self.srtp.unprotect(datagram) { + Ok(packet) => packet, + Err(reason) => return vec![NvstReceiveEvent::Dropped(reason)], + }; + if let Some(expected) = self.config.expected_payload_type + && packet.header.payload_type != expected + { + return vec![NvstReceiveEvent::Dropped( + NvstDropReason::UnexpectedPayloadType { + expected, + actual: packet.header.payload_type, + }, + )]; + } + let expected_ssrc = self.config.expected_ssrc.or(self.bound_ssrc); + if let Some(expected) = expected_ssrc + && packet.header.ssrc != expected + { + return vec![NvstReceiveEvent::Dropped(NvstDropReason::UnexpectedSsrc { + expected, + actual: packet.header.ssrc, + })]; + } + self.bound_ssrc.get_or_insert(packet.header.ssrc); + self.last_authenticated_packet = Some(now); + self.authenticated_packets += 1; + let sequence = u32::try_from(packet.index & 0xffff_ffff).unwrap_or(u32::MAX); + self.highest_sequence_received = self.highest_sequence_received.max(sequence); + self.config.feedback.publish_stream( + packet.header.ssrc, + self.highest_sequence_received, + packet.header.timestamp, + now, + ); + self.config.feedback.resolve_nack(packet.index); + + let result = self.reorder.push(packet, now); + let mut events = Vec::new(); + if let Some((first_missing_index, last_missing_index)) = result.nack { + self.config + .feedback + .request_nack(first_missing_index, last_missing_index); + } + if let Some(reason) = result.dropped { + events.push(NvstReceiveEvent::Dropped(reason)); + } + if let Some(recovery) = result.recovery { + self.assembler.reset(); + self.next_frame_contiguous = false; + // A sequence gap breaks the decoder's reference chain; ask (via the + // bundle's rtcp1 channel) for a fresh keyframe to recover. + self.config.feedback.request_keyframe(); + events.push(NvstReceiveEvent::RecoveryNeeded(recovery)); + } + for packet in result.ready { + let payload = match packet.header.payload(&packet.plaintext) { + Ok(payload) => payload, + Err(error) => { + events.push(NvstReceiveEvent::Dropped(NvstDropReason::MalformedRtp( + error, + ))); + continue; + } + }; + let (nv_packet, media) = match NvVideoPacket::parse(&packet.header, payload) { + Ok(value) => value, + Err(error) => { + self.assembler.reset(); + self.last_stream_packet_index = None; + self.next_frame_contiguous = false; + self.config.feedback.request_keyframe(); + events.push(NvstReceiveEvent::Dropped(NvstDropReason::MalformedRtp( + error, + ))); + continue; + } + }; + if nv_packet.is_fec { + self.fec_packets += 1; + events.push(NvstReceiveEvent::Dropped(NvstDropReason::Unsupported( + NvstUnsupportedFeature::FecRepair, + ))); + continue; + } + let same_frame_continuation = !nv_packet.is_start_of_frame() + && self.assembler.current_frame == Some(nv_packet.frame_index); + if same_frame_continuation + && self.last_stream_packet_index.is_some_and(|last| { + last.wrapping_add(1) & STREAM_PACKET_INDEX_MASK != nv_packet.stream_packet_index + }) + { + self.assembler.reset(); + self.last_stream_packet_index = Some(nv_packet.stream_packet_index); + self.next_frame_contiguous = false; + self.config.feedback.request_keyframe(); + events.push(NvstReceiveEvent::Dropped( + NvstDropReason::FrameDiscontinuity, + )); + continue; + } + self.last_stream_packet_index = Some(nv_packet.stream_packet_index); + match self + .assembler + .push(nv_packet, packet.header.timestamp, media) + { + Ok(Some(mut frame)) => { + frame.contiguous = self.next_frame_contiguous; + self.next_frame_contiguous = true; + self.frames_emitted += 1; + self.config.feedback.publish_completed_frame(&frame); + events.push(NvstReceiveEvent::Frame(frame)); + } + Ok(None) => {} + Err(reason) => { + if matches!( + reason, + NvstDropReason::FrameDiscontinuity + | NvstDropReason::InvalidLastPacketPayloadLength { .. } + ) { + self.next_frame_contiguous = false; + self.config.feedback.request_keyframe(); + } + events.push(NvstReceiveEvent::Dropped(reason)); + } + } + } + events + } + + /// Returns an SRTCP Receiver Report to send to the video peer, at most once per + /// interval, once the media SSRC is known. Keeps the peer's video flowing. + pub fn poll_receiver_report(&mut self, now: Instant) -> Option> { + if self.state != NvstReceiverState::Running { + return None; + } + self.srtcp + .as_mut()? + .poll_receiver_report(self.config.feedback.report_snapshot(true), now) + } + + /// Elapsed-since-start receive counters for ground-truth timing that does not + /// depend on when buffered log lines happen to flush. + pub fn stats_line(&self, origin: Instant) -> String { + format!( + "elapsed={:.1}s auth={} fec={} frames={} ssrc={:?}", + origin.elapsed().as_secs_f64(), + self.authenticated_packets, + self.fec_packets, + self.frames_emitted, + self.bound_ssrc, + ) + } + + fn process_mjolnir_payload( + &mut self, + ssrc: u32, + rtp_timestamp: u32, + _payload: &[u8], + now: Instant, + ) -> Vec { + match self.state { + NvstReceiverState::Paused => { + return vec![NvstReceiveEvent::Dropped(NvstDropReason::Paused)]; + } + NvstReceiverState::Stopped => { + return vec![NvstReceiveEvent::Dropped(NvstDropReason::Stopped)]; + } + NvstReceiverState::RecoveryRequired => { + return vec![NvstReceiveEvent::Dropped(NvstDropReason::RecoveryRequired)]; + } + NvstReceiverState::Running => {} + } + self.bound_ssrc.get_or_insert(ssrc); + self.last_authenticated_packet = Some(now); + // The bundle path cannot assemble video: the Mjolnir frame metadata lives + // in the `0x4753` RTP extension, which str0m does not surface. The official + // cloud path delivers video exclusively on the raw Mjolnir socket, so bundle + // RTP (audio/control) is intentionally ignored here. + let _ = rtp_timestamp; + Vec::new() + } + + fn reset_media_state(&mut self) { + self.reorder.reset(); + self.assembler.reset(); + self.last_stream_packet_index = None; + self.next_frame_contiguous = false; + } +} + +enum StunDatagram { + NotStun, + Invalid, + Handled(Option>), +} + +fn append_stun_attribute(packet: &mut Vec, attribute_type: u16, value: &[u8]) { + packet.extend_from_slice(&attribute_type.to_be_bytes()); + packet.extend_from_slice(&(value.len() as u16).to_be_bytes()); + packet.extend_from_slice(value); + packet.resize(packet.len().next_multiple_of(4), 0); +} + +fn build_authenticated_stun_packet( + message_type: u16, + transaction_id: &[u8; 12], + key: &[u8], + attributes: &[(u16, Vec)], +) -> Vec { + let mut packet = Vec::with_capacity(128); + packet.extend_from_slice(&message_type.to_be_bytes()); + packet.extend_from_slice(&0_u16.to_be_bytes()); + packet.extend_from_slice(&STUN_MAGIC_COOKIE.to_be_bytes()); + packet.extend_from_slice(transaction_id); + for (attribute_type, value) in attributes { + append_stun_attribute(&mut packet, *attribute_type, value); + } + + let length_through_integrity = packet.len() - STUN_HEADER_LEN + 24; + packet[2..4].copy_from_slice(&(length_through_integrity as u16).to_be_bytes()); + let mut mac = HmacSha1::new_from_slice(key).expect("HMAC accepts variable-size ICE passwords"); + mac.update(&packet); + append_stun_attribute( + &mut packet, + STUN_ATTR_MESSAGE_INTEGRITY, + &mac.finalize().into_bytes(), + ); + + let final_length = packet.len() - STUN_HEADER_LEN + 8; + packet[2..4].copy_from_slice(&(final_length as u16).to_be_bytes()); + let fingerprint = crc32(&packet) ^ STUN_FINGERPRINT_XOR; + append_stun_attribute( + &mut packet, + STUN_ATTR_FINGERPRINT, + &fingerprint.to_be_bytes(), + ); + packet +} + +fn build_stun_binding_request( + credentials: &NvstStunCredentials, + transaction_id: &[u8; 12], +) -> Vec { + let username = format!( + "{}:{}", + credentials.remote_username_fragment, credentials.local_username_fragment + ); + build_authenticated_stun_packet( + STUN_BINDING_REQUEST, + transaction_id, + credentials.remote_password.as_bytes(), + &[(STUN_ATTR_USERNAME, username.into_bytes())], + ) +} + +/// Official `NattHolePunch::SendPing` (pingVersion=6) encodes +/// `SetStunCredentials(local, pingPayload, …, describePassword)` as +/// USERNAME `pingPayload:localUfrag` and HMAC-SHA1 with the DESCRIBE password. +/// WebRtcTransport ICE uses the V2 ufrag via [`build_stun_binding_request`]. +fn build_natt_hole_punch_request( + local_username_fragment: &str, + ping_payload: &[u8], + remote_password: &str, + transaction_id: &[u8; 12], +) -> Vec { + let username = format!( + "{}:{local_username_fragment}", + String::from_utf8_lossy(ping_payload) + ); + build_authenticated_stun_packet( + STUN_BINDING_REQUEST, + transaction_id, + remote_password.as_bytes(), + &[(STUN_ATTR_USERNAME, username.into_bytes())], + ) +} + +fn xor_mapped_address(source: SocketAddr, transaction_id: &[u8; 12]) -> Vec { + let mut value = Vec::with_capacity(20); + value.push(0); + value.push(if source.is_ipv4() { 1 } else { 2 }); + value.extend_from_slice(&(source.port() ^ ((STUN_MAGIC_COOKIE >> 16) as u16)).to_be_bytes()); + match source.ip() { + IpAddr::V4(ip) => { + for (octet, mask) in ip.octets().into_iter().zip(STUN_MAGIC_COOKIE.to_be_bytes()) { + value.push(octet ^ mask); + } + } + IpAddr::V6(ip) => { + let mut mask = [0_u8; 16]; + mask[..4].copy_from_slice(&STUN_MAGIC_COOKIE.to_be_bytes()); + mask[4..].copy_from_slice(transaction_id); + for (octet, mask) in ip.octets().into_iter().zip(mask) { + value.push(octet ^ mask); + } + } + } + value +} + +fn find_stun_attribute(packet: &[u8], wanted_type: u16) -> Option<(usize, &[u8])> { + let mut offset = STUN_HEADER_LEN; + while offset + 4 <= packet.len() { + let attribute_type = u16::from_be_bytes([packet[offset], packet[offset + 1]]); + let length = usize::from(u16::from_be_bytes([packet[offset + 2], packet[offset + 3]])); + let value_start = offset + 4; + let value_end = value_start.checked_add(length)?; + if value_end > packet.len() { + return None; + } + if attribute_type == wanted_type { + return Some((offset, &packet[value_start..value_end])); + } + offset = value_end.next_multiple_of(4); + } + None +} + +fn valid_stun_fingerprint(packet: &[u8]) -> bool { + let Some((offset, value)) = find_stun_attribute(packet, STUN_ATTR_FINGERPRINT) else { + return false; + }; + if value.len() != 4 || offset + 8 != packet.len() { + return false; + } + let expected = crc32(&packet[..offset]) ^ STUN_FINGERPRINT_XOR; + expected.to_be_bytes().ct_eq(value).into() +} + +fn valid_stun_message_integrity(packet: &[u8], key: &[u8]) -> bool { + let Some((integrity_offset, integrity)) = + find_stun_attribute(packet, STUN_ATTR_MESSAGE_INTEGRITY) + else { + return false; + }; + if integrity.len() != 20 { + return false; + } + let fingerprint_bytes = if find_stun_attribute(packet, STUN_ATTR_FINGERPRINT).is_some() { + 8 + } else { + 0 + }; + let Some(adjusted_length) = packet + .len() + .checked_sub(STUN_HEADER_LEN + fingerprint_bytes) + else { + return false; + }; + let mut authenticated = packet[..integrity_offset].to_vec(); + authenticated[2..4].copy_from_slice(&(adjusted_length as u16).to_be_bytes()); + let mut mac = HmacSha1::new_from_slice(key).expect("HMAC accepts variable-size ICE passwords"); + mac.update(&authenticated); + mac.finalize().into_bytes().ct_eq(integrity).into() +} + +fn handle_stun_datagram( + datagram: &[u8], + source: SocketAddr, + credentials: &NvstStunCredentials, +) -> StunDatagram { + if datagram.len() < STUN_HEADER_LEN + || datagram[0] & 0xc0 != 0 + || u32::from_be_bytes([datagram[4], datagram[5], datagram[6], datagram[7]]) + != STUN_MAGIC_COOKIE + { + return StunDatagram::NotStun; + } + let message_length = usize::from(u16::from_be_bytes([datagram[2], datagram[3]])); + if STUN_HEADER_LEN + message_length != datagram.len() || !valid_stun_fingerprint(datagram) { + return StunDatagram::Invalid; + } + let message_type = u16::from_be_bytes([datagram[0], datagram[1]]); + let transaction_id: [u8; 12] = datagram[8..20] + .try_into() + .expect("STUN header length checked above"); + match message_type { + STUN_BINDING_REQUEST => { + let Some((_, username)) = find_stun_attribute(datagram, STUN_ATTR_USERNAME) else { + return StunDatagram::Invalid; + }; + let expected_username = format!( + "{}:{}", + credentials.local_username_fragment, credentials.remote_username_fragment + ); + if !bool::from(expected_username.as_bytes().ct_eq(username)) + || !valid_stun_message_integrity(datagram, credentials.local_password.as_bytes()) + { + return StunDatagram::Invalid; + } + let mapped_address = xor_mapped_address(source, &transaction_id); + StunDatagram::Handled(Some(build_authenticated_stun_packet( + STUN_BINDING_SUCCESS_RESPONSE, + &transaction_id, + credentials.local_password.as_bytes(), + &[(STUN_ATTR_XOR_MAPPED_ADDRESS, mapped_address)], + ))) + } + STUN_BINDING_SUCCESS_RESPONSE => { + if valid_stun_message_integrity(datagram, credentials.remote_password.as_bytes()) { + StunDatagram::Handled(None) + } else { + StunDatagram::Invalid + } + } + _ => StunDatagram::Invalid, + } +} + +enum UdpReceiverCommand { + Pause, + Resume, + Recover, + SendInput { + bytes: Vec, + reply: Option>>, + }, + Stop, +} + +/// Owns the bounded UDP receive worker. Frames go through the same bounded `MediaConsumer` used +/// by WebRTC, so a slow decoder cannot make UDP receive unbounded. +pub struct NvstUdpReceiverSession { + commands: Sender, + join: Option>, + input_ready: Arc, +} + +#[derive(Clone)] +pub struct NvstUdpReceiverControl { + commands: Sender, + input_ready: Arc, +} + +#[derive(Debug, Error)] +pub enum NvstUdpReceiverError { + #[error("failed to bind NVST UDP socket: {0}")] + Bind(#[source] std::io::Error), + #[error("failed to configure NVST UDP socket: {0}")] + Configure(#[source] std::io::Error), + #[error("failed to start NVST receive worker: {0}")] + Spawn(#[source] std::io::Error), + #[error("NVST receive worker is no longer running")] + Closed, + #[error("failed to prepare NVST WebRTC bundle: {0}")] + WebrtcBundle(String), +} + +impl NvstUdpReceiverSession { + pub fn control(&self) -> NvstUdpReceiverControl { + NvstUdpReceiverControl { + commands: self.commands.clone(), + input_ready: Arc::clone(&self.input_ready), + } + } + + pub fn pause(&self) -> Result<(), NvstUdpReceiverError> { + self.control().pause() + } + + pub fn resume(&self) -> Result<(), NvstUdpReceiverError> { + self.control().resume() + } + + pub fn recover(&self) -> Result<(), NvstUdpReceiverError> { + self.control().recover() + } + + pub fn send_input( + &self, + bytes: Vec, + partially_reliable: bool, + ) -> Result<(), TransportError> { + self.control().send_input(bytes, partially_reliable) + } + + pub fn stop(mut self) { + let _ = self.commands.send(UdpReceiverCommand::Stop); + if let Some(join) = self.join.take() { + let _ = join.join(); + } + } +} + +impl NvstUdpReceiverControl { + pub fn pause(&self) -> Result<(), NvstUdpReceiverError> { + self.send(UdpReceiverCommand::Pause) + } + + pub fn resume(&self) -> Result<(), NvstUdpReceiverError> { + self.send(UdpReceiverCommand::Resume) + } + + pub fn recover(&self) -> Result<(), NvstUdpReceiverError> { + self.send(UdpReceiverCommand::Recover) + } + + pub fn send_input( + &self, + bytes: Vec, + _partially_reliable: bool, + ) -> Result<(), TransportError> { + if !self.input_ready.load(Ordering::Acquire) { + return Err(TransportError::InputNotReady); + } + let (reply, result) = mpsc::sync_channel(1); + self.commands + .send(UdpReceiverCommand::SendInput { + bytes, + reply: Some(reply), + }) + .map_err(|_| TransportError::Closed)?; + result + .recv_timeout(Duration::from_millis(500)) + .map_err(|_| TransportError::Closed)? + } + + /// Queues latency-sensitive locally captured input without waiting for the + /// receive worker to round-trip an acknowledgement. Readiness is still + /// checked before enqueueing and the ordered command channel preserves the + /// exact keyboard/button/motion sequence. + pub fn queue_input( + &self, + bytes: Vec, + _partially_reliable: bool, + ) -> Result<(), TransportError> { + if !self.input_ready.load(Ordering::Acquire) { + return Err(TransportError::InputNotReady); + } + self.commands + .send(UdpReceiverCommand::SendInput { bytes, reply: None }) + .map_err(|_| TransportError::Closed) + } + + pub fn stop(&self) -> Result<(), NvstUdpReceiverError> { + self.send(UdpReceiverCommand::Stop) + } + + fn send(&self, command: UdpReceiverCommand) -> Result<(), NvstUdpReceiverError> { + self.commands + .send(command) + .map_err(|_| NvstUdpReceiverError::Closed) + } +} + +impl Drop for NvstUdpReceiverSession { + fn drop(&mut self) { + let _ = self.commands.send(UdpReceiverCommand::Stop); + } +} + +fn discover_routed_ipv4() -> Option { + let probe = UdpSocket::bind(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)).ok()?; + probe + .connect(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)), 9)) + .ok()?; + let addr = probe.local_addr().ok()?; + if addr.ip().is_unspecified() || addr.ip().is_loopback() { + return None; + } + Some(addr.ip()) +} + +pub fn reserve_nvst_udp_socket() -> std::io::Result { + // Official binds the bundle sockets on 0.0.0.0 and advertises the routed + // NIC IPv4 separately via clientPorts.localAddress + host a=candidate. + bind_nvst_udp(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0) +} + +/// IPv4 OpenNOW should put in ANNOUNCE `localAddress` / host candidate. +/// Independent of the bind address: official listens on 0.0.0.0. +pub fn advertised_nvst_ipv4() -> Option { + discover_routed_ipv4() +} + +/// ICE + DTLS identity that already owns the reserved bundle socket. +#[derive(Debug, Clone)] +pub struct NvstBundleIdentity { + pub ice_username_fragment: String, + pub ice_password: String, + pub dtls_fingerprint: String, +} + +/// UDP socket plus the `Rtc` that will speak ICE/DTLS on it, plus the dedicated +/// NATT-only video (Mjolnir) socket the official two-socket cloud model uses for +/// raw-SRTP video. +pub struct ReservedNvstBundle { + socket: UdpSocket, + rtc: Rtc, + mjolnir_socket: UdpSocket, +} + +impl ReservedNvstBundle { + pub fn reserve() -> Result { + // Bifrost's legacy dedicated-socket layout assigns video to N and the + // native ICE/DTLS bundle to N+1. The server still relies on this pairing + // even though ANNOUNCE advertises clientPorts.video=0 and routes video + // after the Mjolnir NATT ping. Reserving the bundle first reverses those + // ports and causes some seats to keep all video off the client entirely. + let (socket, mjolnir_socket) = + reserve_nvst_socket_pair().map_err(NvstUdpReceiverError::Bind)?; + let rtc = create_nvst_bundle_rtc(&socket)?; + Ok(Self { + socket, + rtc, + mjolnir_socket, + }) + } + + pub fn local_addr(&self) -> std::io::Result { + self.socket.local_addr() + } + + pub fn mjolnir_local_addr(&self) -> std::io::Result { + self.mjolnir_socket.local_addr() + } + + pub fn advertised_local_address(&self) -> Option { + match self.socket.local_addr().ok()?.ip() { + IpAddr::V4(ip) if !ip.is_unspecified() && !ip.is_loopback() => Some(ip.to_string()), + _ => advertised_nvst_ipv4().map(|ip| ip.to_string()), + } + } + + pub fn identity(&mut self) -> NvstBundleIdentity { + nvst_local_bundle_identity(&mut self.rtc) + } + + pub fn send_to(&self, payload: &[u8], host: &str, port: u16) -> std::io::Result { + self.socket.send_to(payload, (host, port)) + } + + pub fn try_clone_socket(&self) -> std::io::Result { + self.socket.try_clone() + } + + pub fn into_parts(self) -> (UdpSocket, Rtc, UdpSocket) { + (self.socket, self.rtc, self.mjolnir_socket) + } +} + +fn generate_gfn_local_ice_credentials() -> Result { + const ALPHABET: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/"; + let mut random = [0_u8; 26]; + getrandom::fill(&mut random)?; + let encode = |start: usize, length: usize| { + random[start..start + length] + .iter() + .map(|value| ALPHABET[usize::from(*value) & 0x3f] as char) + .collect::() + }; + Ok(IceCreds { + ufrag: encode(0, 4), + pass: encode(4, 22), + }) +} + +fn create_nvst_bundle_rtc(socket: &UdpSocket) -> Result { + install_crypto(); + let _ = socket; + // Official GenerateIceCredentials() is 4-char ufrag / 22-char password. + // str0m's default 16-char ufrag is rejected by Bifrost length checks. + let mut rtc_config = RtcConfig::new().set_rtp_mode(true); + rtc_config.codec_config().add_config( + GFN_RED_PAYLOAD_TYPE.into(), + None, + Codec::Opus, + Frequency::FORTY_EIGHT_KHZ, + Some(2), + FormatParams::default(), + ); + let mut rtc = rtc_config.build(Instant::now()); + let credentials = generate_gfn_local_ice_credentials() + .map_err(|error| NvstUdpReceiverError::WebrtcBundle(error.to_string()))?; + rtc.direct_api().set_local_ice_credentials(credentials); + Ok(rtc) +} + +fn nvst_local_bundle_identity(rtc: &mut Rtc) -> NvstBundleIdentity { + let creds = rtc.direct_api().local_ice_credentials(); + let fingerprint = rtc.direct_api().local_dtls_fingerprint().clone(); + NvstBundleIdentity { + ice_username_fragment: creds.ufrag, + ice_password: creds.pass, + dtls_fingerprint: nvst_fingerprint_hex(&fingerprint), + } +} + +fn nvst_fingerprint_hex(fingerprint: &Fingerprint) -> String { + fingerprint + .bytes + .iter() + .map(|byte| format!("{byte:02X}")) + .collect::>() + .join(":") +} + +fn routed_host_addr(peer: Option, local: SocketAddr) -> SocketAddr { + if !local.ip().is_unspecified() && !local.ip().is_loopback() { + return local; + } + if let Some(peer) = peer + && let Ok(probe) = UdpSocket::bind(SocketAddr::new( + if peer.is_ipv4() { + IpAddr::V4(Ipv4Addr::UNSPECIFIED) + } else { + IpAddr::V6(Ipv6Addr::UNSPECIFIED) + }, + 0, + )) + { + let _ = probe.connect(peer); + if let Ok(addr) = probe.local_addr() + && !addr.ip().is_unspecified() + && !addr.ip().is_loopback() + { + return SocketAddr::new(addr.ip(), local.port()); + } + } + local +} + +fn logical_ice_addr(addr: SocketAddr, loopback_octet: u8) -> SocketAddr { + match addr.ip() { + IpAddr::V4(ip) if ip.is_link_local() => SocketAddr::new( + IpAddr::V4(Ipv4Addr::new(127, 0, 0, loopback_octet)), + addr.port(), + ), + _ => addr, + } +} + +fn parse_nvst_fingerprint(value: &str) -> Result { + let trimmed = value.trim(); + let sdp = if trimmed.contains(' ') { + trimmed.to_owned() + } else { + format!("sha-256 {trimmed}") + }; + sdp.parse() +} + +fn bind_nvst_udp(bind_ip: IpAddr, port: u16) -> std::io::Result { + #[cfg(unix)] + if let Ok(fd_text) = std::env::var("OPENNOW_NVST_VIDEO_UDP_FD") { + if let Ok(fd) = fd_text.parse::() { + use std::os::unix::io::FromRawFd; + // Electron dups the probe socket onto this fd so native never rebinds. + eprintln!("NVST inheriting video UDP socket from fd {fd}"); + return Ok(unsafe { UdpSocket::from_raw_fd(fd) }); + } + } + bind_nvst_udp_socket(bind_ip, port) +} + +fn bind_nvst_udp_socket(bind_ip: IpAddr, port: u16) -> std::io::Result { + let domain = if bind_ip.is_ipv4() { + Domain::IPV4 + } else { + Domain::IPV6 + }; + let socket = Socket::new(domain, Type::DGRAM, Some(Protocol::UDP))?; + socket.set_reuse_address(true)?; + if let Err(error) = socket.set_recv_buffer_size(NVST_UDP_RECEIVE_BUFFER_BYTES) { + eprintln!( + "NVST could not enlarge UDP receive buffer to {NVST_UDP_RECEIVE_BUFFER_BYTES} bytes: {error}" + ); + } + #[cfg(unix)] + socket.set_reuse_port(true)?; + socket.bind(&SocketAddr::new(bind_ip, port).into())?; + Ok(socket.into()) +} + +/// Reserves the dedicated NATT-only video (Mjolnir) socket. The native streamer +/// always owns this socket outright, so it never inherits an Electron-owned fd. +pub fn reserve_nvst_mjolnir_udp_socket() -> std::io::Result { + bind_nvst_udp_socket(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0) +} + +fn reserve_nvst_socket_pair() -> std::io::Result<(UdpSocket, UdpSocket)> { + // Bifrost's Windows client reserves this exact pair first + // (`general.clientPorts.useReserved=1`) and only falls back to dynamic + // ports when it is unavailable. Some cloud seats do not route the + // dedicated Mjolnir video flow back to an arbitrary source port even + // though the version-6 NATT request is otherwise valid. Match the + // official preference while preserving a non-fatal fallback for users + // that already have either port occupied. + const OFFICIAL_MJOLNIR_PORT: u16 = 49_005; + const OFFICIAL_BUNDLE_PORT: u16 = 49_006; + const MAX_PAIR_ATTEMPTS: usize = 32; + let bind_ip = IpAddr::V4(Ipv4Addr::UNSPECIFIED); + let mut last_error = match bind_nvst_udp_socket(bind_ip, OFFICIAL_MJOLNIR_PORT) { + Ok(mjolnir) => match bind_nvst_udp_socket(bind_ip, OFFICIAL_BUNDLE_PORT) { + Ok(bundle) => return Ok((bundle, mjolnir)), + Err(error) => error, + }, + Err(error) => error, + }; + + for _ in 0..MAX_PAIR_ATTEMPTS { + let mjolnir = reserve_nvst_mjolnir_udp_socket()?; + let video_port = mjolnir.local_addr()?.port(); + let Some(bundle_port) = video_port.checked_add(1) else { + continue; + }; + match bind_nvst_udp_socket(bind_ip, bundle_port) { + Ok(bundle) => return Ok((bundle, mjolnir)), + Err(error) => last_error = error, + } + } + Err(last_error) +} + +pub fn spawn_nvst_udp_receiver( + config: NvstVideoConfig, + media_consumer: MediaConsumer, + event_sender: Sender, +) -> Result { + spawn_nvst_udp_receiver_with_socket(config, media_consumer, event_sender, None, None) +} + +pub fn spawn_nvst_udp_receiver_with_socket( + config: NvstVideoConfig, + media_consumer: MediaConsumer, + event_sender: Sender, + reserved_socket: Option, + reserved_rtc: Option, +) -> Result { + let bind_ip = match config.video_peer.ip() { + IpAddr::V4(_) => IpAddr::V4(Ipv4Addr::UNSPECIFIED), + IpAddr::V6(_) => IpAddr::V6(Ipv6Addr::UNSPECIFIED), + }; + let socket = match reserved_socket { + Some(socket) => { + eprintln!( + "NVST using UDP socket reserved before ANNOUNCE ({})", + socket + .local_addr() + .map(|addr| addr.to_string()) + .unwrap_or_else(|_| "unknown".to_owned()) + ); + socket + } + None => { + bind_nvst_udp(bind_ip, config.client_udp_port).map_err(NvstUdpReceiverError::Bind)? + } + }; + socket + .set_read_timeout(Some(UDP_RECEIVE_POLL_INTERVAL)) + .map_err(NvstUdpReceiverError::Configure)?; + let rtc = if config.remote_dtls_fingerprint().is_some() { + let rtc = match reserved_rtc { + Some(rtc) => rtc, + None => create_nvst_bundle_rtc(&socket)?, + }; + Some(prepare_nvst_webrtc_bundle(&socket, &config, rtc)?) + } else { + None + }; + spawn_receiver_thread( + "opennow-nvst-video", + socket, + config, + media_consumer, + event_sender, + rtc, + ) +} + +/// Spawns the raw-SRTP NATT video receiver on the reserved Mjolnir socket. +/// +/// Official GFN cloud (`nativeRtcOnBundlePort=1`) delivers video RTP/SRTP to this +/// dedicated NATT-only socket while the ICE/DTLS bundle socket carries +/// control/audio. The raw receiver's NATT keepalive pings are what route video +/// here, and it decrypts with the runtime encryptionKey sent in ANNOUNCE. +pub fn spawn_nvst_mjolnir_receiver( + socket: UdpSocket, + config: NvstVideoConfig, + media_consumer: MediaConsumer, + event_sender: Sender, +) -> Result { + eprintln!( + "NVST Mjolnir raw-SRTP video receiver arming on {}", + socket + .local_addr() + .map(|addr| addr.to_string()) + .unwrap_or_else(|_| "unknown".to_owned()) + ); + spawn_receiver_thread( + "opennow-nvst-mjolnir", + socket, + config, + media_consumer, + event_sender, + None, + ) +} + +struct NvstReceiverOutputs { + media_consumer: MediaConsumer, + event_sender: Sender, + input_ready: Arc, +} + +fn spawn_receiver_thread( + name: &str, + socket: UdpSocket, + config: NvstVideoConfig, + media_consumer: MediaConsumer, + event_sender: Sender, + rtc: Option, +) -> Result { + socket + .set_read_timeout(Some(UDP_RECEIVE_POLL_INTERVAL)) + .map_err(NvstUdpReceiverError::Configure)?; + let (commands, receiver) = mpsc::channel(); + let input_ready = Arc::new(AtomicBool::new(false)); + let worker_input_ready = input_ready.clone(); + let transport_origin = Instant::now(); + let join = thread::Builder::new() + .name(name.to_owned()) + .spawn(move || { + run_nvst_udp_receiver( + socket, + config, + receiver, + NvstReceiverOutputs { + media_consumer, + event_sender, + input_ready: worker_input_ready.clone(), + }, + transport_origin, + rtc, + ); + worker_input_ready.store(false, Ordering::Release); + }) + .map_err(NvstUdpReceiverError::Spawn)?; + Ok(NvstUdpReceiverSession { + commands, + join: Some(join), + input_ready, + }) +} + +fn prepare_nvst_webrtc_bundle( + socket: &UdpSocket, + config: &NvstVideoConfig, + mut rtc: Rtc, +) -> Result { + let fingerprint = config.remote_dtls_fingerprint().ok_or_else(|| { + NvstUdpReceiverError::WebrtcBundle("missing remote DTLS fingerprint".into()) + })?; + let remote_fingerprint = + parse_nvst_fingerprint(fingerprint).map_err(NvstUdpReceiverError::WebrtcBundle)?; + let credentials = config.stun_credentials.as_ref().ok_or_else(|| { + NvstUdpReceiverError::WebrtcBundle( + "DTLS bundle requires local and remote ICE credentials".into(), + ) + })?; + let local_addr = socket + .local_addr() + .map_err(NvstUdpReceiverError::Configure)?; + let bundle_peer = config.bundle_peer(); + let physical_local = routed_host_addr(Some(bundle_peer), local_addr); + let local_candidate = Candidate::host(logical_ice_addr(physical_local, 1), "udp") + .map_err(|error| NvstUdpReceiverError::WebrtcBundle(error.to_string()))?; + let remote_candidate = Candidate::host(logical_ice_addr(bundle_peer, 2), "udp") + .map_err(|error| NvstUdpReceiverError::WebrtcBundle(error.to_string()))?; + rtc.add_local_candidate(local_candidate); + rtc.add_remote_candidate(remote_candidate); + { + let mut api = rtc.direct_api(); + api.set_ice_controlling(true); + api.set_local_ice_credentials(IceCreds { + ufrag: credentials.local_username_fragment.clone(), + pass: credentials.local_password.clone(), + }); + api.set_remote_ice_credentials(IceCreds { + ufrag: credentials.remote_username_fragment.clone(), + pass: credentials.remote_password.clone(), + }); + api.set_remote_fingerprint(remote_fingerprint); + if let Some(audio) = config.audio_track() { + api.declare_media(Mid::from(audio.mid.as_str()), MediaKind::Audio); + } + api.start_dtls(true) + .map_err(|error| NvstUdpReceiverError::WebrtcBundle(error.to_string()))?; + } + eprintln!( + "NVST WebRTC bundle armed (local={}, peer={}, remoteFingerprintBytes={})", + physical_local, + bundle_peer, + fingerprint.len() + ); + Ok(rtc) +} + +fn looks_like_rtp(datagram: &[u8]) -> bool { + datagram.len() >= RTP_FIXED_HEADER_LEN + && datagram[0] >> 6 == 2 + && !looks_like_stun(datagram) + && !looks_like_dtls(datagram) + && !looks_like_rtcp(datagram) +} + +fn looks_like_rtcp(datagram: &[u8]) -> bool { + datagram.len() >= 4 && datagram[0] >> 6 == 2 && matches!(datagram[1], 192..=223) +} + +fn looks_like_stun(datagram: &[u8]) -> bool { + datagram.len() >= STUN_HEADER_LEN && datagram[4..8] == STUN_MAGIC_COOKIE.to_be_bytes() +} + +#[cfg_attr(not(test), allow(dead_code))] +fn synthesize_ice_binding_success( + transaction_id: &[u8; 12], + mapped: SocketAddr, + remote_password: &str, +) -> Vec { + build_authenticated_stun_packet( + STUN_BINDING_SUCCESS_RESPONSE, + transaction_id, + remote_password.as_bytes(), + &[( + STUN_ATTR_XOR_MAPPED_ADDRESS, + xor_mapped_address(mapped, transaction_id), + )], + ) +} + +fn looks_like_dtls(datagram: &[u8]) -> bool { + matches!(datagram.first().copied(), Some(20..=63)) +} + +fn peek_rtp_ssrc(datagram: &[u8]) -> Option { + looks_like_rtp(datagram) + .then(|| u32::from_be_bytes([datagram[8], datagram[9], datagram[10], datagram[11]])) +} + +fn peek_rtp_payload_type(datagram: &[u8]) -> Option { + looks_like_rtp(datagram).then(|| datagram[1] & 0x7f) +} + +fn matches_audio_track(track: &NvstAudioTrack, payload_type: u8, ssrc: u32) -> bool { + let matches_payload_type = payload_type == track.payload_type + || (track.payload_type == GFN_OPUS_PAYLOAD_TYPE && payload_type == GFN_RED_PAYLOAD_TYPE); + matches_payload_type && track.ssrc.is_none_or(|expected| expected == ssrc) +} + +fn extract_red_opus_primary(payload: &[u8]) -> Option<&[u8]> { + let mut header_offset = 0_usize; + let mut redundant_payload_bytes = 0_usize; + let mut redundant_blocks = 0_usize; + loop { + let header = *payload.get(header_offset)?; + let payload_type = header & 0x7f; + if header & 0x80 == 0 { + if payload_type != GFN_OPUS_PAYLOAD_TYPE { + return None; + } + let primary_offset = header_offset + .checked_add(1)? + .checked_add(redundant_payload_bytes)?; + let primary = payload.get(primary_offset..)?; + return (!primary.is_empty() && primary.len() <= MAX_OPUS_PACKET_BYTES) + .then_some(primary); + } + if redundant_blocks == MAX_REDUNDANT_AUDIO_BLOCKS { + return None; + } + let header_bytes = payload.get(header_offset..header_offset.checked_add(4)?)?; + let block_len = (usize::from(header_bytes[2] & 0x03) << 8) | usize::from(header_bytes[3]); + redundant_payload_bytes = redundant_payload_bytes.checked_add(block_len)?; + redundant_blocks += 1; + header_offset = header_offset.checked_add(4)?; + } +} + +fn finish_nvst_input_handshake( + input_state: &mut NvstInputChannelState, + channels: NvstInputChannels, + rtc: &mut Rtc, + transport_origin: Instant, + input_ready: &AtomicBool, + event_sender: &Sender, + version: u16, +) -> bool { + if !input_state.activation_sent() { + let timestamp_us = transport_origin + .elapsed() + .as_micros() + .try_into() + .unwrap_or(u64::MAX); + if !channels.send_activation(rtc, timestamp_us) { + let _ = event_sender.send(NvstReceiveEvent::InputUnavailable( + "input activation could not be queued".to_owned(), + )); + return false; + } + eprintln!( + "NVST cursor capture tx: channel={} command=0x0308 enabled=true reason=input-activation", + channels.label(channels.control_reliable), + ); + eprintln!( + "NVST remote cursor tracking tx: channel={} command=0x030d enabled=true reason=input-activation", + channels.label(channels.control_reliable), + ); + eprintln!( + "NVST client state tx: channel={} window_state=19 system_state=0 frame=0", + channels.label(channels.control_reliable), + ); + input_state.mark_activation_sent(); + } + input_ready.store(true, Ordering::Release); + let _ = event_sender.send(NvstReceiveEvent::InputReady(version)); + true +} + +fn run_nvst_webrtc_bundle( + socket: UdpSocket, + config: NvstVideoConfig, + commands: Receiver, + outputs: NvstReceiverOutputs, + transport_origin: Instant, + mut rtc: Rtc, +) { + let NvstReceiverOutputs { + media_consumer, + event_sender, + input_ready, + } = outputs; + let bundle_peer = config.bundle_peer(); + let stun_credentials = config.stun_credentials.clone(); + let ping_payload = config.ping_payload.clone(); + // Feedback plane shared with the Mjolnir video receiver: it publishes the + // stream SSRC/sequence and recovery requests; this bundle sends the RTCP + // Receiver Reports / NACK / PLI over the `rtcp1` SCTP data channel. + let feedback = config.feedback(); + let audio_track = config.audio_track().cloned(); + let frame_time_us = config.frame_time_us; + // With a dedicated Mjolnir video socket the bundle only carries + // control/audio keepalive traffic; the Mjolnir receiver owns the media + // timeout, so the bundle must not raise a spurious media recovery. + let owns_media_timeout = config.mjolnir_udp_port.is_none(); + let physical_local = socket.local_addr().ok().map_or_else( + || bundle_peer, + |local| routed_host_addr(Some(bundle_peer), local), + ); + let receive_destination = logical_ice_addr(physical_local, 1); + let receive_source = logical_ice_addr(bundle_peer, 2); + let mut receiver = NvstVideoReceiver::new(config); + let mut datagram = vec![0_u8; 65_536]; + let mut inbound_datagrams = 0_u64; + let mut outbound_datagrams = 0_u64; + let mut hole_punch_pings = 0_u64; + let mut last_hole_punch = Instant::now() - PING_INTERVAL_BEFORE_CONNECTION; + let mut seen_ssrcs = HashSet::new(); + let mut dtls_ready = false; + // RTCP-over-SCTP (`rtcp1`) feedback channel state. + let mut sctp_started = false; + let mut rtcp_channel: Option = None; + let mut rtcp_channel_open = false; + let mut control_partial_open = false; + let rtcp_sender_ssrc = RTCP_SENDER_SSRC; + let mut last_rtcp_send = Instant::now() - SRTCP_RR_INTERVAL; + let mut last_recovery_send = Instant::now(); + let mut rtcp_reports_sent = 0_u64; + let mut last_frame_accepted_at: Option = None; + let mut qos_sequence = 0_u32; + let mut last_qos_send = Instant::now() - QOS_REPORT_INTERVAL; + let mut sctp_started_at: Option = None; + let mut input_channels: Option = None; + let mut input_state = NvstInputChannelState::default(); + let mut input_codec = NvstInputCodec::default(); + let mut last_input_types = Vec::new(); + let mut mouse_motion_packets = 0_u64; + let mut server_cursor_hidden = false; + let mut cursor_capture_retry_at: Option = None; + let mut cursor_capture_attempts = 0_u8; + let mut control_keepalive_at = next_control_keepalive(Instant::now()); + let mut input_timeout_reported = false; + let mut last_audio_sequence: Option<(u32, u16)> = None; + loop { + loop { + match commands.try_recv() { + Ok(UdpReceiverCommand::Pause) => forward_optional(&event_sender, receiver.pause()), + Ok(UdpReceiverCommand::Resume) => { + forward_optional(&event_sender, receiver.resume()) + } + Ok(UdpReceiverCommand::Recover) => { + forward_optional(&event_sender, receiver.recover()) + } + Ok(UdpReceiverCommand::SendInput { bytes, reply }) => { + let mut sent = true; + if input_state.is_ready() + && let Some(channels) = input_channels + { + let input_types = native_input_types(&bytes); + let should_log = verbose_diagnostics_enabled() + && match input_types.as_ref() { + Ok(types) => { + let only_motion = !types.is_empty() + && types.iter().all(|input_type| { + native_input_type_is_motion(*input_type) + }); + if only_motion { + mouse_motion_packets = mouse_motion_packets.wrapping_add(1); + } + let changed = *types != last_input_types; + if changed { + last_input_types.clone_from(types); + } + changed || !only_motion || mouse_motion_packets % 120 == 1 + } + Err(_) => true, + }; + if should_log { + match input_types.as_ref() { + Ok(types) => { + let names = types + .iter() + .map(|input_type| { + format!( + "{}({input_type})", + native_input_type_name(*input_type) + ) + }) + .collect::>() + .join(","); + eprintln!( + "NVST native input rx: events=[{names}] bytes={} raw={}", + bytes.len(), + diagnostic_hex(&bytes, 128), + ); + } + Err(error) => eprintln!( + "NVST native input rx undecodable: error={error} bytes={} raw={}", + bytes.len(), + diagnostic_hex(&bytes, 128), + ), + } + } + let timestamp_us = transport_origin + .elapsed() + .as_micros() + .try_into() + .unwrap_or(u64::MAX); + match input_codec.encode(&bytes, timestamp_us) { + Ok(messages) => { + for message in messages { + if should_log { + eprintln!( + "NVST encoded input tx: route={:?} bytes={} raw={}", + message.route, + message.bytes.len(), + diagnostic_hex(&message.bytes, 128), + ); + } + if !channels.send_encoded(&mut rtc, &message) { + sent = false; + eprintln!( + "NVST input packet could not be queued on {:?}", + message.route + ); + } + } + } + Err(error) => { + sent = false; + eprintln!("NVST input packet rejected: {error}"); + } + } + } else { + sent = false; + } + if let Some(reply) = reply { + let _ = reply.send(if sent { + Ok(()) + } else { + Err(TransportError::InputNotReady) + }); + } + } + Ok(UdpReceiverCommand::Stop) | Err(TryRecvError::Disconnected) => { + rtc.disconnect(); + forward_optional(&event_sender, receiver.stop()); + return; + } + Err(TryRecvError::Empty) => break, + } + } + + // Official first burst is three ICE Binding Requests, plus NATT + // ping-string PING. After DTLS they keep pinging at 100ms. + let now = Instant::now(); + if input_state.control_is_open() && now >= control_keepalive_at { + if let Some(channels) = input_channels + && !channels.send_keepalive(&mut rtc, 0) + { + eprintln!("NVST control keepalive could not be queued"); + } + control_keepalive_at = next_control_keepalive(now); + } + if !server_cursor_hidden + && cursor_capture_attempts < MAX_CURSOR_CAPTURE_ATTEMPTS + && cursor_capture_retry_at.is_some_and(|retry_at| now >= retry_at) + && let Some(channels) = input_channels + { + cursor_capture_attempts += 1; + let capture_sent = channels.send_mouse_cursor_capture(&mut rtc, true); + let tracking_sent = channels.send_remote_cursor_tracking(&mut rtc, true); + if capture_sent && tracking_sent { + eprintln!( + "NVST cursor capture tx: channel={} command=0x0308 enabled=true reason=post-play-retry attempt={cursor_capture_attempts}", + channels.label(channels.control_reliable), + ); + eprintln!( + "NVST remote cursor tracking tx: channel={} command=0x030d enabled=true reason=post-play-retry attempt={cursor_capture_attempts}", + channels.label(channels.control_reliable), + ); + } else { + eprintln!( + "NVST cursor feature retry could not be queued: attempt={cursor_capture_attempts} captureSent={capture_sent} trackingSent={tracking_sent}" + ); + } + cursor_capture_retry_at = Some(now + CURSOR_CAPTURE_RETRY_INTERVAL); + } + if !input_timeout_reported && input_state.handshake_timed_out(sctp_started_at, now) { + input_timeout_reported = true; + let _ = event_sender.send(NvstReceiveEvent::InputUnavailable( + "input handshake timed out".to_owned(), + )); + } + let ping_interval = if dtls_ready { + PING_INTERVAL_AFTER_CONNECTION + } else { + PING_INTERVAL_BEFORE_CONNECTION + }; + if now.duration_since(last_hole_punch) >= ping_interval + && let Some(credentials) = stun_credentials.as_ref() + { + let mut ice_bytes = 0_usize; + if !dtls_ready { + for _ in 0..3 { + let mut ice_tid = [0_u8; 12]; + if getrandom::fill(&mut ice_tid).is_ok() { + let ice = build_stun_binding_request(credentials, &ice_tid); + ice_bytes = ice.len(); + if let Err(error) = socket.send_to(&ice, bundle_peer) { + eprintln!("NVST ICE send failed: {error}"); + forward_optional(&event_sender, receiver.stop()); + return; + } + } + } + } + let mut natt_tid = [0_u8; 12]; + let natt = if getrandom::fill(&mut natt_tid).is_ok() { + let natt = build_natt_hole_punch_request( + &credentials.local_username_fragment, + &ping_payload, + &credentials.remote_password, + &natt_tid, + ); + if let Err(error) = socket.send_to(&natt, bundle_peer) { + eprintln!("NVST NATT send failed: {error}"); + forward_optional(&event_sender, receiver.stop()); + return; + } + Some(natt) + } else { + None + }; + hole_punch_pings += 1; + if hole_punch_pings == 1 || hole_punch_pings % 50 == 0 { + eprintln!( + "NVST hole-punch ping={hole_punch_pings} dest={bundle_peer} iceBurst={} iceBytes={ice_bytes} nattBytes={} credentials=redacted", + if dtls_ready { 0 } else { 3 }, + natt.as_ref().map_or(0, Vec::len), + ); + } + last_hole_punch = now; + } + + if control_partial_open && let Some(channels) = input_channels { + while let Some(frame) = feedback.take_completed_frame() { + let observed_us = + last_frame_accepted_at + .replace(frame.accepted_at) + .map(|previous| { + u32::try_from( + frame + .accepted_at + .saturating_duration_since(previous) + .as_micros(), + ) + .unwrap_or(u32::MAX) + }); + let pacing_error_us = observed_us.map_or(frame_time_us, |observed| { + observed.abs_diff(frame_time_us).min(frame_time_us) + }); + if frame.frame_number % FRAMES_PER_PACING_REPORT == 1 { + let pacing = + frame_pacing_report(frame.frame_number, frame_time_us, pacing_error_us) + .encoded(); + let _ = channels.send_partial_control(&mut rtc, &pacing); + } + let client_time_ms = frame + .accepted_at + .saturating_duration_since(transport_origin) + .as_secs_f64() + * 1_000.0; + let ack = frame_ack( + frame.frame_number, + client_time_ms, + frame.bytes, + frame_time_us, + None, + ) + .encoded(); + if !channels.send_partial_control(&mut rtc, &ack) { + break; + } + } + } + + if control_partial_open + && now.duration_since(last_qos_send) >= QOS_REPORT_INTERVAL + && let Some(channels) = input_channels + { + let (frames_received, bytes_received, rtp_timestamp) = + feedback.completed_frame_snapshot(); + qos_sequence = qos_sequence.wrapping_add(1); + let command = QosReport { + sequence: qos_sequence, + frames_received, + bytes_received, + rtp_timestamp, + previous_bytes_received: bytes_received, + warmed_up: now.saturating_duration_since(transport_origin) >= QOS_WARM_UP, + } + .command() + .encoded(); + let _ = channels.send_partial_control(&mut rtc, &command); + last_qos_send = now; + } + + // Send RTCP feedback over the rtcp1 SCTP channel once it is open and the + // Mjolnir receiver has bound the video stream. A Receiver Report goes out + // every second. + if rtcp_channel_open + && now.duration_since(last_rtcp_send) >= SRTCP_RR_INTERVAL + && let Some(channel_id) = rtcp_channel + && let Some(report_block) = feedback.report_snapshot(true) + { + let mut channel = rtc.channel(channel_id); + if let Some(channel) = channel.as_mut() { + let report = build_rtcp_receiver_report(rtcp_sender_ssrc, report_block); + if channel.write(true, &report).unwrap_or(false) { + rtcp_reports_sent += 1; + if rtcp_reports_sent == 1 || rtcp_reports_sent % 10 == 0 { + eprintln!( + "NVST rtcp1 RR sent={rtcp_reports_sent} mediaSsrc={} highestSeq={}", + report_block.media_ssrc, report_block.highest_sequence, + ); + } + } + } + last_rtcp_send = now; + } + + // Loss feedback cannot wait for the one-second Receiver Report cadence: + // request retransmission while the reorder buffer still holds later + // packets, then request a keyframe if bounded recovery was exhausted. + if now.duration_since(last_recovery_send) >= RTCP_RECOVERY_INTERVAL + && let Some((media_ssrc, _)) = feedback.stream_snapshot() + { + if rtcp_channel_open + && let Some(channel_id) = rtcp_channel + && let Some(mut channel) = rtc.channel(channel_id) + { + if let Some((first_missing_index, last_missing_index)) = feedback.take_nack() { + let nack = build_rtcp_nack( + rtcp_sender_ssrc, + media_ssrc, + first_missing_index, + last_missing_index, + ); + if channel.write(true, &nack).unwrap_or(false) { + eprintln!( + "NVST rtcp1 NACK sent for mediaSsrc={media_ssrc} missing={first_missing_index}..={last_missing_index}" + ); + } else { + feedback.request_nack(first_missing_index, last_missing_index); + } + } + } + if feedback.take_keyframe_request() { + let mut sent = false; + if rtcp_channel_open + && let Some(channel_id) = rtcp_channel + && let Some(mut channel) = rtc.channel(channel_id) + { + let pli = build_rtcp_pli(rtcp_sender_ssrc, media_ssrc); + if channel.write(true, &pli).unwrap_or(false) { + eprintln!("NVST rtcp1 PLI sent for mediaSsrc={media_ssrc}"); + sent = true; + } + } + if input_state.control_is_open() + && let Some(channels) = input_channels + && channels.send_control(&mut rtc, &idr_request().encoded()) + { + eprintln!("NVST control 0x302 IDR request sent"); + sent = true; + } + if !sent { + feedback.request_keyframe(); + } + } + last_recovery_send = now; + } + + let timeout = loop { + match rtc.poll_output() { + Ok(Output::Timeout(timeout)) => break timeout, + Ok(Output::Transmit(transmit)) => { + outbound_datagrams += 1; + let kind = if looks_like_stun(&transmit.contents) { + "stun" + } else if looks_like_dtls(&transmit.contents) { + "dtls" + } else { + "other" + }; + if outbound_datagrams <= 8 + || (verbose_diagnostics_enabled() && outbound_datagrams % 50 == 0) + { + eprintln!( + "NVST WebRTC outbound={outbound_datagrams} kind={kind} dest={} bytes={}", + bundle_peer, + transmit.contents.len() + ); + } + if let Err(error) = socket.send_to(&transmit.contents, bundle_peer) { + eprintln!("NVST WebRTC send failed: {error}"); + forward_optional(&event_sender, receiver.stop()); + return; + } + // Official ICE-on WebRtcTransport skips setupDtls until a real + // inbound STUN. Do not synthesize Binding Success — that only + // unblocks str0m and sends ClientHello before GFN has a pair. + } + Ok(Output::Event(event)) => match event { + Event::IceConnectionStateChange(state) => { + eprintln!("NVST ICE state: {state:?}"); + // Official GFN treats hole-punch / ICE receive failure as + // non-fatal. Media is gated on DTLS, not ICE success. + } + Event::Connected => { + dtls_ready = true; + let _ = event_sender.send(NvstReceiveEvent::TransportReady("dtls")); + eprintln!("NVST DTLS handshake complete; waiting for SRTP/Mjolnir"); + if !sctp_started { + sctp_started = true; + sctp_started_at = Some(Instant::now()); + rtc.direct_api().start_sctp(true); + let channels = NvstInputChannels::create(&mut rtc); + rtcp_channel = Some(channels.rtcp); + input_channels = Some(channels); + let _ = event_sender.send(NvstReceiveEvent::TransportReady("sctp")); + eprintln!("NVST SCTP started with the eight-channel Bifrost profile"); + } + } + Event::ChannelOpen(id, label) => { + eprintln!("NVST data channel open: id={id:?} label={label}"); + if let Some(channels) = input_channels { + if id == channels.control_reliable { + if !channels.send_keepalive(&mut rtc, 0) { + eprintln!("NVST initial control keepalive could not be queued"); + } + control_keepalive_at = next_control_keepalive(Instant::now()); + } + if id == channels.control_partial { + control_partial_open = true; + } + if let Some(version) = input_state.channel_opened(channels, id) { + if !finish_nvst_input_handshake( + &mut input_state, + channels, + &mut rtc, + transport_origin, + &input_ready, + &event_sender, + version, + ) { + continue; + } + cursor_capture_attempts = 1; + cursor_capture_retry_at = + Some(Instant::now() + CURSOR_CAPTURE_RETRY_INTERVAL); + } + } + if Some(id) == rtcp_channel { + rtcp_channel_open = true; + // Ask for a keyframe immediately so the decoder can start. + feedback.request_keyframe(); + } + } + Event::ChannelData(data) => { + if let Some(channels) = input_channels + && channels.contains(data.id) + { + let label = channels.label(data.id); + let cursor_messages = server_cursor_messages(&data.data); + for message in cursor_messages { + eprintln!( + "NVST cursor wire rx: channel={label} id={:?} command=0x{:04x} offset={} cursorId={:?} position={:?} visible={:?} bytes={} raw={}", + data.id, + message.command, + message.offset, + message.cursor_id, + message.position, + message.visible, + message.raw.len(), + diagnostic_hex(&message.raw, 512), + ); + if let Some(cursor) = message.normalized { + cursor_capture_retry_at = None; + if !server_cursor_hidden + && channels.send_mouse_cursor_capture(&mut rtc, false) + { + server_cursor_hidden = true; + eprintln!( + "NVST cursor capture tx: channel={} command=0x0308 enabled=false reason=first-local-cursor", + channels.label(channels.control_reliable), + ); + } + eprintln!( + "NVST cursor dispatch: source={label} type={} id={} bytes={} raw={}", + cursor[0], + cursor[1], + cursor.len(), + diagnostic_hex(&cursor, 512), + ); + let _ = event_sender.send(NvstReceiveEvent::Cursor(cursor)); + } + } + + if data.id == channels.cursor { + cursor_capture_retry_at = None; + if !server_cursor_hidden + && channels.send_mouse_cursor_capture(&mut rtc, false) + { + server_cursor_hidden = true; + eprintln!( + "NVST cursor capture tx: channel={} command=0x0308 enabled=false reason=cursor-channel", + channels.label(channels.control_reliable), + ); + } + eprintln!( + "NVST cursor-channel raw rx: id={:?} bytes={} type={:?} cursorId={:?} raw={}", + data.id, + data.data.len(), + data.data.first(), + data.data.get(1), + diagnostic_hex(&data.data, 512), + ); + let _ = + event_sender.send(NvstReceiveEvent::Cursor(data.data.to_vec())); + continue; + } + + if verbose_diagnostics_enabled() { + eprintln!( + "NVST data channel rx: channel={label} id={:?} bytes={} raw={}", + data.id, + data.data.len(), + diagnostic_hex(&data.data, 128), + ); + } + } + if let Some(channels) = input_channels + && let Some(version) = + input_state.channel_data(channels, data.id, &data.data) + { + if !finish_nvst_input_handshake( + &mut input_state, + channels, + &mut rtc, + transport_origin, + &input_ready, + &event_sender, + version, + ) { + continue; + } + cursor_capture_attempts = 1; + cursor_capture_retry_at = + Some(Instant::now() + CURSOR_CAPTURE_RETRY_INTERVAL); + } else if Some(data.id) == rtcp_channel { + eprintln!( + "NVST rtcp1 inbound: id={:?} binary={} bytes={}", + data.id, + data.binary, + data.data.len(), + ); + } + } + Event::ChannelClose(id) => { + if let Some(channels) = input_channels { + if id == channels.control_reliable { + server_cursor_hidden = false; + cursor_capture_retry_at = None; + cursor_capture_attempts = 0; + } + let input_channel_closed = id == channels.input_partial; + if input_state.channel_closed(channels, id) || input_channel_closed { + input_ready.store(false, Ordering::Release); + let reason = if input_channel_closed { + "partially reliable input data channel closed" + } else { + "reliable input data channel closed" + }; + let _ = event_sender + .send(NvstReceiveEvent::InputUnavailable(reason.to_owned())); + } + } + if input_channels.is_some_and(|channels| id == channels.control_partial) { + control_partial_open = false; + } + if Some(id) == rtcp_channel { + rtcp_channel_open = false; + rtcp_channel = None; + } + } + Event::RtpPacket(packet) => { + let outer_payload_type = *packet.header.payload_type; + let is_audio = audio_track.as_ref().is_some_and(|audio| { + matches_audio_track(audio, outer_payload_type, *packet.header.ssrc) + }); + if is_audio { + let audio = audio_track.as_ref().expect("audio track checked above"); + let payload = if outer_payload_type == GFN_RED_PAYLOAD_TYPE { + let Some(primary) = extract_red_opus_primary(&packet.payload) + else { + let _ = event_sender.send(NvstReceiveEvent::Dropped( + NvstDropReason::MalformedRedAudio, + )); + continue; + }; + Arc::from(primary) + } else { + packet.payload + }; + let audio_ssrc = *packet.header.ssrc; + let contiguous = last_audio_sequence.is_none_or(|(ssrc, previous)| { + ssrc != audio_ssrc + || previous.wrapping_add(1) == packet.header.sequence_number + }); + last_audio_sequence = Some((audio_ssrc, packet.header.sequence_number)); + let received_at_us = packet + .timestamp + .saturating_duration_since(transport_origin) + .as_micros() + .try_into() + .unwrap_or(u64::MAX); + let frame = EncodedMediaFrame { + mid: audio.mid.clone(), + codec: "opus".to_owned(), + payload, + rtp_timestamp: u64::from(packet.header.timestamp), + clock_rate_hz: audio.clock_rate_hz, + channels: Some(audio.channels), + received_at_us, + keyframe: false, + contiguous, + }; + if let Err(error) = deliver_media_frame(&media_consumer, frame) { + if matches!(error, TransportError::MediaConsumerBackpressured) { + // Audio is real-time data. If the decoder briefly falls + // behind, discard this packet and keep the transport alive; + // queued audio is more harmful than a short concealment gap. + continue; + } + let _ = event_sender.send(NvstReceiveEvent::Dropped( + NvstDropReason::MediaConsumerClosed, + )); + rtc.disconnect(); + forward_optional(&event_sender, receiver.stop()); + return; + } + } else { + for event in receiver.process_mjolnir_payload( + *packet.header.ssrc, + packet.header.timestamp, + &packet.payload, + Instant::now(), + ) { + if !forward_receive_event( + &media_consumer, + &event_sender, + transport_origin, + event, + ) { + rtc.disconnect(); + forward_optional(&event_sender, receiver.stop()); + return; + } + } + } + } + _ => {} + }, + Err(error) => { + eprintln!("NVST WebRTC bundle failed: {error}"); + forward_optional(&event_sender, receiver.stop()); + return; + } + } + }; + + let wait = timeout + .saturating_duration_since(Instant::now()) + .min(CONTROL_RECEIVE_POLL_INTERVAL); + if wait.is_zero() { + if let Err(error) = rtc.handle_input(Input::Timeout(Instant::now())) { + eprintln!("NVST WebRTC timer failed: {error}"); + forward_optional(&event_sender, receiver.stop()); + return; + } + } else { + if let Err(error) = socket.set_read_timeout(Some(wait)) { + eprintln!("NVST UDP timeout configuration failed: {error}"); + forward_optional(&event_sender, receiver.stop()); + return; + } + match socket.recv_from(&mut datagram) { + Ok((length, source)) => { + inbound_datagrams += 1; + if inbound_datagrams == 1 + || (verbose_diagnostics_enabled() && inbound_datagrams % 50 == 0) + { + eprintln!( + "NVST WebRTC inbound={inbound_datagrams} source={source} bytes={length} dtlsReady={dtls_ready}" + ); + } + if source != bundle_peer { + continue; + } + if datagram[..length] == *b"PING" { + if let Err(error) = socket.send_to(b"PONG", source) { + eprintln!("NVST PONG send failed: {error}"); + forward_optional(&event_sender, receiver.stop()); + return; + } + continue; + } + if looks_like_rtp(&datagram[..length]) + && let Some(ssrc) = peek_rtp_ssrc(&datagram[..length]) + && seen_ssrcs.insert(ssrc) + { + let mid = audio_track + .as_ref() + .filter(|audio| { + peek_rtp_payload_type(&datagram[..length]).is_some_and( + |payload_type| matches_audio_track(audio, payload_type, ssrc), + ) + }) + .map_or_else(|| Mid::from("0"), |audio| Mid::from(audio.mid.as_str())); + rtc.direct_api() + .expect_stream_rx(Ssrc::from(ssrc), None, mid, None); + eprintln!("NVST expecting SSRC {ssrc} on bundle mid={mid}"); + } + let destination = receive_destination; + let contents = match datagram[..length].try_into() { + Ok(value) => value, + Err(error) => { + eprintln!("NVST dropping oversized UDP packet: {error}"); + continue; + } + }; + if let Err(error) = rtc.handle_input(Input::Receive( + Instant::now(), + Receive { + proto: RtcProtocol::Udp, + source: receive_source, + destination, + contents, + }, + )) { + eprintln!("NVST WebRTC handle_input failed: {error}"); + forward_optional(&event_sender, receiver.stop()); + return; + } + } + Err(error) + if matches!( + error.kind(), + std::io::ErrorKind::WouldBlock | std::io::ErrorKind::TimedOut + ) => + { + let _ = rtc.handle_input(Input::Timeout(Instant::now())); + } + Err(_) => { + forward_optional(&event_sender, receiver.stop()); + return; + } + } + } + + let timeout = if owns_media_timeout { + receiver.poll_timeout(Instant::now()) + } else { + None + }; + if timeout.is_some() { + eprintln!( + "NVST WebRTC timeout counters: inbound={inbound_datagrams}, dtlsReady={dtls_ready}" + ); + } + forward_optional(&event_sender, timeout); + } +} + +fn run_nvst_udp_receiver( + socket: UdpSocket, + config: NvstVideoConfig, + commands: Receiver, + outputs: NvstReceiverOutputs, + transport_origin: Instant, + rtc: Option, +) { + if let Some(rtc) = rtc { + run_nvst_webrtc_bundle(socket, config, commands, outputs, transport_origin, rtc); + return; + } + let NvstReceiverOutputs { + media_consumer, + event_sender, + .. + } = outputs; + let mut receiver = NvstVideoReceiver::new(config); + let stun_credentials = receiver.config.stun_credentials.clone(); + let mut datagram = vec![0_u8; 65_536]; + let mut peer_seen = false; + let mut last_ping = Instant::now() - PING_INTERVAL_BEFORE_CONNECTION; + let mut pings_sent = 0_u64; + let mut inbound_datagrams = 0_u64; + let mut handled_stun = 0_u64; + let mut invalid_stun = 0_u64; + let mut non_stun = 0_u64; + let mut wrong_source = 0_u64; + let mut receiver_reports_sent = 0_u64; + let stats_origin = Instant::now(); + let mut last_stats_log = Instant::now(); + loop { + loop { + match commands.try_recv() { + Ok(UdpReceiverCommand::Pause) => forward_optional(&event_sender, receiver.pause()), + Ok(UdpReceiverCommand::Resume) => { + forward_optional(&event_sender, receiver.resume()) + } + Ok(UdpReceiverCommand::Recover) => { + forward_optional(&event_sender, receiver.recover()) + } + Ok(UdpReceiverCommand::SendInput { reply, .. }) => { + if let Some(reply) = reply { + let _ = reply.send(Err(TransportError::InputNotReady)); + } + } + Ok(UdpReceiverCommand::Stop) | Err(TryRecvError::Disconnected) => { + forward_optional(&event_sender, receiver.stop()); + return; + } + Err(TryRecvError::Empty) => break, + } + } + + let now = Instant::now(); + let ping_interval = if peer_seen { + PING_INTERVAL_AFTER_CONNECTION + } else { + PING_INTERVAL_BEFORE_CONNECTION + }; + if now.duration_since(last_ping) >= ping_interval { + if let Some(credentials) = stun_credentials.as_ref() { + // Bifrost's dedicated Mjolnir video socket still uses the + // legacy literal PING to select the return path, even when + // ping-version 6 and ICE credentials are present. Send it + // before the authenticated binding request. Some seats accept + // the latter alone, while others leave video unrouted. + if let Err(error) = socket.send_to(b"PING", receiver.config.video_peer) { + eprintln!("NVST legacy video PING send failed: {error}"); + forward_optional(&event_sender, receiver.stop()); + return; + } + let mut transaction_id = [0_u8; 12]; + if let Err(error) = getrandom::fill(&mut transaction_id) { + eprintln!("NVST NATT transaction generation failed: {error}"); + forward_optional(&event_sender, receiver.stop()); + return; + } + let ping = build_natt_hole_punch_request( + &credentials.local_username_fragment, + &receiver.config.ping_payload, + &credentials.remote_password, + &transaction_id, + ); + if let Err(error) = socket.send_to(&ping, receiver.config.video_peer) { + eprintln!("NVST NATT send failed: {error}"); + forward_optional(&event_sender, receiver.stop()); + return; + } + pings_sent += 1; + } else { + if let Err(error) = + socket.send_to(&receiver.config.ping_payload, receiver.config.video_peer) + { + eprintln!("NVST ping send failed: {error}"); + forward_optional(&event_sender, receiver.stop()); + return; + } + pings_sent += 1; + } + last_ping = now; + } + + match socket.recv_from(&mut datagram) { + Ok((length, source)) => { + inbound_datagrams += 1; + if inbound_datagrams == 1 { + eprintln!( + "NVST raw-SRTP inbound first datagram: source={source} bytes={length} peer={}", + receiver.config.video_peer + ); + } + if source != receiver.config.video_peer { + wrong_source += 1; + } + if source == receiver.config.video_peer + && let Some(credentials) = stun_credentials.as_ref() + { + match handle_stun_datagram(&datagram[..length], source, credentials) { + StunDatagram::Handled(response) => { + handled_stun += 1; + peer_seen = true; + if let Some(response) = response + && let Err(error) = socket.send_to(&response, source) + { + eprintln!("NVST STUN response send failed: {error}"); + forward_optional(&event_sender, receiver.stop()); + return; + } + continue; + } + StunDatagram::Invalid => { + invalid_stun += 1; + continue; + } + StunDatagram::NotStun => non_stun += 1, + } + } + peer_seen |= source == receiver.config.video_peer; + for event in receiver.process_datagram(source, &datagram[..length], Instant::now()) + { + if !forward_receive_event( + &media_consumer, + &event_sender, + transport_origin, + event, + ) { + forward_optional(&event_sender, receiver.stop()); + return; + } + } + } + Err(error) if error.kind() == std::io::ErrorKind::TimedOut => {} + Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => {} + Err(_) => { + forward_optional(&event_sender, receiver.stop()); + return; + } + } + let now = Instant::now(); + if let Some(report) = receiver.poll_receiver_report(now) { + if let Err(error) = socket.send_to(&report, receiver.config.video_peer) { + eprintln!("NVST receiver report send failed: {error}"); + forward_optional(&event_sender, receiver.stop()); + return; + } + receiver_reports_sent += 1; + } + if now.duration_since(last_stats_log) >= Duration::from_secs(2) { + last_stats_log = now; + eprintln!( + "NVST rx-stats {} inbound={inbound_datagrams} pings={pings_sent} rr={receiver_reports_sent}", + receiver.stats_line(stats_origin), + ); + } + let timeout = receiver.poll_timeout(now); + if timeout.is_some() { + eprintln!( + "NVST transport timeout counters: pings={pings_sent}, inbound={inbound_datagrams}, stunHandled={handled_stun}, stunInvalid={invalid_stun}, nonStun={non_stun}, wrongSource={wrong_source}" + ); + } + forward_optional(&event_sender, timeout); + } +} + +fn forward_optional(sender: &Sender, event: Option) { + if let Some(event) = event { + let _ = sender.send(event); + } +} + +fn forward_receive_event( + media_consumer: &MediaConsumer, + event_sender: &Sender, + transport_origin: Instant, + event: NvstReceiveEvent, +) -> bool { + if let NvstReceiveEvent::Frame(frame) = event { + let media_frame = EncodedMediaFrame { + mid: "nvst-video-0".to_owned(), + codec: frame.codec.label().to_owned(), + payload: Arc::from(frame.bytes), + rtp_timestamp: u64::from(frame.timestamp), + clock_rate_hz: 90_000, + channels: None, + received_at_us: transport_origin + .elapsed() + .as_micros() + .try_into() + .unwrap_or(u64::MAX), + keyframe: frame.keyframe, + contiguous: frame.contiguous, + }; + let (reason, keep_running) = match deliver_media_frame(media_consumer, media_frame) { + Ok(()) => return true, + Err(TransportError::MediaConsumerBackpressured) => { + (NvstDropReason::MediaConsumerBackpressured, true) + } + Err(TransportError::MediaConsumerClosed) => { + (NvstDropReason::MediaConsumerClosed, false) + } + Err(_) => (NvstDropReason::MediaConsumerClosed, false), + }; + let _ = event_sender.send(NvstReceiveEvent::Dropped(reason)); + return keep_running; + } + let _ = event_sender.send(event); + true +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + const TEST_KEY: &str = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"; + const TEST_SALT: &str = "000102030405060708090A0B0C0D"; + const TEST_PEER: &str = "192.0.2.20"; + + #[test] + fn transient_video_consumer_backpressure_does_not_stop_receiver() { + let (media_consumer, _media_receiver) = std::sync::mpsc::sync_channel(1); + let (event_sender, event_receiver) = std::sync::mpsc::channel(); + let frame = || { + NvstReceiveEvent::Frame(EncodedVideoAccessUnit { + codec: NvstVideoCodec::H265, + timestamp: 90_000, + frame_index: 1, + first_stream_packet_index: 1, + keyframe: true, + contiguous: true, + bytes: vec![0, 0, 0, 1, 0x26], + }) + }; + + assert!(forward_receive_event( + &media_consumer, + &event_sender, + Instant::now(), + frame(), + )); + assert!(forward_receive_event( + &media_consumer, + &event_sender, + Instant::now(), + frame(), + )); + assert!(matches!( + event_receiver.recv().expect("backpressure event"), + NvstReceiveEvent::Dropped(NvstDropReason::MediaConsumerBackpressured) + )); + } + + fn legacy_handoff() -> Value { + json!({ + "clientUdpPort": 49005, + "videoPeerIp": TEST_PEER, + "videoPeerPort": 5004, + "srtpAesKeyHex": TEST_KEY, + "srtpSaltHex": "00000000000000009ECA935E", + "codec": "H264", + "rtpPayloadType": 96, + "rtpSsrc": 0x11223344u32, + "reorderWindowPackets": 4, + "maxAccessUnitBytes": 4096, + "timeoutMs": 500 + }) + } + + fn config() -> NvstVideoConfig { + NvstVideoConfig::from_legacy_handoff(&legacy_handoff(), None).expect("valid config") + } + + fn peer() -> SocketAddr { + SocketAddr::new(TEST_PEER.parse().expect("test IP"), 5004) + } + + fn stun_credentials() -> NvstStunCredentials { + NvstStunCredentials { + local_username_fragment: "loc1".to_owned(), + local_password: "local-password-value-01".to_owned(), + remote_username_fragment: "remote01".to_owned(), + remote_password: "remote-password-with-36-byte-value-001".to_owned(), + } + } + + fn build_plaintext_rtp_with_fec_blocks( + sequence: u16, + flags: u8, + frame_index: u32, + fec_current_block: u8, + fec_last_block: u8, + media: &[u8], + ) -> Vec { + let mut packet = vec![0x90, 0xe0]; + packet.extend_from_slice(&sequence.to_be_bytes()); + packet.extend_from_slice(&0x01020304u32.to_be_bytes()); + packet.extend_from_slice(&0x11223344u32.to_be_bytes()); + packet.extend_from_slice(&GS_VIDEO_EXTENSION_PROFILE.to_be_bytes()); + packet.extend_from_slice(&4_u16.to_be_bytes()); + packet.extend_from_slice(&(u32::from(sequence) << 8).to_le_bytes()); + packet.extend_from_slice(&frame_index.to_le_bytes()); + packet.push(flags); + packet.extend_from_slice(&[ + 0, + 0, + (fec_current_block & 0x03) << 4 | (fec_last_block & 0x03) << 6, + ]); + packet.extend_from_slice(&[0; 4]); + packet.extend_from_slice(media); + packet + } + + fn build_plaintext_rtp(sequence: u16, flags: u8, frame_index: u32, media: &[u8]) -> Vec { + build_plaintext_rtp_with_fec_blocks(sequence, flags, frame_index, 0, 0, media) + } + + fn test_srtp(config: &NvstVideoConfig) -> SrtpReceiver { + SrtpReceiver::from_material(&config.srtp) + } + + fn protect_for_test(crypto: &SrtpReceiver, mut packet: Vec, roc: u32) -> Vec { + let header = RtpHeader::parse(&packet).expect("RTP header"); + let packet_index = (u64::from(roc) << 16) | u64::from(header.sequence_number); + match &crypto.cipher { + SrtpCipher::AeadAes128Gcm { + encryption_key, + session_salt, + authentication_tag_len, + } => { + let iv = srtp_gcm_iv(*session_salt, header.ssrc, roc, header.sequence_number); + protect_aes_gcm( + &mut packet, + header.payload_offset, + encryption_key, + &iv, + *authentication_tag_len, + ); + } + SrtpCipher::AeadAes256Gcm { + encryption_key, + session_salt, + authentication_tag_len, + } => { + let iv = srtp_gcm_iv(*session_salt, header.ssrc, roc, header.sequence_number); + protect_aes_gcm( + &mut packet, + header.payload_offset, + encryption_key, + &iv, + *authentication_tag_len, + ); + } + SrtpCipher::AesCm128HmacSha1 { + encryption_key, + authentication_key, + session_salt, + authentication_tag_len, + } => { + let iv = srtp_aes_cm_iv(session_salt, header.ssrc, packet_index); + let mut cipher = Aes128Ctr::new(encryption_key.into(), (&iv).into()); + cipher.apply_keystream(&mut packet[header.payload_offset..]); + let mut mac = HmacSha1::new_from_slice(authentication_key).expect("fixed key"); + mac.update(&packet); + mac.update(&roc.to_be_bytes()); + packet.extend_from_slice(&mac.finalize().into_bytes()[..*authentication_tag_len]); + } + SrtpCipher::AesCm256HmacSha1 { + encryption_key, + authentication_key, + session_salt, + authentication_tag_len, + } => { + let iv = srtp_aes_cm_iv(session_salt, header.ssrc, packet_index); + let mut cipher = Aes256Ctr::new(encryption_key.into(), (&iv).into()); + cipher.apply_keystream(&mut packet[header.payload_offset..]); + let mut mac = HmacSha1::new_from_slice(authentication_key).expect("fixed key"); + mac.update(&packet); + mac.update(&roc.to_be_bytes()); + packet.extend_from_slice(&mac.finalize().into_bytes()[..*authentication_tag_len]); + } + } + packet + } + + #[test] + fn legacy_schema_defaults_to_aes_256_gcm_8_with_explicit_salt() { + let config = config(); + assert_eq!(config.video_peer(), peer()); + assert_eq!(config.bundle_peer(), peer()); + assert_eq!(config.srtp_profile(), NvstSrtpProfile::AeadAes256Gcm8); + let NvstSrtpMaterial::AeadAes256Gcm { master_salt, .. } = config.srtp else { + panic!("legacy handoff must choose AES-256-GCM"); + }; + assert_eq!( + master_salt, + decode_fixed_hex::<12>("00000000000000009ECA935E", NvstConfigError::InvalidSrtpSalt) + .expect("salt"), + ); + } + + #[test] + fn handoff_uses_distinct_routable_bundle_peer_when_supplied() { + let mut handoff = legacy_handoff(); + handoff["videoPeerIp"] = json!("169.254.0.21"); + handoff["bundlePeerIp"] = json!("198.51.100.20"); + handoff["bundlePeerPort"] = json!(5006); + let config = NvstVideoConfig::from_legacy_handoff(&handoff, None).expect("valid peers"); + assert_eq!(config.video_peer(), "169.254.0.21:5004".parse().unwrap()); + assert_eq!(config.bundle_peer(), "198.51.100.20:5006".parse().unwrap()); + } + + #[test] + fn handoff_accepts_only_explicit_standard_opus_track_metadata() { + let mut handoff = legacy_handoff(); + handoff["audioTrack"] = json!({ + "payloadType": 97, + "codec": "opus", + "clockRateHz": 48_000, + "channels": 2, + "mid": "audio-main", + "ssrc": 424242, + }); + let config = + NvstVideoConfig::from_legacy_handoff(&handoff, None).expect("standard Opus track"); + let audio = config.audio_track().expect("audio track"); + assert_eq!(audio.payload_type, 97); + assert_eq!(audio.clock_rate_hz, 48_000); + assert_eq!(audio.channels, 2); + assert_eq!(audio.mid, "audio-main"); + assert!(matches_audio_track(audio, 97, 424242)); + assert!(!matches_audio_track(audio, 96, 424242)); + assert!(!matches_audio_track(audio, 97, 7)); + + handoff["audioTrack"]["codec"] = json!("proprietary"); + assert!(matches!( + NvstVideoConfig::from_legacy_handoff(&handoff, None), + Err(NvstConfigError::InvalidAudioTrack) + )); + } + + #[test] + fn red_pt63_routes_to_negotiated_opus_pt111_and_extracts_the_primary_block() { + let track = NvstAudioTrack { + payload_type: GFN_OPUS_PAYLOAD_TYPE, + clock_rate_hz: 48_000, + channels: 2, + mid: "audio".to_owned(), + ssrc: Some(42), + }; + assert!(matches_audio_track(&track, GFN_OPUS_PAYLOAD_TYPE, 42)); + assert!(matches_audio_track(&track, GFN_RED_PAYLOAD_TYPE, 42)); + assert!(!matches_audio_track(&track, GFN_RED_PAYLOAD_TYPE, 7)); + + let red_payload = [ + 0x80 | GFN_OPUS_PAYLOAD_TYPE, + 0x00, + 0x00, + 0x03, + GFN_OPUS_PAYLOAD_TYPE, + 0x11, + 0x22, + 0x33, + 0xf8, + 0xff, + ]; + assert_eq!( + extract_red_opus_primary(&red_payload), + Some(&[0xf8, 0xff][..]) + ); + } + + #[test] + fn red_primary_extraction_rejects_malformed_or_unbounded_payloads() { + assert_eq!(extract_red_opus_primary(&[]), None); + assert_eq!(extract_red_opus_primary(&[110, 0xf8]), None); + assert_eq!(extract_red_opus_primary(&[GFN_OPUS_PAYLOAD_TYPE]), None); + + let mut too_many_blocks = Vec::new(); + for _ in 0..=MAX_REDUNDANT_AUDIO_BLOCKS { + too_many_blocks.extend_from_slice(&[0x80 | GFN_OPUS_PAYLOAD_TYPE, 0, 0, 0]); + } + too_many_blocks.extend_from_slice(&[GFN_OPUS_PAYLOAD_TYPE, 0xf8]); + assert_eq!(extract_red_opus_primary(&too_many_blocks), None); + + let mut oversized_primary = vec![GFN_OPUS_PAYLOAD_TYPE]; + oversized_primary.resize(MAX_OPUS_PACKET_BYTES + 2, 0xf8); + assert_eq!(extract_red_opus_primary(&oversized_primary), None); + } + + #[test] + fn ping_version_six_requires_all_ice_credentials() { + let mut handoff = legacy_handoff(); + handoff["pingVersion"] = json!(6); + assert!(matches!( + NvstVideoConfig::from_legacy_handoff(&handoff, None), + Err(NvstConfigError::MissingField("localIceUsernameFragment")) + )); + + handoff["localIceUsernameFragment"] = json!("loc1"); + handoff["localIcePassword"] = json!("local-password-value-01"); + handoff["remoteIceUsernameFragment"] = json!("remote01"); + handoff["remoteIcePassword"] = json!("remote-password-with-36-byte-value-001"); + let config = NvstVideoConfig::from_legacy_handoff(&handoff, None) + .expect("complete version-six credentials"); + assert_eq!(config.ping_version, Some(6)); + assert!(config.stun_credentials.is_some()); + assert!(!format!("{config:?}").contains("local-password-value-01")); + } + + #[test] + fn reserved_bundle_socket_binds_unspecified_ipv4() { + let socket = reserve_nvst_udp_socket().expect("reserve"); + let addr = socket.local_addr().expect("local"); + assert!( + addr.ip().is_unspecified(), + "official binds 0.0.0.0, advertised NIC IPv4 is separate" + ); + assert_ne!(addr.port(), 0); + } + + #[test] + fn reserved_nvst_pair_places_bundle_immediately_after_video() { + let (bundle, video) = reserve_nvst_socket_pair().expect("reserve pair"); + let bundle_addr = bundle.local_addr().expect("bundle address"); + let video_addr = video.local_addr().expect("video address"); + + assert!(bundle_addr.ip().is_unspecified()); + assert!(video_addr.ip().is_unspecified()); + assert_eq!(bundle_addr.port(), video_addr.port() + 1); + } + + #[test] + fn link_local_interfaces_use_distinct_logical_ice_addresses() { + let local: SocketAddr = "169.254.0.21:49000".parse().unwrap(); + let remote: SocketAddr = "169.254.0.22:5006".parse().unwrap(); + assert_eq!( + logical_ice_addr(local, 1), + "127.0.0.1:49000".parse().unwrap() + ); + assert_eq!( + logical_ice_addr(remote, 2), + "127.0.0.2:5006".parse().unwrap() + ); + assert!(Candidate::host(logical_ice_addr(local, 1), "udp").is_ok()); + assert!(Candidate::host(logical_ice_addr(remote, 2), "udp").is_ok()); + } + + #[test] + fn natt_hole_punch_uses_setup_ping_payload_not_v2_ufrag() { + let credentials = stun_credentials(); + let packet = build_natt_hole_punch_request( + &credentials.local_username_fragment, + b"srv1", + &credentials.remote_password, + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], + ); + let (_, username) = find_stun_attribute(&packet, STUN_ATTR_USERNAME).expect("USERNAME"); + assert_eq!(username, b"srv1:loc1"); + assert_ne!( + username, + format!( + "{}:{}", + credentials.remote_username_fragment, credentials.local_username_fragment + ) + .as_bytes() + ); + assert!(valid_stun_fingerprint(&packet)); + assert!(valid_stun_message_integrity( + &packet, + credentials.remote_password.as_bytes() + )); + } + + #[test] + fn version_six_binding_request_matches_known_answer() { + let packet = build_stun_binding_request( + &stun_credentials(), + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], + ); + assert_eq!( + packet, + hex_bytes( + "000100342112A442000102030405060708090A0B0006000D72656D6F746530313A6C6F633100000000080014B276DC1C7949494C7EF7EB226BE8BB5E0EE5AABD802800045A8349EF" + ), + ); + assert!(valid_stun_fingerprint(&packet)); + assert!(valid_stun_message_integrity( + &packet, + b"remote-password-with-36-byte-value-001" + )); + } + + #[test] + fn version_six_validates_requests_and_builds_authenticated_responses() { + let credentials = stun_credentials(); + let transaction_id = [0x11; 12]; + let request = build_authenticated_stun_packet( + STUN_BINDING_REQUEST, + &transaction_id, + credentials.local_password.as_bytes(), + &[(STUN_ATTR_USERNAME, b"loc1:remote01".to_vec())], + ); + let source: SocketAddr = "192.0.2.20:5004".parse().expect("source"); + let StunDatagram::Handled(Some(response)) = + handle_stun_datagram(&request, source, &credentials) + else { + panic!("authenticated binding request must produce a response"); + }; + assert_eq!( + u16::from_be_bytes([response[0], response[1]]), + STUN_BINDING_SUCCESS_RESPONSE + ); + assert_eq!(&response[8..20], &transaction_id); + assert!(valid_stun_fingerprint(&response)); + assert!(valid_stun_message_integrity( + &response, + credentials.local_password.as_bytes() + )); + let (_, mapped) = find_stun_attribute(&response, STUN_ATTR_XOR_MAPPED_ADDRESS) + .expect("XOR-MAPPED-ADDRESS"); + assert_eq!(mapped[1], 1); + assert_eq!( + u16::from_be_bytes([mapped[2], mapped[3]]) ^ ((STUN_MAGIC_COOKIE >> 16) as u16), + 5004 + ); + + let mut tampered = request; + tampered[24] ^= 1; + assert!(matches!( + handle_stun_datagram(&tampered, source, &credentials), + StunDatagram::Invalid + )); + } + + #[test] + fn gfn_local_ice_credentials_match_official_lengths() { + let creds = generate_gfn_local_ice_credentials().expect("OS randomness"); + assert_eq!(creds.ufrag.len(), 4); + assert_eq!(creds.pass.len(), 22); + } + + #[test] + fn synthesized_ice_success_matches_the_request_transaction() { + let credentials = stun_credentials(); + let transaction_id = [7_u8; 12]; + let mapped = "192.168.1.104:54454".parse().expect("mapped"); + let response = + synthesize_ice_binding_success(&transaction_id, mapped, &credentials.remote_password); + assert_eq!( + u16::from_be_bytes([response[0], response[1]]), + STUN_BINDING_SUCCESS_RESPONSE + ); + assert_eq!(&response[8..20], &transaction_id); + assert!(valid_stun_fingerprint(&response)); + assert!(valid_stun_message_integrity( + &response, + credentials.remote_password.as_bytes() + )); + } + + #[test] + fn legacy_gcm_key_derivation_matches_known_answer() { + let config = config(); + let receiver = test_srtp(&config); + let SrtpCipher::AeadAes256Gcm { + encryption_key, + session_salt, + .. + } = receiver.cipher + else { + panic!("legacy handoff must derive an AES-256-GCM session"); + }; + assert_eq!( + encryption_key, + decode_fixed_hex::<32>( + "0E44A0B0E7F1BDBB298CBEE52C9F8AC1C37726768C946F59BDAAA099608CBF66", + NvstConfigError::InvalidAesKey, + ) + .expect("key"), + ); + assert_eq!( + session_salt, + decode_fixed_hex::<12>("78B9D97B7FFB37CAD539A29D", NvstConfigError::InvalidSrtpSalt) + .expect("salt"), + ); + } + + #[test] + fn selector_prefers_valid_legacy_nvst_and_falls_back_for_h265() { + let context = json!({ "nvstVideo": legacy_handoff() }); + assert!(matches!( + select_preferred_video_transport(&context), + PreferredVideoTransport::Nvst(_) + )); + let configured = parse_nvst_video_handoff(&json!({ + "nvstVideo": legacy_handoff(), + "settings": { "fps": 60 }, + "session": { "negotiatedStreamProfile": { "fps": 120 } } + })) + .expect("valid NVST context") + .expect("NVST handoff"); + assert_eq!(configured.frame_time_us, 8_333); + let capped = parse_nvst_video_handoff(&json!({ + "nvstVideo": legacy_handoff(), + "settings": { "fps": 360 } + })) + .expect("valid high-FPS NVST context") + .expect("NVST handoff"); + assert_eq!(capped.frame_time_us, 4_166); + assert!(matches!( + select_preferred_video_transport(&json!({ "nvstTransport": { "tracks": [] } })), + PreferredVideoTransport::WebRtcFallback(NvstFallbackReason::InvalidNvstHandoff( + NvstConfigError::MissingNvstVideoHandoff + )) + )); + + let mut missing_gcm_salt = legacy_handoff(); + missing_gcm_salt + .as_object_mut() + .expect("handoff object") + .remove("srtpSaltHex"); + assert!(matches!( + NvstVideoConfig::from_legacy_handoff(&missing_gcm_salt, None), + Err(NvstConfigError::MissingField("srtpSaltHex")) + )); + + let mut invalid = legacy_handoff(); + invalid["codec"] = json!("VP9"); + let context = json!({ "nvstVideo": invalid }); + assert!(matches!( + select_preferred_video_transport(&context), + PreferredVideoTransport::WebRtcFallback(NvstFallbackReason::InvalidNvstHandoff( + NvstConfigError::UnsupportedCodec(_) + )) + )); + + let mut missing_cm_salt = legacy_handoff(); + missing_cm_salt + .as_object_mut() + .expect("handoff object") + .remove("srtpSaltHex"); + missing_cm_salt["srtpProfile"] = json!("AES_CM_128_HMAC_SHA1_80"); + missing_cm_salt["srtpAesKeyHex"] = json!("000102030405060708090A0B0C0D0E0F"); + assert!(matches!( + NvstVideoConfig::from_legacy_handoff(&missing_cm_salt, None), + Err(NvstConfigError::MissingField("srtpSaltHex")) + )); + missing_cm_salt["srtpSaltHex"] = json!(TEST_SALT); + let explicit_cm = NvstVideoConfig::from_legacy_handoff(&missing_cm_salt, None) + .expect("explicit AES-CM profile"); + assert_eq!( + explicit_cm.srtp_profile(), + NvstSrtpProfile::AesCm128HmacSha1_80 + ); + + let mut gcm_128 = legacy_handoff(); + gcm_128["srtpProfile"] = json!("AEAD_AES_128_GCM"); + gcm_128["srtpAesKeyHex"] = json!("000102030405060708090A0B0C0D0E0F"); + gcm_128["srtpSaltHex"] = json!("00000000000000009ECA935E"); + assert_eq!( + NvstVideoConfig::from_legacy_handoff(&gcm_128, None) + .expect("explicit AES-128-GCM profile") + .srtp_profile(), + NvstSrtpProfile::AeadAes128Gcm + ); + + let mut cm_32 = gcm_128; + cm_32["srtpProfile"] = json!("AES_CM_128_HMAC_SHA1_32"); + cm_32["srtpSaltHex"] = json!(TEST_SALT); + assert_eq!( + NvstVideoConfig::from_legacy_handoff(&cm_32, None) + .expect("explicit AES-CM-32 profile") + .srtp_profile(), + NvstSrtpProfile::AesCm128HmacSha1_32 + ); + } + + #[test] + fn rejects_invalid_peer_and_secret_material() { + let mut handoff = legacy_handoff(); + handoff["videoPeerIp"] = json!("0.0.0.0"); + assert!(matches!( + NvstVideoConfig::from_legacy_handoff(&handoff, None), + Err(NvstConfigError::InvalidPeerIp(_)) + )); + let mut handoff = legacy_handoff(); + handoff["srtpAesKeyHex"] = json!("not-a-key"); + assert!(matches!( + NvstVideoConfig::from_legacy_handoff(&handoff, None), + Err(NvstConfigError::InvalidAesKey) + )); + + let mut aes_128 = legacy_handoff(); + aes_128["srtpProfile"] = json!("AEAD_AES_128_GCM"); + aes_128["srtpAesKeyHex"] = json!("000102030405060708090A0B0C0D0E0G"); + assert!(matches!( + NvstVideoConfig::from_legacy_handoff(&aes_128, None), + Err(NvstConfigError::InvalidAesKey) + )); + } + + #[test] + fn srtp_aes_cm_hmac_sha1_known_answer_unprotects_packet_when_explicitly_selected() { + let key = decode_fixed_hex::<16>( + "000102030405060708090A0B0C0D0E0F", + NvstConfigError::InvalidAesKey, + ) + .expect("key"); + let salt = + decode_fixed_hex::<14>(TEST_SALT, NvstConfigError::InvalidSrtpSalt).expect("salt"); + let material = NvstSrtpMaterial::AesCm128HmacSha1 { + master_key: key, + master_salt: salt, + authentication_tag_len: SRTP_AES_CM_HMAC_SHA1_80_TAG_LEN, + }; + let crypto = SrtpReceiver::from_material(&material); + // Frozen plaintext so the crypto known-answer vector stays independent of + // the RTP packet-layout helper: 12-byte header + 16-byte inline metadata + // + 6 bytes of media. + let plaintext = + hex_bytes("80E01234010203041122334434120000070000000700000000000000000000016588"); + let protected = protect_for_test(&crypto, plaintext.clone(), 0); + assert_eq!( + protected, + hex_bytes( + "80E01234010203041122334408BA995FCB62EA430BE6EDEF8D4DE06268F0D6D702702082DDFADA13AE83402B" + ), + "independent AES-CTR/HMAC known-answer vector", + ); + let mut receiver = SrtpReceiver::from_material(&material); + let unprotected = receiver.unprotect(&protected).expect("authenticated SRTP"); + assert_eq!(unprotected.plaintext, plaintext); + assert_eq!(unprotected.index, 0x1234); + + let mut tampered = protected; + let last = tampered.last_mut().expect("authentication tag"); + *last ^= 0x01; + let mut receiver = SrtpReceiver::from_material(&material); + assert!(matches!( + receiver.unprotect(&tampered), + Err(NvstDropReason::AuthenticationFailed) + )); + } + + #[test] + fn srtp_aead_aes_256_gcm_rfc_known_answer_unprotects_and_rejects_tampering_and_replay() { + let session_key = + decode_fixed_hex::<32>(TEST_KEY, NvstConfigError::InvalidAesKey).expect("key"); + let session_salt = + decode_fixed_hex::<12>("517569642070726F2071756F", NvstConfigError::InvalidSrtpSalt) + .expect("salt"); + let mut receiver = SrtpReceiver { + cipher: SrtpCipher::AeadAes256Gcm { + encryption_key: session_key, + session_salt, + authentication_tag_len: SRTP_AEAD_AES_GCM_TAG_LEN, + }, + replay: ReplayWindow::default(), + }; + let protected = hex_bytes( + "8040F17B8041F8D35501A0B232B1DE78A822FE12EF9F78FA332E33AAB18012389A58E2F3B50B2A0276FFAE0F1BA63799B87B7AA3DB36DFFFD6B0F9BB7878D7A76C13", + ); + let expected = hex_bytes( + "8040F17B8041F8D35501A0B247616C6C696120657374206F6D6E69732064697669736120696E207061727465732074726573", + ); + let unprotected = receiver.unprotect(&protected).expect("RFC 7714 packet"); + assert_eq!(unprotected.plaintext, expected); + assert!(matches!( + receiver.unprotect(&protected), + Err(NvstDropReason::ReplayRejected) + )); + + let mut tampered = protected; + tampered[20] ^= 0x01; + let mut receiver = SrtpReceiver { + cipher: SrtpCipher::AeadAes256Gcm { + encryption_key: session_key, + session_salt, + authentication_tag_len: SRTP_AEAD_AES_GCM_TAG_LEN, + }, + replay: ReplayWindow::default(), + }; + assert!(matches!( + receiver.unprotect(&tampered), + Err(NvstDropReason::AuthenticationFailed) + )); + } + + #[test] + fn srtp_aead_aes_128_gcm_rfc_known_answer_unprotects_and_rejects_tampering_and_replay() { + let session_key = decode_fixed_hex::<16>( + "000102030405060708090A0B0C0D0E0F", + NvstConfigError::InvalidAesKey, + ) + .expect("key"); + let session_salt = + decode_fixed_hex::<12>("517569642070726F2071756F", NvstConfigError::InvalidSrtpSalt) + .expect("salt"); + let mut receiver = SrtpReceiver { + cipher: SrtpCipher::AeadAes128Gcm { + encryption_key: session_key, + session_salt, + authentication_tag_len: SRTP_AEAD_AES_GCM_TAG_LEN, + }, + replay: ReplayWindow::default(), + }; + let protected = hex_bytes( + "8040F17B8041F8D35501A0B2F24DE3A3FB34DE6CACBA861C9D7E4BCABE633BD50D294E6F42A5F47A51C7D19B36DE3ADF8833899D7F27BEB16A9152CF765EE4390CCE", + ); + let expected = hex_bytes( + "8040F17B8041F8D35501A0B247616C6C696120657374206F6D6E69732064697669736120696E207061727465732074726573", + ); + let unprotected = receiver.unprotect(&protected).expect("RFC 7714 packet"); + assert_eq!(unprotected.plaintext, expected); + assert!(matches!( + receiver.unprotect(&protected), + Err(NvstDropReason::ReplayRejected) + )); + + let mut tampered = protected; + tampered[20] ^= 0x01; + let mut receiver = SrtpReceiver { + cipher: SrtpCipher::AeadAes128Gcm { + encryption_key: session_key, + session_salt, + authentication_tag_len: SRTP_AEAD_AES_GCM_TAG_LEN, + }, + replay: ReplayWindow::default(), + }; + assert!(matches!( + receiver.unprotect(&tampered), + Err(NvstDropReason::AuthenticationFailed) + )); + } + + #[test] + fn parses_rtp_extensions_and_padding_after_srtp_unprotect() { + let mut packet = vec![0xb0, 0x60, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1]; + packet.extend_from_slice(&[0xbe, 0xde, 0, 1, 0xaa, 0xbb, 0xcc, 0xdd]); + packet.extend_from_slice(&[1, 2, 3, 4, 2, 2]); + let header = RtpHeader::parse(&packet).expect("extension parsed"); + assert_eq!(header.payload_offset, 20); + assert_eq!( + header.payload(&packet).expect("padding removed"), + &[1, 2, 3, 4] + ); + } + + #[test] + fn gs_extension_requires_exactly_four_words() { + let exact = build_plaintext_rtp(1, FLAG_SOF, 7, &[0, 0, 1, 0x65]); + assert!(RtpHeader::parse(&exact).is_ok()); + + let mut oversized = exact.clone(); + oversized[14..16].copy_from_slice(&5_u16.to_be_bytes()); + oversized.splice(32..32, [0_u8; 4]); + assert!(matches!( + RtpHeader::parse(&oversized), + Err(RtpParseError::InvalidExtensionLength) + )); + + let mut truncated = exact; + truncated[14..16].copy_from_slice(&5_u16.to_be_bytes()); + assert!(matches!( + RtpHeader::parse(&truncated), + Err(RtpParseError::InvalidExtensionLength) + )); + } + + #[test] + fn parses_the_wire_stream_packet_index_as_a_24_bit_value() { + let packet = build_plaintext_rtp(1, FLAG_SOF | FLAG_EOF | FLAG_CONTAINS_PIC_DATA, 7, &[]); + // Point the packet index at a 24-bit value to verify the wire shift. + let mut packet = packet; + packet[16..20].copy_from_slice(&(0x12_34_56_u32 << 8).to_le_bytes()); + + let header = RtpHeader::parse(&packet).expect("RTP header"); + let payload = header.payload(&packet).expect("payload"); + let (video, media) = NvVideoPacket::parse(&header, payload).expect("NV video header"); + assert_eq!(video.stream_packet_index, 0x12_34_56); + assert_eq!(video.frame_index, 7); + assert!(!video.is_fec); + assert!(media.is_empty()); + } + + #[test] + fn classifies_fec_packets_from_the_extension_group_coordinates() { + let mut packet = build_plaintext_rtp(3, FLAG_CONTAINS_PIC_DATA, 7, &[0xaa]); + // FecId=3, SrcPkts=3 with the FEC-group marker bits set => correction packet. + packet[28..32].copy_from_slice(&0x00c0_3420_u32.to_le_bytes()); + let header = RtpHeader::parse(&packet).expect("RTP header"); + let payload = header.payload(&packet).expect("payload"); + let (video, _) = NvVideoPacket::parse(&header, payload).expect("NV video header"); + assert!(video.is_fec); + + // Source packet: FecId=2 < SrcPkts=3. + let mut packet = build_plaintext_rtp(2, FLAG_CONTAINS_PIC_DATA, 7, &[0xaa]); + packet[28..32].copy_from_slice(&0x00c0_2420_u32.to_le_bytes()); + let header = RtpHeader::parse(&packet).expect("RTP header"); + let payload = header.payload(&packet).expect("payload"); + let (video, _) = NvVideoPacket::parse(&header, payload).expect("NV video header"); + assert!(!video.is_fec); + } + + #[test] + fn strips_the_gamestream_frame_header_before_annex_b_video() { + let header = NvVideoPacket { + stream_packet_index: 1, + frame_index: 9, + flags: FLAG_SOF | FLAG_EOF | FLAG_CONTAINS_PIC_DATA, + fec_current_block: 0, + fec_last_block: 0, + is_fec: false, + }; + let mut payload = vec![0x01, 0, 0, 2, 0, 0, 0, 0]; + payload.extend_from_slice(&[ + 0, 0, 1, 0x67, 0xaa, 0, 0, 0, 1, 0x68, 0xbb, 0, 0, 1, 0x65, 0xcc, + ]); + + let mut assembler = VideoAccessUnitAssembler::new(NvstVideoCodec::H264, 4096); + let frame = assembler + .push(header, 90_000, &payload) + .expect("valid frame") + .expect("complete frame"); + + assert_eq!( + frame.bytes, + [ + 0, 0, 0, 1, 0x67, 0xaa, 0, 0, 0, 1, 0x68, 0xbb, 0, 0, 1, 0x65, 0xcc, + ] + ); + assert!(frame.keyframe); + } + + #[test] + fn assembles_h265_annex_b_and_detects_irap_keyframes() { + let header = NvVideoPacket { + stream_packet_index: 1, + frame_index: 10, + flags: FLAG_SOF | FLAG_EOF | FLAG_CONTAINS_PIC_DATA, + fec_current_block: 0, + fec_last_block: 0, + is_fec: false, + }; + let mut payload = vec![0x01, 0, 0, 2, 0, 0, 0, 0]; + payload.extend_from_slice(&[0, 0, 0, 1, 19 << 1, 1, 0xaa]); + let mut assembler = VideoAccessUnitAssembler::new(NvstVideoCodec::H265, 4096); + + let frame = assembler + .push(header, 90_000, &payload) + .expect("valid H.265 frame") + .expect("complete frame"); + + assert_eq!(frame.codec, NvstVideoCodec::H265); + assert_eq!(frame.bytes, [0, 0, 0, 1, 19 << 1, 1, 0xaa]); + assert!(frame.keyframe); + } + + #[test] + fn assembles_av1_payload_after_the_gamestream_frame_header() { + let header = NvVideoPacket { + stream_packet_index: 1, + frame_index: 11, + flags: FLAG_SOF | FLAG_EOF | FLAG_CONTAINS_PIC_DATA, + fec_current_block: 0, + fec_last_block: 0, + is_fec: false, + }; + let payload = [0x01, 0, 0, 2, 11, 0, 0, 0, 0x12, 0x34, 0x56]; + let mut assembler = VideoAccessUnitAssembler::new(NvstVideoCodec::Av1, 4096); + + let frame = assembler + .push(header, 90_000, &payload) + .expect("valid AV1 frame") + .expect("complete frame"); + + assert_eq!(frame.codec, NvstVideoCodec::Av1); + assert_eq!(frame.bytes, [0x12, 0x34, 0x56]); + assert!(frame.keyframe); + } + + #[test] + fn strips_the_gfn_cloud_extended_av1_frame_header() { + let header = NvVideoPacket { + stream_packet_index: 1, + frame_index: 12, + flags: FLAG_SOF | FLAG_EOF | FLAG_CONTAINS_PIC_DATA, + fec_current_block: 0, + fec_last_block: 0, + is_fec: false, + }; + let mut payload = vec![0_u8; GFN_EXTENDED_FRAME_HEADER_BYTES]; + payload[0] = 0x81; + payload[3] = 2; + payload[16..20].copy_from_slice(&3_u32.to_le_bytes()); + // A temporal-unit length byte is not necessarily a valid OBU header. + payload.extend_from_slice(&[0x81, 0x01, 0x12]); + let mut assembler = VideoAccessUnitAssembler::new(NvstVideoCodec::Av1, 4096); + + let frame = assembler + .push(header, 90_000, &payload) + .expect("valid extended AV1 frame") + .expect("complete frame"); + + assert_eq!(frame.bytes, [0x81, 0x01, 0x12]); + assert!(frame.keyframe); + } + + #[test] + fn trims_gfn_cloud_av1_padding_to_the_advertised_access_unit_size() { + let header = NvVideoPacket { + stream_packet_index: 1, + frame_index: 13, + flags: FLAG_SOF | FLAG_EOF | FLAG_CONTAINS_PIC_DATA, + fec_current_block: 0, + fec_last_block: 0, + is_fec: false, + }; + let mut payload = vec![0_u8; GFN_EXTENDED_FRAME_HEADER_BYTES]; + payload[0] = 0x81; + payload[3] = 2; + payload[16..20].copy_from_slice(&5_u32.to_le_bytes()); + payload.extend_from_slice(&[0x12, 0x00, 0x32, 0x01, 0xaa, 0, 0, 0]); + let mut assembler = VideoAccessUnitAssembler::new(NvstVideoCodec::Av1, 4096); + + let frame = assembler + .push(header, 90_000, &payload) + .expect("valid padded AV1 frame") + .expect("complete frame"); + + assert_eq!(frame.bytes, [0x12, 0x00, 0x32, 0x01, 0xaa]); + assert!(frame.keyframe); + } + + #[test] + fn trims_av1_fec_padding_from_the_final_packet() { + let first = NvVideoPacket { + stream_packet_index: 1, + frame_index: 12, + flags: FLAG_SOF | FLAG_CONTAINS_PIC_DATA, + fec_current_block: 0, + fec_last_block: 0, + is_fec: false, + }; + let last = NvVideoPacket { + stream_packet_index: 2, + frame_index: 12, + flags: FLAG_EOF | FLAG_CONTAINS_PIC_DATA, + fec_current_block: 0, + fec_last_block: 0, + is_fec: false, + }; + let first_payload = [0x01, 0, 0, 2, 3, 0, 0, 0, 0x12, 0x00]; + let padded_last_payload = [0x32, 0x01, 0xaa, 0, 0, 0, 0]; + let mut assembler = VideoAccessUnitAssembler::new(NvstVideoCodec::Av1, 4096); + + assert!( + assembler + .push(first, 90_000, &first_payload) + .expect("valid AV1 first packet") + .is_none() + ); + let frame = assembler + .push(last, 90_000, &padded_last_payload) + .expect("valid AV1 final packet") + .expect("complete frame"); + + assert_eq!(frame.bytes, [0x12, 0x00, 0x32, 0x01, 0xaa]); + assert!(frame.keyframe); + } + + #[test] + fn parses_all_supported_nvst_video_codec_names() { + assert_eq!( + NvstVideoCodec::parse("AVC").expect("AVC"), + NvstVideoCodec::H264 + ); + assert_eq!( + NvstVideoCodec::parse("HEVC").expect("HEVC"), + NvstVideoCodec::H265 + ); + assert_eq!( + NvstVideoCodec::parse("AV1").expect("AV1"), + NvstVideoCodec::Av1 + ); + } + + #[test] + fn annex_b_scanner_returns_the_earliest_mixed_width_start_code() { + assert_eq!( + find_annex_b_start_code(&[0, 0, 1, 0x67, 0, 0, 0, 1, 0x68]), + Some((0, 3)) + ); + assert_eq!( + find_annex_b_start_code(&[0, 0, 0, 1, 0x67, 0, 0, 1, 0x68]), + Some((0, 4)) + ); + } + + #[test] + fn strips_a_terminal_access_unit_delimiter_before_decoder_submission() { + let mut bytes = vec![0, 0, 0, 1, 0x65, 0xaa, 0, 0, 0, 1, 0x09, 0xf0]; + strip_trailing_access_unit_delimiter(NvstVideoCodec::H264, &mut bytes); + assert_eq!(bytes, [0, 0, 0, 1, 0x65, 0xaa]); + + let mut bytes = vec![0, 0, 0, 1, 0x09, 0xf0, 0, 0, 1, 0x61, 0xbb]; + strip_trailing_access_unit_delimiter(NvstVideoCodec::H264, &mut bytes); + assert_eq!(bytes, [0, 0, 0, 1, 0x09, 0xf0, 0, 0, 1, 0x61, 0xbb]); + } + + #[test] + fn assembles_a_single_packet_frame_without_the_picture_data_flag() { + let header = NvVideoPacket { + stream_packet_index: 25, + frame_index: 12, + flags: FLAG_SOF | FLAG_EOF, + fec_current_block: 0, + fec_last_block: 0, + is_fec: false, + }; + let mut assembler = VideoAccessUnitAssembler::new(NvstVideoCodec::H264, 4096); + let frame = assembler + .push(header, 90_000, &[0x81, 0x08, 0, 0, 0, 1, 0x61, 0xaa]) + .expect("source packet") + .expect("complete frame"); + assert_eq!(frame.bytes, [0, 0, 0, 1, 0x61, 0xaa]); + } + + #[test] + fn rejects_a_start_packet_without_nearby_annex_b_video() { + let header = NvVideoPacket { + stream_packet_index: 1, + frame_index: 9, + flags: FLAG_SOF | FLAG_EOF | FLAG_CONTAINS_PIC_DATA, + fec_current_block: 0, + fec_last_block: 0, + is_fec: false, + }; + let payload = vec![0x81; MAX_GS_FRAME_HEADER_BYTES + 8]; + let mut assembler = VideoAccessUnitAssembler::new(NvstVideoCodec::H264, 4096); + + assert!(matches!( + assembler.push(header, 90_000, &payload), + Err(NvstDropReason::MissingAnnexBStartCode) + )); + } + + #[test] + fn receiver_reorders_authenticated_packets_and_emits_annex_b_frame() { + let config = config(); + let feedback = config.feedback(); + let crypto = test_srtp(&config); + let first = protect_for_test( + &crypto, + build_plaintext_rtp( + 10, + FLAG_SOF | FLAG_CONTAINS_PIC_DATA, + 9, + &[0, 0, 0, 1, 0x65], + ), + 0, + ); + let middle = protect_for_test( + &crypto, + build_plaintext_rtp(11, FLAG_CONTAINS_PIC_DATA, 9, &[0xaa]), + 0, + ); + let last = protect_for_test( + &crypto, + build_plaintext_rtp(12, FLAG_EOF | FLAG_CONTAINS_PIC_DATA, 9, &[0xbb]), + 0, + ); + let mut receiver = NvstVideoReceiver::new(config); + assert!( + receiver + .process_datagram(peer(), &first, Instant::now()) + .is_empty() + ); + assert!( + receiver + .process_datagram(peer(), &last, Instant::now()) + .is_empty() + ); + let events = receiver.process_datagram(peer(), &middle, Instant::now()); + assert_eq!(events.len(), 1); + let NvstReceiveEvent::Frame(frame) = &events[0] else { + panic!("expected frame, got {events:?}"); + }; + assert_eq!(frame.frame_index, 9); + assert!(frame.keyframe); + assert_eq!(frame.bytes, [0, 0, 0, 1, 0x65, 0xaa, 0xbb]); + assert_eq!(feedback.take_nack(), None); + assert_eq!(feedback.completed_frame_snapshot(), (1, 7, frame.timestamp)); + assert!(feedback.take_completed_frame().is_none()); + feedback.publish_accepted_frame(7, Instant::now()); + let pending_ack = feedback + .take_completed_frame() + .expect("accepted frame acknowledgment"); + assert_eq!(pending_ack.frame_number, 1); + assert_eq!(pending_ack.bytes, 7); + } + + #[test] + fn accepted_frame_queue_discards_stale_feedback_and_preserves_sequence_numbers() { + let feedback = NvstFeedbackState::default(); + for bytes in 1..=u32::try_from(MAX_PENDING_FRAME_ACKS + 2).unwrap() { + feedback.publish_accepted_frame(bytes, Instant::now()); + } + + let first = feedback.take_completed_frame().expect("newest queue head"); + assert_eq!(first.frame_number, 3); + assert_eq!(first.bytes, 3); + + let mut last = first; + while let Some(frame) = feedback.take_completed_frame() { + last = frame; + } + assert_eq!(last.frame_number, 514); + assert_eq!(last.bytes, 514); + } + + #[test] + fn continuous_rtp_with_a_gs_index_gap_discards_the_frame_and_requests_pli() { + let config = config(); + let feedback = config.feedback(); + let crypto = test_srtp(&config); + let first = protect_for_test( + &crypto, + build_plaintext_rtp(10, FLAG_SOF, 9, &[0, 0, 1, 0x65]), + 0, + ); + let mut skipped_gs_index = build_plaintext_rtp(11, FLAG_EOF, 9, &[0xaa]); + skipped_gs_index[16..20].copy_from_slice(&(12_u32 << 8).to_le_bytes()); + let skipped_gs_index = protect_for_test(&crypto, skipped_gs_index, 0); + let mut receiver = NvstVideoReceiver::new(config); + + assert!( + receiver + .process_datagram(peer(), &first, Instant::now()) + .is_empty() + ); + assert_eq!( + receiver.process_datagram(peer(), &skipped_gs_index, Instant::now()), + [NvstReceiveEvent::Dropped( + NvstDropReason::FrameDiscontinuity + )] + ); + assert!(feedback.take_keyframe_request()); + } + + #[test] + fn a_new_frame_start_recovers_after_a_gs_index_gap() { + let config = config(); + let crypto = test_srtp(&config); + let first = protect_for_test( + &crypto, + build_plaintext_rtp( + 10, + FLAG_SOF | FLAG_EOF | FLAG_CONTAINS_PIC_DATA, + 9, + &[0, 0, 1, 0x65], + ), + 0, + ); + let mut next_frame = build_plaintext_rtp( + 11, + FLAG_SOF | FLAG_EOF | FLAG_CONTAINS_PIC_DATA, + 10, + &[0, 0, 1, 0x65], + ); + next_frame[16..20].copy_from_slice(&(30_u32 << 8).to_le_bytes()); + let next_frame = protect_for_test(&crypto, next_frame, 0); + let mut receiver = NvstVideoReceiver::new(config); + + assert!( + receiver + .process_datagram(peer(), &first, Instant::now()) + .iter() + .any(|event| matches!(event, NvstReceiveEvent::Frame(_))) + ); + assert!( + receiver + .process_datagram(peer(), &next_frame, Instant::now()) + .iter() + .any(|event| matches!(event, NvstReceiveEvent::Frame(_))) + ); + } + + #[test] + fn fec_repair_packets_do_not_advance_gs_source_index_continuity() { + let config = config(); + let feedback = config.feedback(); + let crypto = test_srtp(&config); + let first = protect_for_test( + &crypto, + build_plaintext_rtp(10, FLAG_SOF, 9, &[0, 0, 1, 0x65]), + 0, + ); + let mut repair = build_plaintext_rtp(11, FLAG_CONTAINS_PIC_DATA, 9, &[0xee]); + repair[28..32].copy_from_slice(&0x00c0_3420_u32.to_le_bytes()); + let repair = protect_for_test(&crypto, repair, 0); + let mut next_source = build_plaintext_rtp(12, FLAG_EOF, 9, &[0xaa]); + next_source[16..20].copy_from_slice(&(11_u32 << 8).to_le_bytes()); + let next_source = protect_for_test(&crypto, next_source, 0); + let mut receiver = NvstVideoReceiver::new(config); + + assert!( + receiver + .process_datagram(peer(), &first, Instant::now()) + .is_empty() + ); + assert_eq!( + receiver.process_datagram(peer(), &repair, Instant::now()), + [NvstReceiveEvent::Dropped(NvstDropReason::Unsupported( + NvstUnsupportedFeature::FecRepair + ))] + ); + let events = receiver.process_datagram(peer(), &next_source, Instant::now()); + let [NvstReceiveEvent::Frame(frame)] = events.as_slice() else { + panic!("expected a frame after filtered FEC repair, got {events:?}"); + }; + assert_eq!(frame.bytes, [0, 0, 1, 0x65, 0xaa]); + assert!(!feedback.take_keyframe_request()); + } + + #[test] + fn authenticated_packet_without_gs_metadata_discards_reassembly_and_requests_pli() { + let config = config(); + let feedback = config.feedback(); + let crypto = test_srtp(&config); + let first = protect_for_test( + &crypto, + build_plaintext_rtp(10, FLAG_SOF, 9, &[0, 0, 1, 0x65]), + 0, + ); + let mut missing_gs = build_plaintext_rtp(11, FLAG_EOF, 9, &[0xaa]); + missing_gs[12..14].copy_from_slice(&0xbede_u16.to_be_bytes()); + let missing_gs = protect_for_test(&crypto, missing_gs, 0); + let mut receiver = NvstVideoReceiver::new(config); + + assert!( + receiver + .process_datagram(peer(), &first, Instant::now()) + .is_empty() + ); + assert_eq!( + receiver.process_datagram(peer(), &missing_gs, Instant::now()), + [NvstReceiveEvent::Dropped(NvstDropReason::MalformedRtp( + RtpParseError::MissingNvVideoHeader + ))] + ); + assert!(feedback.take_keyframe_request()); + } + + #[test] + fn receiver_assembles_one_frame_across_multiple_fec_blocks() { + let config = config(); + let crypto = test_srtp(&config); + let block_zero_start = protect_for_test( + &crypto, + build_plaintext_rtp_with_fec_blocks( + 20, + FLAG_SOF | FLAG_CONTAINS_PIC_DATA, + 9, + 0, + 1, + &[0, 0, 0, 1, 0x65], + ), + 0, + ); + let block_zero_end = protect_for_test( + &crypto, + build_plaintext_rtp_with_fec_blocks( + 21, + FLAG_EOF | FLAG_CONTAINS_PIC_DATA, + 9, + 0, + 1, + &[0xaa], + ), + 0, + ); + let block_one_start = protect_for_test( + &crypto, + build_plaintext_rtp_with_fec_blocks( + 22, + FLAG_SOF | FLAG_CONTAINS_PIC_DATA, + 9, + 1, + 1, + &[0xbb], + ), + 0, + ); + let block_one_end = protect_for_test( + &crypto, + build_plaintext_rtp_with_fec_blocks( + 23, + FLAG_EOF | FLAG_CONTAINS_PIC_DATA, + 9, + 1, + 1, + &[0xcc], + ), + 0, + ); + let mut receiver = NvstVideoReceiver::new(config); + for packet in [&block_zero_start, &block_zero_end, &block_one_start] { + assert!( + receiver + .process_datagram(peer(), packet, Instant::now()) + .is_empty() + ); + } + let events = receiver.process_datagram(peer(), &block_one_end, Instant::now()); + let [NvstReceiveEvent::Frame(frame)] = events.as_slice() else { + panic!("expected one complete frame, got {events:?}"); + }; + assert_eq!(frame.frame_index, 9); + assert!(frame.keyframe); + assert_eq!(frame.bytes, [0, 0, 0, 1, 0x65, 0xaa, 0xbb, 0xcc]); + } + + #[test] + fn receiver_rejects_wrong_peer_and_duplicate_authenticated_packet() { + let config = config(); + let crypto = test_srtp(&config); + let packet = protect_for_test( + &crypto, + build_plaintext_rtp( + 1, + FLAG_SOF | FLAG_EOF | FLAG_CONTAINS_PIC_DATA, + 1, + &[0, 0, 1, 0x65], + ), + 0, + ); + let mut receiver = NvstVideoReceiver::new(config); + let wrong_peer = SocketAddr::new("192.0.2.21".parse().expect("IP"), 5004); + assert!(matches!( + receiver + .process_datagram(wrong_peer, &packet, Instant::now()) + .as_slice(), + [NvstReceiveEvent::Dropped( + NvstDropReason::UnexpectedSource { .. } + )] + )); + assert!(matches!( + receiver + .process_datagram(peer(), &packet, Instant::now()) + .as_slice(), + [NvstReceiveEvent::Frame(_)] + )); + assert!(matches!( + receiver + .process_datagram(peer(), &packet, Instant::now()) + .as_slice(), + [NvstReceiveEvent::Dropped(NvstDropReason::ReplayRejected)] + )); + } + + #[test] + fn reorder_nack_excludes_packets_already_buffered_after_the_gap() { + let config = config(); + let feedback = Arc::clone(&config.feedback); + let crypto = test_srtp(&config); + let packets = [1_u16, 3, 4].map(|sequence| { + protect_for_test( + &crypto, + build_plaintext_rtp( + sequence, + FLAG_SOF | FLAG_EOF | FLAG_CONTAINS_PIC_DATA, + u32::from(sequence), + &[0, 0, 1, 0x65], + ), + 0, + ) + }); + let mut receiver = NvstVideoReceiver::new(config); + for packet in &packets { + let _ = receiver.process_datagram(peer(), packet, Instant::now()); + } + assert_eq!(feedback.take_nack(), Some((2, 2))); + assert_eq!(feedback.take_nack(), None); + } + + #[test] + fn reorder_gap_uses_mjolnir_dequeue_deadline_instead_of_filling_the_window() { + fn packet(index: u64) -> RtpPacket { + RtpPacket { + index, + header: RtpHeader { + payload_type: 96, + sequence_number: index as u16, + timestamp: 90_000, + ssrc: 1, + payload_offset: RTP_FIXED_HEADER_LEN, + has_padding: false, + gs_video_header: None, + }, + plaintext: vec![0; RTP_FIXED_HEADER_LEN], + } + } + + let started = Instant::now(); + let mut reorder = RtpReorderBuffer::new(DEFAULT_REORDER_WINDOW); + assert_eq!(reorder.push(packet(1), started).ready.len(), 1); + + let waiting = reorder.push(packet(3), started + Duration::from_millis(1)); + assert_eq!(waiting.nack, Some((2, 2))); + assert!(waiting.ready.is_empty()); + assert!(waiting.recovery.is_none()); + + let still_waiting = reorder.push(packet(4), started + Duration::from_millis(8)); + assert_eq!(still_waiting.nack, Some((2, 2))); + assert!(still_waiting.ready.is_empty()); + assert!(still_waiting.recovery.is_none()); + + let recovered = reorder.push(packet(5), started + Duration::from_millis(9)); + assert_eq!( + recovered.recovery, + Some(NvstRecovery::PacketGap { + first_missing_index: 2, + last_missing_index: 2, + }) + ); + assert_eq!( + recovered + .ready + .iter() + .map(|packet| packet.index) + .collect::>(), + [3, 4, 5] + ); + assert_eq!(recovered.nack, None); + } + + #[test] + fn gaps_require_recovery_and_never_emit_an_incomplete_frame() { + let config = config(); + let crypto = test_srtp(&config); + let first = protect_for_test( + &crypto, + build_plaintext_rtp(1, FLAG_SOF | FLAG_CONTAINS_PIC_DATA, 1, &[0, 0, 1, 0x65]), + 0, + ); + let far = protect_for_test( + &crypto, + build_plaintext_rtp(6, FLAG_EOF | FLAG_CONTAINS_PIC_DATA, 1, &[0xaa]), + 0, + ); + let mut receiver = NvstVideoReceiver::new(config); + let _ = receiver.process_datagram(peer(), &first, Instant::now()); + let events = receiver.process_datagram(peer(), &far, Instant::now()); + assert!(events.iter().any(|event| matches!( + event, + NvstReceiveEvent::RecoveryNeeded(NvstRecovery::PacketGap { .. }) + ))); + assert!( + !events + .iter() + .any(|event| matches!(event, NvstReceiveEvent::Frame(_))) + ); + + let fresh = protect_for_test( + &crypto, + build_plaintext_rtp( + 7, + FLAG_SOF | FLAG_EOF | FLAG_CONTAINS_PIC_DATA, + 2, + &[0, 0, 1, 0x65, 0xbb], + ), + 0, + ); + let fresh_events = receiver.process_datagram(peer(), &fresh, Instant::now()); + let Some(NvstReceiveEvent::Frame(frame)) = fresh_events + .iter() + .find(|event| matches!(event, NvstReceiveEvent::Frame(_))) + else { + panic!("expected a fresh frame after the gap, got {fresh_events:?}"); + }; + assert!(!frame.contiguous); + } + + #[test] + fn generic_nack_encodes_wrapping_sequence_range() { + let packet = build_rtcp_nack(0x0102_0304, 0x0506_0708, 65_534, 65_536); + assert_eq!( + packet, + [0x81, 205, 0, 3, 1, 2, 3, 4, 5, 6, 7, 8, 0xff, 0xfe, 0, 3,] + ); + } + + #[test] + fn picture_loss_indication_uses_rfc_4585_psfb_layout() { + assert_eq!( + build_rtcp_pli(0x0102_0304, 0x0506_0708), + [0x81, 206, 0, 2, 1, 2, 3, 4, 5, 6, 7, 8] + ); + } + + #[test] + fn raw_srtcp_gcm8_matches_the_macforce_pr66_layout() { + let key = decode_fixed_hex::<32>( + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + NvstConfigError::InvalidAesKey, + ) + .expect("key"); + let salt = + decode_fixed_hex::<12>("A0A1A2A3A4A5A6A7A8A9AAAB", NvstConfigError::InvalidSrtpSalt) + .expect("salt"); + let packet = protect_srtcp_receiver_report_gcm( + RtcpReportBlock { + media_ssrc: 0x1122_3344, + fraction_lost: 0x55, + cumulative_lost: -2, + highest_sequence: 0x0102_0304, + jitter: 0x0506_0708, + }, + 0x0123_4567, + &key, + &salt, + SRTP_AEAD_AES_GCM_8_TAG_LEN, + ); + + assert_eq!( + packet, + hex_bytes( + "81C900074F4E4F57ECBBE4F812433B089B30BF8BA442E7BB3C3C706A5BC548980601CFF1E416E06F81234567" + ) + ); + assert_eq!(&packet[..8], &[0x81, 201, 0, 7, b'O', b'N', b'O', b'W']); + assert_eq!(&packet[packet.len() - 4..], &0x8123_4567_u32.to_be_bytes()); + } + + #[test] + fn receiver_report_tracks_loss_interval_and_late_recovery() { + let feedback = NvstFeedbackState::default(); + let now = Instant::now(); + feedback.publish_stream(7, 10, 1_000, now); + feedback.publish_stream(7, 12, 2_800, now + Duration::from_millis(20)); + + let report = feedback.report_snapshot(true).expect("report"); + assert_eq!(report.media_ssrc, 7); + assert_eq!(report.highest_sequence, 12); + assert_eq!(report.cumulative_lost, 1); + assert_eq!(report.fraction_lost, 85); + assert_eq!(report.jitter, 0); + + feedback.publish_stream(7, 12, 1_900, now + Duration::from_millis(10)); + let recovered = feedback.report_snapshot(true).expect("report"); + assert_eq!(recovered.cumulative_lost, 0); + assert_eq!(recovered.fraction_lost, 0); + } + + #[test] + fn raw_receiver_report_advances_interval_loss_counters() { + let config = config(); + let feedback = config.feedback(); + let crypto = test_srtp(&config); + let first = protect_for_test( + &crypto, + build_plaintext_rtp(10, FLAG_SOF | FLAG_EOF, 1, &[0, 0, 1, 0x65]), + 0, + ); + let later = protect_for_test( + &crypto, + build_plaintext_rtp(12, FLAG_SOF | FLAG_EOF, 2, &[0, 0, 1, 0x65]), + 0, + ); + let now = Instant::now(); + let mut receiver = NvstVideoReceiver::new(config); + let _ = receiver.process_datagram(peer(), &first, now); + let _ = receiver.process_datagram(peer(), &later, now + Duration::from_millis(20)); + + assert!(receiver.poll_receiver_report(now).is_some()); + assert_eq!( + *feedback + .report_prior + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner), + (3, 2) + ); + } + + #[test] + fn duplicate_rtp_timestamps_do_not_inflate_interarrival_jitter() { + let feedback = NvstFeedbackState::default(); + let now = Instant::now(); + feedback.publish_stream(7, 10, 1_000, now); + feedback.publish_stream(7, 11, 1_000, now + Duration::from_millis(10)); + feedback.publish_stream(7, 12, 2_800, now + Duration::from_millis(20)); + + assert_eq!(feedback.report_snapshot(false).expect("report").jitter, 0); + } + + #[test] + fn rtp_classifier_does_not_bind_rtcp_or_dtls_as_media_streams() { + let rtcp = build_rtcp_receiver_report( + 1, + RtcpReportBlock { + media_ssrc: 2, + fraction_lost: 0, + cumulative_lost: 0, + highest_sequence: 3, + jitter: 0, + }, + ); + assert!(looks_like_rtcp(&rtcp)); + assert!(!looks_like_rtp(&rtcp)); + assert_eq!(peek_rtp_ssrc(&rtcp), None); + + let mut dtls = vec![0_u8; RTP_FIXED_HEADER_LEN]; + dtls[0] = 23; + assert!(looks_like_dtls(&dtls)); + assert!(!looks_like_rtp(&dtls)); + } + + #[test] + fn generic_nack_is_bounded() { + let packet = build_rtcp_nack(1, 2, 10, 10_000); + assert_eq!(packet.len(), 12 + MAX_NACK_FCI_ENTRIES * 4); + assert_eq!( + &packet[2..4], + &(2_u16 + MAX_NACK_FCI_ENTRIES as u16).to_be_bytes() + ); + assert_eq!(&packet[packet.len() - 4..], &[0, 61, 0x0f, 0xff]); + } + + #[test] + fn pending_nack_ranges_are_chunked_without_discarding_tail() { + let feedback = NvstFeedbackState::default(); + feedback.request_nack(10, 100); + feedback.resolve_nack(12); + assert_eq!(feedback.take_nack(), Some((10, 11))); + assert_eq!(feedback.take_nack(), Some((13, 76))); + assert_eq!(feedback.take_nack(), Some((77, 100))); + assert_eq!(feedback.take_nack(), None); + + feedback.request_nack(10, 100); + assert_eq!(feedback.take_nack(), Some((10, 73))); + assert_eq!(feedback.take_nack(), Some((74, 100))); + assert_eq!(feedback.take_nack(), None); + } + + #[test] + fn pause_timeout_recovery_and_stop_fail_closed() { + let mut receiver = NvstVideoReceiver::new(config()); + assert_eq!( + receiver.pause(), + Some(NvstReceiveEvent::Lifecycle(NvstReceiverState::Paused)) + ); + assert!(matches!( + receiver + .process_datagram(peer(), &[], Instant::now()) + .as_slice(), + [NvstReceiveEvent::Dropped(NvstDropReason::Paused)] + )); + assert_eq!( + receiver.resume(), + Some(NvstReceiveEvent::Lifecycle(NvstReceiverState::Running)) + ); + receiver.last_authenticated_packet = Some(Instant::now() - Duration::from_secs(1)); + assert!(matches!( + receiver.poll_timeout(Instant::now()), + Some(NvstReceiveEvent::RecoveryNeeded( + NvstRecovery::Timeout { .. } + )) + )); + assert_eq!(receiver.state(), NvstReceiverState::RecoveryRequired); + assert_eq!( + receiver.recover(), + Some(NvstReceiveEvent::Lifecycle(NvstReceiverState::Running)) + ); + assert_eq!( + receiver.stop(), + Some(NvstReceiveEvent::Lifecycle(NvstReceiverState::Stopped)) + ); + assert!(matches!( + receiver + .process_datagram(peer(), &[], Instant::now()) + .as_slice(), + [NvstReceiveEvent::Dropped(NvstDropReason::Stopped)] + )); + } + + #[test] + fn startup_without_authenticated_packets_times_out() { + let mut receiver = NvstVideoReceiver::new(config()); + receiver.timeout_origin = Instant::now() - Duration::from_secs(1); + + assert!(matches!( + receiver.poll_timeout(Instant::now()), + Some(NvstReceiveEvent::RecoveryNeeded( + NvstRecovery::Timeout { .. } + )) + )); + assert_eq!(receiver.state(), NvstReceiverState::RecoveryRequired); + } + + #[test] + fn udp_receiver_repeats_the_negotiated_ping_before_media_arrives() { + let server = UdpSocket::bind("127.0.0.1:0").expect("server socket"); + server + .set_read_timeout(Some(Duration::from_millis(250))) + .expect("server timeout"); + let client_reservation = UdpSocket::bind("127.0.0.1:0").expect("client reservation"); + let client_port = client_reservation + .local_addr() + .expect("client address") + .port(); + drop(client_reservation); + + let mut config = config(); + config.client_udp_port = client_port; + config.video_peer = server.local_addr().expect("server address"); + config.ping_payload = b"negotiated-ping".to_vec(); + let (media_consumer, _media_receiver) = mpsc::sync_channel(1); + let (event_sender, _event_receiver) = mpsc::channel(); + let session = + spawn_nvst_udp_receiver(config, media_consumer, event_sender).expect("UDP receiver"); + + let mut datagram = [0_u8; 64]; + let (first_len, _) = server.recv_from(&mut datagram).expect("first ping"); + assert_eq!(&datagram[..first_len], b"negotiated-ping"); + let (second_len, _) = server.recv_from(&mut datagram).expect("repeated ping"); + assert_eq!(&datagram[..second_len], b"negotiated-ping"); + + session.stop(); + } + + #[test] + fn h264_frame_queue_is_bounded_and_prefers_current_frames() { + let mut queue = BoundedFrameQueue::new(2); + for frame_index in 1..=3 { + queue.push(EncodedVideoAccessUnit { + codec: NvstVideoCodec::H264, + timestamp: frame_index, + frame_index, + first_stream_packet_index: frame_index, + keyframe: false, + contiguous: true, + bytes: vec![frame_index as u8], + }); + } + assert_eq!(queue.dropped_frames(), 1); + assert_eq!(queue.pop().expect("frame").frame_index, 2); + assert_eq!(queue.pop().expect("frame").frame_index, 3); + } + + fn hex_bytes(value: &str) -> Vec { + value + .as_bytes() + .chunks(2) + .map(|chunk| { + u8::from_str_radix(std::str::from_utf8(chunk).expect("hex"), 16).expect("hex") + }) + .collect() + } +} + +/// In-process bounded queue for callers that drive `NvstVideoReceiver` directly rather than +/// using the UDP worker. It drops the oldest frame to keep interactive latency bounded. +#[derive(Debug)] +pub struct BoundedFrameQueue { + frames: VecDeque, + capacity: usize, + dropped_frames: u64, +} + +impl BoundedFrameQueue { + pub fn new(capacity: usize) -> Self { + Self { + frames: VecDeque::with_capacity(capacity), + capacity: capacity.max(1), + dropped_frames: 0, + } + } + + pub fn push(&mut self, frame: EncodedVideoAccessUnit) { + if self.frames.len() == self.capacity { + let _ = self.frames.pop_front(); + self.dropped_frames += 1; + } + self.frames.push_back(frame); + } + + pub fn pop(&mut self) -> Option { + self.frames.pop_front() + } + + pub fn dropped_frames(&self) -> u64 { + self.dropped_frames + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-transport/src/nvst_control.rs b/native/opennow-streamer/crates/opennow-streamer-transport/src/nvst_control.rs new file mode 100644 index 000000000..2306fe6a5 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-transport/src/nvst_control.rs @@ -0,0 +1,238 @@ +use std::time::Duration; + +pub(crate) const FRAME_ACK_CODE: u16 = 0x204; +pub(crate) const FRAME_PACING_CODE: u16 = 0x203; +pub(crate) const QOS_REPORT_CODE: u16 = 0x207; +pub(crate) const IDR_REQUEST_CODE: u16 = 0x302; + +pub(crate) const FRAME_ACK_PAYLOAD_LEN: usize = 102; +pub(crate) const FRAME_PACING_PAYLOAD_LEN: usize = 28; +pub(crate) const QOS_REPORT_PAYLOAD_LEN: usize = 52; +pub(crate) const FRAMES_PER_PACING_REPORT: u32 = 3; +pub(crate) const DEFAULT_FRAME_TIME_US: u32 = 16_000; +pub(crate) const QOS_REPORT_INTERVAL: Duration = Duration::from_micros(55_556); +pub(crate) const QOS_WARM_UP: Duration = Duration::from_millis(1_900); + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct NvstControlCommand { + pub(crate) code: u16, + pub(crate) payload: Vec, +} + +impl NvstControlCommand { + pub(crate) fn encoded(&self) -> Vec { + let Ok(payload_len) = u16::try_from(self.payload.len()) else { + return Vec::new(); + }; + let mut encoded = Vec::with_capacity(4 + self.payload.len()); + encoded.extend_from_slice(&self.code.to_le_bytes()); + encoded.extend_from_slice(&payload_len.to_le_bytes()); + encoded.extend_from_slice(&self.payload); + encoded + } +} + +pub(crate) fn frame_ack( + frame_number: u32, + client_time_ms: f64, + frame_bytes: u32, + frame_time_us: u32, + measured_stage_ms: Option, +) -> NvstControlCommand { + let mut payload = vec![0; FRAME_ACK_PAYLOAD_LEN]; + put_u16(&mut payload, 0, 1); + put_u16(&mut payload, 2, 9); + put_u32(&mut payload, 4, frame_number); + put_u64(&mut payload, 12, client_time_ms.to_bits()); + if let Some(stage_ms) = measured_stage_ms.filter(|value| value.is_finite() && *value >= 0.0) { + for offset in (28..=44).step_by(4) { + put_u32(&mut payload, offset, stage_ms.to_bits()); + } + } + put_u32(&mut payload, 48, (-1.0_f32).to_bits()); + put_u32(&mut payload, 72, frame_bytes); + put_u32(&mut payload, 84, 16_384); + put_u32(&mut payload, 96, frame_time_us); + NvstControlCommand { + code: FRAME_ACK_CODE, + payload, + } +} + +pub(crate) fn frame_pacing_report( + frame_number: u32, + target_frame_time_us: u32, + pacing_error_us: u32, +) -> NvstControlCommand { + let mut payload = vec![0; FRAME_PACING_PAYLOAD_LEN]; + put_u32(&mut payload, 0, 5); + put_u32(&mut payload, 8, 2); + put_u32(&mut payload, 12, frame_number); + put_u32(&mut payload, 16, target_frame_time_us); + put_u32(&mut payload, 20, pacing_error_us.min(target_frame_time_us)); + put_u32(&mut payload, 24, 0x341a); + NvstControlCommand { + code: FRAME_PACING_CODE, + payload, + } +} + +pub(crate) struct QosReport { + pub(crate) sequence: u32, + pub(crate) frames_received: u32, + pub(crate) bytes_received: u32, + pub(crate) rtp_timestamp: u32, + pub(crate) previous_bytes_received: u32, + pub(crate) warmed_up: bool, +} + +impl QosReport { + pub(crate) fn command(&self) -> NvstControlCommand { + let mut payload = vec![0; QOS_REPORT_PAYLOAD_LEN]; + put_u32(&mut payload, 0, 7); + put_u32(&mut payload, 8, self.sequence); + put_u32(&mut payload, 12, self.frames_received); + put_u32(&mut payload, 16, self.bytes_received); + put_u16(&mut payload, 28, if self.warmed_up { 2 } else { 0 }); + put_u16(&mut payload, 30, 1_000); + put_u16(&mut payload, 32, 1_000); + put_u16(&mut payload, 34, 12_708); + put_u32(&mut payload, 36, self.rtp_timestamp); + put_u32(&mut payload, 48, self.previous_bytes_received); + NvstControlCommand { + code: QOS_REPORT_CODE, + payload, + } + } +} + +pub(crate) fn idr_request() -> NvstControlCommand { + NvstControlCommand { + code: IDR_REQUEST_CODE, + payload: 0_u16.to_le_bytes().to_vec(), + } +} + +fn put_u16(payload: &mut [u8], offset: usize, value: u16) { + payload[offset..offset + 2].copy_from_slice(&value.to_le_bytes()); +} + +fn put_u32(payload: &mut [u8], offset: usize, value: u32) { + payload[offset..offset + 4].copy_from_slice(&value.to_le_bytes()); +} + +fn put_u64(payload: &mut [u8], offset: usize, value: u64) { + payload[offset..offset + 8].copy_from_slice(&value.to_le_bytes()); +} + +#[cfg(test)] +mod tests { + use super::*; + + fn hex(value: &str) -> Vec { + value + .as_bytes() + .chunks_exact(2) + .map(|pair| { + u8::from_str_radix(std::str::from_utf8(pair).expect("ASCII hex"), 16) + .expect("valid hex") + }) + .collect() + } + + #[test] + fn command_header_is_little_endian_and_byte_exact() { + let command = NvstControlCommand { + code: 0x207, + payload: vec![1, 2, 3], + }; + assert_eq!(command.encoded(), [0x07, 0x02, 0x03, 0x00, 1, 2, 3]); + } + + #[test] + fn frame_pacing_report_matches_the_source_test_vector() { + let command = frame_pacing_report(1, 16_000, 16_000); + assert_eq!(command.code, FRAME_PACING_CODE); + assert_eq!( + command.payload, + hex("05000000000000000200000001000000803e0000803e00001a340000") + ); + assert_eq!(command.encoded().len(), 4 + FRAME_PACING_PAYLOAD_LEN); + } + + #[test] + fn frame_ack_places_only_source_pinned_fields() { + let command = frame_ack(42, 20_320.16, 15_168, 16_667, Some(4.5)); + assert_eq!(command.code, FRAME_ACK_CODE); + assert_eq!(command.payload.len(), FRAME_ACK_PAYLOAD_LEN); + assert_eq!(&command.payload[0..4], &[1, 0, 9, 0]); + assert_eq!( + u32::from_le_bytes(command.payload[4..8].try_into().unwrap()), + 42 + ); + assert_eq!( + u64::from_le_bytes(command.payload[12..20].try_into().unwrap()), + 20_320.16_f64.to_bits() + ); + for offset in (28..=44).step_by(4) { + assert_eq!( + u32::from_le_bytes(command.payload[offset..offset + 4].try_into().unwrap()), + 4.5_f32.to_bits() + ); + } + assert_eq!( + u32::from_le_bytes(command.payload[48..52].try_into().unwrap()), + (-1.0_f32).to_bits() + ); + assert_eq!( + u32::from_le_bytes(command.payload[72..76].try_into().unwrap()), + 15_168 + ); + assert_eq!( + u32::from_le_bytes(command.payload[84..88].try_into().unwrap()), + 16_384 + ); + assert_eq!( + u32::from_le_bytes(command.payload[96..100].try_into().unwrap()), + 16_667 + ); + assert_eq!(&command.payload[100..102], &[0, 0]); + assert_eq!( + command.payload, + hex( + "010009002a00000000000000d7a3703d0ad8d34000000000000000000000904000009040000090400000904000009040000080bf0000000000000000000000000000000000000000403b000000000000000000000040000000000000000000001b4100000000" + ) + ); + } + + #[test] + fn frame_ack_leaves_unavailable_stage_metrics_zero() { + let command = frame_ack(1, 0.0, 7, DEFAULT_FRAME_TIME_US, None); + assert!(command.payload[28..48].iter().all(|byte| *byte == 0)); + } + + #[test] + fn qos_report_matches_the_source_test_layout() { + let command = QosReport { + sequence: 6, + frames_received: 2, + bytes_received: 244_808, + rtp_timestamp: 1_818_674, + previous_bytes_received: 244_808, + warmed_up: false, + } + .command(); + assert_eq!(command.code, QOS_REPORT_CODE); + assert_eq!( + command.payload, + hex( + "0700000000000000060000000200000048bc030000000000000000000000e803e803a43132c01b00000000000000000048bc0300" + ) + ); + } + + #[test] + fn idr_request_matches_the_source_layout() { + assert_eq!(idr_request().encoded(), [0x02, 0x03, 0x02, 0x00, 0, 0]); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-transport/src/nvst_input.rs b/native/opennow-streamer/crates/opennow-streamer-transport/src/nvst_input.rs new file mode 100644 index 000000000..b3c0a97da --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer-transport/src/nvst_input.rs @@ -0,0 +1,1272 @@ +use std::fmt; +use std::time::{Duration, Instant}; + +use str0m::Rtc; +use str0m::channel::{ChannelConfig, ChannelId, Reliability}; + +pub(crate) const CONTROL_KEEPALIVE_INTERVAL: Duration = Duration::from_secs(3); +pub(crate) const INPUT_HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(5); + +const CONTROL_RELIABLE_LABEL: &str = "control_channel_reliable"; +const CUSTOM_RELIABLE_LABEL: &str = "custom_message_on_sctp_private_reliable"; +const CUSTOM_PARTIAL_LABEL: &str = "custom_message_on_sctp_private_partially_reliable"; +const CONTROL_PARTIAL_LABEL: &str = "control_channel_partially_reliable"; +const CONTROL_UNRELIABLE_LABEL: &str = "control_channel_unreliable"; +const INPUT_PARTIAL_LABEL: &str = "input_channel_partially_reliable"; +const CURSOR_LABEL: &str = "cursor_channel"; +const RTCP_ON_SCTP_LABEL: &str = "rtcp_on_sctp_private"; +const PARTIAL_RELIABLE_LIFETIME_MS: u16 = 300; + +const COMMAND_SYSTEM_CURSOR: u16 = 0x010f; +const COMMAND_BITMAP_CURSOR: u16 = 0x0110; +const COMMAND_KEEPALIVE: u16 = 0x0200; +const COMMAND_REMOTE_INPUT: u16 = 0x0206; +const COMMAND_ENABLE_INPUT: u16 = 0x020b; +const COMMAND_GAMEPAD: u16 = 0x020d; +const COMMAND_INPUT_VERSION: u16 = 0x020e; +// Controls whether the server composites its cursor into the video. The +// official client enables this for startup, waits for the first ServerControl +// cursor notification, then disables it and renders the reported cursor +// locally. Notifications continue after the server-rendered cursor is hidden. +const COMMAND_MOUSE_CURSOR_CAPTURE: u16 = 0x0308; +// NVB feature type 8 ("track remote cursor image") is distinct from cursor +// capture. Bifrost keeps this enabled after it turns capture back off so the +// server continues publishing cursor shape and mode changes. +const COMMAND_TRACK_REMOTE_CURSOR_IMAGE: u16 = 0x030d; +const COMMAND_WINDOW_STATE: u16 = 0x0320; +const COMMAND_SYSTEM_STATE: u16 = 0x0321; + +const INPUT_KEY_DOWN: u32 = 3; +const INPUT_KEY_UP: u32 = 4; +const INPUT_MOUSE_ABSOLUTE: u32 = 5; +const INPUT_MOUSE_RELATIVE: u32 = 7; +const INPUT_MOUSE_BUTTON_DOWN: u32 = 8; +const INPUT_MOUSE_BUTTON_UP: u32 = 9; +const INPUT_MOUSE_WHEEL: u32 = 10; +const INPUT_GAMEPAD: u32 = 12; +const INPUT_TEXT: u32 = 23; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum NvstChannelReliability { + Reliable, + Lifetime(u16), + MaxRetransmits(u16), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) struct NvstChannelDefinition { + pub(crate) sid: u16, + pub(crate) label: &'static str, + pub(crate) ordered: bool, + pub(crate) reliability: NvstChannelReliability, +} + +pub(crate) const NVST_CHANNEL_PROFILE: [NvstChannelDefinition; 8] = [ + NvstChannelDefinition { + sid: 0, + label: CONTROL_RELIABLE_LABEL, + ordered: true, + reliability: NvstChannelReliability::Reliable, + }, + NvstChannelDefinition { + sid: 2, + label: CUSTOM_RELIABLE_LABEL, + ordered: true, + reliability: NvstChannelReliability::Reliable, + }, + NvstChannelDefinition { + sid: 4, + label: CUSTOM_PARTIAL_LABEL, + ordered: true, + reliability: NvstChannelReliability::Lifetime(PARTIAL_RELIABLE_LIFETIME_MS), + }, + NvstChannelDefinition { + sid: 6, + label: CONTROL_PARTIAL_LABEL, + ordered: true, + reliability: NvstChannelReliability::Lifetime(PARTIAL_RELIABLE_LIFETIME_MS), + }, + NvstChannelDefinition { + sid: 8, + label: CONTROL_UNRELIABLE_LABEL, + ordered: true, + reliability: NvstChannelReliability::MaxRetransmits(0), + }, + NvstChannelDefinition { + sid: 10, + label: INPUT_PARTIAL_LABEL, + ordered: true, + reliability: NvstChannelReliability::Lifetime(PARTIAL_RELIABLE_LIFETIME_MS), + }, + NvstChannelDefinition { + sid: 12, + label: CURSOR_LABEL, + ordered: true, + reliability: NvstChannelReliability::Reliable, + }, + NvstChannelDefinition { + sid: 14, + label: RTCP_ON_SCTP_LABEL, + ordered: true, + reliability: NvstChannelReliability::Reliable, + }, +]; + +#[derive(Debug, Clone, Copy)] +pub(crate) struct NvstInputChannels { + pub(crate) control_reliable: ChannelId, + pub(crate) custom_reliable: ChannelId, + pub(crate) custom_partial: ChannelId, + pub(crate) control_partial: ChannelId, + pub(crate) control_unreliable: ChannelId, + pub(crate) input_partial: ChannelId, + pub(crate) cursor: ChannelId, + pub(crate) rtcp: ChannelId, +} + +impl NvstInputChannels { + pub(crate) fn create(rtc: &mut Rtc) -> Self { + let mut ids = Vec::with_capacity(NVST_CHANNEL_PROFILE.len()); + for definition in NVST_CHANNEL_PROFILE { + ids.push( + rtc.direct_api() + .create_data_channel(channel_config(definition)), + ); + } + Self { + control_reliable: ids[0], + custom_reliable: ids[1], + custom_partial: ids[2], + control_partial: ids[3], + control_unreliable: ids[4], + input_partial: ids[5], + cursor: ids[6], + rtcp: ids[7], + } + } + + pub(crate) fn contains(self, id: ChannelId) -> bool { + self.all().contains(&id) + } + + pub(crate) fn label(self, id: ChannelId) -> &'static str { + if id == self.control_reliable { + CONTROL_RELIABLE_LABEL + } else if id == self.custom_reliable { + CUSTOM_RELIABLE_LABEL + } else if id == self.custom_partial { + CUSTOM_PARTIAL_LABEL + } else if id == self.control_partial { + CONTROL_PARTIAL_LABEL + } else if id == self.control_unreliable { + CONTROL_UNRELIABLE_LABEL + } else if id == self.input_partial { + INPUT_PARTIAL_LABEL + } else if id == self.cursor { + CURSOR_LABEL + } else if id == self.rtcp { + RTCP_ON_SCTP_LABEL + } else { + "unknown" + } + } + + pub(crate) fn send_control(self, rtc: &mut Rtc, bytes: &[u8]) -> bool { + write_channel(rtc, self.control_reliable, bytes) + } + + pub(crate) fn send_partial_control(self, rtc: &mut Rtc, bytes: &[u8]) -> bool { + write_channel(rtc, self.control_partial, bytes) + } + + pub(crate) fn send_keepalive(self, rtc: &mut Rtc, stream_value: u32) -> bool { + self.send_control(rtc, &control_keepalive(stream_value)) + } + + pub(crate) fn send_activation(self, rtc: &mut Rtc, timestamp_us: u64) -> bool { + activation_chain(timestamp_us) + .iter() + .all(|bytes| self.send_control(rtc, bytes)) + } + + pub(crate) fn send_mouse_cursor_capture(self, rtc: &mut Rtc, enabled: bool) -> bool { + self.send_control(rtc, &mouse_cursor_capture(enabled)) + } + + pub(crate) fn send_remote_cursor_tracking(self, rtc: &mut Rtc, enabled: bool) -> bool { + self.send_control(rtc, &remote_cursor_tracking(enabled)) + } + + pub(crate) fn send_encoded(self, rtc: &mut Rtc, message: &NvstEncodedInput) -> bool { + let id = match message.route { + NvstInputRoute::ControlReliable => self.control_reliable, + NvstInputRoute::ControlPartial => self.control_partial, + NvstInputRoute::InputPartial => self.input_partial, + }; + write_channel(rtc, id, &message.bytes) + } + + fn all(self) -> [ChannelId; 7] { + [ + self.control_reliable, + self.custom_reliable, + self.custom_partial, + self.control_partial, + self.control_unreliable, + self.input_partial, + self.cursor, + ] + } +} + +fn channel_config(definition: NvstChannelDefinition) -> ChannelConfig { + let reliability = match definition.reliability { + NvstChannelReliability::Reliable => Reliability::Reliable, + NvstChannelReliability::Lifetime(lifetime) => Reliability::MaxPacketLifetime { lifetime }, + NvstChannelReliability::MaxRetransmits(retransmits) => { + Reliability::MaxRetransmits { retransmits } + } + }; + ChannelConfig { + label: definition.label.to_owned(), + ordered: definition.ordered, + reliability, + negotiated: None, + protocol: String::new(), + } +} + +fn write_channel(rtc: &mut Rtc, id: ChannelId, bytes: &[u8]) -> bool { + rtc.channel(id) + .is_some_and(|mut channel| channel.write(true, bytes).unwrap_or(false)) +} + +#[derive(Debug, Default)] +pub(crate) struct NvstInputChannelState { + control_open: bool, + negotiated_version: Option, + ready_reported: bool, + activation_sent: bool, +} + +impl NvstInputChannelState { + pub(crate) fn channel_opened( + &mut self, + channels: NvstInputChannels, + id: ChannelId, + ) -> Option { + if id == channels.control_reliable { + self.control_open = true; + } + self.take_new_ready_version() + } + + pub(crate) fn channel_data( + &mut self, + channels: NvstInputChannels, + id: ChannelId, + bytes: &[u8], + ) -> Option { + if id == channels.control_reliable + && let Some(version) = input_protocol_version(bytes) + { + self.negotiated_version = Some(version); + } + self.take_new_ready_version() + } + + pub(crate) fn is_ready(&self) -> bool { + self.control_open && self.negotiated_version.is_some() + } + + pub(crate) fn control_is_open(&self) -> bool { + self.control_open + } + + pub(crate) fn handshake_timed_out(&self, started_at: Option, now: Instant) -> bool { + !self.is_ready() + && started_at.is_some_and(|started| { + now.saturating_duration_since(started) >= INPUT_HANDSHAKE_TIMEOUT + }) + } + + pub(crate) fn activation_sent(&self) -> bool { + self.activation_sent + } + + pub(crate) fn mark_activation_sent(&mut self) { + self.activation_sent = true; + } + + pub(crate) fn channel_closed(&mut self, channels: NvstInputChannels, id: ChannelId) -> bool { + if id == channels.input_partial { + return self.is_ready(); + } + if id != channels.control_reliable { + return false; + } + let was_ready = self.is_ready(); + self.control_open = false; + self.negotiated_version = None; + self.ready_reported = false; + self.activation_sent = false; + was_ready + } + + fn take_new_ready_version(&mut self) -> Option { + if self.ready_reported || !self.is_ready() { + return None; + } + self.ready_reported = true; + self.negotiated_version + } +} + +pub(crate) fn next_control_keepalive(now: Instant) -> Instant { + now + CONTROL_KEEPALIVE_INTERVAL +} + +pub(crate) fn input_protocol_version(bytes: &[u8]) -> Option { + if bytes.len() < 2 { + return None; + } + let mut cursor = 0; + while bytes.len().saturating_sub(cursor) >= 4 { + let code = u16::from_le_bytes([bytes[cursor], bytes[cursor + 1]]); + let payload_len = usize::from(u16::from_le_bytes([bytes[cursor + 2], bytes[cursor + 3]])); + let payload_start = cursor + 4; + let payload_end = payload_start.checked_add(payload_len)?; + if payload_end > bytes.len() { + break; + } + if code == COMMAND_INPUT_VERSION && payload_len >= 2 { + return Some(u16::from_le_bytes([ + bytes[payload_start], + bytes[payload_start + 1], + ])); + } + cursor = payload_end; + } + let first = u16::from_le_bytes([bytes[0], bytes[1]]); + if first == COMMAND_INPUT_VERSION { + return Some(if bytes.len() >= 4 { + u16::from_le_bytes([bytes[2], bytes[3]]) + } else { + 2 + }); + } + (bytes[0] == 0x0e).then_some(first) +} + +/// Extracts server cursor notifications from the reliable control stream and +/// normalizes them for the platform output layer. +/// +/// Bifrost's current Windows client dispatches 0x010f (system cursor) and +/// 0x0110 (bitmap cursor) through ServerControl. The separately negotiated +/// `cursor_channel` is not used for these notifications by current GFN hosts. +#[cfg(test)] +pub(crate) fn server_cursor_updates(bytes: &[u8]) -> Vec> { + server_cursor_messages(bytes) + .into_iter() + .filter_map(|message| message.normalized) + .collect() +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct NvstServerCursorMessage { + pub(crate) command: u16, + pub(crate) offset: usize, + pub(crate) raw: Vec, + pub(crate) cursor_id: Option, + pub(crate) position: Option<(u16, u16)>, + pub(crate) visible: Option, + pub(crate) normalized: Option>, +} + +/// Scans a data-channel message for cursor commands instead of assuming that +/// the host always places them at byte zero on `control_channel_reliable`. +/// This is deliberately cursor-specific: arbitrary custom-channel payloads +/// must not be interpreted as general NVST control traffic. +pub(crate) fn server_cursor_messages(bytes: &[u8]) -> Vec { + let mut updates = Vec::new(); + let mut offset = 0_usize; + while bytes.len().saturating_sub(offset) >= 4 { + let code = u16::from_le_bytes([bytes[offset], bytes[offset + 1]]); + let payload_len = usize::from(u16::from_le_bytes([bytes[offset + 2], bytes[offset + 3]])); + let payload_start = offset + 4; + let Some(payload_end) = payload_start.checked_add(payload_len) else { + break; + }; + if payload_end > bytes.len() { + offset += 1; + continue; + } + let payload = &bytes[payload_start..payload_end]; + match code { + COMMAND_SYSTEM_CURSOR if payload.len() >= 4 => { + let cursor_id = + u32::from_le_bytes([payload[0], payload[1], payload[2], payload[3]]); + let position = (payload.len() >= 8).then(|| { + ( + u16::from_le_bytes([payload[4], payload[5]]), + u16::from_le_bytes([payload[6], payload[7]]), + ) + }); + let visible = payload.get(8).map(|value| *value != 0); + let normalized = u8::try_from(cursor_id).ok().map(|cursor_id| { + // Platform cursor wire shape: + // type, id, hotspot x/y, empty MIME/image, optional x/y. + // + // The optional byte after x/y is cursor visibility metadata, + // not the relative-mouse sentinel. Geronimo preserves the + // cursor ID verbatim; predefined ID 0 is what selects locked + // input in the official SDL cursor manager. + let mut normalized = vec![0, cursor_id, 0, 0, 0, 0, 0]; + if payload.len() >= 8 { + normalized.extend_from_slice(&payload[4..8]); + } + normalized + }); + updates.push(NvstServerCursorMessage { + command: code, + offset, + raw: bytes[offset..payload_end].to_vec(), + cursor_id: Some(cursor_id), + position, + visible, + normalized, + }); + } + COMMAND_BITMAP_CURSOR => { + // Bitmap cursor payloads have a distinct native pixel layout. + // Keep detecting them explicitly so they cannot be mistaken for + // input/control commands while raw bitmap support is added. + updates.push(NvstServerCursorMessage { + command: code, + offset, + raw: bytes[offset..payload_end].to_vec(), + cursor_id: None, + position: None, + visible: None, + normalized: None, + }); + } + _ => { + offset += 1; + continue; + } + } + offset = payload_end; + } + updates +} + +pub(crate) fn native_input_types(packet: &[u8]) -> Result, NvstInputCodecError> { + native_events(packet, 0).map(|events| { + events + .into_iter() + .filter_map(|event| read_u32_le(event.bytes, 0)) + .collect() + }) +} + +pub(crate) fn native_input_type_name(input_type: u32) -> &'static str { + match input_type { + INPUT_KEY_DOWN => "key-down", + INPUT_KEY_UP => "key-up", + INPUT_MOUSE_ABSOLUTE => "mouse-absolute", + INPUT_MOUSE_RELATIVE => "mouse-relative", + INPUT_MOUSE_BUTTON_DOWN => "mouse-button-down", + INPUT_MOUSE_BUTTON_UP => "mouse-button-up", + INPUT_MOUSE_WHEEL => "mouse-wheel", + INPUT_GAMEPAD => "gamepad", + INPUT_TEXT => "text", + _ => "unknown", + } +} + +pub(crate) fn native_input_type_is_motion(input_type: u32) -> bool { + matches!(input_type, INPUT_MOUSE_ABSOLUTE | INPUT_MOUSE_RELATIVE) +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum NvstInputRoute { + ControlReliable, + ControlPartial, + InputPartial, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct NvstEncodedInput { + pub(crate) route: NvstInputRoute, + pub(crate) bytes: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) enum NvstInputCodecError { + Malformed(&'static str), + UnsupportedType(u32), + UnsupportedText, +} + +impl fmt::Display for NvstInputCodecError { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Malformed(reason) => write!(formatter, "malformed native input: {reason}"), + Self::UnsupportedType(input_type) => { + write!(formatter, "unsupported native input type {input_type}") + } + Self::UnsupportedText => { + formatter.write_str("native NVST text contains an unmappable character") + } + } + } +} + +#[derive(Debug, Default)] +pub(crate) struct NvstInputCodec { + gamepad_sequence: u8, + gamepad_registered: bool, +} + +impl NvstInputCodec { + pub(crate) fn encode( + &mut self, + packet: &[u8], + fallback_timestamp_us: u64, + ) -> Result, NvstInputCodecError> { + let events = native_events(packet, fallback_timestamp_us)?; + let mut encoded = Vec::new(); + for event in events { + let input_type = read_u32_le(event.bytes, 0) + .ok_or(NvstInputCodecError::Malformed("missing input type"))?; + match input_type { + INPUT_KEY_DOWN | INPUT_KEY_UP => { + require_len(event.bytes, 18, "short keyboard packet")?; + let key = read_u16_be(event.bytes, 4).expect("keyboard length checked"); + let modifiers = read_u16_be(event.bytes, 6).expect("keyboard length checked"); + let timestamp = read_u64_be(event.bytes, 10).unwrap_or(event.timestamp_us); + encoded.push(remote_input_message( + remote_input_packet( + input_type, + &[ + (key >> 8) as u8, + key as u8, + (modifiers >> 8) as u8, + modifiers as u8, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + ), + timestamp, + )); + } + INPUT_MOUSE_RELATIVE => { + require_len(event.bytes, 22, "short relative mouse packet")?; + let body = [ + event.bytes[4], + event.bytes[5], + event.bytes[6], + event.bytes[7], + 0, + 0, + ]; + encoded.push(remote_input_message( + remote_input_packet(input_type, &body), + read_u64_be(event.bytes, 14).unwrap_or(event.timestamp_us), + )); + } + INPUT_MOUSE_ABSOLUTE => { + require_len(event.bytes, 26, "short absolute mouse packet")?; + let body = [ + event.bytes[4], + event.bytes[5], + event.bytes[6], + event.bytes[7], + 0x08, + 0x00, + event.bytes[10], + event.bytes[11], + event.bytes[12], + event.bytes[13], + ]; + encoded.push(remote_input_message( + remote_input_packet(input_type, &body), + read_u64_be(event.bytes, 18).unwrap_or(event.timestamp_us), + )); + } + INPUT_MOUSE_BUTTON_DOWN | INPUT_MOUSE_BUTTON_UP => { + require_len(event.bytes, 18, "short mouse button packet")?; + encoded.push(remote_input_message( + remote_input_packet(input_type, &[event.bytes[4], 0]), + read_u64_be(event.bytes, 10).unwrap_or(event.timestamp_us), + )); + } + INPUT_MOUSE_WHEEL => { + require_len(event.bytes, 22, "short mouse wheel packet")?; + let body = [0, 0, event.bytes[6], event.bytes[7], 0, 0]; + encoded.push(remote_input_message( + remote_input_packet(input_type, &body), + read_u64_be(event.bytes, 14).unwrap_or(event.timestamp_us), + )); + } + INPUT_GAMEPAD => { + require_len(event.bytes, 38, "short gamepad packet")?; + let timestamp = read_u64_le(event.bytes, 30).unwrap_or(event.timestamp_us); + if !self.gamepad_registered { + self.gamepad_registered = true; + encoded.push(NvstEncodedInput { + route: NvstInputRoute::ControlReliable, + bytes: device_descriptor(timestamp, 3), + }); + } + self.gamepad_sequence = self.gamepad_sequence.wrapping_add(1); + encoded.push(NvstEncodedInput { + route: NvstInputRoute::InputPartial, + bytes: gamepad_command(event.bytes, timestamp, self.gamepad_sequence), + }); + } + INPUT_TEXT => encoded.extend(text_messages(&event)?), + other => return Err(NvstInputCodecError::UnsupportedType(other)), + } + } + Ok(encoded) + } +} + +#[derive(Debug, Clone, Copy)] +struct NativeEvent<'a> { + bytes: &'a [u8], + timestamp_us: u64, +} + +fn native_events( + packet: &[u8], + fallback_timestamp_us: u64, +) -> Result>, NvstInputCodecError> { + if packet.is_empty() { + return Err(NvstInputCodecError::Malformed("empty packet")); + } + if packet[0] == 0x22 { + if packet.len() < 5 || read_u32_le(packet, 1) != Some(INPUT_TEXT) { + return Err(NvstInputCodecError::Malformed( + "unknown leading 0x22 packet", + )); + } + return Ok(vec![NativeEvent { + bytes: &packet[1..], + timestamp_us: fallback_timestamp_us, + }]); + } + if packet[0] != 0x23 { + return Ok(vec![NativeEvent { + bytes: packet, + timestamp_us: fallback_timestamp_us, + }]); + } + require_len(packet, 10, "short protocol-v3 wrapper")?; + let timestamp_us = read_u64_be(packet, 1).expect("wrapper length checked"); + let mut cursor = 9; + let mut events = Vec::new(); + while cursor < packet.len() { + match packet[cursor] { + 0x22 => { + let start = cursor + 1; + let input_type = read_u32_le(packet, start) + .ok_or(NvstInputCodecError::Malformed("short single-event wrapper"))?; + let length = native_event_length(input_type, packet.len() - start)?; + let end = start + length; + if end > packet.len() { + return Err(NvstInputCodecError::Malformed("truncated single event")); + } + events.push(NativeEvent { + bytes: &packet[start..end], + timestamp_us, + }); + cursor = end; + } + 0x21 => { + require_remaining(packet, cursor, 3, "short length-prefixed wrapper")?; + let length = + usize::from(u16::from_be_bytes([packet[cursor + 1], packet[cursor + 2]])); + let start = cursor + 3; + let end = start + length; + if end > packet.len() { + return Err(NvstInputCodecError::Malformed( + "truncated length-prefixed event", + )); + } + events.push(NativeEvent { + bytes: &packet[start..end], + timestamp_us, + }); + cursor = end; + } + 0x26 => { + require_remaining(packet, cursor, 7, "short partially-reliable wrapper")?; + if packet[cursor + 4] != 0x21 { + return Err(NvstInputCodecError::Malformed( + "missing gamepad payload marker", + )); + } + let length = + usize::from(u16::from_be_bytes([packet[cursor + 5], packet[cursor + 6]])); + let start = cursor + 7; + let end = start + length; + if end > packet.len() { + return Err(NvstInputCodecError::Malformed("truncated gamepad event")); + } + events.push(NativeEvent { + bytes: &packet[start..end], + timestamp_us, + }); + cursor = end; + } + _ => return Err(NvstInputCodecError::Malformed("unknown protocol-v3 marker")), + } + } + Ok(events) +} + +fn native_event_length(input_type: u32, remaining: usize) -> Result { + match input_type { + INPUT_KEY_DOWN | INPUT_KEY_UP | INPUT_MOUSE_BUTTON_DOWN | INPUT_MOUSE_BUTTON_UP => Ok(18), + INPUT_MOUSE_RELATIVE | INPUT_MOUSE_WHEEL => Ok(22), + INPUT_MOUSE_ABSOLUTE => Ok(26), + INPUT_GAMEPAD => Ok(38), + INPUT_TEXT => Ok(remaining), + other => Err(NvstInputCodecError::UnsupportedType(other)), + } +} + +fn remote_input_message(inner: Vec, timestamp_us: u64) -> NvstEncodedInput { + let input_type = read_u32_le(&inner, 4).expect("remote input packet has type"); + let mut body = inner; + let padded = 24.max(body.len().div_ceil(8) * 8); + body.resize(padded, 0); + let timestamp_count = usize::from(matches!( + input_type, + INPUT_KEY_DOWN | INPUT_KEY_UP | INPUT_MOUSE_ABSOLUTE + )) + 1; + for _ in 0..timestamp_count { + body.extend_from_slice(×tamp_us.to_le_bytes()); + } + NvstEncodedInput { + route: if matches!(input_type, INPUT_MOUSE_RELATIVE | INPUT_MOUSE_ABSOLUTE) { + NvstInputRoute::ControlPartial + } else { + NvstInputRoute::ControlReliable + }, + bytes: control_command(COMMAND_REMOTE_INPUT, &remote_input_packet(0x0e, &body)), + } +} + +fn remote_input_packet(input_type: u32, body: &[u8]) -> Vec { + let mut packet = Vec::with_capacity(8 + body.len()); + packet.extend_from_slice(&(4_u32 + body.len() as u32).to_be_bytes()); + packet.extend_from_slice(&input_type.to_le_bytes()); + packet.extend_from_slice(body); + packet +} + +fn gamepad_command(packet: &[u8], timestamp_us: u64, sequence: u8) -> Vec { + let mut payload = Vec::with_capacity(52); + payload.push(0x23); + payload.extend_from_slice(×tamp_us.to_be_bytes()); + let mut body = [ + 0x26, 0x00, 0x00, 0x00, 0x22, 0x0c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; + body[3] = sequence; + body[17..19].copy_from_slice(&packet[12..14]); + body[19] = packet[14]; + body[20] = packet[15]; + body[21..29].copy_from_slice(&packet[16..24]); + payload.extend_from_slice(&body); + control_command(COMMAND_GAMEPAD, &payload) +} + +fn text_messages(event: &NativeEvent<'_>) -> Result, NvstInputCodecError> { + require_len(event.bytes, 5, "short text packet")?; + let text = + std::str::from_utf8(&event.bytes[5..]).map_err(|_| NvstInputCodecError::UnsupportedText)?; + let mut messages = Vec::with_capacity(text.chars().count() * 2); + for character in text.chars() { + let (virtual_key, modifiers) = + text_keystroke(character).ok_or(NvstInputCodecError::UnsupportedText)?; + for input_type in [INPUT_KEY_DOWN, INPUT_KEY_UP] { + let mut body = Vec::with_capacity(14); + body.extend_from_slice(&virtual_key.to_be_bytes()); + body.extend_from_slice(&modifiers.to_be_bytes()); + body.resize(14, 0); + messages.push(remote_input_message( + remote_input_packet(input_type, &body), + event.timestamp_us, + )); + } + } + Ok(messages) +} + +fn text_keystroke(character: char) -> Option<(u16, u16)> { + let virtual_key = match character { + 'A'..='Z' => return Some((character as u16, 1)), + 'a'..='z' => return Some((character.to_ascii_uppercase() as u16, 0)), + '0'..='9' => return Some((character as u16, 0)), + ' ' => return Some((0x20, 0)), + '\t' => return Some((0x09, 0)), + '\n' | '\r' => return Some((0x0d, 0)), + '!' => 0x31, + '@' => 0x32, + '#' => 0x33, + '$' => 0x34, + '%' => 0x35, + '^' => 0x36, + '&' => 0x37, + '*' => 0x38, + '(' => 0x39, + ')' => 0x30, + '_' => 0xbd, + '+' => 0xbb, + '{' => 0xdb, + '}' => 0xdd, + '|' => 0xdc, + ':' => 0xba, + '"' => 0xde, + '<' => 0xbc, + '>' => 0xbe, + '?' => 0xbf, + '~' => 0xc0, + '-' => return Some((0xbd, 0)), + '=' => return Some((0xbb, 0)), + '[' => return Some((0xdb, 0)), + ']' => return Some((0xdd, 0)), + '\\' => return Some((0xdc, 0)), + ';' => return Some((0xba, 0)), + '\'' => return Some((0xde, 0)), + ',' => return Some((0xbc, 0)), + '.' => return Some((0xbe, 0)), + '/' => return Some((0xbf, 0)), + '`' => return Some((0xc0, 0)), + _ => return None, + }; + Some((virtual_key, 1)) +} + +fn activation_chain(timestamp_us: u64) -> [Vec; 7] { + [ + enable_input(1, false), + device_descriptor(timestamp_us, 2), + mouse_cursor_capture(true), + remote_cursor_tracking(true), + state_change(COMMAND_WINDOW_STATE, 19, 0), + state_change(COMMAND_SYSTEM_STATE, 0, 0), + enable_input(1, true), + ] +} + +fn mouse_cursor_capture(enabled: bool) -> Vec { + control_command(COMMAND_MOUSE_CURSOR_CAPTURE, &[u8::from(enabled)]) +} + +fn remote_cursor_tracking(enabled: bool) -> Vec { + control_command(COMMAND_TRACK_REMOTE_CURSOR_IMAGE, &[u8::from(enabled)]) +} + +fn control_keepalive(stream_value: u32) -> Vec { + control_command(COMMAND_KEEPALIVE, &stream_value.to_le_bytes()) +} + +fn enable_input(counter: u32, enabled: bool) -> Vec { + let mut payload = Vec::with_capacity(12); + payload.extend_from_slice(&0_u32.to_le_bytes()); + payload.extend_from_slice(&counter.to_le_bytes()); + payload.extend_from_slice(&u32::from(enabled).to_le_bytes()); + control_command(COMMAND_ENABLE_INPUT, &payload) +} + +fn device_descriptor(timestamp_us: u64, descriptor_index: u8) -> Vec { + let mut payload = Vec::with_capacity(48); + payload.push(0x23); + payload.extend_from_slice(×tamp_us.to_be_bytes()); + let mut body = [ + 0x22, 0x0c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; + body[9] = descriptor_index; + payload.extend_from_slice(&body); + control_command(COMMAND_GAMEPAD, &payload) +} + +fn state_change(code: u16, state: u32, frame_number: u32) -> Vec { + // Bifrost serializes these as three little-endian u32 fields: stream + // index, requested state, and frame number. The desktop client announces + // window state 19 at frame zero once input is activated. Advertising the + // previous all-zero window state leaves the session looking inactive and + // prevents the server from sending its system-cursor mode updates. + let mut payload = Vec::with_capacity(12); + payload.extend_from_slice(&0_u32.to_le_bytes()); + payload.extend_from_slice(&state.to_le_bytes()); + payload.extend_from_slice(&frame_number.to_le_bytes()); + control_command(code, &payload) +} + +fn control_command(code: u16, payload: &[u8]) -> Vec { + let mut bytes = Vec::with_capacity(4 + payload.len()); + bytes.extend_from_slice(&code.to_le_bytes()); + bytes.extend_from_slice(&(payload.len() as u16).to_le_bytes()); + bytes.extend_from_slice(payload); + bytes +} + +fn require_len( + bytes: &[u8], + minimum: usize, + reason: &'static str, +) -> Result<(), NvstInputCodecError> { + if bytes.len() < minimum { + return Err(NvstInputCodecError::Malformed(reason)); + } + Ok(()) +} + +fn require_remaining( + bytes: &[u8], + offset: usize, + minimum: usize, + reason: &'static str, +) -> Result<(), NvstInputCodecError> { + if bytes.len().saturating_sub(offset) < minimum { + return Err(NvstInputCodecError::Malformed(reason)); + } + Ok(()) +} + +fn read_u16_be(bytes: &[u8], offset: usize) -> Option { + Some(u16::from_be_bytes( + bytes.get(offset..offset + 2)?.try_into().ok()?, + )) +} + +fn read_u32_le(bytes: &[u8], offset: usize) -> Option { + Some(u32::from_le_bytes( + bytes.get(offset..offset + 4)?.try_into().ok()?, + )) +} + +fn read_u64_be(bytes: &[u8], offset: usize) -> Option { + Some(u64::from_be_bytes( + bytes.get(offset..offset + 8)?.try_into().ok()?, + )) +} + +fn read_u64_le(bytes: &[u8], offset: usize) -> Option { + Some(u64::from_le_bytes( + bytes.get(offset..offset + 8)?.try_into().ok()?, + )) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn hex(value: &str) -> Vec { + assert_eq!(value.len() % 2, 0, "hex input must contain whole bytes"); + value + .as_bytes() + .chunks_exact(2) + .map(|pair| { + u8::from_str_radix(std::str::from_utf8(pair).expect("hex utf8"), 16) + .expect("hex byte") + }) + .collect() + } + + #[test] + fn channel_profile_matches_official_sids_labels_and_reliability() { + assert_eq!( + NVST_CHANNEL_PROFILE.map(|definition| definition.sid), + [0, 2, 4, 6, 8, 10, 12, 14] + ); + assert_eq!( + NVST_CHANNEL_PROFILE.map(|definition| definition.label), + [ + CONTROL_RELIABLE_LABEL, + CUSTOM_RELIABLE_LABEL, + CUSTOM_PARTIAL_LABEL, + CONTROL_PARTIAL_LABEL, + CONTROL_UNRELIABLE_LABEL, + INPUT_PARTIAL_LABEL, + CURSOR_LABEL, + RTCP_ON_SCTP_LABEL, + ] + ); + assert!( + NVST_CHANNEL_PROFILE + .iter() + .all(|definition| definition.ordered) + ); + assert_eq!( + NVST_CHANNEL_PROFILE.map(|definition| definition.reliability), + [ + NvstChannelReliability::Reliable, + NvstChannelReliability::Reliable, + NvstChannelReliability::Lifetime(300), + NvstChannelReliability::Lifetime(300), + NvstChannelReliability::MaxRetransmits(0), + NvstChannelReliability::Lifetime(300), + NvstChannelReliability::Reliable, + NvstChannelReliability::Reliable, + ] + ); + let configs = NVST_CHANNEL_PROFILE.map(channel_config); + assert_eq!(configs.clone().map(|config| config.ordered), [true; 8]); + assert_eq!( + configs.map(|config| config.reliability), + [ + Reliability::Reliable, + Reliability::Reliable, + Reliability::MaxPacketLifetime { lifetime: 300 }, + Reliability::MaxPacketLifetime { lifetime: 300 }, + Reliability::MaxRetransmits { retransmits: 0 }, + Reliability::MaxPacketLifetime { lifetime: 300 }, + Reliability::Reliable, + Reliability::Reliable, + ] + ); + + let mut rtc = Rtc::new(Instant::now()); + let channels = NvstInputChannels::create(&mut rtc); + assert_eq!(channels.label(channels.rtcp), RTCP_ON_SCTP_LABEL); + assert!(!channels.contains(channels.rtcp)); + } + + #[test] + fn parses_full_control_handshake_and_requires_only_control_plus_version() { + assert_eq!( + input_protocol_version(&[0x0e, 0x02, 0x02, 0x00, 0x03, 0x00]), + Some(3) + ); + assert_eq!(input_protocol_version(&[0x0e, 0x02, 0x03, 0x00]), Some(3)); + assert_eq!(input_protocol_version(&[0x0e, 0x03]), Some(0x030e)); + assert_eq!(input_protocol_version(&[0x0e, 0x02]), Some(2)); + assert_eq!(input_protocol_version(&[1]), None); + assert_eq!( + input_protocol_version(&[0x01, 0x01, 0x00, 0x00, 0x0e, 0x02, 0x02, 0x00, 0x03, 0x00,]), + Some(3) + ); + + let mut rtc = Rtc::new(Instant::now()); + let channels = NvstInputChannels::create(&mut rtc); + let mut state = NvstInputChannelState::default(); + assert_eq!( + state.channel_opened(channels, channels.control_reliable), + None + ); + assert!(!state.is_ready()); + assert_eq!( + state.channel_data( + channels, + channels.input_partial, + &[0x0e, 0x02, 0x02, 0x00, 0x03, 0x00], + ), + None + ); + assert!(!state.is_ready()); + assert_eq!( + state.channel_data( + channels, + channels.control_reliable, + &[0x0e, 0x02, 0x02, 0x00, 0x03, 0x00], + ), + Some(3) + ); + assert!(state.is_ready()); + } + + #[test] + fn extracts_system_cursor_notifications_from_server_control() { + let visible = hex("0f010900010000000c80168001"); + assert_eq!( + server_cursor_updates(&visible), + vec![hex("000100000000000c801680")] + ); + + let mut concatenated = visible; + concatenated.extend_from_slice(&hex("0f0109000c0000000000000000")); + assert_eq!( + server_cursor_updates(&concatenated), + vec![hex("000100000000000c801680"), hex("000c000000000000000000")] + ); + + assert_eq!( + server_cursor_updates(&hex("0f010800010000000c801680")), + vec![hex("000100000000000c801680")] + ); + assert_eq!( + server_cursor_updates(&hex("0f01040000000000")), + vec![hex("00000000000000")] + ); + assert!(server_cursor_updates(&hex("0f010400010000")).is_empty()); + assert!(server_cursor_updates(&hex("0a0102007b7d")).is_empty()); + } + + #[test] + fn control_keepalive_and_activation_are_byte_exact() { + assert_eq!(control_keepalive(0), hex("0002040000000000")); + assert_eq!(mouse_cursor_capture(false), hex("0803010000")); + assert_eq!(mouse_cursor_capture(true), hex("0803010001")); + assert_eq!(remote_cursor_tracking(false), hex("0d03010000")); + assert_eq!(remote_cursor_tracking(true), hex("0d03010001")); + let now = Instant::now(); + assert_eq!( + next_control_keepalive(now).duration_since(now), + Duration::from_secs(3) + ); + + let chain = activation_chain(20_102_193); + assert_eq!(chain[0], hex("0b020c00000000000100000000000000")); + assert_eq!( + chain[1], + hex( + "0d02300023000000000132bc31220c0000001a000000020014000000000000000000000000000000550000000000000000000000" + ) + ); + assert_eq!(chain[2], hex("0803010001")); + assert_eq!(chain[3], hex("0d03010001")); + assert_eq!(chain[4], hex("20030c00000000001300000000000000")); + assert_eq!(chain[5], hex("21030c00000000000000000000000000")); + assert_eq!(chain[6], hex("0b020c00000000000100000001000000")); + } + + #[test] + fn keyboard_and_mouse_translate_to_byte_exact_control_commands() { + let mut codec = NvstInputCodec::default(); + let mut key = vec![0; 18]; + key[..4].copy_from_slice(&INPUT_KEY_DOWN.to_le_bytes()); + key[4..6].copy_from_slice(&0x41_u16.to_be_bytes()); + key[6..8].copy_from_slice(&1_u16.to_be_bytes()); + key[10..18].copy_from_slice(&0x015b_15b1_u64.to_be_bytes()); + let mut wrapped_key = vec![0x23]; + wrapped_key.extend_from_slice(&99_u64.to_be_bytes()); + wrapped_key.push(0x22); + wrapped_key.extend_from_slice(&key); + let key = codec.encode(&wrapped_key, 0).expect("key"); + assert_eq!(key.len(), 1); + assert_eq!(key[0].route, NvstInputRoute::ControlReliable); + assert_eq!( + key[0].bytes, + hex( + "060230000000002c0e000000000000120300000000410001000000000000000000000000b1155b0100000000b1155b0100000000" + ) + ); + + let mut mouse = vec![0; 22]; + mouse[..4].copy_from_slice(&INPUT_MOUSE_RELATIVE.to_le_bytes()); + mouse[4..6].copy_from_slice(&24_i16.to_be_bytes()); + mouse[6..8].copy_from_slice(&24_i16.to_be_bytes()); + mouse[14..22].copy_from_slice(&0x0186_1330_u64.to_be_bytes()); + let mut wrapped_mouse = vec![0x23]; + wrapped_mouse.extend_from_slice(&100_u64.to_be_bytes()); + wrapped_mouse.push(0x21); + wrapped_mouse.extend_from_slice(&(mouse.len() as u16).to_be_bytes()); + wrapped_mouse.extend_from_slice(&mouse); + let mouse = codec.encode(&wrapped_mouse, 0).expect("mouse"); + assert_eq!(mouse[0].route, NvstInputRoute::ControlPartial); + assert_eq!( + mouse[0].bytes, + hex( + "06022800000000240e0000000000000a07000000001800180000000000000000000000003013860100000000" + ) + ); + } + + #[test] + fn standard_gamepad_translates_to_input_partial_and_registers_once() { + let mut codec = NvstInputCodec::default(); + let mut gamepad = vec![0; 38]; + gamepad[..4].copy_from_slice(&INPUT_GAMEPAD.to_le_bytes()); + gamepad[12..14].copy_from_slice(&0x1000_u16.to_le_bytes()); + gamepad[30..38].copy_from_slice(&0x015b_171a_u64.to_le_bytes()); + let mut wrapped_gamepad = vec![0x23]; + wrapped_gamepad.extend_from_slice(&101_u64.to_be_bytes()); + wrapped_gamepad.extend_from_slice(&[0x26, 0, 0, 1, 0x21]); + wrapped_gamepad.extend_from_slice(&(gamepad.len() as u16).to_be_bytes()); + wrapped_gamepad.extend_from_slice(&gamepad); + + let first = codec.encode(&wrapped_gamepad, 0).expect("gamepad"); + assert_eq!(first.len(), 2); + assert_eq!(first[0].route, NvstInputRoute::ControlReliable); + assert_eq!(first[1].route, NvstInputRoute::InputPartial); + assert_eq!( + first[1].bytes, + hex( + "0d0234002300000000015b171a26000001220c0000001a000000030014000010000000000000000000000000550000000000000000000000" + ) + ); + + let second = codec.encode(&wrapped_gamepad, 0).expect("second gamepad"); + assert_eq!(second.len(), 1); + assert_eq!(second[0].route, NvstInputRoute::InputPartial); + assert_eq!(second[0].bytes[16], 2); + } + + #[test] + fn unsupported_packets_fail_closed() { + let mut codec = NvstInputCodec::default(); + assert_eq!( + codec.encode(&13_u32.to_le_bytes(), 0), + Err(NvstInputCodecError::UnsupportedType(13)) + ); + let mut text = vec![0x22]; + text.extend_from_slice(&INPUT_TEXT.to_le_bytes()); + text.extend_from_slice("é".as_bytes()); + assert_eq!( + codec.encode(&text, 0), + Err(NvstInputCodecError::UnsupportedText) + ); + } + + #[test] + fn closure_and_timeout_state_are_predictable() { + let now = Instant::now(); + let mut rtc = Rtc::new(now); + let channels = NvstInputChannels::create(&mut rtc); + let mut state = NvstInputChannelState::default(); + state.channel_opened(channels, channels.control_reliable); + assert!(!state.handshake_timed_out(Some(now), now + Duration::from_millis(4_999))); + assert!(state.handshake_timed_out(Some(now), now + INPUT_HANDSHAKE_TIMEOUT)); + state.channel_data( + channels, + channels.control_reliable, + &[0x0e, 0x02, 0x02, 0x00, 0x03, 0x00], + ); + assert!(!state.handshake_timed_out(Some(now), now + INPUT_HANDSHAKE_TIMEOUT)); + state.mark_activation_sent(); + assert_eq!( + state.channel_data( + channels, + channels.control_reliable, + &[0x0e, 0x02, 0x02, 0x00, 0x03, 0x00], + ), + None + ); + assert!(state.activation_sent()); + assert!(state.channel_closed(channels, channels.input_partial)); + assert!(state.is_ready()); + assert!(state.channel_closed(channels, channels.control_reliable)); + assert!(!state.is_ready()); + assert!(!state.channel_closed(channels, channels.input_partial)); + assert!(!state.is_ready()); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer/Cargo.toml b/native/opennow-streamer/crates/opennow-streamer/Cargo.toml new file mode 100644 index 000000000..34b4d3be9 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "opennow-streamer" +version.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true + +[features] +default = [] +linux-vaapi = ["opennow-streamer-platform/linux-vaapi"] +linux-ffmpeg = ["opennow-streamer-platform/linux-ffmpeg"] +linux-ffmpeg-bundled = ["opennow-streamer-platform/linux-ffmpeg-bundled"] + +[dependencies] +opennow-streamer-core = { path = "../opennow-streamer-core" } +opennow-streamer-platform = { path = "../opennow-streamer-platform" } +opennow-streamer-protocol = { path = "../opennow-streamer-protocol" } +serde_json.workspace = true +tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/native/opennow-streamer/crates/opennow-streamer/build.rs b/native/opennow-streamer/crates/opennow-streamer/build.rs new file mode 100644 index 000000000..bca8c323f --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer/build.rs @@ -0,0 +1,17 @@ +fn main() { + if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("windows") { + println!("cargo:rustc-link-arg=/DELAYLOAD:mfplat.dll"); + println!("cargo:rustc-link-lib=delayimp"); + } + + if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("linux") + && std::env::var_os("CARGO_FEATURE_LINUX_FFMPEG_BUNDLED").is_some() + { + // OpenH264 is compiled from C++ sources. The production Linux binary + // carries that runtime and GCC's unwinder just like its other native + // media libraries. + println!("cargo:rustc-link-lib=static=stdc++"); + println!("cargo:rustc-link-lib=static=gcc"); + println!("cargo:rustc-link-lib=static=gcc_eh"); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer/src/main.rs b/native/opennow-streamer/crates/opennow-streamer/src/main.rs new file mode 100644 index 000000000..4567da338 --- /dev/null +++ b/native/opennow-streamer/crates/opennow-streamer/src/main.rs @@ -0,0 +1,91 @@ +#![cfg_attr(all(windows, not(debug_assertions)), windows_subsystem = "windows")] + +use std::io::{self, BufRead, Write}; +use std::sync::mpsc; +use std::thread; + +use opennow_streamer_core::Engine; +use opennow_streamer_platform::{MediaRuntime, create_runtime}; +use opennow_streamer_protocol::{Command, error}; +use serde_json::Value; + +fn write_message(message: &Value) -> io::Result<()> { + let mut stdout = io::stdout().lock(); + serde_json::to_writer(&mut stdout, message)?; + writeln!(stdout)?; + stdout.flush() +} + +fn run_protocol(media_runtime: MediaRuntime) -> io::Result<()> { + let (event_tx, event_rx) = mpsc::channel::(); + let event_writer = thread::spawn(move || { + while let Ok(message) = event_rx.recv() { + if write_message(&message).is_err() { + break; + } + } + }); + let mut engine = Engine::with_media_runtime(event_tx, media_runtime); + + for line in io::stdin().lock().lines() { + let line = line?; + if line.trim().is_empty() { + continue; + } + let command: Command = match serde_json::from_str(&line) { + Ok(command) => command, + Err(parse_error) => { + write_message(&error(None, "invalid-command", parse_error.to_string()))?; + continue; + } + }; + let (responses, keep_running) = engine.handle(command); + for response in responses { + write_message(&response)?; + } + if !keep_running { + break; + } + } + + drop(engine); + let _ = event_writer.join(); + Ok(()) +} + +fn main() -> io::Result<()> { + // Optional verbose tracing of the str0m SCTP/DTLS stack to stderr (stdout is + // reserved for the JSON protocol). Enable with OPENNOW_STREAMER_TRACE=1. + if std::env::var_os("OPENNOW_STREAMER_TRACE").is_some() { + use tracing_subscriber::EnvFilter; + let _ = tracing_subscriber::fmt() + .with_env_filter( + EnvFilter::try_from_default_env() + .unwrap_or_else(|_| EnvFilter::new("str0m=debug,sctp_proto=debug")), + ) + .with_writer(std::io::stderr) + .with_ansi(false) + .try_init(); + } + #[cfg(target_os = "macos")] + if std::env::var_os("OPENNOW_DEBUG_WINDOW").is_some() { + opennow_streamer_platform::debug_show_overlay_window(); + } + let (host, media_runtime) = create_runtime().map_err(io::Error::other)?; + let shutdown_runtime = media_runtime.clone(); + let protocol = thread::Builder::new() + .name("opennow-protocol".to_owned()) + .spawn(move || { + let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + run_protocol(media_runtime) + })); + shutdown_runtime.shutdown(); + result + })?; + host.run(); + match protocol.join() { + Ok(Ok(result)) => result, + Ok(Err(payload)) => std::panic::resume_unwind(payload), + Err(payload) => std::panic::resume_unwind(payload), + } +} diff --git a/native/opennow-streamer/src/backend.rs b/native/opennow-streamer/src/backend.rs deleted file mode 100644 index 8e1d7e0b6..000000000 --- a/native/opennow-streamer/src/backend.rs +++ /dev/null @@ -1,790 +0,0 @@ -use crate::input::{PARTIALLY_RELIABLE_GAMEPAD_MASK_ALL, PARTIALLY_RELIABLE_HID_DEVICE_MASK_ALL}; -use crate::protocol::{ - missing_field, ColorQuality, CommandEnvelope, Event, MediaConnectionInfo, - NativeStreamerCapabilities, NativeStreamerSessionContext, Response, VideoCodec, - PROTOCOL_VERSION, -}; -use crate::sdp::{ - duplicate_session_webrtc_attributes_to_media, extract_ice_credentials, fix_server_ip, - parse_resolution, prefer_codec, rewrite_sdp_ice_candidate_endpoints, - sanitize_ice_pwd_for_gstreamer, summarize_media_transport_attributes, NvstParams, - PreferCodecOptions, -}; -use std::env; -use std::sync::mpsc::Sender; - -pub trait NativeStreamerBackend { - fn capabilities(&self) -> NativeStreamerCapabilities; - fn start(&mut self, command: CommandEnvelope) -> BackendReply; - fn handle_offer(&mut self, command: CommandEnvelope) -> BackendReply; - fn add_remote_ice(&mut self, command: CommandEnvelope) -> BackendReply; - fn send_input(&mut self, command: CommandEnvelope) -> BackendReply; - fn set_input_paused(&mut self, command: CommandEnvelope) -> BackendReply; - fn update_render_surface(&mut self, command: CommandEnvelope) -> BackendReply; - fn update_bitrate_limit(&mut self, command: CommandEnvelope) -> BackendReply; - fn update_shortcuts(&mut self, command: CommandEnvelope) -> BackendReply; - fn stop(&mut self, command: CommandEnvelope) -> BackendReply; -} - -const BACKEND_ENV: &str = "OPENNOW_NATIVE_STREAMER_BACKEND"; -const NATIVE_CODEC_ENV: &str = "OPENNOW_NATIVE_CODEC"; -const MIN_BITRATE_KBPS: u32 = 5_000; -const MAX_BITRATE_KBPS: u32 = 150_000; - -pub fn create_backend(event_sender: Option>) -> Box { - let requested = env::var(BACKEND_ENV) - .ok() - .map(|value| value.trim().to_ascii_lowercase()) - .filter(|value| !value.is_empty()); - create_backend_for_name(requested.as_deref(), event_sender) -} - -fn create_backend_for_name( - requested: Option<&str>, - event_sender: Option>, -) -> Box { - #[cfg(not(feature = "gstreamer"))] - let _ = &event_sender; - - match requested.unwrap_or(default_backend_name()) { - "stub" => Box::::default(), - #[cfg(feature = "gstreamer")] - "gstreamer" => Box::new(crate::gstreamer_backend::GstreamerBackend::new( - event_sender, - )), - #[cfg(not(feature = "gstreamer"))] - "gstreamer" => Box::new(StubBackend::with_fallback( - "gstreamer", - "GStreamer backend was requested, but this binary was built without the gstreamer feature.", - )), - other => Box::new(StubBackend::with_fallback( - other, - format!("Unknown native streamer backend \"{other}\"; using stub."), - )), - } -} - -fn default_backend_name() -> &'static str { - #[cfg(feature = "gstreamer")] - { - "gstreamer" - } - #[cfg(not(feature = "gstreamer"))] - { - "stub" - } -} - -#[derive(Debug, Default)] -pub struct BackendReply { - pub events: Vec, - pub response: Option, - pub should_continue: bool, -} - -impl BackendReply { - pub fn response(response: Response) -> Self { - Self { - events: Vec::new(), - response: Some(response), - should_continue: true, - } - } - - pub fn continue_without_response() -> Self { - Self { - events: Vec::new(), - response: None, - should_continue: true, - } - } - - pub fn stop(id: String, message: String) -> Self { - Self { - events: vec![Event::Status { - status: "stopped", - message: Some(message), - }], - response: Some(Response::Ok { id }), - should_continue: false, - } - } -} - -#[derive(Debug, Clone)] -pub struct PreparedNativeOffer { - pub original_sdp_len: usize, - pub fixed_offer_sdp: String, - pub gstreamer_offer_sdp: String, - pub gstreamer_ice_pwd_replacements: usize, - pub gstreamer_framerate_adjusted: bool, - pub media_connection_ice_replacements: usize, - pub nvst_params: NvstParams, - pub media_connection_info: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum PrepareNativeOfferError { - InvalidResolution { resolution: String }, -} - -impl PrepareNativeOfferError { - pub fn into_response(self, id: String) -> Response { - match self { - Self::InvalidResolution { resolution } => Response::Error { - id: Some(id), - code: "invalid-resolution".to_owned(), - message: format!("Invalid stream resolution: {resolution}"), - }, - } - } -} - -pub fn prepare_native_offer( - context: &NativeStreamerSessionContext, - offer_sdp: &str, -) -> Result { - let Some((width, height)) = parse_resolution(&context.settings.resolution) else { - return Err(PrepareNativeOfferError::InvalidResolution { - resolution: context.settings.resolution.clone(), - }); - }; - - let fixed_offer_sdp = fix_server_ip(offer_sdp, &context.session.server_ip); - let (fixed_offer_sdp, media_connection_ice_replacements) = - if let Some(media_connection_info) = web_rtc_media_connection_info(context) { - rewrite_sdp_ice_candidate_endpoints( - &fixed_offer_sdp, - &media_connection_info.ip, - media_connection_info.port, - ) - } else { - (fixed_offer_sdp, 0) - }; - let fixed_offer_sdp = duplicate_session_webrtc_attributes_to_media(&fixed_offer_sdp); - let codec = resolve_native_codec(context.settings.codec); - let fixed_offer_sdp = prefer_codec( - &fixed_offer_sdp, - codec, - PreferCodecOptions { - prefer_hevc_profile_id: Some(preferred_hevc_profile_id(context.settings.color_quality)), - }, - ); - let (gstreamer_framerate_offer_sdp, gstreamer_framerate_adjusted) = - align_video_sdp_framerate_for_gstreamer(&fixed_offer_sdp, context.settings.fps); - let (gstreamer_offer_sdp, gstreamer_ice_pwd_replacements) = - sanitize_ice_pwd_for_gstreamer(&gstreamer_framerate_offer_sdp); - let credentials = extract_ice_credentials(&fixed_offer_sdp); - let nvst_params = NvstParams { - width, - height, - fps: context.settings.fps, - max_bitrate_kbps: context.settings.max_bitrate_mbps.saturating_mul(1000), - partial_reliable_threshold_ms: 16, - codec, - color_quality: context.settings.color_quality, - credentials, - hid_device_mask: Some(PARTIALLY_RELIABLE_HID_DEVICE_MASK_ALL), - enable_partially_reliable_transfer_gamepad: Some(PARTIALLY_RELIABLE_GAMEPAD_MASK_ALL), - enable_partially_reliable_transfer_hid: Some(PARTIALLY_RELIABLE_HID_DEVICE_MASK_ALL), - }; - - Ok(PreparedNativeOffer { - original_sdp_len: offer_sdp.len(), - fixed_offer_sdp, - gstreamer_offer_sdp, - gstreamer_ice_pwd_replacements, - gstreamer_framerate_adjusted, - media_connection_ice_replacements, - nvst_params, - media_connection_info: context.session.media_connection_info.clone(), - }) -} - -pub(crate) fn web_rtc_media_connection_info( - context: &NativeStreamerSessionContext, -) -> Option<&MediaConnectionInfo> { - let media_connection_info = context.session.media_connection_info.as_ref()?; - if matches!(media_connection_info.usage, Some(2 | 17)) - && !media_connection_info.ip.trim().is_empty() - && media_connection_info.port > 0 - { - Some(media_connection_info) - } else { - None - } -} - -fn align_video_sdp_framerate_for_gstreamer(sdp: &str, fps: u32) -> (String, bool) { - if fps == 0 { - return (sdp.to_owned(), false); - } - - let line_ending = if sdp.contains("\r\n") { "\r\n" } else { "\n" }; - let has_trailing_ending = sdp.ends_with(line_ending); - let mut lines: Vec = sdp - .split(line_ending) - .filter(|line| !line.is_empty() || !has_trailing_ending) - .map(ToOwned::to_owned) - .collect(); - let mut output = Vec::with_capacity(lines.len() + 1); - let mut in_video = false; - let mut video_has_framerate = false; - let mut changed = false; - let target = format!("a=framerate:{fps}"); - - for line in lines.drain(..) { - if line.starts_with("m=") { - if in_video && !video_has_framerate { - output.push(target.clone()); - changed = true; - } - in_video = line.starts_with("m=video"); - video_has_framerate = false; - output.push(line); - continue; - } - - if in_video && line.starts_with("a=framerate:") { - video_has_framerate = true; - if line != target { - output.push(target.clone()); - changed = true; - } else { - output.push(line); - } - continue; - } - - output.push(line); - } - - if in_video && !video_has_framerate { - output.push(target); - changed = true; - } - - let mut result = output.join(line_ending); - if has_trailing_ending { - result.push_str(line_ending); - } - (result, changed) -} - -fn resolve_native_codec(configured: VideoCodec) -> VideoCodec { - match env::var(NATIVE_CODEC_ENV) - .unwrap_or_else(|_| "auto".to_owned()) - .to_ascii_lowercase() - .as_str() - { - "h264" | "avc" => VideoCodec::H264, - "h265" | "hevc" => VideoCodec::H265, - "av1" => VideoCodec::AV1, - _ => configured, - } -} - -pub fn prepared_offer_events(prepared: &PreparedNativeOffer) -> Vec { - let nvst = &prepared.nvst_params; - let mut events = vec![Event::Log { - level: "info", - message: format!( - "Prepared native offer for {}x{}@{} {} {}bit; SDP {} -> {} bytes.", - nvst.width, - nvst.height, - nvst.fps, - codec_label(nvst.codec), - color_quality_bit_depth(nvst.color_quality), - prepared.original_sdp_len, - prepared.fixed_offer_sdp.len(), - ), - }]; - - if prepared.gstreamer_framerate_adjusted { - events.push(Event::Log { - level: "info", - message: format!( - "Aligned native WebRTC video SDP framerate to {} fps for GStreamer caps negotiation.", - nvst.fps - ), - }); - } - - if let Some(media_connection_info) = &prepared.media_connection_info { - events.push(Event::Log { - level: "debug", - message: format!( - "GFN media connection hint {}:{} (usage={}).", - media_connection_info.ip, - media_connection_info.port, - media_connection_info - .usage - .map(|usage| usage.to_string()) - .unwrap_or_else(|| "unknown".to_owned()) - ), - }); - } - if prepared.media_connection_ice_replacements > 0 { - if let Some(media_connection_info) = &prepared.media_connection_info { - events.push(Event::Log { - level: "info", - message: format!( - "Rewrote {} remote ICE candidate endpoint(s) to GFN media connection hint {}:{}.", - prepared.media_connection_ice_replacements, - media_connection_info.ip, - media_connection_info.port - ), - }); - } - } - events.push(Event::Log { - level: "debug", - message: format!( - "Prepared native WebRTC SDP transport summary: {}.", - summarize_media_transport_attributes(&prepared.fixed_offer_sdp) - ), - }); - if prepared.gstreamer_ice_pwd_replacements > 0 { - events.push(Event::Log { - level: "warn", - message: format!( - "GFN offer uses non-standard ICE password characters; sanitized {} ice-pwd line(s) for GStreamer validation only.", - prepared.gstreamer_ice_pwd_replacements - ), - }); - } - - events -} - -pub fn normalize_bitrate_kbps(value: u32) -> u32 { - value.clamp(MIN_BITRATE_KBPS, MAX_BITRATE_KBPS) -} - -pub fn bitrate_kbps_to_mbps(value: u32) -> u32 { - normalize_bitrate_kbps(value).div_ceil(1000) -} - -pub fn update_context_bitrate_limit( - context: &mut Option, - max_bitrate_kbps: u32, -) { - if let Some(context) = context { - context.settings.max_bitrate_mbps = bitrate_kbps_to_mbps(max_bitrate_kbps); - } -} - -#[derive(Debug, Default)] -pub struct StubBackend { - active_context: Option, - startup_warning: Option, - requested_backend: Option, - fallback_reason: Option, -} - -impl StubBackend { - fn with_fallback(requested_backend: impl Into, reason: impl Into) -> Self { - let requested_backend = requested_backend.into(); - let reason = reason.into(); - Self { - active_context: None, - startup_warning: Some(reason.clone()), - requested_backend: Some(requested_backend), - fallback_reason: Some(reason), - } - } -} - -impl NativeStreamerBackend for StubBackend { - fn capabilities(&self) -> NativeStreamerCapabilities { - NativeStreamerCapabilities { - protocol_version: PROTOCOL_VERSION, - backend: "stub", - requested_backend: self.requested_backend.clone(), - fallback_reason: self.fallback_reason.clone(), - supports_offer_answer: false, - supports_remote_ice: true, - supports_local_ice: false, - supports_input: false, - video_backends: Vec::new(), - } - } - - fn start(&mut self, command: CommandEnvelope) -> BackendReply { - let id = command.id; - let Some(context) = command.context else { - return BackendReply::response(missing_field(&id, "context")); - }; - let session_id = context.session.session_id.clone(); - self.active_context = Some(context); - let mut events = Vec::new(); - if let Some(message) = self.startup_warning.take() { - events.push(Event::Log { - level: "warn", - message, - }); - } - events.push(Event::Status { - status: "ready", - message: Some(format!( - "Native streamer process is running for session {session_id}; media backend is not enabled." - )), - }); - BackendReply { - events, - response: Some(Response::Ok { id }), - should_continue: true, - } - } - - fn handle_offer(&mut self, command: CommandEnvelope) -> BackendReply { - let id = command.id.clone(); - let Some(context) = command.context else { - return BackendReply::response(missing_field(&id, "context")); - }; - let Some(offer_sdp) = command.sdp else { - return BackendReply::response(missing_field(&id, "sdp")); - }; - - let prepared = match prepare_native_offer(&context, &offer_sdp) { - Ok(prepared) => prepared, - Err(error) => return BackendReply::response(error.into_response(id)), - }; - - BackendReply { - events: prepared_offer_events(&prepared), - response: Some(Response::Error { - id: Some(id), - code: "backend-unavailable".to_owned(), - message: "The native streamer parsed the GFN offer, but no WebRTC media backend is enabled yet.".to_owned(), - }), - should_continue: true, - } - } - - fn add_remote_ice(&mut self, command: CommandEnvelope) -> BackendReply { - if command.candidate.is_none() { - return BackendReply::response(missing_field(&command.id, "candidate")); - } - - BackendReply::response(Response::Ok { id: command.id }) - } - - fn send_input(&mut self, command: CommandEnvelope) -> BackendReply { - if let Some(packet) = command.input { - let _ = packet.payload_bytes(); - } - BackendReply::continue_without_response() - } - - fn set_input_paused(&mut self, command: CommandEnvelope) -> BackendReply { - if command.paused.is_none() { - return BackendReply::response(missing_field(&command.id, "paused")); - } - - BackendReply::response(Response::Ok { id: command.id }) - } - - fn update_render_surface(&mut self, command: CommandEnvelope) -> BackendReply { - if command.surface.is_none() { - return BackendReply::response(missing_field(&command.id, "surface")); - } - - BackendReply::response(Response::Ok { id: command.id }) - } - - fn update_bitrate_limit(&mut self, command: CommandEnvelope) -> BackendReply { - let Some(max_bitrate_kbps) = command.max_bitrate_kbps else { - return BackendReply::response(missing_field(&command.id, "maxBitrateKbps")); - }; - - let max_bitrate_kbps = normalize_bitrate_kbps(max_bitrate_kbps); - update_context_bitrate_limit(&mut self.active_context, max_bitrate_kbps); - - BackendReply { - events: vec![Event::Log { - level: "info", - message: format!( - "Updated native bitrate limit to {max_bitrate_kbps} Kbps for the next native offer." - ), - }], - response: Some(Response::Ok { id: command.id }), - should_continue: true, - } - } - - fn update_shortcuts(&mut self, command: CommandEnvelope) -> BackendReply { - // Stub backend has no native window; accept the command without applying it. - BackendReply::response(Response::Ok { id: command.id }) - } - - fn stop(&mut self, command: CommandEnvelope) -> BackendReply { - self.active_context = None; - let message = command - .reason - .unwrap_or_else(|| "stop requested".to_owned()); - BackendReply::stop(command.id, message) - } -} - -fn codec_label(codec: VideoCodec) -> &'static str { - match codec { - VideoCodec::H264 => "H264", - VideoCodec::H265 => "H265", - VideoCodec::AV1 => "AV1", - } -} - -fn color_quality_bit_depth(color_quality: ColorQuality) -> u8 { - color_quality.bit_depth() -} - -fn preferred_hevc_profile_id(color_quality: ColorQuality) -> u8 { - if color_quality.bit_depth() >= 10 { - 2 - } else { - 1 - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::protocol::{ColorQuality, NativeStreamerShortcutBindings, SessionInfo, StreamSettings}; - - fn context(resolution: &str) -> NativeStreamerSessionContext { - NativeStreamerSessionContext { - session: SessionInfo { - session_id: "session-1".to_owned(), - server_ip: "80-250-97-40.cloudmatchbeta.nvidiagrid.net".to_owned(), - ice_servers: Vec::new(), - media_connection_info: Some(MediaConnectionInfo { - ip: "10.0.0.7".to_owned(), - port: 49003, - usage: Some(2), - }), - negotiated_stream_profile: None, - requested_streaming_features: None, - finalized_streaming_features: None, - }, - settings: StreamSettings { - resolution: resolution.to_owned(), - fps: 120, - max_bitrate_mbps: 75, - codec: VideoCodec::H265, - color_quality: ColorQuality::TenBit420, - enable_cloud_gsync: false, - native_transition_diagnostics: None, - }, - shortcuts: NativeStreamerShortcutBindings::default(), - nvst_video: None, - } - } - - #[test] - fn prepares_offer_once_for_all_backends() { - let offer = "v=0\nc=IN IP4 0.0.0.0\na=ice-ufrag:user\na=ice-pwd:pass\na=fingerprint:sha-256 AA:BB\n"; - let prepared = prepare_native_offer(&context("1920x1080"), offer).expect("valid offer"); - - assert!(prepared.fixed_offer_sdp.contains("c=IN IP4 80.250.97.40")); - assert!(prepared - .gstreamer_offer_sdp - .contains("c=IN IP4 80.250.97.40")); - assert_eq!(prepared.nvst_params.width, 1920); - assert_eq!(prepared.nvst_params.height, 1080); - assert_eq!(prepared.nvst_params.fps, 120); - assert_eq!(prepared.nvst_params.max_bitrate_kbps, 75_000); - assert_eq!(prepared.nvst_params.credentials.ufrag, "user"); - assert_eq!( - prepared - .media_connection_info - .as_ref() - .map(|info| info.port), - Some(49003), - ); - } - - #[test] - fn prepares_offer_rewrites_server_ice_candidates_to_media_connection_info() { - let offer = [ - "v=0", - "a=ice-ufrag:user", - "a=ice-pwd:pass", - "a=fingerprint:sha-256 AA:BB", - "m=audio 47998 UDP/TLS/RTP/SAVPF 111", - "a=candidate:1 1 udp 2122260223 203.0.113.10 47998 typ host", - "m=video 47998 UDP/TLS/RTP/SAVPF 96", - "a=candidate:2 1 udp 2122260223 203.0.113.10 47998 typ host", - "a=rtpmap:96 H265/90000", - ] - .join("\n"); - - let prepared = prepare_native_offer(&context("1920x1080"), &offer).expect("valid offer"); - - assert_eq!(prepared.media_connection_ice_replacements, 2); - assert!(prepared - .fixed_offer_sdp - .contains("a=candidate:1 1 udp 2122260223 10.0.0.7 49003 typ host")); - assert!(prepared - .fixed_offer_sdp - .contains("a=candidate:2 1 udp 2122260223 10.0.0.7 49003 typ host")); - } - - #[test] - fn prepares_offer_skips_non_webrtc_media_connection_info() { - let mut context = context("1920x1080"); - context - .session - .media_connection_info - .as_mut() - .expect("media connection") - .usage = Some(14); - let offer = [ - "v=0", - "a=ice-ufrag:user", - "a=ice-pwd:pass", - "a=fingerprint:sha-256 AA:BB", - "a=candidate:1 1 udp 2122260223 203.0.113.10 47998 typ host", - ] - .join("\n"); - - let prepared = prepare_native_offer(&context, &offer).expect("valid offer"); - - assert_eq!(prepared.media_connection_ice_replacements, 0); - assert!(prepared - .fixed_offer_sdp - .contains("a=candidate:1 1 udp 2122260223 203.0.113.10 47998 typ host")); - } - - #[test] - fn prepares_offer_filters_remote_video_to_requested_codec() { - let offer = [ - "v=0", - "a=group:BUNDLE 0 1", - "a=ice-ufrag:user", - "a=ice-pwd:pass", - "a=fingerprint:sha-256 AA:BB", - "m=audio 9 UDP/TLS/RTP/SAVPF 111", - "a=rtpmap:111 OPUS/48000/2", - "m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100", - "a=rtpmap:96 AV1/90000", - "a=rtpmap:97 rtx/90000", - "a=fmtp:97 apt=96", - "a=rtpmap:98 H265/90000", - "a=fmtp:98 profile-id=2;level-id=186", - "a=rtpmap:99 rtx/90000", - "a=fmtp:99 apt=98", - "a=rtpmap:100 flexfec-03/90000", - ] - .join("\n"); - - let prepared = prepare_native_offer(&context("1920x1080"), &offer).expect("valid offer"); - - assert!(prepared - .gstreamer_offer_sdp - .contains("a=rtpmap:98 H265/90000")); - assert!(prepared - .gstreamer_offer_sdp - .contains("a=rtpmap:99 rtx/90000")); - assert!(!prepared - .gstreamer_offer_sdp - .contains("a=rtpmap:96 AV1/90000")); - assert!(!prepared - .gstreamer_offer_sdp - .contains("a=rtpmap:97 rtx/90000")); - assert!(prepared - .gstreamer_offer_sdp - .contains("m=video 9 UDP/TLS/RTP/SAVPF 98 99 100")); - assert!(prepared - .gstreamer_offer_sdp - .contains("a=rtpmap:100 flexfec-03/90000")); - } - - #[test] - fn aligns_gstreamer_video_sdp_framerate() { - let sdp = "v=0\nm=video 9 UDP/TLS/RTP/SAVPF 96\na=framerate:60\na=rtpmap:96 H265/90000\n"; - - let (aligned, changed) = align_video_sdp_framerate_for_gstreamer(sdp, 240); - - assert!(changed); - assert!(aligned.contains("a=framerate:240\n")); - assert!(!aligned.contains("a=framerate:60")); - } - - #[test] - fn inserts_gstreamer_video_sdp_framerate_when_absent() { - let sdp = "v=0\nm=audio 9 UDP/TLS/RTP/SAVPF 111\na=rtpmap:111 OPUS/48000/2\nm=video 9 UDP/TLS/RTP/SAVPF 96\na=rtpmap:96 H265/90000\nm=application 9 UDP/DTLS/SCTP webrtc-datachannel\n"; - - let (aligned, changed) = align_video_sdp_framerate_for_gstreamer(sdp, 120); - - assert!(changed); - assert!(aligned.contains( - "m=video 9 UDP/TLS/RTP/SAVPF 96\na=rtpmap:96 H265/90000\na=framerate:120\nm=application" - )); - } - - #[test] - fn preserves_gstreamer_video_sdp_framerate_line_endings() { - let sdp = "v=0\r\nm=video 9 UDP/TLS/RTP/SAVPF 96\r\na=rtpmap:96 H265/90000\r\n"; - - let (aligned, changed) = align_video_sdp_framerate_for_gstreamer(sdp, 240); - - assert!(changed); - assert!(aligned.contains("a=framerate:240\r\n")); - assert!(!aligned.contains('\n') || aligned.contains("\r\n")); - } - - #[test] - fn rejects_invalid_resolution_during_offer_preparation() { - let error = prepare_native_offer(&context("bad"), "v=0").expect_err("invalid resolution"); - assert_eq!( - error, - PrepareNativeOfferError::InvalidResolution { - resolution: "bad".to_owned(), - }, - ); - } - - #[test] - fn normalizes_native_bitrate_limits_to_slider_bounds() { - assert_eq!(normalize_bitrate_kbps(1_000), 5_000); - assert_eq!(normalize_bitrate_kbps(75_000), 75_000); - assert_eq!(normalize_bitrate_kbps(250_000), 150_000); - assert_eq!(bitrate_kbps_to_mbps(75_500), 76); - } - - #[test] - fn creates_expected_default_backend_for_build_features() { - let backend = create_backend_for_name(None, None); - let capabilities = backend.capabilities(); - #[cfg(not(feature = "gstreamer"))] - assert_eq!(capabilities.backend, "stub"); - #[cfg(feature = "gstreamer")] - assert_eq!(capabilities.backend, "gstreamer"); - } - - #[test] - fn reports_unknown_backend_fallback_in_capabilities() { - let backend = create_backend_for_name(Some("missing"), None); - let capabilities = backend.capabilities(); - assert_eq!(capabilities.backend, "stub"); - assert_eq!(capabilities.requested_backend.as_deref(), Some("missing")); - assert!(capabilities - .fallback_reason - .as_deref() - .is_some_and(|reason| reason.contains("Unknown native streamer backend")),); - } - - #[cfg(not(feature = "gstreamer"))] - #[test] - fn reports_gstreamer_feature_fallback_in_capabilities() { - let backend = create_backend_for_name(Some("gstreamer"), None); - let capabilities = backend.capabilities(); - assert_eq!(capabilities.backend, "stub"); - assert_eq!(capabilities.requested_backend.as_deref(), Some("gstreamer")); - assert!(capabilities - .fallback_reason - .as_deref() - .is_some_and(|reason| reason.contains("without the gstreamer feature")),); - } -} diff --git a/native/opennow-streamer/src/gstreamer_backend.rs b/native/opennow-streamer/src/gstreamer_backend.rs deleted file mode 100644 index c72879b04..000000000 --- a/native/opennow-streamer/src/gstreamer_backend.rs +++ /dev/null @@ -1,1215 +0,0 @@ -use crate::backend::{ - normalize_bitrate_kbps, prepare_native_offer, prepared_offer_events, - update_context_bitrate_limit, BackendReply, NativeStreamerBackend, - web_rtc_media_connection_info, -}; -use crate::gstreamer_config::{ - resolve_d3d_fullscreen_sink, resolve_present_max_fps, use_internal_renderer, - NATIVE_D3D_FULLSCREEN_ENV, NATIVE_PRESENT_MAX_FPS_ENV, PRESENT_LIMITER_AUTO_SENTINEL, - PRESENT_LIMITER_VRR_SENTINEL, -}; -use crate::gstreamer_platform::{clear_native_shortcut_bindings, set_native_shortcut_bindings}; -use crate::gstreamer_pipeline::{ - current_platform_label, init_gstreamer, native_video_backend_capabilities, GstreamerPipeline, -}; -use crate::protocol::{ - missing_field, CommandEnvelope, Event, IceCandidatePayload, NativeRenderSurface, - NativeStreamerCapabilities, NativeStreamerSessionContext, NativeVideoBackendCapability, - Response, SendAnswerRequest, PROTOCOL_VERSION, -}; -use crate::sdp::{ - build_nvst_sdp_for_answer, extract_negotiated_video_codec, munge_answer_sdp, - rewrite_ice_candidate_endpoint, -}; -use std::sync::mpsc::Sender; - -pub(crate) fn send_log(event_sender: &Option>, level: &'static str, message: String) { - if let Some(event_sender) = event_sender { - let _ = event_sender.send(Event::Log { level, message }); - } else { - eprintln!("[NativeStreamer] {message}"); - } -} - -#[derive(Debug)] -pub struct GstreamerBackend { - active_context: Option, - pending_remote_ice: Vec, - pipeline: Option, - event_sender: Option>, - remote_description_set: bool, - render_surface: Option, -} - -impl GstreamerBackend { - pub fn new(event_sender: Option>) -> Self { - Self { - active_context: None, - pending_remote_ice: Vec::new(), - pipeline: None, - event_sender, - remote_description_set: false, - render_surface: None, - } - } - - fn replay_pending_remote_ice(&mut self) -> Vec { - let candidates = std::mem::take(&mut self.pending_remote_ice); - let Some(pipeline) = self.pipeline.as_mut() else { - self.pending_remote_ice = candidates; - return Vec::new(); - }; - - let mut events = Vec::new(); - for candidate in candidates { - if let Err(message) = pipeline.add_remote_ice(&candidate) { - events.push(Event::Error { - code: "remote-ice-failed".to_owned(), - message, - }); - } - } - events - } - - fn rewrite_remote_ice_candidate(&self, candidate: IceCandidatePayload) -> IceCandidatePayload { - let Some(context) = self.active_context.as_ref() else { - return candidate; - }; - let Some(media_connection_info) = web_rtc_media_connection_info(context) else { - return candidate; - }; - let (rewritten, changed) = rewrite_ice_candidate_endpoint( - &candidate.candidate, - &media_connection_info.ip, - media_connection_info.port, - ); - if changed { - send_log( - &self.event_sender, - "info", - format!( - "Rewrote remote ICE candidate endpoint to GFN media connection hint {}:{}.", - media_connection_info.ip, media_connection_info.port - ), - ); - IceCandidatePayload { - candidate: rewritten, - ..candidate - } - } else { - candidate - } - } -} - -impl NativeStreamerBackend for GstreamerBackend { - fn capabilities(&self) -> NativeStreamerCapabilities { - NativeStreamerCapabilities { - protocol_version: PROTOCOL_VERSION, - backend: "gstreamer", - requested_backend: None, - fallback_reason: None, - supports_offer_answer: true, - supports_remote_ice: true, - supports_local_ice: true, - supports_input: true, - video_backends: match init_gstreamer() { - Ok(()) => native_video_backend_capabilities(), - Err(error) => vec![NativeVideoBackendCapability { - backend: "gstreamer".to_owned(), - platform: current_platform_label().to_owned(), - codecs: Vec::new(), - zero_copy_modes: Vec::new(), - sink: None, - available: false, - reason: Some(error), - }], - }, - } - } - - fn start(&mut self, command: CommandEnvelope) -> BackendReply { - let id = command.id; - let Some(context) = command.context else { - return BackendReply::response(missing_field(&id, "context")); - }; - - let session_id = context.session.session_id.clone(); - let pipeline = match GstreamerPipeline::build( - self.event_sender.clone(), - &context.session.ice_servers, - ) { - Ok(pipeline) => pipeline, - Err(message) => { - return BackendReply { - events: vec![Event::Error { - code: "gstreamer-start-failed".to_owned(), - message: message.clone(), - }], - response: Some(Response::Error { - id: Some(id), - code: "gstreamer-start-failed".to_owned(), - message, - }), - should_continue: true, - }; - } - }; - - if let Some(old_pipeline) = self.pipeline.take() { - if let Err(message) = old_pipeline.stop() { - eprintln!("[NativeStreamer] {message}"); - } - } - - set_native_shortcut_bindings(&context.shortcuts); - self.active_context = Some(context); - self.pending_remote_ice.clear(); - self.remote_description_set = false; - let webrtc_name = pipeline.webrtc_name(); - self.pipeline = Some(pipeline); - - let mut events = vec![Event::Status { - status: "ready", - message: Some(format!( - "GStreamer backend selected for session {session_id}; {} pipeline is ready.", - webrtc_name - )), - }]; - - if let Some(nvst) = self - .active_context - .as_ref() - .and_then(|ctx| ctx.nvst_video.clone()) - { - let fallback_codec = self - .active_context - .as_ref() - .map(|ctx| ctx.settings.codec.as_str().to_owned()) - .unwrap_or_else(|| "H265".to_owned()); - let requested_fps = self - .active_context - .as_ref() - .map(|ctx| ctx.settings.fps); - let d3d_fullscreen = resolve_d3d_fullscreen_sink( - self.active_context - .as_ref() - .map(|ctx| ctx.settings.enable_cloud_gsync) - .unwrap_or(false), - ); - let cloud_gsync_enabled = self - .active_context - .as_ref() - .map(|ctx| ctx.settings.enable_cloud_gsync) - .unwrap_or(false); - let present_max_fps = resolve_present_max_fps(cloud_gsync_enabled); - if let Some(pipeline) = self.pipeline.as_mut() { - pipeline.set_present_max_fps(present_max_fps); - pipeline.set_d3d_fullscreen_sink(d3d_fullscreen); - if let Some(ctx) = self.active_context.as_ref() { - let bitrate_kbps = ctx.settings.max_bitrate_mbps.saturating_mul(1000); - pipeline.configure_stats(ctx, bitrate_kbps); - } - match pipeline.attach_nvst_video( - nvst, - &fallback_codec, - requested_fps.filter(|fps| *fps > 0), - d3d_fullscreen, - ) { - Ok(()) => events.push(Event::Log { - level: "info", - message: "NVST classic UDP video receive scaffold attached (hybrid WebRTC input)." - .to_owned(), - }), - Err(message) => { - events.push(Event::Error { - code: "nvst-video-attach-failed".to_owned(), - message: message.clone(), - }); - return BackendReply { - events, - response: Some(Response::Error { - id: Some(id), - code: "nvst-video-attach-failed".to_owned(), - message, - }), - should_continue: true, - }; - } - } - } - } - - if let (Some(surface), Some(pipeline)) = - (self.render_surface.clone(), self.pipeline.as_ref()) - { - if let Err(message) = pipeline.update_render_surface(surface) { - if let Some(pipeline) = self.pipeline.take() { - let _ = pipeline.stop(); - } - return BackendReply { - events: vec![Event::Error { - code: "native-render-surface-failed".to_owned(), - message: message.clone(), - }], - response: Some(Response::Error { - id: Some(id), - code: "native-render-surface-failed".to_owned(), - message, - }), - should_continue: true, - }; - } - } - - BackendReply { - events, - response: Some(Response::Ok { id }), - should_continue: true, - } - } - - fn handle_offer(&mut self, command: CommandEnvelope) -> BackendReply { - let id = command.id.clone(); - let Some(context) = command.context else { - return BackendReply::response(missing_field(&id, "context")); - }; - let Some(offer_sdp) = command.sdp else { - return BackendReply::response(missing_field(&id, "sdp")); - }; - - let prepared = match prepare_native_offer(&context, &offer_sdp) { - Ok(prepared) => prepared, - Err(error) => return BackendReply::response(error.into_response(id)), - }; - - let mut events = prepared_offer_events(&prepared); - let parsed_offer = match GstreamerPipeline::parse_offer_sdp(&prepared.gstreamer_offer_sdp) { - Ok(offer) => offer, - Err(message) => { - return BackendReply { - events, - response: Some(Response::Error { - id: Some(id), - code: "invalid-remote-sdp".to_owned(), - message, - }), - should_continue: true, - }; - } - }; - - let Some(pipeline) = self.pipeline.as_mut() else { - return BackendReply { - events, - response: Some(Response::Error { - id: Some(id), - code: "gstreamer-not-started".to_owned(), - message: "GStreamer pipeline is not started.".to_owned(), - }), - should_continue: true, - }; - }; - - let present_max_fps = resolve_present_max_fps(context.settings.enable_cloud_gsync); - // Internal child-surface mode never uses exclusive D3D fullscreen present. - let d3d_fullscreen_sink = resolve_d3d_fullscreen_sink(context.settings.enable_cloud_gsync); - set_native_shortcut_bindings(&context.shortcuts); - pipeline.set_present_max_fps(present_max_fps); - pipeline.set_d3d_fullscreen_sink(d3d_fullscreen_sink); - pipeline.configure_stats(&context, prepared.nvst_params.max_bitrate_kbps); - if present_max_fps > 0 - && present_max_fps != PRESENT_LIMITER_AUTO_SENTINEL - && present_max_fps != PRESENT_LIMITER_VRR_SENTINEL - { - events.push(Event::Log { - level: "info", - message: format!( - "Native present limiter enabled at {present_max_fps} fps for {} fps stream; set {NATIVE_PRESENT_MAX_FPS_ENV}=0 to disable.", - context.settings.fps - ), - }); - } else if present_max_fps == PRESENT_LIMITER_AUTO_SENTINEL { - events.push(Event::Log { - level: "info", - message: format!( - "Native present limiter auto mode for {} fps stream (D3D11 caps to display Hz when stream fps exceeds it); set {NATIVE_PRESENT_MAX_FPS_ENV}=0 to disable.", - context.settings.fps - ), - }); - } else if present_max_fps == PRESENT_LIMITER_VRR_SENTINEL { - events.push(Event::Log { - level: "info", - message: format!( - "Native VRR present limiter auto mode for {} fps stream (caps below the display refresh ceiling when needed).", - context.settings.fps - ), - }); - } else { - events.push(Event::Log { - level: "info", - message: "Native present limiter disabled for uncapped VSync-off presentation." - .to_owned(), - }); - } - if d3d_fullscreen_sink { - events.push(Event::Log { - level: "info", - message: format!( - "Native D3D fullscreen presentation is enabled for Cloud G-Sync/VRR; set {NATIVE_D3D_FULLSCREEN_ENV}=0 to disable." - ), - }); - } else if use_internal_renderer() { - events.push(Event::Log { - level: "info", - message: "Native Internal renderer keeps exclusive D3D fullscreen off (child HWND present; sync=false, depth-1 post-decode queue)." - .to_owned(), - }); - } - - let answer_sdp = match pipeline.negotiate_answer( - parsed_offer, - (prepared.gstreamer_ice_pwd_replacements > 0) - .then_some(&prepared.nvst_params.credentials), - prepared.nvst_params.partial_reliable_threshold_ms, - ) { - Ok(answer_sdp) => munge_answer_sdp(&answer_sdp, prepared.nvst_params.max_bitrate_kbps), - Err(message) => { - return BackendReply { - events, - response: Some(Response::Error { - id: Some(id), - code: "gstreamer-negotiation-failed".to_owned(), - message, - }), - should_continue: true, - }; - } - }; - self.remote_description_set = true; - events.extend(self.replay_pending_remote_ice()); - - events.push(Event::Log { - level: "info", - message: - "GStreamer created a local WebRTC answer and replayed queued remote ICE candidates." - .to_owned(), - }); - - if let Some(negotiated_codec) = extract_negotiated_video_codec(&answer_sdp) { - if negotiated_codec != prepared.nvst_params.codec { - events.push(Event::Log { - level: "warn", - message: format!( - "Negotiated video codec is {} while requested codec was {}; building NVST SDP for the negotiated codec to avoid server/client codec mismatch.", - negotiated_codec.as_str(), - prepared.nvst_params.codec.as_str(), - ), - }); - } else { - events.push(Event::Log { - level: "debug", - message: format!( - "Negotiated video codec confirmed as {}.", - negotiated_codec.as_str() - ), - }); - } - } - - let nvst_sdp = match build_nvst_sdp_for_answer(&prepared.nvst_params, &answer_sdp) { - Ok(nvst_sdp) => nvst_sdp, - Err(message) => { - return BackendReply { - events, - response: Some(Response::Error { - id: Some(id), - code: "invalid-local-answer-sdp".to_owned(), - message, - }), - should_continue: true, - }; - } - }; - - events.push(Event::Log { - level: "debug", - message: "Built native NVST SDP from the local WebRTC answer transport credentials." - .to_owned(), - }); - - BackendReply { - events, - response: Some(Response::Answer { - id, - answer: SendAnswerRequest { - sdp: answer_sdp, - nvst_sdp: Some(nvst_sdp), - }, - }), - should_continue: true, - } - } - - fn add_remote_ice(&mut self, command: CommandEnvelope) -> BackendReply { - let Some(candidate) = command.candidate else { - return BackendReply::response(missing_field(&command.id, "candidate")); - }; - let candidate = self.rewrite_remote_ice_candidate(candidate); - - if self.remote_description_set { - if let Some(pipeline) = self.pipeline.as_mut() { - if let Err(message) = pipeline.add_remote_ice(&candidate) { - return BackendReply::response(Response::Error { - id: Some(command.id), - code: "remote-ice-failed".to_owned(), - message, - }); - } - } else { - self.pending_remote_ice.push(candidate); - } - } else { - self.pending_remote_ice.push(candidate); - } - BackendReply::response(Response::Ok { id: command.id }) - } - - fn send_input(&mut self, command: CommandEnvelope) -> BackendReply { - let Some(packet) = command.input else { - return BackendReply::continue_without_response(); - }; - - let Ok(payload) = packet.payload_bytes() else { - return BackendReply::continue_without_response(); - }; - - if payload.is_empty() || payload.len() > 4096 { - return BackendReply::continue_without_response(); - } - - if let Some(pipeline) = self.pipeline.as_ref() { - let _ = pipeline.send_input_packet(&payload, packet.partially_reliable); - } - - BackendReply::continue_without_response() - } - - fn set_input_paused(&mut self, command: CommandEnvelope) -> BackendReply { - let Some(paused) = command.paused else { - return BackendReply::response(missing_field(&command.id, "paused")); - }; - - if let Some(pipeline) = self.pipeline.as_ref() { - pipeline.set_input_paused(paused); - } - - BackendReply::response(Response::Ok { id: command.id }) - } - - fn update_render_surface(&mut self, command: CommandEnvelope) -> BackendReply { - let Some(surface) = command.surface else { - return BackendReply::response(missing_field(&command.id, "surface")); - }; - - self.render_surface = Some(surface.clone()); - if let Some(pipeline) = self.pipeline.as_ref() { - if let Err(message) = pipeline.update_render_surface(surface) { - return BackendReply { - events: vec![Event::Error { - code: "native-render-surface-failed".to_owned(), - message: message.clone(), - }], - response: Some(Response::Error { - id: Some(command.id), - code: "native-render-surface-failed".to_owned(), - message, - }), - should_continue: true, - }; - } - } - - BackendReply::response(Response::Ok { id: command.id }) - } - - fn update_bitrate_limit(&mut self, command: CommandEnvelope) -> BackendReply { - let Some(max_bitrate_kbps) = command.max_bitrate_kbps else { - return BackendReply::response(missing_field(&command.id, "maxBitrateKbps")); - }; - - let max_bitrate_kbps = normalize_bitrate_kbps(max_bitrate_kbps); - update_context_bitrate_limit(&mut self.active_context, max_bitrate_kbps); - - BackendReply { - events: vec![Event::Log { - level: "info", - message: format!( - "Updated native bitrate limit to {max_bitrate_kbps} Kbps. The active GFN server bitrate cap is negotiated in NVST SDP and will apply on the next native offer/reconnect." - ), - }], - response: Some(Response::Ok { id: command.id }), - should_continue: true, - } - } - - fn update_shortcuts(&mut self, command: CommandEnvelope) -> BackendReply { - let Some(shortcuts) = command.shortcuts else { - return BackendReply::response(missing_field(&command.id, "shortcuts")); - }; - set_native_shortcut_bindings(&shortcuts); - if let Some(context) = self.active_context.as_mut() { - context.shortcuts = shortcuts; - } - BackendReply::response(Response::Ok { id: command.id }) - } - - fn stop(&mut self, command: CommandEnvelope) -> BackendReply { - self.active_context = None; - self.pending_remote_ice.clear(); - self.remote_description_set = false; - clear_native_shortcut_bindings(); - if let Some(pipeline) = self.pipeline.take() { - if let Err(message) = pipeline.stop() { - return BackendReply { - events: vec![Event::Error { - code: "gstreamer-stop-failed".to_owned(), - message: message.clone(), - }], - response: Some(Response::Error { - id: Some(command.id), - code: "gstreamer-stop-failed".to_owned(), - message, - }), - should_continue: true, - }; - } - } - let message = command - .reason - .unwrap_or_else(|| "stop requested".to_owned()); - BackendReply::stop(command.id, message) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::gstreamer_config::PRESENT_LIMITER_AUTO_SENTINEL; - use crate::gstreamer_input::parse_input_handshake_version; - use crate::gstreamer_liveness::{ - caps_framerate_summary, classify_video_startup_failure, sink_stats_summary, - VideoStallAction, VideoStallTracker, - }; - use crate::gstreamer_pipeline::{ - backend_runs_on_platform, configure_stats_overlay_element, - default_rtp_video_api_priority, effective_present_max_fps, format_video_chain_selection, - init_gstreamer, preferred_rtp_video_apis_for, resolve_gstreamer_stun_server, - rtp_video_chain_definition, RtpVideoApi, RtpVideoChainRole, - }; - use crate::gstreamer_transitions::resolve_queue_mode; - use crate::protocol::{IceServer, NativeQueueMode, StreamSettings, VideoCodec}; - use crate::sdp::IceCredentials; - use gst::prelude::*; - use gstreamer as gst; - use gstreamer_webrtc as gst_webrtc; - - #[test] - fn builds_and_stops_webrtc_pipeline() { - let pipeline = GstreamerPipeline::build(None, &[]).expect("GStreamer webrtcbin pipeline"); - assert_eq!(pipeline.webrtc.name(), "opennow-webrtcbin"); - assert_eq!( - pipeline.webrtc.property::("stun-server"), - "stun://stun2.l.google.com:19302" - ); - pipeline.stop().expect("pipeline stops"); - } - - #[test] - fn invalid_internal_render_surface_fails_before_stream_negotiation() { - if crate::gstreamer_config::use_external_renderer_window() { - return; - } - - let pipeline = GstreamerPipeline::build(None, &[]).expect("GStreamer pipeline"); - let error = pipeline - .update_render_surface(NativeRenderSurface { - window_handle: Some("not-a-native-handle".to_owned()), - rect: Some(crate::protocol::NativeRenderRect { - x: 0, - y: 0, - width: 1280, - height: 720, - }), - visible: true, - device_scale_factor: 1.0, - show_stats: false, - }) - .expect_err("invalid native parent handle must fail"); - assert!(error.contains("Invalid native parent window handle")); - pipeline.stop().expect("pipeline stops"); - } - - #[test] - fn classifies_native_video_startup_failure_stage() { - assert_eq!( - classify_video_startup_failure(0, 0, 0), - ("native-video-input-startup-timeout", "RTP video input") - ); - assert_eq!( - classify_video_startup_failure(4096, 0, 0), - ( - "native-video-decoder-startup-timeout", - "video decoder output" - ) - ); - assert_eq!( - classify_video_startup_failure(4096, 10, 0), - ( - "native-video-renderer-startup-timeout", - "video renderer input" - ) - ); - } - - #[test] - fn configures_session_stun_server_for_gstreamer() { - let servers = vec![ - IceServer { - urls: vec!["turn:relay.example.test:3478".to_owned()], - username: None, - credential: None, - }, - IceServer { - urls: vec!["stun:192.0.2.10:19302".to_owned()], - username: None, - credential: None, - }, - ]; - - assert_eq!( - resolve_gstreamer_stun_server(&servers), - "stun://192.0.2.10:19302" - ); - let pipeline = - GstreamerPipeline::build(None, &servers).expect("GStreamer webrtcbin pipeline"); - assert_eq!( - pipeline.webrtc.property::("stun-server"), - "stun://192.0.2.10:19302" - ); - pipeline.stop().expect("pipeline stops"); - } - - #[test] - fn configures_dwrite_stats_overlay_without_type_panics() { - gst::init().expect("gstreamer init"); - let Some(overlay) = gst::ElementFactory::make("dwritetextoverlay").build().ok() else { - return; - }; - - configure_stats_overlay_element(&overlay); - overlay.set_property("text", "OpenNOW native stats"); - } - - #[test] - fn parses_basic_remote_offer_sdp() { - let sdp = "v=0\r\no=- 1 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\nm=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 127.0.0.1\r\na=mid:0\r\na=sctp-port:5000\r\n"; - let parsed = GstreamerPipeline::parse_offer_sdp(sdp).expect("valid SDP"); - assert_eq!(parsed.medias_len(), 1); - } - - #[test] - fn defers_gfn_uuid_ice_password_until_actual_ice_stream_exists() { - let mut pipeline = - GstreamerPipeline::build(None, &[]).expect("GStreamer webrtcbin pipeline"); - let credentials = IceCredentials { - ufrag: "2efecf37".to_owned(), - pwd: "26b335b8-6cb2-4c18-96d0-963e5e586c9a".to_owned(), - fingerprint: String::new(), - }; - - pipeline.original_remote_ice_credentials = Some(credentials); - assert!(!pipeline - .try_restore_original_remote_ice_credentials("without negotiated streams") - .expect("remote ICE credential restoration can be deferred")); - pipeline.stop().expect("pipeline stops"); - } - - #[test] - fn remote_ice_credential_restore_after_remote_description_does_not_probe_fake_streams() { - let mut pipeline = - GstreamerPipeline::build(None, &[]).expect("GStreamer webrtcbin pipeline"); - let sdp = concat!( - "v=0\r\n", - "o=- 4373647202393833435 2 IN IP4 127.0.0.1\r\n", - "s=-\r\n", - "t=0 0\r\n", - "a=group:BUNDLE 0 1 2 3\r\n", - "a=ice-options:trickle\r\n", - "a=ice-lite\r\n", - "m=audio 9 UDP/TLS/RTP/SAVPF 111\r\n", - "c=IN IP4 0.0.0.0\r\n", - "a=mid:0\r\n", - "a=ice-ufrag:2efecf37\r\n", - "a=ice-pwd:26b335b899a84ffab9aaf38ddad1e2b4\r\n", - "a=fingerprint:sha-256 94:6C:60:66:35:B9:F6:B4:BC:46:60:EF:81:AC:AB:87:A9:45:4A:09:92:E4:3E:16:28:7E:BD:6D:8C:1A:7D:6B\r\n", - "a=setup:actpass\r\n", - "a=rtcp-mux\r\n", - "a=rtpmap:111 OPUS/48000/2\r\n", - "m=video 9 UDP/TLS/RTP/SAVPF 96\r\n", - "c=IN IP4 0.0.0.0\r\n", - "a=mid:1\r\n", - "a=ice-ufrag:2efecf37\r\n", - "a=ice-pwd:26b335b899a84ffab9aaf38ddad1e2b4\r\n", - "a=fingerprint:sha-256 94:6C:60:66:35:B9:F6:B4:BC:46:60:EF:81:AC:AB:87:A9:45:4A:09:92:E4:3E:16:28:7E:BD:6D:8C:1A:7D:6B\r\n", - "a=setup:actpass\r\n", - "a=rtcp-mux\r\n", - "a=rtpmap:96 H264/90000\r\n", - "m=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\n", - "c=IN IP4 0.0.0.0\r\n", - "a=mid:2\r\n", - "a=ice-ufrag:2efecf37\r\n", - "a=ice-pwd:26b335b899a84ffab9aaf38ddad1e2b4\r\n", - "a=fingerprint:sha-256 94:6C:60:66:35:B9:F6:B4:BC:46:60:EF:81:AC:AB:87:A9:45:4A:09:92:E4:3E:16:28:7E:BD:6D:8C:1A:7D:6B\r\n", - "a=setup:actpass\r\n", - "a=sctp-port:5000\r\n", - "m=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\n", - "c=IN IP4 0.0.0.0\r\n", - "a=mid:3\r\n", - "a=ice-ufrag:2efecf37\r\n", - "a=ice-pwd:26b335b899a84ffab9aaf38ddad1e2b4\r\n", - "a=fingerprint:sha-256 94:6C:60:66:35:B9:F6:B4:BC:46:60:EF:81:AC:AB:87:A9:45:4A:09:92:E4:3E:16:28:7E:BD:6D:8C:1A:7D:6B\r\n", - "a=setup:actpass\r\n", - "a=sctp-port:5000\r\n", - ); - let offer_sdp = GstreamerPipeline::parse_offer_sdp(sdp).expect("valid SDP"); - let offer = - gst_webrtc::WebRTCSessionDescription::new(gst_webrtc::WebRTCSDPType::Offer, offer_sdp); - pipeline - .pipeline - .set_state(gst::State::Playing) - .expect("pipeline plays"); - pipeline - .set_description("set-remote-description", &offer) - .expect("remote description"); - - let credentials = IceCredentials { - ufrag: "2efecf37".to_owned(), - pwd: "26b335b8-99a8-4ffa-b9aa-f38ddad1e2b4".to_owned(), - fingerprint: String::new(), - }; - pipeline.original_remote_ice_credentials = Some(credentials); - pipeline - .try_restore_original_remote_ice_credentials("after remote description") - .expect("remote ICE credential restoration does not fail without actual streams"); - pipeline.stop().expect("pipeline stops"); - } - - #[test] - fn reports_offer_answer_and_local_ice_capabilities() { - let backend = GstreamerBackend::new(None); - let capabilities = backend.capabilities(); - assert!(capabilities.supports_offer_answer); - assert!(capabilities.supports_local_ice); - assert!(capabilities.supports_input); - } - - #[test] - #[cfg(target_os = "linux")] - fn bundles_av1_rtp_depayloading() { - init_gstreamer().expect("GStreamer initializes"); - assert!(gst::ElementFactory::find("rtpav1depay").is_some()); - } - - #[test] - fn parses_input_handshake_versions() { - assert_eq!( - parse_input_handshake_version(&[0x0e, 0x02, 0x03, 0x00]), - Some(3) - ); - assert_eq!(parse_input_handshake_version(&[0x0e, 0x02]), Some(2)); - assert_eq!(parse_input_handshake_version(&[0x0e, 0x03]), Some(0x030e)); - assert_eq!(parse_input_handshake_version(&[0x01, 0x02, 0x03]), None); - assert_eq!(parse_input_handshake_version(&[0x0e]), None); - } - - #[test] - fn maps_rtp_video_codecs_to_explicit_gpu_decode_chains() { - let h265 = - rtp_video_chain_definition("H265", RtpVideoApi::D3D11).expect("H265 D3D11 chain"); - assert_eq!(h265[0].factory, "rtph265depay"); - assert_eq!(h265[3].factory, "d3d11h265dec"); - assert_eq!(h265[4].factory, "dwritetextoverlay"); - assert_eq!(h265[6].factory, "d3d11videosink"); - assert!(!h265 - .iter() - .any(|spec| spec.role == RtpVideoChainRole::PostDecodeCapsFilter)); - - let h264 = - rtp_video_chain_definition("h264", RtpVideoApi::D3D12).expect("H264 D3D12 chain"); - assert_eq!(h264[0].factory, "rtph264depay"); - assert_eq!(h264[3].factory, "d3d12h264dec"); - assert_eq!(h264[4].factory, "dwritetextoverlay"); - assert_eq!(h264[6].factory, "d3d12videosink"); - assert!(!h264 - .iter() - .any(|spec| spec.role == RtpVideoChainRole::PostDecodeCapsFilter)); - - let av1 = rtp_video_chain_definition("AV1", RtpVideoApi::D3D11).expect("AV1 D3D11 chain"); - assert_eq!(av1[0].factory, "rtpav1depay"); - assert_eq!(av1[3].factory, "d3d11av1dec"); - assert_eq!(av1[4].factory, "dwritetextoverlay"); - assert_eq!(av1[6].factory, "d3d11videosink"); - } - - #[test] - fn does_not_force_d3d_memory_caps_by_default() { - let d3d11 = - rtp_video_chain_definition("H265", RtpVideoApi::D3D11).expect("H265 D3D11 chain"); - let d3d12 = - rtp_video_chain_definition("H264", RtpVideoApi::D3D12).expect("H264 D3D12 chain"); - - assert!(!d3d11 - .iter() - .any(|spec| spec.role == RtpVideoChainRole::PostDecodeCapsFilter)); - assert!(!d3d12 - .iter() - .any(|spec| spec.role == RtpVideoChainRole::PostDecodeCapsFilter)); - } - - #[test] - fn maps_cross_platform_video_paths_to_expected_decoders() { - let vt = - rtp_video_chain_definition("H264", RtpVideoApi::VideoToolbox).expect("VideoToolbox"); - assert_eq!(vt[3].factory, "vtdec_hw"); - assert!(vt.iter().any(|spec| spec.factory == "videoconvert")); - assert_eq!(vt.last().map(|spec| spec.factory), Some("glimagesink")); - assert!(!vt.iter().any(|spec| spec.factory == "capsfilter")); - - let vaapi = rtp_video_chain_definition("AV1", RtpVideoApi::Vaapi).expect("VAAPI AV1"); - assert_eq!(vaapi[3].factory, "vaav1dec"); - assert!(vaapi.iter().any(|spec| spec.factory == "videoconvert")); - assert_eq!(vaapi.last().map(|spec| spec.factory), Some("glimagesink")); - - let nvdec = rtp_video_chain_definition("AV1", RtpVideoApi::Nvdec).expect("NVDEC AV1"); - assert_eq!(nvdec[3].factory, "nvav1dec"); - assert!(nvdec.iter().any(|spec| spec.factory == "videoconvert")); - assert_eq!(nvdec.last().map(|spec| spec.factory), Some("glimagesink")); - - let v4l2 = rtp_video_chain_definition("H265", RtpVideoApi::V4L2).expect("V4L2 H265"); - assert_eq!(v4l2[3].factory, "v4l2slh265dec"); - assert!(!v4l2.iter().any(|spec| spec.factory == "videoconvert")); - - let v4l2_av1 = - rtp_video_chain_definition("AV1", RtpVideoApi::V4L2).expect("V4L2 AV1"); - assert_eq!(v4l2_av1[3].factory, "v4l2slav1dec"); - - let vulkan = rtp_video_chain_definition("H265", RtpVideoApi::Vulkan).expect("Vulkan H265"); - #[cfg(target_os = "windows")] - { - assert_eq!(vulkan[3].factory, "d3d12h265dec"); - assert!(!vulkan.iter().any(|spec| spec.factory == "vulkanh265dec")); - // Default Internal renderer: Electron cannot composite vulkansink. - assert_eq!( - vulkan.last().map(|spec| spec.factory), - Some("d3d12videosink") - ); - assert!(vulkan.iter().any(|spec| { - spec.role == RtpVideoChainRole::StatsOverlay && spec.factory == "dwritetextoverlay" - })); - assert!(!vulkan.iter().any(|spec| spec.factory == "vulkanupload")); - } - #[cfg(not(target_os = "windows"))] - { - assert_eq!(vulkan[3].factory, "vulkanh265dec"); - assert!(vulkan - .iter() - .any(|spec| spec.factory == "vulkancolorconvert")); - assert_eq!(vulkan.last().map(|spec| spec.factory), Some("vulkansink")); - } - let vulkan_av1 = - rtp_video_chain_definition("AV1", RtpVideoApi::Vulkan).expect("Vulkan AV1"); - #[cfg(target_os = "windows")] - assert_eq!(vulkan_av1[3].factory, "d3d12av1dec"); - #[cfg(not(target_os = "windows"))] - assert_eq!(vulkan_av1[3].factory, "vulkanav1dec"); - - let software = - rtp_video_chain_definition("H264", RtpVideoApi::Software).expect("software H264"); - assert_eq!(software[3].factory, "avdec_h264"); - assert!(software.iter().any(|spec| spec.factory == "videoconvert")); - assert_eq!( - software.last().map(|spec| spec.factory), - Some("autovideosink") - ); - } - - #[test] - fn exposes_vulkan_on_windows_and_linux_only() { - assert!(backend_runs_on_platform(RtpVideoApi::Vulkan, "windows")); - assert!(backend_runs_on_platform(RtpVideoApi::Vulkan, "linux")); - assert!(!backend_runs_on_platform(RtpVideoApi::Vulkan, "macos")); - assert!(!backend_runs_on_platform(RtpVideoApi::Vulkan, "other")); - } - - #[test] - fn explicit_linux_backend_selection_retains_native_software_fallback() { - assert_eq!( - preferred_rtp_video_apis_for("nvdec", Some(120)), - vec![RtpVideoApi::Nvdec, RtpVideoApi::Software] - ); - assert_eq!( - preferred_rtp_video_apis_for("vaapi", Some(120)), - vec![RtpVideoApi::Vaapi, RtpVideoApi::Software] - ); - assert_eq!( - preferred_rtp_video_apis_for("v4l2", Some(120)), - vec![RtpVideoApi::V4L2, RtpVideoApi::Software] - ); - assert_eq!( - preferred_rtp_video_apis_for("vulkan", Some(240)), - vec![RtpVideoApi::Vulkan, RtpVideoApi::Software] - ); - assert_eq!( - preferred_rtp_video_apis_for("vk", Some(120)), - vec![RtpVideoApi::Vulkan, RtpVideoApi::Software] - ); - } - - #[test] - #[cfg(target_os = "windows")] - fn windows_default_video_api_prefers_d3d12_for_high_fps() { - assert_eq!( - default_rtp_video_api_priority(Some(240)), - vec![ - RtpVideoApi::D3D12, - RtpVideoApi::D3D11, - RtpVideoApi::Software - ] - ); - assert_eq!( - default_rtp_video_api_priority(Some(120)), - vec![ - RtpVideoApi::D3D11, - RtpVideoApi::D3D12, - RtpVideoApi::Software - ] - ); - } - - #[test] - #[cfg(all(target_os = "linux", target_arch = "aarch64"))] - fn linux_arm64_prefers_v4l2_for_raspberry_pi_and_arm_devices() { - assert_eq!( - default_rtp_video_api_priority(Some(60)), - vec![ - RtpVideoApi::V4L2, - RtpVideoApi::Nvdec, - RtpVideoApi::Vaapi, - RtpVideoApi::Vulkan, - RtpVideoApi::Software, - ] - ); - } - - #[test] - #[cfg(all(target_os = "linux", not(target_arch = "aarch64")))] - fn linux_desktop_prefers_vendor_decoders_before_generic_paths() { - assert_eq!( - default_rtp_video_api_priority(Some(120)), - vec![ - RtpVideoApi::Nvdec, - RtpVideoApi::Vaapi, - RtpVideoApi::Vulkan, - RtpVideoApi::V4L2, - RtpVideoApi::Software, - ] - ); - } - - #[test] - fn automatic_present_limiter_targets_d3d_present_paths() { - assert_eq!( - effective_present_max_fps( - PRESENT_LIMITER_AUTO_SENTINEL, - Some(240), - RtpVideoApi::D3D11, - Some(165) - ), - 165 - ); - assert_eq!( - effective_present_max_fps( - PRESENT_LIMITER_AUTO_SENTINEL, - Some(240), - RtpVideoApi::D3D12, - Some(165) - ), - 165 - ); - assert_eq!( - effective_present_max_fps(144, Some(240), RtpVideoApi::D3D12, Some(165)), - 144 - ); - assert_eq!( - effective_present_max_fps(0, Some(240), RtpVideoApi::D3D11, Some(165)), - 0 - ); - assert_eq!( - effective_present_max_fps( - PRESENT_LIMITER_VRR_SENTINEL, - Some(240), - RtpVideoApi::D3D11, - Some(165) - ), - 162 - ); - assert_eq!( - effective_present_max_fps( - PRESENT_LIMITER_VRR_SENTINEL, - Some(120), - RtpVideoApi::D3D11, - Some(165) - ), - 0 - ); - } - - #[test] - fn formats_selected_video_chain_diagnostics() { - let specs = - rtp_video_chain_definition("H264", RtpVideoApi::Software).expect("software H264"); - let message = format_video_chain_selection("H264", RtpVideoApi::Software, &specs); - - assert!(message.contains("backend=software")); - assert!(message.contains("decoder=avdec_h264")); - assert!(message.contains("converter=videoconvert")); - assert!(message.contains("memory=system-memory")); - } - - #[test] - fn extracts_caps_framerate_summary() { - let caps = "video/x-raw(memory:D3D11Memory), format=(string)NV12, framerate=(fraction)240/1; zeroCopyD3D11=true"; - assert_eq!(caps_framerate_summary(caps).as_deref(), Some("240/1")); - assert_eq!(caps_framerate_summary("video/x-raw").as_deref(), None); - } - - #[test] - fn video_stall_tracker_waits_until_threshold() { - let mut tracker = VideoStallTracker::default(); - - assert_eq!(tracker.evaluate(2_499, 0), VideoStallAction::None); - } - - #[test] - fn video_stall_tracker_progresses_recovery_attempts() { - let mut tracker = VideoStallTracker::default(); - - assert_eq!( - tracker.evaluate(2_500, 0), - VideoStallAction::RequestKeyframe { - attempt: 1, - stall_ms: 2_500, - }, - ); - assert_eq!(tracker.evaluate(3_000, 0), VideoStallAction::None); - assert_eq!( - tracker.evaluate(5_000, 0), - VideoStallAction::RequestKeyframe { - attempt: 2, - stall_ms: 5_000, - }, - ); - assert_eq!( - tracker.evaluate(8_000, 0), - VideoStallAction::Resync { - attempt: 3, - stall_ms: 8_000, - }, - ); - assert_eq!( - tracker.evaluate(12_000, 0), - VideoStallAction::PartialFlush { - attempt: 4, - stall_ms: 12_000, - }, - ); - assert_eq!( - tracker.evaluate(16_000, 0), - VideoStallAction::CompleteFlush { - attempt: 5, - stall_ms: 16_000, - }, - ); - assert_eq!( - tracker.evaluate(20_000, 0), - VideoStallAction::Fatal { - attempt: 6, - stall_ms: 20_000, - }, - ); - } - - #[test] - fn video_stall_tracker_resets_after_recovery() { - let mut tracker = VideoStallTracker::default(); - - assert_eq!( - tracker.evaluate(2_500, 0), - VideoStallAction::RequestKeyframe { - attempt: 1, - stall_ms: 2_500, - }, - ); - assert_eq!( - tracker.evaluate(2_600, 2_600), - VideoStallAction::Recovered { stall_ms: 2_600 }, - ); - assert_eq!(tracker.evaluate(3_000, 2_600), VideoStallAction::None); - assert_eq!( - tracker.evaluate(5_100, 2_600), - VideoStallAction::RequestKeyframe { - attempt: 1, - stall_ms: 2_500, - }, - ); - } - - #[test] - fn resolve_queue_mode_prefers_adaptive_for_240_fps_and_vrr_for_cloud_gsync() { - let adaptive = resolve_queue_mode(&StreamSettings { - resolution: "2560x1440".to_owned(), - fps: 240, - max_bitrate_mbps: 75, - codec: VideoCodec::H265, - color_quality: crate::protocol::ColorQuality::TenBit420, - enable_cloud_gsync: false, - native_transition_diagnostics: None, - }); - assert_eq!(adaptive, NativeQueueMode::Adaptive); - - let vrr = resolve_queue_mode(&StreamSettings { - resolution: "2560x1440".to_owned(), - fps: 120, - max_bitrate_mbps: 75, - codec: VideoCodec::H265, - color_quality: crate::protocol::ColorQuality::TenBit420, - enable_cloud_gsync: true, - native_transition_diagnostics: None, - }); - assert_eq!(vrr, NativeQueueMode::Vrr); - } - - #[test] - fn reports_missing_sink_stats_as_unavailable() { - gst::init().expect("gstreamer init"); - let sink = gst::ElementFactory::make("fakesink") - .build() - .expect("fakesink"); - assert_eq!( - sink_stats_summary(&sink), - "sinkStats rendered=0 dropped=0 averageRate=0.0" - ); - } -} diff --git a/native/opennow-streamer/src/gstreamer_config.rs b/native/opennow-streamer/src/gstreamer_config.rs deleted file mode 100644 index 0b08f8284..000000000 --- a/native/opennow-streamer/src/gstreamer_config.rs +++ /dev/null @@ -1,175 +0,0 @@ -// Always compiled so present-policy unit tests run without the optional -// `gstreamer` feature; production callers live behind that feature. -#![allow(dead_code)] - -pub(crate) const EXTERNAL_RENDERER_ENV: &str = "OPENNOW_NATIVE_EXTERNAL_RENDERER"; -pub(crate) const NATIVE_VIDEO_API_ENV: &str = "OPENNOW_NATIVE_VIDEO_API"; -pub(crate) const NATIVE_VIDEO_BACKEND_ENV: &str = "OPENNOW_NATIVE_VIDEO_BACKEND"; -pub(crate) const NATIVE_ZERO_COPY_ENV: &str = "OPENNOW_NATIVE_ZERO_COPY"; -pub(crate) const NATIVE_PRESENT_MAX_FPS_ENV: &str = "OPENNOW_NATIVE_PRESENT_MAX_FPS"; -pub(crate) const NATIVE_D3D_FULLSCREEN_ENV: &str = "OPENNOW_NATIVE_D3D_FULLSCREEN"; -pub(crate) const PRESENT_LIMITER_AUTO_SENTINEL: u32 = u32::MAX; -pub(crate) const PRESENT_LIMITER_VRR_SENTINEL: u32 = u32::MAX - 1; -const VRR_REFRESH_HEADROOM_FPS: u32 = 3; - -pub(crate) fn use_external_renderer_window() -> bool { - std::env::var(EXTERNAL_RENDERER_ENV) - .map(|value| { - !matches!( - value.trim().to_ascii_lowercase().as_str(), - "0" | "false" | "no" | "off" - ) - }) - // Default to the internal child-surface renderer (single Electron window). - .unwrap_or(false) -} - -pub(crate) fn use_internal_renderer() -> bool { - !use_external_renderer_window() -} - -pub(crate) fn requested_video_backend() -> String { - std::env::var(NATIVE_VIDEO_BACKEND_ENV) - .or_else(|_| std::env::var(NATIVE_VIDEO_API_ENV)) - .unwrap_or_else(|_| "auto".to_owned()) - .to_ascii_lowercase() -} - -pub(crate) fn zero_copy_requested() -> bool { - matches!( - std::env::var(NATIVE_ZERO_COPY_ENV) - .unwrap_or_else(|_| "auto".to_owned()) - .to_ascii_lowercase() - .as_str(), - "1" | "true" | "yes" | "forced" - ) -} - -pub(crate) fn resolve_present_max_fps(cloud_gsync_enabled: bool) -> u32 { - if let Ok(value) = std::env::var(NATIVE_PRESENT_MAX_FPS_ENV) { - let value = value.trim().to_ascii_lowercase(); - if value == "0" || value == "off" || value == "false" || value == "unlimited" { - return 0; - } - if value == "auto" { - return PRESENT_LIMITER_AUTO_SENTINEL; - } - if let Ok(fps) = value.parse::() { - return fps; - } - } - if cloud_gsync_enabled { - PRESENT_LIMITER_VRR_SENTINEL - } else { - 0 - } -} - -pub(crate) fn automatic_present_max_fps(requested_fps: u32, display_hz: Option) -> u32 { - display_hz - .filter(|display_hz| *display_hz >= 30 && *display_hz < requested_fps) - .unwrap_or(0) -} - -pub(crate) fn vrr_present_max_fps(requested_fps: u32, display_hz: Option) -> u32 { - display_hz - .filter(|display_hz| *display_hz >= 30 && *display_hz <= requested_fps) - .map(|display_hz| display_hz.saturating_sub(VRR_REFRESH_HEADROOM_FPS)) - .unwrap_or(0) -} - -pub(crate) fn resolve_d3d_fullscreen_sink(cloud_gsync_enabled: bool) -> bool { - resolve_d3d_fullscreen_sink_for( - use_internal_renderer(), - cloud_gsync_enabled, - std::env::var(NATIVE_D3D_FULLSCREEN_ENV).ok(), - ) -} - -/// Pure policy for exclusive D3D fullscreen present. -/// -/// Internal (child HWND) always stays windowed — exclusive fullscreen fights -/// Electron parenting. External may enable it for Cloud G-Sync/VRR, or via -/// `OPENNOW_NATIVE_D3D_FULLSCREEN`. -pub(crate) fn resolve_d3d_fullscreen_sink_for( - internal_renderer: bool, - cloud_gsync_enabled: bool, - env_override: Option, -) -> bool { - if internal_renderer { - return false; - } - - if let Some(value) = env_override { - let value = value.trim().to_ascii_lowercase(); - if matches!(value.as_str(), "1" | "on" | "true" | "yes") { - return true; - } - if matches!(value.as_str(), "0" | "off" | "false" | "no") { - return false; - } - } - - cloud_gsync_enabled -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn automatic_present_limiter_uses_display_refresh_below_requested_fps() { - assert_eq!(automatic_present_max_fps(240, Some(165)), 165); - assert_eq!(automatic_present_max_fps(240, Some(240)), 0); - assert_eq!(automatic_present_max_fps(240, Some(1)), 0); - assert_eq!(automatic_present_max_fps(240, None), 0); - } - - #[test] - fn default_present_policy_is_uncapped_without_vrr() { - assert_eq!(resolve_present_max_fps(false), 0); - assert_eq!( - resolve_present_max_fps(true), - PRESENT_LIMITER_VRR_SENTINEL - ); - } - - #[test] - fn vrr_present_limiter_stays_below_refresh_ceiling() { - assert_eq!(vrr_present_max_fps(240, Some(165)), 162); - assert_eq!(vrr_present_max_fps(165, Some(165)), 162); - assert_eq!(vrr_present_max_fps(120, Some(165)), 0); - assert_eq!(vrr_present_max_fps(240, None), 0); - } - - #[test] - fn internal_renderer_never_enables_exclusive_d3d_fullscreen() { - assert!(!resolve_d3d_fullscreen_sink_for(true, true, None)); - assert!(!resolve_d3d_fullscreen_sink_for( - true, - true, - Some("1".to_owned()) - )); - assert!(!resolve_d3d_fullscreen_sink_for( - true, - false, - Some("on".to_owned()) - )); - } - - #[test] - fn external_renderer_follows_cloud_gsync_and_env_for_d3d_fullscreen() { - assert!(resolve_d3d_fullscreen_sink_for(false, true, None)); - assert!(!resolve_d3d_fullscreen_sink_for(false, false, None)); - assert!(resolve_d3d_fullscreen_sink_for( - false, - false, - Some("1".to_owned()) - )); - assert!(!resolve_d3d_fullscreen_sink_for( - false, - true, - Some("0".to_owned()) - )); - } -} diff --git a/native/opennow-streamer/src/gstreamer_input.rs b/native/opennow-streamer/src/gstreamer_input.rs deleted file mode 100644 index eaa129a98..000000000 --- a/native/opennow-streamer/src/gstreamer_input.rs +++ /dev/null @@ -1,1279 +0,0 @@ -use crate::gstreamer_backend::send_log; -#[cfg(target_os = "windows")] -use crate::gstreamer_platform::win32_renderer_window; -use crate::input::InputEncoder; -#[cfg(target_os = "windows")] -use crate::input::{ - finalize_reliable_single_input_packets, layout_mapped_keyboard_keycode, - layout_mapped_keyboard_scancode, restamp_protocol_v3_outer_timestamp, GamepadInput, - KeyboardPayload, MouseButtonPayload, MouseMovePayload, MouseWheelPayload, - GAMEPAD_MAX_CONTROLLERS, PARTIALLY_RELIABLE_GAMEPAD_MASK_ALL, -}; -use crate::protocol::Event; -#[cfg(target_os = "windows")] -use crate::protocol::NativeStreamerShortcutAction; -use gst::glib; -use gst::prelude::*; -use gstreamer as gst; -use gstreamer_webrtc as gst_webrtc; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::mpsc::Sender; -#[cfg(target_os = "windows")] -use std::sync::mpsc::{self, RecvTimeoutError, TryRecvError}; -#[cfg(target_os = "windows")] -use std::sync::OnceLock; -use std::sync::{Arc, Mutex}; -use std::thread::{self, JoinHandle}; -use std::time::Duration; -#[cfg(target_os = "windows")] -use std::time::Instant; - -const RELIABLE_INPUT_CHANNEL_LABEL: &str = "input_channel_v1"; -const PARTIALLY_RELIABLE_INPUT_CHANNEL_LABEL: &str = "input_channel_partially_reliable"; -const DEFAULT_PARTIAL_RELIABLE_THRESHOLD_MS: u32 = 300; -const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(2); -const HEARTBEAT_STOP_POLL_INTERVAL: Duration = Duration::from_millis(50); -#[cfg(target_os = "windows")] -const NATIVE_INPUT_BRIDGE_POLL_INTERVAL: Duration = Duration::from_millis(1); -#[cfg(target_os = "windows")] -const NATIVE_INPUT_DRAIN_MAX_EVENTS: usize = 512; -#[cfg(target_os = "windows")] -const NATIVE_GAMEPAD_POLL_INTERVAL: Duration = Duration::from_millis(4); -#[cfg(target_os = "windows")] -const NATIVE_GAMEPAD_KEEPALIVE_INTERVAL: Duration = Duration::from_millis(100); - -#[cfg(target_os = "windows")] -static NATIVE_INPUT_STARTED_AT: OnceLock = OnceLock::new(); - -#[derive(Clone)] -pub(crate) struct GstreamerInputState { - encoder: Arc>, - pub(crate) ready: Arc, - pub(crate) paused: Arc, - heartbeat_stop: Arc, - heartbeat_thread: Arc>>>, -} - -impl std::fmt::Debug for GstreamerInputState { - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter - .debug_struct("GstreamerInputState") - .field("ready", &self.ready.load(Ordering::SeqCst)) - .field("paused", &self.paused.load(Ordering::SeqCst)) - .finish_non_exhaustive() - } -} - -impl Default for GstreamerInputState { - fn default() -> Self { - Self { - encoder: Arc::new(Mutex::new(InputEncoder::default())), - ready: Arc::new(AtomicBool::new(false)), - paused: Arc::new(AtomicBool::new(false)), - heartbeat_stop: Arc::new(AtomicBool::new(false)), - heartbeat_thread: Arc::new(Mutex::new(None)), - } - } -} - -impl GstreamerInputState { - pub(crate) fn reset(&self) { - self.ready.store(false, Ordering::SeqCst); - self.paused.store(false, Ordering::SeqCst); - if let Ok(mut encoder) = self.encoder.lock() { - encoder.set_protocol_version(2); - encoder.reset_gamepad_sequences(); - } - } - - pub(crate) fn stop_heartbeat(&self) { - self.heartbeat_stop.store(true, Ordering::SeqCst); - let Some(handle) = self - .heartbeat_thread - .lock() - .ok() - .and_then(|mut thread| thread.take()) - else { - return; - }; - - if let Err(error) = handle.join() { - eprintln!("[NativeStreamer] Input heartbeat thread panicked: {error:?}"); - } - } -} - -#[cfg(target_os = "windows")] -#[derive(Debug, Clone, Copy)] -pub(crate) enum NativeWindowInputEvent { - Shortcut { - action: NativeStreamerShortcutAction, - }, - ClipboardPaste, - InputCaptureChanged { - captured: bool, - }, - Key { - pressed: bool, - keycode: u16, - scancode: u16, - modifiers: u16, - timestamp_us: u64, - }, - MouseMove { - dx: i16, - dy: i16, - timestamp_us: u64, - }, - MouseButton { - pressed: bool, - button: u8, - timestamp_us: u64, - }, - MouseWheel { - delta: i16, - timestamp_us: u64, - }, - LockKeysSync { - state: u8, - }, -} - -#[cfg(target_os = "windows")] -enum EncodedNativeInputBatch { - ReliableSingles(Vec>), - MousePacket(Vec), -} - -#[cfg(target_os = "windows")] -mod win32_xinput { - use std::ffi::{c_char, c_void}; - - type Dword = u32; - type Hmodule = *mut c_void; - type XInputGetStateFn = unsafe extern "system" fn(Dword, *mut XInputStateRaw) -> Dword; - - const ERROR_SUCCESS: Dword = 0; - const XINPUT_DLLS: [&str; 3] = ["xinput1_4.dll", "xinput9_1_0.dll", "xinput1_3.dll"]; - - #[repr(C)] - #[derive(Clone, Copy, Default)] - struct XInputGamepadRaw { - buttons: u16, - left_trigger: u8, - right_trigger: u8, - thumb_lx: i16, - thumb_ly: i16, - thumb_rx: i16, - thumb_ry: i16, - } - - #[repr(C)] - #[derive(Clone, Copy, Default)] - struct XInputStateRaw { - packet_number: Dword, - gamepad: XInputGamepadRaw, - } - - #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] - pub struct XInputGamepadSnapshot { - pub buttons: u16, - pub left_trigger: u8, - pub right_trigger: u8, - pub left_stick_x: i16, - pub left_stick_y: i16, - pub right_stick_x: i16, - pub right_stick_y: i16, - } - - #[derive(Clone, Copy)] - pub struct XInput { - get_state: XInputGetStateFn, - } - - #[link(name = "kernel32")] - unsafe extern "system" { - fn GetProcAddress(module: Hmodule, proc_name: *const c_char) -> *mut c_void; - fn LoadLibraryW(filename: *const u16) -> Hmodule; - } - - impl XInput { - pub unsafe fn load() -> Option { - for dll in XINPUT_DLLS { - let wide = wide_null(dll); - let module = LoadLibraryW(wide.as_ptr()); - if module.is_null() { - continue; - } - - let address = GetProcAddress(module, b"XInputGetState\0".as_ptr() as *const c_char); - if !address.is_null() { - return Some(Self { - get_state: std::mem::transmute::<*mut c_void, XInputGetStateFn>(address), - }); - } - } - - None - } - - pub unsafe fn get_state(self, controller_id: u32) -> Option { - let mut state = XInputStateRaw::default(); - if (self.get_state)(controller_id, &mut state) != ERROR_SUCCESS { - return None; - } - - Some(XInputGamepadSnapshot { - buttons: state.gamepad.buttons, - left_trigger: apply_trigger_deadzone(state.gamepad.left_trigger), - right_trigger: apply_trigger_deadzone(state.gamepad.right_trigger), - left_stick_x: apply_stick_deadzone(state.gamepad.thumb_lx, 7849), - left_stick_y: apply_stick_deadzone(state.gamepad.thumb_ly, 7849), - right_stick_x: apply_stick_deadzone(state.gamepad.thumb_rx, 8689), - right_stick_y: apply_stick_deadzone(state.gamepad.thumb_ry, 8689), - }) - } - } - - fn wide_null(value: &str) -> Vec { - value.encode_utf16().chain(std::iter::once(0)).collect() - } - - fn apply_trigger_deadzone(value: u8) -> u8 { - if value <= 30 { - 0 - } else { - value - } - } - - fn apply_stick_deadzone(value: i16, deadzone: i16) -> i16 { - if (value as i32).abs() <= deadzone as i32 { - 0 - } else { - value - } - } -} - -#[derive(Clone, Debug)] -pub(crate) struct GstreamerInputChannels { - reliable: gst_webrtc::WebRTCDataChannel, - partially_reliable: gst_webrtc::WebRTCDataChannel, -} - -impl GstreamerInputChannels { - pub(crate) fn labels(&self) -> (String, String) { - ( - channel_label(&self.reliable), - channel_label(&self.partially_reliable), - ) - } - - pub(crate) fn send_packet(&self, payload: &[u8], partially_reliable: bool) -> bool { - if payload.is_empty() { - return false; - } - - let channel = if partially_reliable { - if self.partially_reliable.ready_state() != gst_webrtc::WebRTCDataChannelState::Open { - return false; - } - &self.partially_reliable - } else { - &self.reliable - }; - - if channel.ready_state() != gst_webrtc::WebRTCDataChannelState::Open { - return false; - } - - let bytes = glib::Bytes::from_owned(payload.to_vec()); - channel.send_data_full(Some(&bytes)).is_ok() - } -} - -#[cfg(target_os = "windows")] -#[derive(Debug)] -pub(crate) struct NativeWindowInputBridge { - stop: Arc, - input_thread: Option>, - gamepad_thread: Option>, -} - -#[cfg(target_os = "windows")] -impl NativeWindowInputBridge { - pub(crate) fn start( - input_state: GstreamerInputState, - input_channels: GstreamerInputChannels, - event_sender: Option>, - ) -> Self { - let (sender, receiver) = mpsc::channel::(); - unsafe { - win32_renderer_window::set_input_event_sender(Some(sender)); - } - - let stop = Arc::new(AtomicBool::new(false)); - let thread_stop = stop.clone(); - let thread_sender = event_sender.clone(); - let input_thread_state = input_state.clone(); - let input_thread_channels = input_channels.clone(); - let input_thread = thread::spawn(move || { - let mut pending_events = Vec::with_capacity(NATIVE_INPUT_DRAIN_MAX_EVENTS); - send_log( - &thread_sender, - "info", - "Native DX11 window input capture bridge armed.".to_owned(), - ); - - while !thread_stop.load(Ordering::SeqCst) { - pending_events.clear(); - loop { - match receiver.try_recv() { - Ok(event) => pending_events.push(event), - Err(TryRecvError::Empty) => break, - Err(TryRecvError::Disconnected) => return, - } - if pending_events.len() >= NATIVE_INPUT_DRAIN_MAX_EVENTS { - break; - } - } - - if pending_events.is_empty() { - match receiver.recv_timeout(NATIVE_INPUT_BRIDGE_POLL_INTERVAL) { - Ok(event) => pending_events.push(event), - Err(RecvTimeoutError::Timeout) => continue, - Err(RecvTimeoutError::Disconnected) => break, - } - - while pending_events.len() < NATIVE_INPUT_DRAIN_MAX_EVENTS { - match receiver.try_recv() { - Ok(event) => pending_events.push(event), - Err(TryRecvError::Empty) => break, - Err(TryRecvError::Disconnected) => break, - } - } - } - - send_native_window_input_events( - &input_thread_state, - &input_thread_channels, - &thread_sender, - &pending_events, - ); - } - }); - let gamepad_thread = Some(spawn_native_gamepad_thread( - input_state, - input_channels, - event_sender, - stop.clone(), - )); - - Self { - stop, - input_thread: Some(input_thread), - gamepad_thread, - } - } - - pub(crate) fn stop(&mut self) { - self.stop.store(true, Ordering::SeqCst); - unsafe { - win32_renderer_window::release_current_input_capture(); - win32_renderer_window::set_input_event_sender(None); - } - - if let Some(thread) = self.input_thread.take() { - if let Err(error) = thread.join() { - eprintln!("[NativeStreamer] Native window input bridge thread panicked: {error:?}"); - } - } - if let Some(thread) = self.gamepad_thread.take() { - if let Err(error) = thread.join() { - eprintln!("[NativeStreamer] Native XInput gamepad thread panicked: {error:?}"); - } - } - } -} - -#[cfg(target_os = "windows")] -impl Drop for NativeWindowInputBridge { - fn drop(&mut self) { - self.stop(); - } -} - -#[cfg(target_os = "windows")] -fn send_native_window_input_events( - input_state: &GstreamerInputState, - input_channels: &GstreamerInputChannels, - event_sender: &Option>, - events: &[NativeWindowInputEvent], -) { - if events.is_empty() { - return; - } - - // Forward shortcuts and host bridge events immediately (before input readiness check) - // These are local control events and don't need the stream channel - let mut other_events = Vec::new(); - for event in events.iter().copied() { - match event { - NativeWindowInputEvent::Shortcut { action } => { - if let Some(sender) = event_sender.as_ref() { - let _ = sender.send(Event::Shortcut { action }); - } - } - NativeWindowInputEvent::ClipboardPaste => { - if let Some(sender) = event_sender.as_ref() { - let _ = sender.send(Event::ClipboardPaste); - } - } - NativeWindowInputEvent::InputCaptureChanged { captured } => { - if let Some(sender) = event_sender.as_ref() { - let _ = sender.send(Event::InputCaptureChanged { captured }); - } - } - _ => { - other_events.push(event); - } - } - } - - // Only process non-shortcut events if input is ready. - if other_events.is_empty() || !input_state.ready.load(Ordering::SeqCst) { - return; - } - if input_state.paused.load(Ordering::SeqCst) { - other_events.retain(is_native_input_release_event); - if other_events.is_empty() { - return; - } - } - - let mut pending_mouse_move: Option<(i32, i32, u64)> = None; - let mut current_reliable_singles: Vec> = Vec::new(); - let mut input_batches: Vec = Vec::new(); - - { - let Ok(encoder) = input_state.encoder.lock() else { - return; - }; - - let mut flush_current_reliable_singles = |singles: &mut Vec>, - batches: &mut Vec| { - if singles.is_empty() { - return; - } - batches.push(EncodedNativeInputBatch::ReliableSingles(std::mem::take( - singles, - ))); - }; - - for event in other_events.iter().copied() { - if let NativeWindowInputEvent::MouseMove { - dx, - dy, - timestamp_us, - } = event - { - let (pending_dx, pending_dy, pending_timestamp_us) = - pending_mouse_move.get_or_insert((0, 0, timestamp_us)); - *pending_dx = pending_dx.saturating_add(i32::from(dx)); - *pending_dy = pending_dy.saturating_add(i32::from(dy)); - *pending_timestamp_us = timestamp_us; - continue; - } - - if pending_mouse_move.is_some() { - flush_current_reliable_singles( - &mut current_reliable_singles, - &mut input_batches, - ); - collect_pending_mouse_move_packets( - &encoder, - &mut pending_mouse_move, - &mut input_batches, - ); - } - if let Some(payload) = - encode_native_window_input_payload(&encoder, event_sender, event) - { - current_reliable_singles.push(payload); - } - } - - flush_current_reliable_singles( - &mut current_reliable_singles, - &mut input_batches, - ); - collect_pending_mouse_move_packets( - &encoder, - &mut pending_mouse_move, - &mut input_batches, - ); - } - - let send_timestamp_us = native_input_timestamp_us(); - for batch in input_batches { - match batch { - EncodedNativeInputBatch::ReliableSingles(reliable_singles) => { - for payload in finalize_reliable_single_input_packets(&reliable_singles, send_timestamp_us) { - let _ = input_channels.send_packet(&payload, false); - } - } - EncodedNativeInputBatch::MousePacket(mut payload) => { - restamp_protocol_v3_outer_timestamp(&mut payload, send_timestamp_us); - let _ = input_channels.send_packet(&payload, true); - } - } - } -} - -#[cfg(target_os = "windows")] -fn is_native_input_release_event(event: &NativeWindowInputEvent) -> bool { - matches!( - event, - NativeWindowInputEvent::Key { pressed: false, .. } - | NativeWindowInputEvent::MouseButton { pressed: false, .. } - ) -} - -#[cfg(target_os = "windows")] -fn collect_pending_mouse_move_packets( - encoder: &InputEncoder, - pending_mouse_move: &mut Option<(i32, i32, u64)>, - input_batches: &mut Vec, -) { - let Some((mut dx, mut dy, timestamp_us)) = pending_mouse_move.take() else { - return; - }; - - while dx != 0 || dy != 0 { - let chunk_dx = dx.clamp(i32::from(i16::MIN), i32::from(i16::MAX)) as i16; - let chunk_dy = dy.clamp(i32::from(i16::MIN), i32::from(i16::MAX)) as i16; - input_batches.push(EncodedNativeInputBatch::MousePacket(encoder.encode_mouse_move( - MouseMovePayload { - dx: chunk_dx, - dy: chunk_dy, - timestamp_us, - }, - ))); - dx = dx.saturating_sub(i32::from(chunk_dx)); - dy = dy.saturating_sub(i32::from(chunk_dy)); - } -} - -#[cfg(target_os = "windows")] -fn encode_native_window_input_payload( - encoder: &InputEncoder, - event_sender: &Option>, - event: NativeWindowInputEvent, -) -> Option> { - match event { - NativeWindowInputEvent::Shortcut { action } => { - if let Some(sender) = event_sender.as_ref() { - let _ = sender.send(Event::Shortcut { action }); - } - None - } - NativeWindowInputEvent::ClipboardPaste => { - if let Some(sender) = event_sender.as_ref() { - let _ = sender.send(Event::ClipboardPaste); - } - None - } - NativeWindowInputEvent::InputCaptureChanged { captured } => { - if let Some(sender) = event_sender.as_ref() { - let _ = sender.send(Event::InputCaptureChanged { captured }); - } - None - } - NativeWindowInputEvent::Key { - pressed, - keycode, - scancode, - modifiers, - timestamp_us, - } => { - let payload = KeyboardPayload { - keycode: layout_mapped_keyboard_keycode(keycode, scancode), - scancode: layout_mapped_keyboard_scancode(scancode), - modifiers, - timestamp_us, - }; - Some(if pressed { - encoder.encode_key_down(payload) - } else { - encoder.encode_key_up(payload) - }) - } - NativeWindowInputEvent::MouseMove { - dx, - dy, - timestamp_us, - } => Some(encoder.encode_mouse_move(MouseMovePayload { - dx, - dy, - timestamp_us, - })), - NativeWindowInputEvent::MouseButton { - pressed, - button, - timestamp_us, - } => { - let payload = MouseButtonPayload { - button, - timestamp_us, - }; - Some(if pressed { - encoder.encode_mouse_button_down(payload) - } else { - encoder.encode_mouse_button_up(payload) - }) - } - NativeWindowInputEvent::MouseWheel { - delta, - timestamp_us, - } => Some(encoder.encode_mouse_wheel(MouseWheelPayload { - delta, - timestamp_us, - })), - NativeWindowInputEvent::LockKeysSync { state } => { - Some(encoder.encode_lock_keys_sync(state)) - } - } -} - -#[cfg(target_os = "windows")] -#[allow(dead_code)] -fn send_encoded_native_window_input_event( - encoder: &InputEncoder, - input_channels: &GstreamerInputChannels, - event_sender: &Option>, - event: NativeWindowInputEvent, -) { - let Some(payload) = encode_native_window_input_payload(encoder, event_sender, event) else { - return; - }; - - let partially_reliable = matches!( - event, - NativeWindowInputEvent::MouseMove { .. } - ); - let _ = input_channels.send_packet(&payload, partially_reliable); -} - -#[cfg(target_os = "windows")] -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] -struct NativeGamepadSnapshot { - connected: bool, - buttons: u16, - left_trigger: u8, - right_trigger: u8, - left_stick_x: i16, - left_stick_y: i16, - right_stick_x: i16, - right_stick_y: i16, -} - -#[cfg(target_os = "windows")] -impl NativeGamepadSnapshot { - fn from_xinput(snapshot: win32_xinput::XInputGamepadSnapshot) -> Self { - Self { - connected: true, - buttons: snapshot.buttons, - left_trigger: snapshot.left_trigger, - right_trigger: snapshot.right_trigger, - left_stick_x: snapshot.left_stick_x, - left_stick_y: snapshot.left_stick_y, - right_stick_x: snapshot.right_stick_x, - right_stick_y: snapshot.right_stick_y, - } - } - - fn is_neutral(self) -> bool { - self.buttons == 0 - && self.left_trigger == 0 - && self.right_trigger == 0 - && self.left_stick_x == 0 - && self.left_stick_y == 0 - && self.right_stick_x == 0 - && self.right_stick_y == 0 - } -} - -#[cfg(target_os = "windows")] -fn spawn_native_gamepad_thread( - input_state: GstreamerInputState, - input_channels: GstreamerInputChannels, - event_sender: Option>, - stop: Arc, -) -> JoinHandle<()> { - thread::spawn(move || { - let Some(xinput) = (unsafe { win32_xinput::XInput::load() }) else { - send_log( - &event_sender, - "warn", - "Native XInput gamepad bridge unavailable; controller input will require the web renderer fallback.".to_owned(), - ); - return; - }; - - send_log( - &event_sender, - "info", - "Native XInput gamepad bridge armed.".to_owned(), - ); - - let mut previous = [NativeGamepadSnapshot::default(); GAMEPAD_MAX_CONTROLLERS as usize]; - let mut last_sent = [Instant::now(); GAMEPAD_MAX_CONTROLLERS as usize]; - let mut suppress_until_neutral = [false; GAMEPAD_MAX_CONTROLLERS as usize]; - let mut was_paused = false; - - while !stop.load(Ordering::SeqCst) { - if input_state.ready.load(Ordering::SeqCst) { - let (snapshots, bitmap) = poll_xinput_gamepads(xinput); - - if input_state.paused.load(Ordering::SeqCst) { - if !was_paused { - send_neutral_gamepad_snapshots_for_pause( - &input_state, - &input_channels, - &previous, - &snapshots, - ); - } - previous = snapshots; - for controller_id in 0..GAMEPAD_MAX_CONTROLLERS as usize { - last_sent[controller_id] = Instant::now(); - } - was_paused = true; - thread::sleep(NATIVE_GAMEPAD_POLL_INTERVAL); - continue; - } - - if was_paused { - for controller_id in 0..GAMEPAD_MAX_CONTROLLERS as usize { - let snapshot = snapshots[controller_id]; - suppress_until_neutral[controller_id] = - snapshot.connected && !snapshot.is_neutral(); - previous[controller_id] = snapshot; - last_sent[controller_id] = Instant::now(); - } - } - was_paused = false; - - for controller_id in 0..GAMEPAD_MAX_CONTROLLERS as usize { - let snapshot = snapshots[controller_id]; - if suppress_until_neutral[controller_id] { - previous[controller_id] = snapshot; - last_sent[controller_id] = Instant::now(); - if !snapshot.connected || snapshot.is_neutral() { - suppress_until_neutral[controller_id] = false; - } - continue; - } - let state_changed = snapshot != previous[controller_id]; - let keepalive_due = snapshot.connected - && last_sent[controller_id].elapsed() >= NATIVE_GAMEPAD_KEEPALIVE_INTERVAL; - - if state_changed || keepalive_due { - send_native_gamepad_snapshot( - &input_state, - &input_channels, - controller_id as u8, - bitmap, - snapshot, - ); - last_sent[controller_id] = Instant::now(); - - if snapshot.connected != previous[controller_id].connected { - send_log( - &event_sender, - "info", - format!( - "Native XInput controller {controller_id} {}.", - if snapshot.connected { - "connected" - } else { - "disconnected" - } - ), - ); - } - } - - previous[controller_id] = snapshot; - } - } else { - was_paused = false; - } - - thread::sleep(NATIVE_GAMEPAD_POLL_INTERVAL); - } - }) -} - -#[cfg(target_os = "windows")] -fn poll_xinput_gamepads( - xinput: win32_xinput::XInput, -) -> ([NativeGamepadSnapshot; GAMEPAD_MAX_CONTROLLERS as usize], u16) { - let mut snapshots = [NativeGamepadSnapshot::default(); GAMEPAD_MAX_CONTROLLERS as usize]; - let mut bitmap = 0u16; - - for controller_id in 0..GAMEPAD_MAX_CONTROLLERS as usize { - if let Some(snapshot) = unsafe { xinput.get_state(controller_id as u32) } { - snapshots[controller_id] = NativeGamepadSnapshot::from_xinput(snapshot); - bitmap |= 1 << controller_id; - } - } - - (snapshots, bitmap) -} - -#[cfg(target_os = "windows")] -fn send_neutral_gamepad_snapshots_for_pause( - input_state: &GstreamerInputState, - input_channels: &GstreamerInputChannels, - previous: &[NativeGamepadSnapshot; GAMEPAD_MAX_CONTROLLERS as usize], - current: &[NativeGamepadSnapshot; GAMEPAD_MAX_CONTROLLERS as usize], -) { - let bitmap = previous - .iter() - .zip(current.iter()) - .enumerate() - .fold(0u16, |bitmap, (controller_id, (previous, current))| { - if previous.connected || current.connected { - bitmap | (1 << controller_id) - } else { - bitmap - } - }); - - if bitmap == 0 { - return; - } - - for controller_id in 0..GAMEPAD_MAX_CONTROLLERS as usize { - if (bitmap & (1 << controller_id)) == 0 { - continue; - } - - send_native_gamepad_snapshot( - input_state, - input_channels, - controller_id as u8, - bitmap, - NativeGamepadSnapshot { - connected: true, - ..NativeGamepadSnapshot::default() - }, - ); - } -} - -#[cfg(target_os = "windows")] -fn send_native_gamepad_snapshot( - input_state: &GstreamerInputState, - input_channels: &GstreamerInputChannels, - controller_id: u8, - bitmap: u16, - snapshot: NativeGamepadSnapshot, -) { - if !input_state.ready.load(Ordering::SeqCst) { - return; - } - - let use_partially_reliable = - (PARTIALLY_RELIABLE_GAMEPAD_MASK_ALL & (1_u32 << u32::from(controller_id))) != 0; - let input = GamepadInput { - controller_id, - buttons: snapshot.buttons, - left_trigger: snapshot.left_trigger, - right_trigger: snapshot.right_trigger, - left_stick_x: snapshot.left_stick_x, - left_stick_y: snapshot.left_stick_y, - right_stick_x: snapshot.right_stick_x, - right_stick_y: snapshot.right_stick_y, - connected: snapshot.connected, - timestamp_us: native_input_timestamp_us(), - }; - - let Ok(mut encoder) = input_state.encoder.lock() else { - return; - }; - let mut payload = encoder.encode_gamepad_state(bitmap, input, use_partially_reliable); - drop(encoder); - - restamp_protocol_v3_outer_timestamp(&mut payload, native_input_timestamp_us()); - let _ = input_channels.send_packet(&payload, use_partially_reliable); -} - -#[cfg(target_os = "windows")] -fn native_input_timestamp_us() -> u64 { - NATIVE_INPUT_STARTED_AT - .get_or_init(Instant::now) - .elapsed() - .as_micros() - .min(u128::from(u64::MAX)) as u64 -} - -pub(crate) fn wire_remote_data_channels( - webrtc: &gst::Element, - event_sender: Option>, -) { - webrtc.connect("on-data-channel", false, move |values| { - let Some(channel) = values - .get(1) - .and_then(|value| value.get::().ok()) - else { - send_log( - &event_sender, - "warn", - "GStreamer emitted on-data-channel without a channel.".to_owned(), - ); - return None; - }; - - let label = channel_label(&channel); - send_log( - &event_sender, - "info", - format!( - "Remote WebRTC data channel received: label={}, ordered={}.", - label, - channel.is_ordered() - ), - ); - connect_remote_data_channel_callbacks(&label, &channel, event_sender.clone()); - None - }); -} - -pub(crate) fn create_input_data_channels( - webrtc: &gst::Element, - input_state: GstreamerInputState, - event_sender: Option>, - partial_reliable_threshold_ms: u32, -) -> Result { - let reliable = create_data_channel(webrtc, RELIABLE_INPUT_CHANNEL_LABEL, None)?; - connect_input_channel_callbacks( - RELIABLE_INPUT_CHANNEL_LABEL, - &reliable, - input_state.clone(), - event_sender.clone(), - ); - - let clamped_threshold_ms = if partial_reliable_threshold_ms == 0 { - DEFAULT_PARTIAL_RELIABLE_THRESHOLD_MS - } else { - partial_reliable_threshold_ms.clamp(1, 5000) - }; - let options = gst::Structure::builder("data-channel-options") - .field("ordered", false) - .field("max-packet-lifetime", clamped_threshold_ms as i32) - .build(); - let partially_reliable = create_data_channel( - webrtc, - PARTIALLY_RELIABLE_INPUT_CHANNEL_LABEL, - Some(options), - )?; - connect_input_channel_callbacks( - PARTIALLY_RELIABLE_INPUT_CHANNEL_LABEL, - &partially_reliable, - input_state, - event_sender.clone(), - ); - - send_log( - &event_sender, - "info", - format!( - "Created WebRTC input data channels ({}, {} maxPacketLifeTime={}ms).", - RELIABLE_INPUT_CHANNEL_LABEL, - PARTIALLY_RELIABLE_INPUT_CHANNEL_LABEL, - clamped_threshold_ms - ), - ); - - Ok(GstreamerInputChannels { - reliable, - partially_reliable, - }) -} - -fn create_data_channel( - webrtc: &gst::Element, - label: &'static str, - options: Option, -) -> Result { - let channel = match options { - Some(options) => { - let options = Some(options); - webrtc.emit_by_name::( - "create-data-channel", - &[&label, &options], - ) - } - None => webrtc.emit_by_name::( - "create-data-channel", - &[&label, &None::], - ), - }; - - let actual_label = channel_label(&channel); - if actual_label != label { - return Err(format!( - "GStreamer created data channel with unexpected label: expected {label}, got {actual_label}." - )); - } - - Ok(channel) -} - -fn connect_input_channel_callbacks( - label: &'static str, - channel: &gst_webrtc::WebRTCDataChannel, - input_state: GstreamerInputState, - event_sender: Option>, -) { - let open_sender = event_sender.clone(); - channel.connect_on_open(move |channel| { - send_log( - &open_sender, - "info", - format!( - "Input data channel open: label={}, id={}, ordered={}, maxPacketLifeTime={}.", - label, - channel.id(), - channel.is_ordered(), - channel.max_packet_lifetime() - ), - ); - }); - - let close_sender = event_sender.clone(); - let close_state = input_state.clone(); - channel.connect_on_close(move |_| { - if label == RELIABLE_INPUT_CHANNEL_LABEL { - close_state.ready.store(false, Ordering::SeqCst); - close_state.heartbeat_stop.store(true, Ordering::SeqCst); - } - send_log( - &close_sender, - "info", - format!("Input data channel closed: label={label}."), - ); - }); - - let error_sender = event_sender.clone(); - channel.connect_on_error(move |_, error| { - send_log( - &error_sender, - "warn", - format!("Input data channel error on {label}: {error}."), - ); - }); - - if label == RELIABLE_INPUT_CHANNEL_LABEL { - let data_sender = event_sender.clone(); - let data_state = input_state.clone(); - channel.connect_on_message_data(move |channel, data| { - let Some(bytes) = data else { - return; - }; - handle_input_handshake_message( - channel, - bytes.as_ref(), - data_state.clone(), - data_sender.clone(), - ); - }); - - let string_sender = event_sender.clone(); - let string_state = input_state; - channel.connect_on_message_string(move |channel, message| { - let Some(message) = message else { - return; - }; - handle_input_handshake_message( - channel, - message.as_bytes(), - string_state.clone(), - string_sender.clone(), - ); - }); - } -} - -fn connect_remote_data_channel_callbacks( - label: &str, - channel: &gst_webrtc::WebRTCDataChannel, - event_sender: Option>, -) { - let label = label.to_owned(); - let open_sender = event_sender.clone(); - let open_label = label.clone(); - channel.connect_on_open(move |_| { - send_log( - &open_sender, - "info", - format!("Remote data channel open: label={open_label}."), - ); - }); - - let close_sender = event_sender.clone(); - let close_label = label.clone(); - channel.connect_on_close(move |_| { - send_log( - &close_sender, - "info", - format!("Remote data channel closed: label={close_label}."), - ); - }); - - let error_sender = event_sender; - channel.connect_on_error(move |_, error| { - send_log( - &error_sender, - "warn", - format!("Remote data channel error on {label}: {error}."), - ); - }); -} - -fn handle_input_handshake_message( - channel: &gst_webrtc::WebRTCDataChannel, - bytes: &[u8], - input_state: GstreamerInputState, - event_sender: Option>, -) { - let Some(protocol_version) = parse_input_handshake_version(bytes) else { - return; - }; - - let encoder_version = protocol_version.min(u8::MAX as u16) as u8; - if let Ok(mut encoder) = input_state.encoder.lock() { - encoder.set_protocol_version(encoder_version); - } - let was_ready = input_state.ready.swap(true, Ordering::SeqCst); - if was_ready { - return; - } - - send_log( - &event_sender, - "info", - format!( - "Input handshake complete on {} (protocol v{}).", - channel_label(channel), - protocol_version - ), - ); - if let Some(sender) = event_sender.as_ref() { - let _ = sender.send(Event::InputReady { protocol_version }); - } - start_input_heartbeat(input_state, channel.clone(), event_sender); -} - -pub(crate) fn parse_input_handshake_version(bytes: &[u8]) -> Option { - if bytes.len() < 2 { - return None; - } - - let first_word = u16::from_le_bytes([bytes[0], bytes[1]]); - if first_word == 526 { - return Some(if bytes.len() >= 4 { - u16::from_le_bytes([bytes[2], bytes[3]]) - } else { - 2 - }); - } - - if bytes[0] == 0x0e { - return Some(first_word); - } - - None -} - -fn start_input_heartbeat( - input_state: GstreamerInputState, - channel: gst_webrtc::WebRTCDataChannel, - event_sender: Option>, -) { - let Ok(mut heartbeat_thread) = input_state.heartbeat_thread.lock() else { - send_log( - &event_sender, - "warn", - "Failed to acquire input heartbeat thread lock.".to_owned(), - ); - return; - }; - if heartbeat_thread - .as_ref() - .is_some_and(|thread| !thread.is_finished()) - { - return; - } - if let Some(thread) = heartbeat_thread.take() { - let _ = thread.join(); - } - - input_state.heartbeat_stop.store(false, Ordering::SeqCst); - let encoder = input_state.encoder.clone(); - let stop = input_state.heartbeat_stop.clone(); - let thread_sender = event_sender.clone(); - *heartbeat_thread = Some(thread::spawn(move || { - while !stop.load(Ordering::SeqCst) { - send_input_heartbeat(&channel, &encoder, &thread_sender); - - let mut slept = Duration::ZERO; - while slept < HEARTBEAT_INTERVAL { - if stop.load(Ordering::SeqCst) { - break; - } - let remaining = HEARTBEAT_INTERVAL.saturating_sub(slept); - let interval = remaining.min(HEARTBEAT_STOP_POLL_INTERVAL); - thread::sleep(interval); - slept += interval; - } - } - })); -} - -fn send_input_heartbeat( - channel: &gst_webrtc::WebRTCDataChannel, - encoder: &Arc>, - event_sender: &Option>, -) { - if channel.ready_state() != gst_webrtc::WebRTCDataChannelState::Open { - return; - } - - let Ok(encoder) = encoder.lock() else { - send_log( - event_sender, - "warn", - "Failed to acquire input encoder for heartbeat.".to_owned(), - ); - return; - }; - let bytes = glib::Bytes::from_owned(encoder.encode_heartbeat()); - if let Err(error) = channel.send_data_full(Some(&bytes)) { - send_log( - event_sender, - "warn", - format!("Failed to send input heartbeat: {error}."), - ); - } -} - -pub(crate) fn channel_label(channel: &gst_webrtc::WebRTCDataChannel) -> String { - channel - .label() - .map(|label| label.to_string()) - .unwrap_or_else(|| "".to_owned()) -} diff --git a/native/opennow-streamer/src/gstreamer_liveness.rs b/native/opennow-streamer/src/gstreamer_liveness.rs deleted file mode 100644 index bf6b72de7..000000000 --- a/native/opennow-streamer/src/gstreamer_liveness.rs +++ /dev/null @@ -1,1941 +0,0 @@ -use crate::gstreamer_backend::send_log; -use crate::gstreamer_config::use_external_renderer_window; -use crate::gstreamer_pipeline::{configure_queue, set_property_if_supported}; -use crate::gstreamer_transitions::{ - format_transition_summary, resolve_queue_mode, TransitionSnapshot, TransitionTelemetry, - DEFAULT_VIDEO_QUEUE_DEPTH, -}; -use crate::protocol::{Event, NativeQueueMode, NativeStreamerSessionContext, VideoStallEvent}; -use gst::prelude::*; -use gstreamer as gst; -use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering}; -use std::sync::mpsc::Sender; -use std::sync::{Arc, Mutex}; -use std::thread::{self, JoinHandle}; -use std::time::{Duration, Instant}; - -pub(crate) const VIDEO_SINK_RATE_LOG_INTERVAL: Duration = Duration::from_secs(1); -const VIDEO_STALL_WARNING_MS: u64 = 2_500; -const VIDEO_STALL_SECOND_ATTEMPT_MS: u64 = 5_000; -const VIDEO_STALL_RESYNC_MS: u64 = 8_000; -const VIDEO_STALL_PARTIAL_FLUSH_MS: u64 = 12_000; -const VIDEO_STALL_COMPLETE_FLUSH_MS: u64 = 16_000; -const VIDEO_STALL_FATAL_MS: u64 = 20_000; -const VIDEO_STALL_MIN_KEYFRAME_REQUEST_MS: u64 = 2_000; -const VIDEO_STARTUP_KEYFRAME_MS: u64 = 2_500; -const VIDEO_STARTUP_RESYNC_MS: u64 = 5_000; -const VIDEO_STARTUP_FATAL_MS: u64 = 8_000; -const VIDEO_LIVENESS_POLL_INTERVAL: Duration = Duration::from_millis(250); - -#[derive(Debug, Clone, Copy, PartialEq)] -pub(crate) struct VideoRateSnapshot { - encoded_kbps: f64, - decoded_fps: f64, - sink_fps: f64, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum VideoStallAction { - None, - RequestKeyframe { attempt: u8, stall_ms: u64 }, - Resync { attempt: u8, stall_ms: u64 }, - PartialFlush { attempt: u8, stall_ms: u64 }, - CompleteFlush { attempt: u8, stall_ms: u64 }, - Fatal { attempt: u8, stall_ms: u64 }, - Recovered { stall_ms: u64 }, -} - -#[derive(Debug, Clone)] -pub(crate) struct VideoStallTracker { - in_stall: bool, - stall_started_ms: u64, - last_request_ms: Option, - next_attempt: u8, -} - -impl Default for VideoStallTracker { - fn default() -> Self { - Self { - in_stall: false, - stall_started_ms: 0, - last_request_ms: None, - next_attempt: 1, - } - } -} - -impl VideoStallTracker { - pub(crate) fn evaluate(&mut self, now_ms: u64, last_video_ms: u64) -> VideoStallAction { - let stall_ms = now_ms.saturating_sub(last_video_ms); - if stall_ms < VIDEO_STALL_WARNING_MS { - if self.in_stall { - let recovered_ms = now_ms.saturating_sub(self.stall_started_ms); - *self = Self::default(); - return VideoStallAction::Recovered { - stall_ms: recovered_ms, - }; - } - return VideoStallAction::None; - } - - if !self.in_stall { - self.in_stall = true; - self.stall_started_ms = last_video_ms; - self.next_attempt = 1; - } - - let next_due_ms = match self.next_attempt { - 1 => VIDEO_STALL_WARNING_MS, - 2 => VIDEO_STALL_SECOND_ATTEMPT_MS, - 3 => VIDEO_STALL_RESYNC_MS, - 4 => VIDEO_STALL_PARTIAL_FLUSH_MS, - 5 => VIDEO_STALL_COMPLETE_FLUSH_MS, - 6 => VIDEO_STALL_FATAL_MS, - _ => return VideoStallAction::None, - }; - if stall_ms < next_due_ms { - return VideoStallAction::None; - } - if self - .last_request_ms - .is_some_and(|last| now_ms.saturating_sub(last) < VIDEO_STALL_MIN_KEYFRAME_REQUEST_MS) - { - return VideoStallAction::None; - } - - let attempt = self.next_attempt; - self.next_attempt = self.next_attempt.saturating_add(1); - self.last_request_ms = Some(now_ms); - match attempt { - 1 | 2 => VideoStallAction::RequestKeyframe { attempt, stall_ms }, - 3 => VideoStallAction::Resync { attempt, stall_ms }, - 4 => VideoStallAction::PartialFlush { attempt, stall_ms }, - 5 => VideoStallAction::CompleteFlush { attempt, stall_ms }, - _ => VideoStallAction::Fatal { attempt, stall_ms }, - } - } -} - -#[derive(Debug)] -pub(crate) struct VideoLivenessState { - started_at: Instant, - codec: Mutex, - resolution: Mutex, - hardware_acceleration: Mutex, - memory_mode: Mutex, - caps_framerate: Mutex>, - requested_streaming_features_summary: Mutex, - finalized_streaming_features_summary: Mutex, - transition_telemetry: Mutex, - stats_overlay: Mutex>, - pre_decode_queue: Mutex>, - decoder: Mutex>, - post_decode_queue: Mutex>, - stats_overlay_visible: AtomicBool, - target_bitrate_kbps: AtomicU32, - encoded_bytes_total: AtomicU64, - last_encoded_ms: AtomicU64, - last_decoded_ms: AtomicU64, - last_sink_ms: AtomicU64, - last_audio_ms: AtomicU64, - first_startup_audio_ms: AtomicU64, - decoded_total: AtomicU64, - sink_total: AtomicU64, - zero_copy_d3d11: AtomicBool, - zero_copy_d3d12: AtomicBool, - rtp_video_src_pad: Mutex>, - requested_fps: AtomicU32, - framerate_mismatch_warned: AtomicBool, - transition_flush_escalation_enabled: AtomicBool, - first_encoded_logged: AtomicBool, - startup_keyframe_requested: AtomicBool, - startup_resync_requested: AtomicBool, - startup_fatal_reported: AtomicBool, -} - -impl VideoLivenessState { - fn new() -> Self { - Self { - started_at: Instant::now(), - codec: Mutex::new(String::new()), - resolution: Mutex::new(String::new()), - hardware_acceleration: Mutex::new(String::new()), - memory_mode: Mutex::new("system-memory".to_owned()), - caps_framerate: Mutex::new(None), - requested_streaming_features_summary: Mutex::new("none".to_owned()), - finalized_streaming_features_summary: Mutex::new("none".to_owned()), - transition_telemetry: Mutex::new(TransitionTelemetry::default()), - stats_overlay: Mutex::new(None), - pre_decode_queue: Mutex::new(None), - decoder: Mutex::new(None), - post_decode_queue: Mutex::new(None), - stats_overlay_visible: AtomicBool::new(false), - target_bitrate_kbps: AtomicU32::new(0), - encoded_bytes_total: AtomicU64::new(0), - last_encoded_ms: AtomicU64::new(0), - last_decoded_ms: AtomicU64::new(0), - last_sink_ms: AtomicU64::new(0), - last_audio_ms: AtomicU64::new(0), - first_startup_audio_ms: AtomicU64::new(0), - decoded_total: AtomicU64::new(0), - sink_total: AtomicU64::new(0), - zero_copy_d3d11: AtomicBool::new(false), - zero_copy_d3d12: AtomicBool::new(false), - rtp_video_src_pad: Mutex::new(None), - requested_fps: AtomicU32::new(0), - framerate_mismatch_warned: AtomicBool::new(false), - transition_flush_escalation_enabled: AtomicBool::new(true), - first_encoded_logged: AtomicBool::new(false), - startup_keyframe_requested: AtomicBool::new(false), - startup_resync_requested: AtomicBool::new(false), - startup_fatal_reported: AtomicBool::new(false), - } - } - - fn now_ms(&self) -> u64 { - self.started_at - .elapsed() - .as_millis() - .min(u128::from(u64::MAX)) as u64 - } - - pub(crate) fn configure( - &self, - context: &NativeStreamerSessionContext, - target_bitrate_kbps: u32, - ) { - let settings = &context.settings; - if let Ok(mut codec) = self.codec.lock() { - *codec = settings.codec.as_str().to_owned(); - } - if let Ok(mut resolution) = self.resolution.lock() { - *resolution = settings.resolution.clone(); - } - if let Ok(mut caps_framerate) = self.caps_framerate.lock() { - *caps_framerate = None; - } - if let Ok(mut requested_summary) = self.requested_streaming_features_summary.lock() { - *requested_summary = context - .session - .requested_streaming_features - .as_ref() - .map(|features| features.summary()) - .unwrap_or_else(|| "none".to_owned()); - } - if let Ok(mut finalized_summary) = self.finalized_streaming_features_summary.lock() { - *finalized_summary = context - .session - .finalized_streaming_features - .as_ref() - .map(|features| features.summary()) - .unwrap_or_else(|| "none".to_owned()); - } - if let Ok(mut telemetry) = self.transition_telemetry.lock() { - telemetry.queue_mode = resolve_queue_mode(settings); - telemetry.queue_depth = DEFAULT_VIDEO_QUEUE_DEPTH; - telemetry.queue_depth_changes = 0; - telemetry.present_pacing_changes = 0; - telemetry.partial_flush_count = 0; - telemetry.complete_flush_count = 0; - telemetry.last_transition = None; - } - self.target_bitrate_kbps - .store(target_bitrate_kbps, Ordering::Relaxed); - self.requested_fps.store(settings.fps, Ordering::Relaxed); - self.framerate_mismatch_warned - .store(false, Ordering::Relaxed); - self.first_encoded_logged.store(false, Ordering::Relaxed); - self.first_startup_audio_ms.store(0, Ordering::Relaxed); - self.transition_flush_escalation_enabled.store( - settings - .native_transition_diagnostics - .as_ref() - .map(|diagnostics| !diagnostics.disable_transition_flush_escalation) - .unwrap_or(true), - Ordering::Relaxed, - ); - self.startup_keyframe_requested - .store(false, Ordering::Relaxed); - self.startup_resync_requested - .store(false, Ordering::Relaxed); - self.startup_fatal_reported.store(false, Ordering::Relaxed); - } - - pub(crate) fn update_hardware_acceleration(&self, value: impl Into) { - if let Ok(mut hardware_acceleration) = self.hardware_acceleration.lock() { - *hardware_acceleration = value.into(); - } - } - - pub(crate) fn record_encoded_buffer(&self, size: usize) { - self.last_encoded_ms.store(self.now_ms(), Ordering::Relaxed); - self.encoded_bytes_total - .fetch_add(size as u64, Ordering::Relaxed); - } - - pub(crate) fn record_audio_buffer(&self) { - let now_ms = self.now_ms(); - self.last_audio_ms.store(now_ms, Ordering::Relaxed); - if self.last_sink_ms.load(Ordering::Relaxed) == 0 { - let _ = self.first_startup_audio_ms.compare_exchange( - 0, - now_ms, - Ordering::Relaxed, - Ordering::Relaxed, - ); - } - } - - fn log_first_encoded_once(&self) -> bool { - !self.first_encoded_logged.swap(true, Ordering::Relaxed) - } - - pub(crate) fn set_stats_overlay(&self, overlay: Option) { - if let Some(element) = overlay.as_ref() { - set_property_if_supported( - element, - "visible", - self.stats_overlay_visible.load(Ordering::Relaxed), - ); - } - if let Ok(mut current) = self.stats_overlay.lock() { - *current = overlay; - } - } - - pub(crate) fn set_stats_overlay_visible(&self, visible: bool) { - self.stats_overlay_visible.store(visible, Ordering::Relaxed); - if let Ok(current) = self.stats_overlay.lock() { - if let Some(overlay) = current.as_ref() { - set_property_if_supported(overlay, "visible", visible); - } - } - } - - fn update_stats_overlay_text(&self, text: &str) { - if let Ok(current) = self.stats_overlay.lock() { - if let Some(overlay) = current.as_ref() { - overlay.set_property("text", text); - set_property_if_supported( - overlay, - "visible", - self.stats_overlay_visible.load(Ordering::Relaxed) && !text.is_empty(), - ); - } - } - } - - pub(crate) fn record_decoded_buffer(&self) { - self.last_decoded_ms.store(self.now_ms(), Ordering::Relaxed); - self.decoded_total.fetch_add(1, Ordering::Relaxed); - } - - pub(crate) fn record_sink_buffer(&self) { - self.last_sink_ms.store(self.now_ms(), Ordering::Relaxed); - self.sink_total.fetch_add(1, Ordering::Relaxed); - } - - pub(crate) fn update_caps(&self, caps: &str) { - self.zero_copy_d3d11 - .store(caps.contains("memory:D3D11Memory"), Ordering::Relaxed); - self.zero_copy_d3d12 - .store(caps.contains("memory:D3D12Memory"), Ordering::Relaxed); - if let Ok(mut memory_mode) = self.memory_mode.lock() { - *memory_mode = memory_mode_from_caps(caps).to_owned(); - } - if let Ok(mut caps_framerate) = self.caps_framerate.lock() { - *caps_framerate = caps_framerate_summary(caps); - } - } - - fn zero_copy_d3d11(&self) -> bool { - self.zero_copy_d3d11.load(Ordering::Relaxed) - } - - fn zero_copy_d3d12(&self) -> bool { - self.zero_copy_d3d12.load(Ordering::Relaxed) - } - - fn memory_mode(&self) -> String { - self.memory_mode - .lock() - .map(|value| value.clone()) - .unwrap_or_else(|_| "unknown".to_owned()) - } - - fn zero_copy(&self) -> bool { - is_zero_copy_memory_mode(&self.memory_mode()) - } - - pub(crate) fn set_rtp_video_src_pad(&self, pad: &gst::Pad) { - if let Ok(mut current) = self.rtp_video_src_pad.lock() { - *current = Some(pad.clone()); - } - } - - fn requested_fps(&self) -> Option { - let fps = self.requested_fps.load(Ordering::Relaxed); - (fps > 0).then_some(fps) - } - - fn caps_framerate(&self) -> Option { - self.caps_framerate - .lock() - .ok() - .and_then(|value| value.clone()) - } - - fn warn_framerate_mismatch_once(&self) -> bool { - !self.framerate_mismatch_warned.swap(true, Ordering::Relaxed) - } - - fn rtp_video_src_pad(&self) -> Option { - self.rtp_video_src_pad - .lock() - .ok() - .and_then(|current| current.clone()) - } - - fn queue_mode(&self) -> NativeQueueMode { - self.transition_telemetry - .lock() - .map(|telemetry| telemetry.queue_mode) - .unwrap_or(NativeQueueMode::Auto) - } - - pub(crate) fn set_post_decode_queue(&self, queue: gst::Element) { - if let Ok(mut current) = self.post_decode_queue.lock() { - *current = Some(queue); - } - } - - pub(crate) fn set_pre_decode_queue(&self, queue: gst::Element) { - if let Ok(mut current) = self.pre_decode_queue.lock() { - *current = Some(queue); - } - } - - pub(crate) fn set_decoder(&self, decoder: gst::Element) { - if let Ok(mut current) = self.decoder.lock() { - *current = Some(decoder); - } - } - - fn pre_decode_queue(&self) -> Option { - self.pre_decode_queue - .lock() - .ok() - .and_then(|current| current.clone()) - } - - fn decoder(&self) -> Option { - self.decoder.lock().ok().and_then(|current| current.clone()) - } - - fn set_queue_depth( - &self, - max_buffers: u32, - reason: &str, - event_sender: &Option>, - ) { - let queue = self - .post_decode_queue - .lock() - .ok() - .and_then(|current| current.clone()); - if let Some(queue) = queue.as_ref() { - configure_queue(queue, max_buffers, true); - } - - let mut should_log = false; - if let Ok(mut telemetry) = self.transition_telemetry.lock() { - if telemetry.queue_depth != max_buffers { - telemetry.queue_depth = max_buffers; - telemetry.queue_depth_changes = telemetry.queue_depth_changes.saturating_add(1); - should_log = true; - } - } - - if should_log { - send_log( - event_sender, - "info", - format!("Adjusted native post-decode queue depth to {max_buffers} ({reason})."), - ); - } - } - - fn queue_depth(&self) -> u32 { - self.transition_telemetry - .lock() - .map(|telemetry| telemetry.queue_depth) - .unwrap_or(DEFAULT_VIDEO_QUEUE_DEPTH) - } - - fn record_present_pacing_change(&self) { - if let Ok(mut telemetry) = self.transition_telemetry.lock() { - telemetry.present_pacing_changes = telemetry.present_pacing_changes.saturating_add(1); - } - } - - fn transition_flush_escalation_enabled(&self) -> bool { - self.transition_flush_escalation_enabled - .load(Ordering::Relaxed) - } - - fn transition_telemetry_snapshot(&self) -> TransitionTelemetry { - self.transition_telemetry - .lock() - .map(|telemetry| telemetry.clone()) - .unwrap_or_default() - } - - fn requested_streaming_features_summary(&self) -> String { - self.requested_streaming_features_summary - .lock() - .map(|value| value.clone()) - .unwrap_or_else(|_| "none".to_owned()) - } - - fn finalized_streaming_features_summary(&self) -> String { - self.finalized_streaming_features_summary - .lock() - .map(|value| value.clone()) - .unwrap_or_else(|_| "none".to_owned()) - } - - fn record_transition( - &self, - transition_type: &str, - source: &str, - old_caps: Option, - new_caps: Option, - old_framerate: Option, - new_framerate: Option, - old_memory_mode: Option, - new_memory_mode: Option, - event_sender: &Option>, - ) { - let requested_fps = self.requested_fps(); - let queue_mode = self.queue_mode(); - let render_gap_ms = age_since_ms(self.now_ms(), self.last_sink_ms.load(Ordering::Relaxed)); - let high_fps_risk = requested_fps.is_some_and(|fps| fps >= 240) - && new_framerate - .as_deref() - .is_some_and(|value| value != format!("{}/1", requested_fps.unwrap_or_default())); - let summary = format_transition_summary( - transition_type, - source, - requested_fps, - old_framerate.as_deref(), - new_framerate.as_deref(), - high_fps_risk, - ); - let snapshot = TransitionSnapshot { - transition_type: transition_type.to_owned(), - source: source.to_owned(), - at_ms: self.now_ms(), - old_caps, - new_caps, - old_framerate, - new_framerate: new_framerate.clone(), - old_memory_mode, - new_memory_mode, - render_gap_ms, - requested_fps, - caps_framerate: new_framerate, - high_fps_risk, - queue_mode, - summary: summary.clone(), - }; - - if let Ok(mut telemetry) = self.transition_telemetry.lock() { - telemetry.last_transition = Some(snapshot.clone()); - } - - send_log( - event_sender, - "warn", - format!("Native video transition: {summary}"), - ); - if let Some(event_sender) = event_sender { - let _ = event_sender.send(Event::VideoTransition { - transition: snapshot.to_event(), - }); - } - } - - fn increment_partial_flush_count(&self) { - if let Ok(mut telemetry) = self.transition_telemetry.lock() { - telemetry.partial_flush_count = telemetry.partial_flush_count.saturating_add(1); - } - } - - fn increment_complete_flush_count(&self) { - if let Ok(mut telemetry) = self.transition_telemetry.lock() { - telemetry.complete_flush_count = telemetry.complete_flush_count.saturating_add(1); - } - } -} - -#[derive(Debug, Clone)] -pub(crate) struct VideoLivenessMonitor { - state: Arc, - stop: Arc, - started: Arc, - thread: Arc>>>, -} - -impl Default for VideoLivenessMonitor { - fn default() -> Self { - Self { - state: Arc::new(VideoLivenessState::new()), - stop: Arc::new(AtomicBool::new(false)), - started: Arc::new(AtomicBool::new(false)), - thread: Arc::new(Mutex::new(None)), - } - } -} - -impl VideoLivenessMonitor { - pub(crate) fn configure( - &self, - context: &NativeStreamerSessionContext, - target_bitrate_kbps: u32, - ) { - self.state.configure(context, target_bitrate_kbps); - } - - pub(crate) fn update_hardware_acceleration(&self, value: impl Into) { - self.state.update_hardware_acceleration(value); - } - - pub(crate) fn record_encoded_buffer(&self, size: usize) { - self.state.record_encoded_buffer(size); - } - - pub(crate) fn record_audio_buffer(&self) { - self.state.record_audio_buffer(); - } - - pub(crate) fn set_stats_overlay(&self, overlay: Option) { - self.state.set_stats_overlay(overlay); - } - - pub(crate) fn set_stats_overlay_visible(&self, visible: bool) { - self.state.set_stats_overlay_visible(visible); - } - - pub(crate) fn record_decoded_buffer(&self) { - self.state.record_decoded_buffer(); - } - - pub(crate) fn record_sink_buffer(&self) { - self.state.record_sink_buffer(); - } - - pub(crate) fn update_caps(&self, caps: &str) { - self.state.update_caps(caps); - } - - pub(crate) fn set_rtp_video_src_pad(&self, pad: &gst::Pad) { - self.state.set_rtp_video_src_pad(pad); - } - - pub(crate) fn set_post_decode_queue(&self, queue: gst::Element) { - self.state.set_post_decode_queue(queue); - } - - pub(crate) fn set_pre_decode_queue(&self, queue: gst::Element) { - self.state.set_pre_decode_queue(queue); - } - - pub(crate) fn set_decoder(&self, decoder: gst::Element) { - self.state.set_decoder(decoder); - } - - pub(crate) fn log_first_encoded_once(&self) -> bool { - self.state.log_first_encoded_once() - } - - pub(crate) fn requested_fps(&self) -> Option { - self.state.requested_fps() - } - - pub(crate) fn warn_framerate_mismatch_once(&self) -> bool { - self.state.warn_framerate_mismatch_once() - } - - pub(crate) fn record_present_pacing_change(&self) { - self.state.record_present_pacing_change(); - } - - pub(crate) fn stop_flag(&self) -> Arc { - self.stop.clone() - } - - pub(crate) fn record_transition( - &self, - transition_type: &str, - source: &str, - old_caps: Option, - new_caps: Option, - old_framerate: Option, - new_framerate: Option, - old_memory_mode: Option, - new_memory_mode: Option, - event_sender: &Option>, - ) { - self.state.record_transition( - transition_type, - source, - old_caps, - new_caps, - old_framerate, - new_framerate, - old_memory_mode, - new_memory_mode, - event_sender, - ); - } - - pub(crate) fn start( - &self, - pipeline: gst::Pipeline, - sink: gst::Element, - event_sender: Option>, - ) { - if self.started.swap(true, Ordering::SeqCst) { - return; - } - - self.stop.store(false, Ordering::SeqCst); - let state = self.state.clone(); - let stop = self.stop.clone(); - let thread = thread::spawn(move || { - run_video_liveness_watchdog(state, stop, pipeline, sink, event_sender); - }); - if let Ok(mut slot) = self.thread.lock() { - *slot = Some(thread); - } - } - - pub(crate) fn stop(&self) { - self.stop.store(true, Ordering::SeqCst); - self.started.store(false, Ordering::SeqCst); - let handle = self.thread.lock().ok().and_then(|mut slot| slot.take()); - if let Some(handle) = handle { - let _ = handle.join(); - } - } -} - -fn run_video_liveness_watchdog( - state: Arc, - stop: Arc, - pipeline: gst::Pipeline, - sink: gst::Element, - event_sender: Option>, -) { - let mut tracker = VideoStallTracker::default(); - let mut last_rate_at = Instant::now(); - let mut last_encoded_bytes_total = state.encoded_bytes_total.load(Ordering::Relaxed); - let mut last_decoded_total = state.decoded_total.load(Ordering::Relaxed); - let mut last_sink_total = state.sink_total.load(Ordering::Relaxed); - let mut rates = VideoRateSnapshot { - encoded_kbps: 0.0, - decoded_fps: 0.0, - sink_fps: 0.0, - }; - - while !stop.load(Ordering::SeqCst) { - thread::sleep(VIDEO_LIVENESS_POLL_INTERVAL); - - let elapsed = last_rate_at.elapsed(); - if elapsed >= VIDEO_SINK_RATE_LOG_INTERVAL { - let encoded_bytes_total = state.encoded_bytes_total.load(Ordering::Relaxed); - let decoded_total = state.decoded_total.load(Ordering::Relaxed); - let sink_total = state.sink_total.load(Ordering::Relaxed); - let elapsed_secs = elapsed.as_secs_f64().max(0.001); - let bitrate_kbps = encoded_bytes_total - .saturating_sub(last_encoded_bytes_total) - .saturating_mul(8) as f64 - / elapsed_secs - / 1000.0; - rates = VideoRateSnapshot { - encoded_kbps: bitrate_kbps.max(0.0), - decoded_fps: decoded_total.saturating_sub(last_decoded_total) as f64 / elapsed_secs, - sink_fps: sink_total.saturating_sub(last_sink_total) as f64 / elapsed_secs, - }; - update_native_stats_overlay( - &sink, - &state, - rates.encoded_kbps.round() as u32, - rates, - decoded_total, - sink_total, - ); - emit_native_stats_event( - &event_sender, - &sink, - &state, - rates.encoded_kbps.round() as u32, - rates, - decoded_total, - sink_total, - ); - last_encoded_bytes_total = encoded_bytes_total; - last_decoded_total = decoded_total; - last_sink_total = sink_total; - last_rate_at = Instant::now(); - } - - let last_sink_ms = state.last_sink_ms.load(Ordering::Relaxed); - if last_sink_ms == 0 { - maybe_recover_video_startup(&state, &pipeline, &event_sender); - continue; - } - - let now_ms = state.now_ms(); - let encoded_age_ms = age_since_ms(now_ms, state.last_encoded_ms.load(Ordering::Relaxed)); - let decoded_age_ms = age_since_ms(now_ms, state.last_decoded_ms.load(Ordering::Relaxed)); - let sink_age_ms = age_since_ms(now_ms, last_sink_ms); - let likely_stage = classify_video_stall(encoded_age_ms, decoded_age_ms, sink_age_ms); - let transition_stall = likely_stage == "decode-chain-stalled" - && encoded_age_ms.is_some_and(|age| age <= 1_000); - - match tracker.evaluate(now_ms, last_sink_ms) { - VideoStallAction::None => {} - VideoStallAction::RequestKeyframe { attempt, stall_ms } => { - request_upstream_key_unit(&state, &event_sender); - emit_video_stall_event( - &event_sender, - &sink, - &state, - rates, - attempt, - stall_ms, - false, - ); - } - VideoStallAction::Resync { attempt, stall_ms } => { - request_upstream_key_unit(&state, &event_sender); - emit_video_stall_event( - &event_sender, - &sink, - &state, - rates, - attempt, - stall_ms, - true, - ); - match pipeline.recalculate_latency() { - Ok(()) => send_log( - &event_sender, - "warn", - "Requested GStreamer latency recalculation after native video stall.".to_owned(), - ), - Err(error) => send_log( - &event_sender, - "warn", - format!( - "Failed to request GStreamer latency recalculation after native video stall: {error}." - ), - ), - } - } - VideoStallAction::PartialFlush { attempt, stall_ms } => { - if transition_stall && state.transition_flush_escalation_enabled() { - request_upstream_key_unit(&state, &event_sender); - perform_transition_flush(&state, &event_sender, TransitionFlushKind::Partial); - } - emit_video_stall_event( - &event_sender, - &sink, - &state, - rates, - attempt, - stall_ms, - false, - ); - } - VideoStallAction::CompleteFlush { attempt, stall_ms } => { - if transition_stall && state.transition_flush_escalation_enabled() { - request_upstream_key_unit(&state, &event_sender); - perform_transition_flush(&state, &event_sender, TransitionFlushKind::Complete); - } - emit_video_stall_event( - &event_sender, - &sink, - &state, - rates, - attempt, - stall_ms, - false, - ); - } - VideoStallAction::Fatal { attempt, stall_ms } => { - emit_video_stall_event( - &event_sender, - &sink, - &state, - rates, - attempt, - stall_ms, - false, - ); - send_log( - &event_sender, - "error", - format!( - "Native video stall recovery exhausted after {stall_ms}ms; stage={likely_stage} queueMode={} transitionFlushEscalation={}.", - state.queue_mode().as_str(), - state.transition_flush_escalation_enabled(), - ), - ); - if let Some(event_sender) = &event_sender { - let _ = event_sender.send(Event::Error { - code: "native-video-stall-fatal".to_owned(), - message: format!( - "Native video stall recovery exhausted after {stall_ms}ms ({likely_stage})." - ), - }); - } - } - VideoStallAction::Recovered { stall_ms } => { - if state.queue_depth() > DEFAULT_VIDEO_QUEUE_DEPTH { - state.set_queue_depth( - DEFAULT_VIDEO_QUEUE_DEPTH, - "transition recovery completed", - &event_sender, - ); - } - send_log( - &event_sender, - "info", - format!("Native video recovered after {stall_ms} ms."), - ); - } - } - } -} - -fn maybe_recover_video_startup( - state: &VideoLivenessState, - pipeline: &gst::Pipeline, - event_sender: &Option>, -) { - let now_ms = state.now_ms(); - let last_audio_ms = state.last_audio_ms.load(Ordering::Relaxed); - let first_audio_ms = state.first_startup_audio_ms.load(Ordering::Relaxed); - let last_encoded_ms = state.last_encoded_ms.load(Ordering::Relaxed); - if first_audio_ms == 0 - || last_audio_ms == 0 - || now_ms.saturating_sub(last_audio_ms) > VIDEO_STARTUP_KEYFRAME_MS - { - return; - } - let audio_active_ms = now_ms.saturating_sub(first_audio_ms); - - let decoded_total = state.decoded_total.load(Ordering::Relaxed); - let sink_total = state.sink_total.load(Ordering::Relaxed); - let encoded_age = if last_encoded_ms == 0 { - "never".to_owned() - } else { - format!("{}ms", now_ms.saturating_sub(last_encoded_ms)) - }; - - if audio_active_ms >= VIDEO_STARTUP_KEYFRAME_MS - && !state - .startup_keyframe_requested - .swap(true, Ordering::Relaxed) - { - send_log( - event_sender, - "warn", - format!( - "Native video startup has no rendered frame after {audio_active_ms}ms of active audio; startupAge={now_ms}ms encodedAge={encoded_age} decoded={decoded_total} sink={sink_total}. Requesting keyframe." - ), - ); - request_upstream_key_unit(state, event_sender); - } - - if audio_active_ms >= VIDEO_STARTUP_RESYNC_MS - && !state.startup_resync_requested.swap(true, Ordering::Relaxed) - { - send_log( - event_sender, - "warn", - format!( - "Native video startup still has no rendered frame after {audio_active_ms}ms of active audio; startupAge={now_ms}ms encodedAge={encoded_age} decoded={decoded_total} sink={sink_total}. Requesting keyframe and GStreamer latency resync." - ), - ); - request_upstream_key_unit(state, event_sender); - if let Err(error) = pipeline.recalculate_latency() { - send_log( - event_sender, - "warn", - format!("Failed to resync GStreamer latency during native video startup recovery: {error}."), - ); - } - } - - if audio_active_ms >= VIDEO_STARTUP_FATAL_MS - && !state.startup_fatal_reported.swap(true, Ordering::Relaxed) - { - let (code, failure_stage) = classify_video_startup_failure( - state.encoded_bytes_total.load(Ordering::Relaxed), - decoded_total, - sink_total, - ); - send_log( - event_sender, - "error", - format!( - "Native video startup still has no rendered frame after {audio_active_ms}ms of active audio; stage={failure_stage} startupAge={now_ms}ms encodedAge={encoded_age} decoded={decoded_total} sink={sink_total}." - ), - ); - request_upstream_key_unit(state, event_sender); - if let Some(event_sender) = event_sender { - let _ = event_sender.send(Event::Error { - code: code.to_owned(), - message: format!( - "Native video startup timed out before the first rendered frame ({failure_stage})." - ), - }); - } - } -} - -pub(crate) fn classify_video_startup_failure( - encoded_bytes: u64, - decoded_frames: u64, - sink_frames: u64, -) -> (&'static str, &'static str) { - if encoded_bytes == 0 { - return ("native-video-input-startup-timeout", "RTP video input"); - } - if decoded_frames == 0 { - return ( - "native-video-decoder-startup-timeout", - "video decoder output", - ); - } - if sink_frames == 0 { - return ( - "native-video-renderer-startup-timeout", - "video renderer input", - ); - } - ( - "native-video-presentation-startup-timeout", - "native presentation", - ) -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum TransitionFlushKind { - Partial, - Complete, -} - -fn perform_transition_flush( - state: &VideoLivenessState, - event_sender: &Option>, - flush_kind: TransitionFlushKind, -) { - let label = match flush_kind { - TransitionFlushKind::Partial => "partial", - TransitionFlushKind::Complete => "complete", - }; - let mut flushed = Vec::new(); - - if matches!( - flush_kind, - TransitionFlushKind::Partial | TransitionFlushKind::Complete - ) { - if let Some(queue) = state.pre_decode_queue() { - flush_element(&queue); - flushed.push("pre-decode queue"); - } - } - - if matches!(flush_kind, TransitionFlushKind::Complete) { - if let Some(decoder) = state.decoder() { - flush_element(&decoder); - flushed.push("decoder"); - } - } - - if let Some(queue) = state - .post_decode_queue - .lock() - .ok() - .and_then(|current| current.clone()) - { - flush_element(&queue); - flushed.push("post-decode queue"); - } - - if flushed.is_empty() { - send_log( - event_sender, - "warn", - "Cannot flush native transition path because no video branch elements are registered." - .to_owned(), - ); - return; - } - - match flush_kind { - TransitionFlushKind::Partial => { - state.increment_partial_flush_count(); - state.set_queue_depth(2, "transition partial flush", event_sender); - } - TransitionFlushKind::Complete => { - state.increment_complete_flush_count(); - state.set_queue_depth(2, "transition complete flush", event_sender); - } - } - - send_log( - event_sender, - "warn", - format!( - "Performed {label} native transition flush on {}.", - flushed.join(", ") - ), - ); -} - -fn flush_element(element: &gst::Element) { - let _ = element.send_event(gst::event::FlushStart::new()); - let _ = element.send_event(gst::event::FlushStop::new(false)); -} - -fn request_upstream_key_unit(state: &VideoLivenessState, event_sender: &Option>) { - let Some(src_pad) = state.rtp_video_src_pad() else { - send_log( - event_sender, - "warn", - "Unable to request upstream video key unit: no RTP video source pad registered." - .to_owned(), - ); - return; - }; - - let event = gst::event::CustomUpstream::builder( - gst::Structure::builder("GstForceKeyUnit") - .field("all-headers", true) - .build(), - ) - .build(); - - if src_pad.send_event(event) { - send_log( - event_sender, - "debug", - "Requested upstream video key unit via RTP source pad.".to_owned(), - ); - } else { - send_log( - event_sender, - "warn", - "Upstream video key-unit request was not accepted by the RTP source pad.".to_owned(), - ); - } -} - -fn emit_native_stats_event( - event_sender: &Option>, - sink: &gst::Element, - state: &VideoLivenessState, - bitrate_kbps: u32, - rates: VideoRateSnapshot, - frames_decoded: u64, - frames_rendered: u64, -) { - let Some(event_sender) = event_sender else { - return; - }; - - let target_bitrate_kbps = state.target_bitrate_kbps.load(Ordering::Relaxed); - let bitrate_performance_percent = if target_bitrate_kbps > 0 { - (f64::from(bitrate_kbps) / f64::from(target_bitrate_kbps)) * 100.0 - } else { - 0.0 - }; - let codec = state - .codec - .lock() - .map(|codec| codec.clone()) - .unwrap_or_default(); - let resolution = state - .resolution - .lock() - .map(|resolution| resolution.clone()) - .unwrap_or_default(); - let hardware_acceleration = state - .hardware_acceleration - .lock() - .map(|value| value.clone()) - .unwrap_or_default(); - let sink_stats = read_sink_stats(sink); - let telemetry = state.transition_telemetry_snapshot(); - let _ = event_sender.send(Event::Stats { - stats: crate::protocol::NativeStatsEvent { - codec, - resolution, - hardware_acceleration, - requested_fps: state.requested_fps(), - caps_framerate: state.caps_framerate(), - bitrate_kbps, - target_bitrate_kbps, - bitrate_performance_percent, - decoded_fps: rates.decoded_fps, - render_fps: rates.sink_fps, - frames_decoded, - frames_rendered, - frames_pending_to_present: frames_decoded.saturating_sub(frames_rendered), - sink_rendered: sink_stats.rendered, - sink_dropped: sink_stats.dropped, - memory_mode: state.memory_mode(), - zero_copy: state.zero_copy(), - queue_mode: telemetry.queue_mode.as_str().to_owned(), - queue_depth_changes: telemetry.queue_depth_changes, - present_pacing_changes: telemetry.present_pacing_changes, - partial_flush_count: telemetry.partial_flush_count, - complete_flush_count: telemetry.complete_flush_count, - last_transition_type: telemetry - .last_transition - .as_ref() - .map(|transition| transition.transition_type.clone()), - last_transition_at_ms: telemetry - .last_transition - .as_ref() - .map(|transition| transition.at_ms), - last_transition_summary: telemetry - .last_transition - .as_ref() - .map(|transition| transition.summary.clone()), - requested_streaming_features_summary: state.requested_streaming_features_summary(), - finalized_streaming_features_summary: state.finalized_streaming_features_summary(), - zero_copy_d3d11: state.zero_copy_d3d11(), - zero_copy_d3d12: state.zero_copy_d3d12(), - }, - }); -} - -fn update_native_stats_overlay( - sink: &gst::Element, - state: &VideoLivenessState, - bitrate_kbps: u32, - rates: VideoRateSnapshot, - _frames_decoded: u64, - frames_rendered: u64, -) { - let target_bitrate_kbps = state.target_bitrate_kbps.load(Ordering::Relaxed); - let bitrate_performance_percent = if target_bitrate_kbps > 0 { - (f64::from(bitrate_kbps) / f64::from(target_bitrate_kbps)) * 100.0 - } else { - 0.0 - }; - let codec = state - .codec - .lock() - .map(|codec| codec.clone()) - .unwrap_or_default(); - let resolution = state - .resolution - .lock() - .map(|resolution| resolution.clone()) - .unwrap_or_default(); - let hardware_acceleration = state - .hardware_acceleration - .lock() - .map(|value| value.clone()) - .unwrap_or_default(); - let sink_stats = read_sink_stats(sink); - let sink_dropped = sink_stats.dropped.unwrap_or(0); - let sink_rendered = sink_stats.rendered.unwrap_or(frames_rendered); - let sink_total = sink_rendered.saturating_add(sink_dropped); - let drop_percent = if sink_total > 0 { - (sink_dropped as f64 / sink_total as f64) * 100.0 - } else { - 0.0 - }; - let target_mbps = f64::from(target_bitrate_kbps) / 1000.0; - let bitrate_mbps = f64::from(bitrate_kbps) / 1000.0; - let memory_mode = state.memory_mode(); - let memory_path = if state.zero_copy() { - format!("{memory_mode} zero-copy") - } else { - memory_mode - }; - let text = format!( - "{} {} {:.1}/{:.1} Mbps Bit {:.0}%\nDecode {:.0}fps Render {:.0}fps Drop {:.2}% {}", - codec, - resolution, - bitrate_mbps, - target_mbps, - bitrate_performance_percent, - rates.decoded_fps, - rates.sink_fps, - drop_percent, - if hardware_acceleration.is_empty() { - memory_path - } else { - format!("{hardware_acceleration} {memory_path}") - }, - ); - state.update_stats_overlay_text(&text); -} - -fn emit_video_stall_event( - event_sender: &Option>, - sink: &gst::Element, - state: &VideoLivenessState, - rates: VideoRateSnapshot, - recovery_attempt: u8, - stall_ms: u64, - will_resync: bool, -) { - let stats = read_sink_stats(sink); - let now_ms = state.now_ms(); - let last_encoded_ms = state.last_encoded_ms.load(Ordering::Relaxed); - let last_decoded_ms = state.last_decoded_ms.load(Ordering::Relaxed); - let last_sink_ms = state.last_sink_ms.load(Ordering::Relaxed); - let encoded_age_ms = age_since_ms(now_ms, last_encoded_ms); - let decoded_age_ms = age_since_ms(now_ms, last_decoded_ms); - let sink_age_ms = age_since_ms(now_ms, last_sink_ms); - let likely_stage = classify_video_stall(encoded_age_ms, decoded_age_ms, sink_age_ms); - let memory_mode = state.memory_mode(); - let zero_copy = state.zero_copy(); - let telemetry = state.transition_telemetry_snapshot(); - let resync_suffix = if will_resync { - " Requesting keyframe and resyncing GStreamer latency." - } else { - " Requesting keyframe." - }; - send_log( - event_sender, - "warn", - format!( - "Native video stall detected: stall={stall_ms}ms stage={likely_stage} encoded={:.0}kbps decoded={:.1}fps sink={:.1}fps requestedFps={} capsFramerate={} queueMode={} partialFlushes={} completeFlushes={} lastTransition={} ages=encoded:{} decoded:{} sink:{} rendered={} dropped={} memoryMode={} zeroCopy={} zeroCopyD3D11={} zeroCopyD3D12={}. If decoded/sink/rendered counters are still flowing but the visible frame is stale, suspect a server-driven mid-stream transition the native decode/present chain failed to absorb rather than pure RTP loss.{}", - rates.encoded_kbps, - rates.decoded_fps, - rates.sink_fps, - state - .requested_fps() - .map(|value| value.to_string()) - .unwrap_or_else(|| "n/a".to_owned()), - state.caps_framerate().unwrap_or_else(|| "unknown".to_owned()), - telemetry.queue_mode.as_str(), - telemetry.partial_flush_count, - telemetry.complete_flush_count, - telemetry - .last_transition - .as_ref() - .map(|transition| transition.transition_type.as_str()) - .unwrap_or("none"), - format_age_ms(encoded_age_ms), - format_age_ms(decoded_age_ms), - format_age_ms(sink_age_ms), - stats - .rendered - .map(|value| value.to_string()) - .unwrap_or_else(|| "n/a".to_owned()), - stats - .dropped - .map(|value| value.to_string()) - .unwrap_or_else(|| "n/a".to_owned()), - memory_mode.as_str(), - zero_copy, - state.zero_copy_d3d11(), - state.zero_copy_d3d12(), - resync_suffix - ), - ); - if let Some(event_sender) = event_sender { - let _ = event_sender.send(Event::VideoStall(VideoStallEvent { - stall_ms, - encoded_kbps: rates.encoded_kbps, - decoded_fps: rates.decoded_fps, - sink_fps: rates.sink_fps, - encoded_age_ms, - decoded_age_ms, - sink_age_ms, - likely_stage: likely_stage.to_owned(), - sink_rendered: stats.rendered, - sink_dropped: stats.dropped, - memory_mode, - zero_copy, - requested_fps: state.requested_fps(), - caps_framerate: state.caps_framerate(), - queue_mode: telemetry.queue_mode.as_str().to_owned(), - partial_flush_count: telemetry.partial_flush_count, - complete_flush_count: telemetry.complete_flush_count, - last_transition_type: telemetry - .last_transition - .as_ref() - .map(|transition| transition.transition_type.clone()), - last_transition_at_ms: telemetry - .last_transition - .as_ref() - .map(|transition| transition.at_ms), - requested_streaming_features_summary: state.requested_streaming_features_summary(), - finalized_streaming_features_summary: state.finalized_streaming_features_summary(), - zero_copy_d3d11: state.zero_copy_d3d11(), - zero_copy_d3d12: state.zero_copy_d3d12(), - recovery_attempt, - })); - } -} - -fn age_since_ms(now_ms: u64, last_ms: u64) -> Option { - (last_ms != 0).then_some(now_ms.saturating_sub(last_ms)) -} - -fn format_age_ms(age_ms: Option) -> String { - age_ms - .map(|value| format!("{value}ms")) - .unwrap_or_else(|| "n/a".to_owned()) -} - -fn classify_video_stall( - encoded_age_ms: Option, - decoded_age_ms: Option, - sink_age_ms: Option, -) -> &'static str { - const ACTIVE_RECENT_MS: u64 = 1_000; - match (encoded_age_ms, decoded_age_ms, sink_age_ms) { - (Some(encoded), _, _) if encoded > VIDEO_STALL_WARNING_MS => "video-rtp-idle", - (Some(encoded), Some(decoded), _) - if encoded <= ACTIVE_RECENT_MS && decoded > VIDEO_STALL_WARNING_MS => - { - "decode-chain-stalled" - } - (_, Some(decoded), Some(sink)) - if decoded <= ACTIVE_RECENT_MS && sink > VIDEO_STALL_WARNING_MS => - { - "present-chain-stalled" - } - (None, _, _) => "video-rtp-not-observed", - _ => "video-output-stalled", - } -} - -pub(crate) fn watch_audio_activity(sink: &gst::Element, video_liveness: &VideoLivenessMonitor) { - let Some(sink_pad) = sink.static_pad("sink") else { - return; - }; - let monitor = video_liveness.clone(); - sink_pad.add_probe(gst::PadProbeType::BUFFER, move |_pad, _info| { - monitor.record_audio_buffer(); - gst::PadProbeReturn::Ok - }); -} - -pub(crate) fn watch_first_sink_buffer( - sink: &gst::Element, - media_label: &str, - event_sender: &Option>, - streaming_reported: &Arc, -) { - let Some(sink_pad) = sink.static_pad("sink") else { - return; - }; - let sender = event_sender.clone(); - let label = media_label.to_owned(); - let reported = streaming_reported.clone(); - sink_pad.add_probe(gst::PadProbeType::BUFFER, move |pad, _info| { - let caps = pad - .current_caps() - .map(|caps| caps.to_string()) - .unwrap_or_else(|| "unknown caps".to_owned()); - let zero_copy_d3d11 = caps.contains("memory:D3D11Memory"); - let zero_copy_d3d12 = caps.contains("memory:D3D12Memory"); - let memory_mode = memory_mode_from_caps(&caps); - let zero_copy = is_zero_copy_memory_mode(memory_mode); - send_log( - &sender, - "info", - format!( - "First decoded {label} buffer reached native sink; caps={caps}; memoryMode={memory_mode}; zeroCopy={zero_copy}; zeroCopyD3D11={zero_copy_d3d11}; zeroCopyD3D12={zero_copy_d3d12}." - ), - ); - - if label == "video" && !reported.swap(true, Ordering::SeqCst) { - if let Some(event_sender) = &sender { - let message = if use_external_renderer_window() { - "Native video frames reached the external low-latency GStreamer renderer window." - } else { - "Native video frames reached the internal child-surface GStreamer renderer." - }; - let _ = event_sender.send(Event::Status { - status: "streaming", - message: Some(message.to_owned()), - }); - } - } - - gst::PadProbeReturn::Remove - }); -} - -pub(crate) fn watch_rtp_video_bitrate( - pad: &gst::Pad, - video_liveness: VideoLivenessMonitor, - event_sender: &Option>, -) { - let sender = event_sender.clone(); - pad.add_probe(gst::PadProbeType::BUFFER, move |_pad, info| { - if let Some(buffer) = info.buffer() { - video_liveness.record_encoded_buffer(buffer.size()); - if video_liveness.log_first_encoded_once() { - send_log( - &sender, - "info", - format!( - "First encoded RTP video buffer arrived; size={} bytes.", - buffer.size() - ), - ); - } - } - gst::PadProbeReturn::Ok - }); -} - -pub(crate) fn watch_video_sink_rate( - sink: &gst::Element, - event_sender: &Option>, - video_liveness: Option, -) { - let Some(sink_pad) = sink.static_pad("sink") else { - return; - }; - let sink = sink.clone(); - watch_video_pad_rate( - &sink_pad, - "Native video sink rate", - Some(sink), - event_sender, - video_liveness.map(|monitor| (monitor, VideoLivenessPadKind::Sink)), - ); -} - -pub(crate) fn watch_video_decoded_rate( - queue: &gst::Element, - event_sender: &Option>, - video_liveness: Option, -) { - let Some(queue_sink_pad) = queue.static_pad("sink") else { - return; - }; - watch_video_pad_rate( - &queue_sink_pad, - "Native decoded video rate before present queue", - None, - event_sender, - video_liveness.map(|monitor| (monitor, VideoLivenessPadKind::Decoded)), - ); -} - -pub(crate) fn watch_video_caps_transitions( - element: &gst::Element, - source: &'static str, - event_sender: &Option>, - video_liveness: VideoLivenessMonitor, -) { - let Some(src_pad) = element.static_pad("src") else { - return; - }; - let sender = event_sender.clone(); - let monitor = video_liveness.clone(); - let last_caps = Arc::new(Mutex::new(None::)); - let last_framerate = Arc::new(Mutex::new(None::)); - let last_memory_mode = Arc::new(Mutex::new(None::)); - let last_caps_for_probe = last_caps.clone(); - let last_framerate_for_probe = last_framerate.clone(); - let last_memory_mode_for_probe = last_memory_mode.clone(); - - src_pad.add_probe(gst::PadProbeType::BUFFER, move |pad, _info| { - let caps = pad - .current_caps() - .map(|caps| caps.to_string()) - .unwrap_or_else(|| "unknown caps".to_owned()); - let framerate = caps_framerate_summary(&caps); - let memory_mode = Some(memory_mode_from_caps(&caps).to_owned()); - - let Ok(mut old_caps) = last_caps_for_probe.lock() else { - return gst::PadProbeReturn::Ok; - }; - let Ok(mut old_framerate) = last_framerate_for_probe.lock() else { - return gst::PadProbeReturn::Ok; - }; - let Ok(mut old_memory_mode) = last_memory_mode_for_probe.lock() else { - return gst::PadProbeReturn::Ok; - }; - - if old_caps.is_none() { - *old_caps = Some(caps); - *old_framerate = framerate; - *old_memory_mode = memory_mode; - return gst::PadProbeReturn::Ok; - } - - let caps_changed = old_caps.as_ref() != Some(&caps); - let framerate_changed = *old_framerate != framerate; - let memory_changed = *old_memory_mode != memory_mode; - if caps_changed || framerate_changed || memory_changed { - monitor.record_transition( - &format!("{source}-caps-change"), - source, - old_caps.clone(), - Some(caps.clone()), - old_framerate.clone(), - framerate.clone(), - old_memory_mode.clone(), - memory_mode.clone(), - &sender, - ); - *old_caps = Some(caps); - *old_framerate = framerate; - *old_memory_mode = memory_mode; - } - - gst::PadProbeReturn::Ok - }); -} - -pub(crate) fn watch_video_sink_caps_transitions( - sink: &gst::Element, - event_sender: &Option>, - video_liveness: Option, -) { - let Some(monitor) = video_liveness else { - return; - }; - let Some(sink_pad) = sink.static_pad("sink") else { - return; - }; - let sender = event_sender.clone(); - let last_caps = Arc::new(Mutex::new(None::)); - let last_framerate = Arc::new(Mutex::new(None::)); - let last_memory_mode = Arc::new(Mutex::new(None::)); - let last_caps_for_probe = last_caps.clone(); - let last_framerate_for_probe = last_framerate.clone(); - let last_memory_mode_for_probe = last_memory_mode.clone(); - - sink_pad.add_probe(gst::PadProbeType::BUFFER, move |pad, _info| { - let caps = pad - .current_caps() - .map(|caps| caps.to_string()) - .unwrap_or_else(|| "unknown caps".to_owned()); - let framerate = caps_framerate_summary(&caps); - let memory_mode = Some(memory_mode_from_caps(&caps).to_owned()); - - let Ok(mut old_caps) = last_caps_for_probe.lock() else { - return gst::PadProbeReturn::Ok; - }; - let Ok(mut old_framerate) = last_framerate_for_probe.lock() else { - return gst::PadProbeReturn::Ok; - }; - let Ok(mut old_memory_mode) = last_memory_mode_for_probe.lock() else { - return gst::PadProbeReturn::Ok; - }; - - if old_caps.is_none() { - *old_caps = Some(caps); - *old_framerate = framerate; - *old_memory_mode = memory_mode; - return gst::PadProbeReturn::Ok; - } - - let caps_changed = old_caps.as_ref() != Some(&caps); - let framerate_changed = *old_framerate != framerate; - let memory_changed = *old_memory_mode != memory_mode; - if caps_changed || framerate_changed || memory_changed { - monitor.record_transition( - "sink-caps-change", - "sink", - old_caps.clone(), - Some(caps.clone()), - old_framerate.clone(), - framerate.clone(), - old_memory_mode.clone(), - memory_mode.clone(), - &sender, - ); - *old_caps = Some(caps); - *old_framerate = framerate; - *old_memory_mode = memory_mode; - } - - gst::PadProbeReturn::Ok - }); -} - -pub(crate) fn install_present_limiter( - sink: &gst::Element, - present_max_fps: Arc, - event_sender: &Option>, - video_liveness: Option, -) { - let Some(sink_pad) = sink.static_pad("sink") else { - return; - }; - - let sender = event_sender.clone(); - let monitor = video_liveness.clone(); - let state = Arc::new(Mutex::new(PresentLimiterState { - next_present_at: Instant::now(), - last_log_at: Instant::now(), - passed: 0, - dropped: 0, - active_fps: 0, - })); - - sink_pad.add_probe(gst::PadProbeType::BUFFER, move |_pad, _info| { - let target_fps = present_max_fps.load(Ordering::Relaxed); - if target_fps == 0 { - return gst::PadProbeReturn::Ok; - } - - let Ok(mut state) = state.lock() else { - return gst::PadProbeReturn::Ok; - }; - - let now = Instant::now(); - if state.active_fps != target_fps { - state.active_fps = target_fps; - state.next_present_at = now; - state.last_log_at = now; - state.passed = 0; - state.dropped = 0; - if let Some(monitor) = &monitor { - monitor.record_present_pacing_change(); - } - } - - let frame_interval = Duration::from_secs_f64(1.0 / f64::from(target_fps.max(1))); - if now < state.next_present_at { - state.dropped = state.dropped.saturating_add(1); - return gst::PadProbeReturn::Drop; - } - - state.passed = state.passed.saturating_add(1); - while state.next_present_at <= now { - state.next_present_at += frame_interval; - } - let elapsed = state.last_log_at.elapsed(); - if elapsed >= VIDEO_SINK_RATE_LOG_INTERVAL { - let passed = state.passed; - let dropped = state.dropped; - send_log( - &sender, - "debug", - format!( - "Native present limiter: target={target_fps} fps; passed={passed}; dropped={dropped} over {:.1}s.", - elapsed.as_secs_f64() - ), - ); - state.last_log_at = now; - state.passed = 0; - state.dropped = 0; - } - - gst::PadProbeReturn::Ok - }); -} - -#[derive(Debug)] -struct PresentLimiterState { - next_present_at: Instant, - last_log_at: Instant, - passed: u32, - dropped: u32, - active_fps: u32, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum VideoLivenessPadKind { - Decoded, - Sink, -} - -fn watch_video_pad_rate( - pad: &gst::Pad, - label: &'static str, - sink: Option, - event_sender: &Option>, - video_liveness: Option<(VideoLivenessMonitor, VideoLivenessPadKind)>, -) { - let sender = event_sender.clone(); - let state = Arc::new(Mutex::new((Instant::now(), 0u32))); - - pad.add_probe(gst::PadProbeType::BUFFER, move |pad, _info| { - if let Some((monitor, kind)) = &video_liveness { - match kind { - VideoLivenessPadKind::Decoded => monitor.record_decoded_buffer(), - VideoLivenessPadKind::Sink => monitor.record_sink_buffer(), - } - } - - let Ok(mut state) = state.lock() else { - return gst::PadProbeReturn::Ok; - }; - - state.1 = state.1.saturating_add(1); - let elapsed = state.0.elapsed(); - if elapsed >= VIDEO_SINK_RATE_LOG_INTERVAL { - let frames = state.1; - let fps = f64::from(frames) / elapsed.as_secs_f64(); - let caps = pad - .current_caps() - .map(|caps| caps.to_string()) - .unwrap_or_else(|| "unknown caps".to_owned()); - let zero_copy_d3d11 = caps.contains("memory:D3D11Memory"); - let zero_copy_d3d12 = caps.contains("memory:D3D12Memory"); - let memory_mode = memory_mode_from_caps(&caps); - let zero_copy = is_zero_copy_memory_mode(memory_mode); - if let Some((monitor, _)) = &video_liveness { - monitor.update_caps(&caps); - } - let caps_framerate = - caps_framerate_summary(&caps).unwrap_or_else(|| "unknown".to_owned()); - let requested_fps = video_liveness - .as_ref() - .and_then(|(monitor, _)| monitor.requested_fps()); - let requested_fps_summary = requested_fps - .map(|fps| format!("; requestedFps={fps}")) - .unwrap_or_default(); - if let (Some((monitor, _)), Some(requested_fps), Some(caps_framerate_value)) = ( - video_liveness.as_ref(), - requested_fps, - caps_framerate_summary(&caps), - ) { - let expected = format!("{requested_fps}/1"); - if caps_framerate_value != expected && monitor.warn_framerate_mismatch_once() { - monitor.record_transition( - "high-fps-transition-risk", - label, - None, - Some(caps.clone()), - None, - Some(caps_framerate_value.clone()), - None, - Some(memory_mode.to_owned()), - &sender, - ); - send_log( - &sender, - "warn", - format!( - "Native video caps framerate {caps_framerate_value} does not match requestedFps={requested_fps}; this can destabilize high-FPS native playback scheduling and buffer pools." - ), - ); - } - } - let sink_stats = sink - .as_ref() - .map(|sink| format!("; {}", sink_stats_summary(sink))) - .unwrap_or_default(); - - send_log( - &sender, - "debug", - format!( - "{label}: {fps:.1} fps; capsFramerate={caps_framerate}{requested_fps_summary}; memoryMode={memory_mode}; zeroCopy={zero_copy}; zeroCopyD3D11={zero_copy_d3d11}; zeroCopyD3D12={zero_copy_d3d12}{sink_stats}." - ), - ); - - *state = (Instant::now(), 0); - } - - gst::PadProbeReturn::Ok - }); -} - -pub(crate) fn sink_stats_summary(sink: &gst::Element) -> String { - let stats = read_sink_stats(sink); - if !stats.available { - return "sinkStats=unavailable".to_owned(); - } - - format!( - "sinkStats rendered={} dropped={} averageRate={}", - stats - .rendered - .map(|value| value.to_string()) - .unwrap_or_else(|| "n/a".to_owned()), - stats - .dropped - .map(|value| value.to_string()) - .unwrap_or_else(|| "n/a".to_owned()), - stats - .average_rate - .map(|value| format!("{value:.1}")) - .unwrap_or_else(|| "n/a".to_owned()) - ) -} - -#[derive(Debug, Clone, Copy, Default)] -struct VideoSinkStats { - available: bool, - rendered: Option, - dropped: Option, - average_rate: Option, -} - -fn read_sink_stats(sink: &gst::Element) -> VideoSinkStats { - if sink.find_property("stats").is_none() { - return VideoSinkStats::default(); - } - - let stats = sink.property::("stats"); - VideoSinkStats { - available: true, - rendered: stats.get::("rendered").ok(), - dropped: stats.get::("dropped").ok(), - average_rate: stats.get::("average-rate").ok(), - } -} - -pub(crate) fn caps_framerate_summary(caps: &str) -> Option { - let marker = "framerate=(fraction)"; - let start = caps.find(marker)? + marker.len(); - let rest = &caps[start..]; - let semicolon = rest.find(';'); - let comma = rest.find(','); - let end = match (semicolon, comma) { - (Some(left), Some(right)) => left.min(right), - (Some(index), None) | (None, Some(index)) => index, - (None, None) => rest.len(), - }; - Some(rest[..end].trim().to_owned()) -} - -pub(crate) fn memory_mode_from_caps(caps: &str) -> &'static str { - if caps.contains("memory:D3D12Memory") { - "D3D12Memory" - } else if caps.contains("memory:D3D11Memory") { - "D3D11Memory" - } else if caps.contains("memory:VulkanImage") { - "VulkanImage" - } else if caps.contains("memory:VAMemory") { - "VAMemory" - } else if caps.contains("memory:GLMemory") { - "GLMemory" - } else { - "system-memory" - } -} - -pub(crate) fn is_zero_copy_memory_mode(memory_mode: &str) -> bool { - matches!( - memory_mode, - "D3D12Memory" | "D3D11Memory" | "VulkanImage" | "VAMemory" | "GLMemory" - ) -} diff --git a/native/opennow-streamer/src/gstreamer_pipeline.rs b/native/opennow-streamer/src/gstreamer_pipeline.rs deleted file mode 100644 index 72ffe032f..000000000 --- a/native/opennow-streamer/src/gstreamer_pipeline.rs +++ /dev/null @@ -1,3062 +0,0 @@ -use crate::gstreamer_backend::send_log; -use crate::gstreamer_config::{ - automatic_present_max_fps, requested_video_backend, use_external_renderer_window, - use_internal_renderer, vrr_present_max_fps, zero_copy_requested, EXTERNAL_RENDERER_ENV, - NATIVE_D3D_FULLSCREEN_ENV, NATIVE_PRESENT_MAX_FPS_ENV, NATIVE_VIDEO_API_ENV, - NATIVE_VIDEO_BACKEND_ENV, PRESENT_LIMITER_AUTO_SENTINEL, PRESENT_LIMITER_VRR_SENTINEL, -}; -#[cfg(target_os = "windows")] -use crate::gstreamer_input::NativeWindowInputBridge; -use crate::gstreamer_input::{ - create_input_data_channels, wire_remote_data_channels, GstreamerInputChannels, - GstreamerInputState, -}; -use crate::gstreamer_liveness::{ - install_present_limiter, watch_audio_activity, watch_first_sink_buffer, - watch_rtp_video_bitrate, watch_video_caps_transitions, watch_video_decoded_rate, - watch_video_sink_caps_transitions, watch_video_sink_rate, VideoLivenessMonitor, -}; -use crate::gstreamer_platform::{ - primary_display_refresh_hz, release_native_input_capture, start_external_renderer_window_guard, - update_external_renderer_surface, -}; -#[cfg(target_os = "windows")] -use crate::gstreamer_platform::arm_internal_child_input; -use crate::gstreamer_transitions::DEFAULT_VIDEO_QUEUE_DEPTH; -use crate::internal_renderer::InternalRenderer; -use crate::nvst_video::{ - annexb_appsrc_caps, spawn_nvst_udp_receive, NvstVideoReceiveHandle, -}; -use crate::protocol::{ - Event, IceCandidatePayload, IceServer, NativeRenderSurface, NativeStreamerSessionContext, - NativeVideoBackendCapability, NativeVideoCodecCapability, NvstVideoSession, -}; -use crate::sdp::IceCredentials; -use gst::glib; -use gst::prelude::*; -use gstreamer as gst; -use gstreamer_sdp as gst_sdp; -use gstreamer_webrtc as gst_webrtc; -use std::collections::{HashMap, HashSet}; -use std::ffi::CString; -use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; -use std::sync::mpsc::Sender; -use std::sync::{Arc, Mutex, OnceLock}; -use std::thread; - -const WEBRTC_LATENCY_MS: u32 = 2; -const DEFAULT_GFN_STUN_SERVER: &str = "stun://stun2.l.google.com:19302"; -const VIDEO_COMPRESSED_QUEUE_MAX_BUFFERS: u32 = 6; -pub(crate) const VIDEO_QUEUE_MAX_BUFFERS: u32 = DEFAULT_VIDEO_QUEUE_DEPTH; -const AUDIO_QUEUE_MAX_BUFFERS: u32 = 2; - -// gstreamer-rs exposes the generic ICE transport but not the NICE stream that -// owns remote credentials. GFN uses UUID ICE passwords, so we need the actual -// NICE stream after GStreamer's SDP parser validates a sanitized copy. -#[repr(C)] -struct GstWebRTCNiceTransportCompat { - parent: gst_webrtc::ffi::GstWebRTCICETransport, - stream: *mut gst_webrtc::ffi::GstWebRTCICEStream, - _priv: glib::ffi::gpointer, -} - -#[derive(Debug, Clone, Copy)] -struct ActualNiceIceStream { - ptr: *mut gst_webrtc::ffi::GstWebRTCICEStream, - stream_id: u32, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum DecodedMediaKind { - Audio, - Video, - Unknown, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum RtpVideoChainRole { - Depayloader, - Parser, - PreDecodeQueue, - Decoder, - PostDecodeRateSetter, - PostDecodeConverter, - PostDecodeCapsFilter, - StatsOverlay, - PostDecodeQueue, - Sink, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum RtpVideoApi { - D3D11, - D3D12, - VideoToolbox, - Nvdec, - Vaapi, - V4L2, - Vulkan, - Software, -} - -impl RtpVideoApi { - fn label(self) -> &'static str { - match self { - Self::D3D11 => "D3D11", - Self::D3D12 => "D3D12", - Self::VideoToolbox => "VideoToolbox", - Self::Nvdec => "NVIDIA NVDEC", - Self::Vaapi => "VAAPI", - Self::V4L2 => "V4L2", - Self::Vulkan => "Vulkan", - Self::Software => "software", - } - } - - fn capability_id(self) -> &'static str { - match self { - Self::D3D11 => "d3d11", - Self::D3D12 => "d3d12", - Self::VideoToolbox => "videotoolbox", - Self::Nvdec => "nvdec", - Self::Vaapi => "vaapi", - Self::V4L2 => "v4l2", - Self::Vulkan => "vulkan", - Self::Software => "software", - } - } - - fn platform(self) -> &'static str { - match self { - Self::D3D11 | Self::D3D12 => "windows", - Self::VideoToolbox => "macos", - Self::Nvdec | Self::Vaapi | Self::V4L2 => "linux", - Self::Vulkan if current_platform_label() == "windows" => "windows", - Self::Vulkan => "linux", - Self::Software => "cross-platform", - } - } - - fn memory_caps(self) -> Option<&'static str> { - match self { - // D3D decoders and sinks can negotiate GPU memory directly. Keep - // the capsfilter opt-in so startup does not fail when a live RTP - // stream's raw caps are still settling. - Self::D3D11 => zero_copy_requested().then_some("video/x-raw(memory:D3D11Memory)"), - Self::D3D12 => zero_copy_requested().then_some("video/x-raw(memory:D3D12Memory)"), - Self::VideoToolbox => zero_copy_requested().then_some("video/x-raw(memory:GLMemory)"), - Self::Vaapi => zero_copy_requested().then_some("video/x-raw(memory:VAMemory)"), - // Linux: keep Vulkan images in-GPU. Windows uses a DXVA→upload hybrid - // (vulkanh264dec currently SIGSEGVs on NVIDIA Windows), so skip a hard - // VulkanImage capsfilter on that path. - Self::Vulkan if cfg!(target_os = "windows") => None, - Self::Vulkan => Some("video/x-raw(memory:VulkanImage)"), - _ => None, - } - } - - fn post_decode_converter_factory(self) -> Option<&'static str> { - match self { - Self::D3D11 | Self::D3D12 => None, - // Windows Vulkan present chain inserts download/convert/upload explicitly. - Self::Vulkan if cfg!(target_os = "windows") => None, - Self::Vulkan => Some("vulkancolorconvert"), - Self::VideoToolbox | Self::Vaapi if zero_copy_requested() => None, - // Non-D3D hardware decoders are not guaranteed to negotiate directly with every - // platform sink. Keep these paths reliable with an explicit raw-video conversion stage. - Self::VideoToolbox | Self::Nvdec | Self::Vaapi | Self::Software => Some("videoconvert"), - // V4L2 stateless decoders expose DMABuf on devices such as Raspberry Pi. - // Let glimagesink import it directly instead of forcing a CPU copy. - Self::V4L2 => None, - } - } - - fn stats_overlay_factory(self) -> Option<&'static str> { - match self { - Self::D3D11 | Self::D3D12 => Some("dwritetextoverlay"), - _ => None, - } - } - - fn sink_factory(self) -> &'static str { - match self { - Self::D3D11 => "d3d11videosink", - Self::D3D12 => "d3d12videosink", - Self::VideoToolbox => "glimagesink", - Self::Nvdec => "glimagesink", - Self::Vaapi => "glimagesink", - Self::V4L2 => "glimagesink", - Self::Vulkan => "vulkansink", - Self::Software => "autovideosink", - } - } - - fn decoder_factory(self, codec: &str) -> Option<&'static str> { - match (self, codec) { - (Self::D3D11, "H265" | "HEVC") => Some("d3d11h265dec"), - (Self::D3D11, "H264") => Some("d3d11h264dec"), - (Self::D3D11, "AV1") => Some("d3d11av1dec"), - (Self::D3D12, "H265" | "HEVC") => Some("d3d12h265dec"), - (Self::D3D12, "H264") => Some("d3d12h264dec"), - (Self::D3D12, "AV1") => Some("d3d12av1dec"), - (Self::VideoToolbox, "H265" | "HEVC" | "H264") => Some("vtdec_hw"), - (Self::Nvdec, "H265" | "HEVC") => Some("nvh265dec"), - (Self::Nvdec, "H264") => Some("nvh264dec"), - (Self::Nvdec, "AV1") => Some("nvav1dec"), - (Self::Vaapi, "H265" | "HEVC") => Some("vah265dec"), - (Self::Vaapi, "H264") => Some("vah264dec"), - (Self::Vaapi, "AV1") => Some("vaav1dec"), - (Self::V4L2, "H265" | "HEVC") => Some("v4l2slh265dec"), - (Self::V4L2, "H264") => Some("v4l2slh264dec"), - (Self::V4L2, "AV1") => Some("v4l2slav1dec"), - // vulkanh264dec/vulkanh265dec SIGSEGV on current NVIDIA Windows drivers; - // use DXVA decode (prefer D3D12) and either D3D present (Internal) or - // upload into Vulkan (External). - (Self::Vulkan, "H265" | "HEVC") if cfg!(target_os = "windows") => Some("d3d12h265dec"), - (Self::Vulkan, "H264") if cfg!(target_os = "windows") => Some("d3d12h264dec"), - (Self::Vulkan, "AV1") if cfg!(target_os = "windows") => Some("d3d12av1dec"), - (Self::Vulkan, "H265" | "HEVC") => Some("vulkanh265dec"), - (Self::Vulkan, "H264") => Some("vulkanh264dec"), - (Self::Vulkan, "AV1") => Some("vulkanav1dec"), - (Self::Software, "H265" | "HEVC") => Some("avdec_h265"), - (Self::Software, "H264") => Some("avdec_h264"), - (Self::Software, "AV1") => Some("avdec_av1"), - _ => None, - } - } - - fn fallback_decoder_factories(self, codec: &str) -> &'static [&'static str] { - match (self, codec) { - (Self::Vaapi, "H265" | "HEVC") => &["vaapih265dec"], - (Self::Vaapi, "H264") => &["vaapih264dec"], - (Self::Vaapi, "AV1") => &["vaapiav1dec"], - (Self::V4L2, "H265" | "HEVC") => &["v4l2h265dec"], - (Self::V4L2, "H264") => &["v4l2h264dec"], - (Self::V4L2, "AV1") => &["v4l2av1dec"], - (Self::VideoToolbox, "H265" | "HEVC" | "H264") => &["vtdec"], - (Self::Vulkan, "H265" | "HEVC") if cfg!(target_os = "windows") => { - &["d3d11h265dec", "nvh265dec"] - } - (Self::Vulkan, "H264") if cfg!(target_os = "windows") => { - &["d3d11h264dec", "nvh264dec"] - } - (Self::Vulkan, "AV1") if cfg!(target_os = "windows") => { - &["d3d11av1dec", "nvav1dec"] - } - (Self::Software, "AV1") => &["dav1ddec", "av1dec"], - _ => &[], - } - } - - fn sink_fallback_factories(self) -> &'static [&'static str] { - match self { - Self::VideoToolbox => &["osxvideosink", "autovideosink"], - // Prefer X11-capable sinks first: Internal Linux embeds via GstVideoOverlay - // into an X11 child. waylandsink cannot paint into that handle. - Self::Nvdec | Self::Vaapi | Self::V4L2 => { - &["ximagesink", "xvimagesink", "glimagesink", "waylandsink", "autovideosink"] - } - Self::Software => &["ximagesink", "xvimagesink", "glimagesink", "waylandsink"], - _ => &[], - } - } - - /// Sinks that can bind to the Internal X11 child via GstVideoOverlay. - fn internal_x11_sink_candidates(self) -> &'static [&'static str] { - match self { - Self::Nvdec | Self::Vaapi | Self::V4L2 | Self::Software => { - &["glimagesink", "ximagesink", "xvimagesink"] - } - // vulkansink implements GstVideoOverlay on Linux, so it can bind - // directly to the X11 child while retaining VulkanImage memory. - Self::Vulkan => &["vulkansink"], - _ => &[], - } - } - - fn is_gpu_path(self) -> bool { - !matches!(self, Self::Software) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) struct RtpVideoChainSpec { - pub(crate) factory: &'static str, - pub(crate) role: RtpVideoChainRole, - pub(crate) caps: Option, -} - -impl RtpVideoChainSpec { - fn new(factory: &'static str, role: RtpVideoChainRole) -> Self { - Self { - factory, - role, - caps: None, - } - } - - fn with_caps(factory: &'static str, role: RtpVideoChainRole, caps: impl Into) -> Self { - Self { - factory, - role, - caps: Some(caps.into()), - } - } -} - -#[derive(Clone, Debug)] -pub(crate) struct GstreamerRenderState { - surface: Arc>>, - video_sink: Arc>>, - internal_renderer: Arc, - external_renderer_logged: Arc, - internal_renderer_logged: Arc, - external_window_guard_started: Arc, - external_window_guard_stop: Arc, -} - -impl Default for GstreamerRenderState { - fn default() -> Self { - Self { - surface: Arc::new(Mutex::new(None)), - video_sink: Arc::new(Mutex::new(None)), - internal_renderer: Arc::new(InternalRenderer::new()), - external_renderer_logged: Arc::new(AtomicBool::new(false)), - internal_renderer_logged: Arc::new(AtomicBool::new(false)), - external_window_guard_started: Arc::new(AtomicBool::new(false)), - external_window_guard_stop: Arc::new(AtomicBool::new(false)), - } - } -} - -impl GstreamerRenderState { - fn set_surface( - &self, - surface: NativeRenderSurface, - event_sender: &Option>, - ) -> Result<(), String> { - if let Ok(mut current) = self.surface.lock() { - *current = Some(surface); - } - self.apply(event_sender) - } - - fn set_video_sink( - &self, - sink: gst::Element, - event_sender: &Option>, - ) -> Result<(), String> { - if let Ok(mut current) = self.video_sink.lock() { - *current = Some(sink.clone()); - } - if use_internal_renderer() { - self.internal_renderer.set_video_sink(sink)?; - } - self.apply(event_sender) - } - - fn apply(&self, event_sender: &Option>) -> Result<(), String> { - if use_external_renderer_window() { - let sink_ready = self.video_sink.lock().ok().and_then(|sink| sink.clone()); - let Some(_sink) = sink_ready else { - return Ok(()); - }; - - if let Some(surface) = self.surface.lock().ok().and_then(|surface| surface.clone()) { - update_external_renderer_surface(&surface); - } - if !self - .external_window_guard_started - .swap(true, Ordering::SeqCst) - { - self.external_window_guard_stop - .store(false, Ordering::SeqCst); - start_external_renderer_window_guard( - event_sender.clone(), - self.external_window_guard_stop.clone(), - ); - } - if !self.external_renderer_logged.swap(true, Ordering::SeqCst) { - send_log( - event_sender, - "info", - format!( - "Using external native GStreamer renderer window; set {EXTERNAL_RENDERER_ENV}=0 for the internal child-surface renderer." - ), - ); - } - return Ok(()); - } - - let surface = self.surface.lock().ok().and_then(|surface| surface.clone()); - let Some(surface) = surface else { - return Ok(()); - }; - - if !self.internal_renderer_logged.swap(true, Ordering::SeqCst) { - send_log( - event_sender, - "info", - format!( - "Using internal native child-surface renderer; set {EXTERNAL_RENDERER_ENV}=1 for the floating GStreamer window." - ), - ); - } - - self.internal_renderer.apply_surface(&surface)?; - - // Keep ClipCursor / capture rect aligned with the StreamView hole, and - // (re)arm RawInput if the child HWND was recreated on parent change. - #[cfg(target_os = "windows")] - { - update_external_renderer_surface(&surface); - let hwnd = self.internal_renderer.child_handle(); - if hwnd != 0 { - let _ = arm_internal_child_input(hwnd); - } - } - - Ok(()) - } - - fn stop_external_renderer_window_guard(&self) { - self.external_window_guard_stop - .store(true, Ordering::SeqCst); - self.external_window_guard_started - .store(false, Ordering::SeqCst); - } - - fn destroy_internal_renderer(&self) { - self.internal_renderer.destroy(); - self.internal_renderer_logged - .store(false, Ordering::SeqCst); - } -} - -#[derive(Debug)] -pub(crate) struct GstreamerPipeline { - pub(crate) pipeline: gst::Pipeline, - pub(crate) webrtc: gst::Element, - input_state: GstreamerInputState, - input_channels: Option, - #[cfg(target_os = "windows")] - native_window_input_bridge: Option, - render_state: GstreamerRenderState, - present_max_fps: Arc, - d3d_fullscreen_sink: Arc, - /// When true, WebRTC RTP video pads are ignored (classic NVST UDP owns video). - skip_webrtc_video: Arc, - nvst_receive: Option, - video_liveness: VideoLivenessMonitor, - event_sender: Option>, - pub(crate) original_remote_ice_credentials: Option, -} - -impl GstreamerPipeline { - pub(crate) fn build( - event_sender: Option>, - ice_servers: &[IceServer], - ) -> Result { - init_gstreamer()?; - - let pipeline = gst::Pipeline::new(); - let webrtc = gst::ElementFactory::make("webrtcbin") - .name("opennow-webrtcbin") - .property_from_str("bundle-policy", "max-bundle") - .build() - .map_err(|error| format!("Failed to create webrtcbin: {error}"))?; - configure_webrtc_low_latency(&webrtc); - let stun_server = resolve_gstreamer_stun_server(ice_servers); - webrtc.set_property("stun-server", &stun_server); - send_log( - &event_sender, - "info", - format!("Configured GStreamer ICE with STUN server {stun_server}."), - ); - - let input_state = GstreamerInputState::default(); - let render_state = GstreamerRenderState::default(); - let video_liveness = VideoLivenessMonitor::default(); - wire_local_ice_events(&webrtc, event_sender.clone())?; - wire_webrtc_state_events(&webrtc, event_sender.clone()); - wire_remote_data_channels(&webrtc, event_sender.clone()); - start_gstreamer_bus_diagnostics( - &pipeline, - event_sender.clone(), - video_liveness.stop_flag(), - video_liveness.clone(), - ); - let present_max_fps = Arc::new(AtomicU32::new(0)); - let d3d_fullscreen_sink = Arc::new(AtomicBool::new(false)); - let skip_webrtc_video = Arc::new(AtomicBool::new(false)); - wire_incoming_media_sink( - &pipeline, - &webrtc, - event_sender.clone(), - render_state.clone(), - present_max_fps.clone(), - d3d_fullscreen_sink.clone(), - skip_webrtc_video.clone(), - video_liveness.clone(), - ); - - pipeline - .add(&webrtc) - .map_err(|error| format!("Failed to add webrtcbin to pipeline: {error}"))?; - pipeline - .set_state(gst::State::Ready) - .map_err(|error| format!("Failed to set GStreamer pipeline to Ready: {error:?}"))?; - - Ok(Self { - pipeline, - webrtc, - input_state, - input_channels: None, - #[cfg(target_os = "windows")] - native_window_input_bridge: None, - render_state, - present_max_fps, - d3d_fullscreen_sink, - skip_webrtc_video, - nvst_receive: None, - video_liveness, - event_sender, - original_remote_ice_credentials: None, - }) - } - - pub(crate) fn parse_offer_sdp(sdp: &str) -> Result { - init_gstreamer()?; - gst_sdp::SDPMessage::parse_buffer(sdp.as_bytes()) - .map_err(|error| format!("GStreamer rejected the remote SDP offer: {error:?}")) - } - - pub(crate) fn webrtc_name(&self) -> String { - self.webrtc.name().to_string() - } - - pub(crate) fn set_present_max_fps(&self, fps: u32) { - self.present_max_fps.store(fps, Ordering::SeqCst); - } - - pub(crate) fn set_d3d_fullscreen_sink(&self, enabled: bool) { - self.d3d_fullscreen_sink.store(enabled, Ordering::SeqCst); - } - - pub(crate) fn configure_stats( - &self, - context: &NativeStreamerSessionContext, - target_bitrate_kbps: u32, - ) { - self.video_liveness.configure(context, target_bitrate_kbps); - } - - /// Attach classic NVST UDP video: appsrc → parse → decoder → sink, plus UDP recv thread. - /// Keeps webrtcbin for SCTP input; ignores WebRTC RTP video pads. - pub(crate) fn attach_nvst_video( - &mut self, - session: NvstVideoSession, - fallback_codec: &str, - requested_fps: Option, - d3d_fullscreen_sink: bool, - ) -> Result<(), String> { - if self.nvst_receive.is_some() { - return Ok(()); - } - - let codec = session - .codec - .as_deref() - .filter(|c| !c.is_empty()) - .unwrap_or(fallback_codec); - let codec_upper = codec.to_ascii_uppercase(); - let encoding = match codec_upper.as_str() { - "H264" => "H264", - "H265" | "HEVC" => "H265", - other => { - return Err(format!( - "NVST classic UDP video scaffold supports H264/H265, got {other}" - )); - } - }; - - self.skip_webrtc_video.store(true, Ordering::SeqCst); - - let (video_api, mut specs) = rtp_video_chain_specs(encoding, requested_fps).ok_or_else(|| { - format!( - "NVST Annex-B decode chain unavailable for {encoding}; install GStreamer plugins or set {NATIVE_VIDEO_BACKEND_ENV}=software." - ) - })?; - // Drop RTP depayloader — appsrc feeds assembled Annex-B AUs. - specs.retain(|spec| spec.role != RtpVideoChainRole::Depayloader); - if specs - .first() - .is_none_or(|spec| spec.role != RtpVideoChainRole::Parser) - { - return Err(format!( - "NVST video chain for {encoding} is missing a parser after depayloader removal." - )); - } - - let caps_str = annexb_appsrc_caps(encoding); - let appsrc = gst::ElementFactory::make("appsrc") - .name("nvst-annexb") - .build() - .map_err(|error| format!("Failed to create nvst-annexb appsrc: {error}"))?; - let caps = caps_str - .parse::() - .map_err(|error| format!("Invalid NVST appsrc caps: {error}"))?; - appsrc.set_property("caps", &caps); - set_property_if_supported(&appsrc, "is-live", true); - set_property_from_str_if_supported(&appsrc, "format", "time"); - set_property_if_supported(&appsrc, "block", false); - set_property_if_supported(&appsrc, "max-bytes", 0u64); - set_property_from_str_if_supported(&appsrc, "stream-type", "stream"); - - let streaming_reported = Arc::new(AtomicBool::new(false)); - let mut elements: Vec = Vec::with_capacity(specs.len() + 1); - - let result = (|| -> Result<(), String> { - send_log( - &self.event_sender, - "info", - format!( - "Attaching NVST classic UDP video ({encoding}) via appsrc Annex-B → {}; {}", - video_api.label(), - format_video_chain_selection(encoding, video_api, &specs) - ), - ); - - let configured_present_max_fps = self.present_max_fps.load(Ordering::SeqCst); - let effective = effective_present_max_fps( - configured_present_max_fps, - requested_fps, - video_api, - primary_display_refresh_hz(), - ); - self.present_max_fps.store(effective, Ordering::SeqCst); - - self.pipeline - .add(&appsrc) - .map_err(|error| format!("Failed to add NVST appsrc: {error}"))?; - elements.push(appsrc.clone()); - - for spec in &specs { - let element = make_element(spec.factory)?; - configure_rtp_video_chain_element( - &element, - spec.clone(), - video_api, - d3d_fullscreen_sink, - ); - if spec.role == RtpVideoChainRole::StatsOverlay { - self.video_liveness.set_stats_overlay(Some(element.clone())); - } - self.pipeline.add(&element).map_err(|error| { - format!( - "Failed to add {} for NVST {encoding} video chain: {error}", - spec.factory - ) - })?; - elements.push(element); - } - - for pair in elements.windows(2) { - pair[0].link(&pair[1]).map_err(|error| { - format!( - "Failed to link {} -> {} for NVST {encoding}: {error:?}", - element_factory_name(&pair[0]), - element_factory_name(&pair[1]) - ) - })?; - } - - let sink = elements - .last() - .ok_or_else(|| format!("NVST {encoding} video chain has no sink."))?; - if let Some(post_decode_queue) = - specs - .iter() - .zip(elements.iter().skip(1)) - .find_map(|(spec, element)| { - (spec.role == RtpVideoChainRole::PostDecodeQueue).then_some(element) - }) - { - self.video_liveness - .set_post_decode_queue(post_decode_queue.clone()); - watch_video_decoded_rate( - post_decode_queue, - &self.event_sender, - Some(self.video_liveness.clone()), - ); - } - if let Some(pre_decode_queue) = - specs - .iter() - .zip(elements.iter().skip(1)) - .find_map(|(spec, element)| { - (spec.role == RtpVideoChainRole::PreDecodeQueue).then_some(element) - }) - { - self.video_liveness - .set_pre_decode_queue(pre_decode_queue.clone()); - } - if let Some(parser) = specs.iter().zip(elements.iter().skip(1)).find_map( - |(spec, element)| (spec.role == RtpVideoChainRole::Parser).then_some(element), - ) { - watch_video_caps_transitions( - parser, - "parser", - &self.event_sender, - self.video_liveness.clone(), - ); - } - if let Some(decoder) = specs.iter().zip(elements.iter().skip(1)).find_map( - |(spec, element)| (spec.role == RtpVideoChainRole::Decoder).then_some(element), - ) { - self.video_liveness.set_decoder(decoder.clone()); - watch_video_caps_transitions( - decoder, - "decoder", - &self.event_sender, - self.video_liveness.clone(), - ); - } - - self.render_state - .set_video_sink(sink.clone(), &self.event_sender) - .map_err(|error| { - format!("Failed to attach NVST video sink to native surface: {error}") - })?; - install_present_limiter( - sink, - self.present_max_fps.clone(), - &self.event_sender, - Some(self.video_liveness.clone()), - ); - watch_video_sink_caps_transitions( - sink, - &self.event_sender, - Some(self.video_liveness.clone()), - ); - watch_first_sink_buffer(sink, "video", &self.event_sender, &streaming_reported); - watch_video_sink_rate( - sink, - &self.event_sender, - Some(self.video_liveness.clone()), - ); - - for element in &elements { - element.sync_state_with_parent().map_err(|error| { - format!("Failed to sync NVST {encoding} video-chain element state: {error}") - })?; - } - - self.video_liveness.update_hardware_acceleration(format!( - "GStreamer {} (NVST UDP)", - video_api.label() - )); - self.video_liveness.start( - self.pipeline.clone(), - sink.clone(), - self.event_sender.clone(), - ); - - let handle = spawn_nvst_udp_receive( - session, - appsrc, - self.event_sender.clone(), - )?; - self.nvst_receive = Some(handle); - - // Ensure pipeline can run the appsrc branch even before WebRTC offer. - let _ = self.pipeline.set_state(gst::State::Playing); - - Ok(()) - })(); - - if result.is_err() { - self.skip_webrtc_video.store(false, Ordering::SeqCst); - for element in &elements { - let _ = element.set_state(gst::State::Null); - let _ = self.pipeline.remove(element); - } - } - - result - } - - fn ensure_input_data_channels( - &mut self, - partial_reliable_threshold_ms: u32, - ) -> Result<(), String> { - if self.input_channels.is_some() { - return Ok(()); - } - - self.input_state.reset(); - let channels = create_input_data_channels( - &self.webrtc, - self.input_state.clone(), - self.event_sender.clone(), - partial_reliable_threshold_ms, - )?; - let _ = channels.labels(); - self.input_channels = Some(channels); - self.ensure_native_window_input_bridge(); - Ok(()) - } - - #[cfg(target_os = "windows")] - fn ensure_native_window_input_bridge(&mut self) { - // Win32 RawInput: floating external window OR internal child HWND. - // Electron click-through across a topmost D3D sibling is unreliable. - if self.native_window_input_bridge.is_some() { - return; - } - let Some(input_channels) = self.input_channels.clone() else { - return; - }; - - self.native_window_input_bridge = Some(NativeWindowInputBridge::start( - self.input_state.clone(), - input_channels, - self.event_sender.clone(), - )); - if use_internal_renderer() { - let hwnd = self.render_state.internal_renderer.child_handle(); - if hwnd != 0 && arm_internal_child_input(hwnd) { - send_log( - &self.event_sender, - "info", - "Armed RawInput capture on the internal child HWND.".to_owned(), - ); - } - } - } - - #[cfg(not(target_os = "windows"))] - fn ensure_native_window_input_bridge(&mut self) { - if use_internal_renderer() { - return; - } - send_log( - &self.event_sender, - "warn", - format!( - "Native OS-level input capture is not implemented for {}; Electron input forwarding remains active.", - std::env::consts::OS - ), - ); - } - - pub(crate) fn negotiate_answer( - &mut self, - offer_sdp: gst_sdp::SDPMessage, - original_remote_credentials: Option<&IceCredentials>, - partial_reliable_threshold_ms: u32, - ) -> Result { - let offer = - gst_webrtc::WebRTCSessionDescription::new(gst_webrtc::WebRTCSDPType::Offer, offer_sdp); - self.pipeline - .set_state(gst::State::Playing) - .map_err(|error| { - format!("Failed to set GStreamer pipeline to Playing before negotiation: {error:?}") - })?; - self.set_description("set-remote-description", &offer)?; - if let Some(credentials) = original_remote_credentials { - self.original_remote_ice_credentials = Some(credentials.clone()); - self.try_restore_original_remote_ice_credentials("after remote description")?; - } - self.ensure_input_data_channels(partial_reliable_threshold_ms)?; - let answer = self.create_answer()?; - let answer_sdp = answer - .sdp() - .as_text() - .map_err(|error| format!("Failed to serialize GStreamer answer SDP: {error}"))?; - self.set_description("set-local-description", &answer)?; - self.try_restore_original_remote_ice_credentials("after local description")?; - Ok(answer_sdp) - } - - pub(crate) fn try_restore_original_remote_ice_credentials( - &mut self, - stage: &str, - ) -> Result { - let Some(credentials) = self.original_remote_ice_credentials.clone() else { - return Ok(false); - }; - - if credentials.ufrag.is_empty() || credentials.pwd.is_empty() { - return Err( - "Cannot restore original remote ICE credentials: offer credentials are empty." - .to_owned(), - ); - } - - let Some(ice_agent) = self - .webrtc - .property::>("ice-agent") - else { - return Err( - "Cannot restore original remote ICE credentials: webrtcbin has no ICE agent." - .to_owned(), - ); - }; - let ice_agent_ptr = ice_agent.as_ptr() as *mut gst_webrtc::ffi::GstWebRTCICE; - let ufrag = CString::new(credentials.ufrag.as_str()) - .map_err(|_| "Cannot restore original remote ICE credentials: ufrag contains NUL.")?; - let pwd = CString::new(credentials.pwd.as_str()) - .map_err(|_| "Cannot restore original remote ICE credentials: pwd contains NUL.")?; - - let streams = self.negotiated_nice_streams(); - if streams.is_empty() { - send_log( - &self.event_sender, - "warn", - format!( - "GStreamer has not exposed actual NICE ICE streams {stage}; deferring GFN remote ICE credential restoration." - ), - ); - return Ok(false); - } - - let mut restored = 0usize; - let stream_ids = streams - .iter() - .map(|stream| stream.stream_id) - .collect::>(); - for stream in &streams { - let accepted = unsafe { - gst_webrtc::ffi::gst_webrtc_ice_set_remote_credentials( - ice_agent_ptr, - stream.ptr, - ufrag.as_ptr(), - pwd.as_ptr(), - ) != glib::ffi::GFALSE - }; - if accepted { - restored += 1; - } else { - send_log( - &self.event_sender, - "warn", - format!( - "GStreamer ICE agent rejected original remote credentials for actual stream {}.", - stream.stream_id - ), - ); - } - } - - if restored == 0 { - send_log( - &self.event_sender, - "warn", - format!( - "GStreamer rejected original GFN remote ICE credentials on all actual streams {stage}; ICE may fail." - ), - ); - return Ok(false); - } - - send_log( - &self.event_sender, - "info", - format!( - "Restored original GFN remote ICE credentials on {restored}/{} actual GStreamer NICE ICE stream(s) {stage}; streamIds={stream_ids:?}.", - streams.len() - ), - ); - Ok(true) - } - - fn negotiated_nice_streams(&self) -> Vec { - let mut streams = Vec::new(); - let mut seen_stream_pointers = HashSet::new(); - let mut seen_transport_summaries = Vec::new(); - for index in 0..8 { - let transceiver = self - .webrtc - .emit_by_name::>( - "get-transceiver", - &[&(index as i32)], - ); - let Some(transceiver) = transceiver else { - continue; - }; - - if let Some(receiver) = transceiver.receiver() { - if let Some(transport) = receiver.transport() { - self.collect_nice_stream_from_dtls_transport( - &transport, - index, - "receiver", - &mut streams, - &mut seen_stream_pointers, - &mut seen_transport_summaries, - ); - } - } - if let Some(sender) = transceiver.sender() { - if let Some(transport) = sender.transport() { - self.collect_nice_stream_from_dtls_transport( - &transport, - index, - "sender", - &mut streams, - &mut seen_stream_pointers, - &mut seen_transport_summaries, - ); - } - } - } - - if !seen_transport_summaries.is_empty() { - send_log( - &self.event_sender, - "debug", - format!( - "GStreamer negotiated ICE transports: {}.", - seen_transport_summaries.join(", ") - ), - ); - } - streams - } - - fn collect_nice_stream_from_dtls_transport( - &self, - dtls_transport: &gst_webrtc::WebRTCDTLSTransport, - transceiver_index: u32, - direction: &str, - streams: &mut Vec, - seen_stream_pointers: &mut HashSet, - seen_transport_summaries: &mut Vec, - ) { - let session_id = dtls_transport.session_id(); - let Some(ice_transport) = dtls_transport.transport() else { - seen_transport_summaries.push(format!( - "transceiver {transceiver_index} {direction} dtlsSession={session_id} iceTransport=none" - )); - return; - }; - - let transport_type = ice_transport.type_().name().to_owned(); - let component = ice_transport.component(); - let state = ice_transport.state(); - let Some(stream) = nice_stream_from_ice_transport(&ice_transport) else { - seen_transport_summaries.push(format!( - "transceiver {transceiver_index} {direction} dtlsSession={session_id} iceTransportType={transport_type} component={component:?} state={state:?} stream=none" - )); - return; - }; - - seen_transport_summaries.push(format!( - "transceiver {transceiver_index} {direction} dtlsSession={session_id} iceTransportType={transport_type} component={component:?} state={state:?} streamId={}", - stream.stream_id - )); - - let stream_pointer = stream.ptr as usize; - if seen_stream_pointers.insert(stream_pointer) { - streams.push(stream); - } - } - - pub(crate) fn set_description( - &self, - signal_name: &'static str, - description: &gst_webrtc::WebRTCSessionDescription, - ) -> Result<(), String> { - let promise = gst::Promise::new(); - self.webrtc - .emit_by_name::<()>(signal_name, &[description, &promise]); - wait_for_promise(&promise, signal_name) - } - - fn create_answer(&self) -> Result { - let promise = gst::Promise::new(); - self.webrtc - .emit_by_name::<()>("create-answer", &[&None::, &promise]); - wait_for_promise(&promise, "create-answer")?; - let reply = promise - .get_reply() - .ok_or_else(|| "GStreamer create-answer resolved without a reply.".to_owned())?; - reply - .get::("answer") - .map_err(|error| { - format!( - "GStreamer create-answer reply did not contain an answer: {error}; reply={}", - describe_structure(reply) - ) - }) - } - - pub(crate) fn add_remote_ice(&mut self, candidate: &IceCandidatePayload) -> Result<(), String> { - if candidate.candidate.trim().is_empty() { - return Err("Remote ICE candidate is empty.".to_owned()); - } - self.try_restore_original_remote_ice_credentials("before adding remote ICE candidate")?; - let sdp_m_line_index = candidate.sdp_m_line_index.unwrap_or(0); - self.webrtc.emit_by_name::<()>( - "add-ice-candidate", - &[&sdp_m_line_index, &candidate.candidate], - ); - Ok(()) - } - - pub(crate) fn send_input_packet(&self, payload: &[u8], partially_reliable: bool) -> bool { - if !self.input_state.ready.load(Ordering::SeqCst) - || self.input_state.paused.load(Ordering::SeqCst) - { - return false; - } - - let Some(input_channels) = &self.input_channels else { - return false; - }; - - input_channels.send_packet(payload, partially_reliable) - } - - pub(crate) fn set_input_paused(&self, paused: bool) { - self.input_state.paused.store(paused, Ordering::SeqCst); - if paused { - release_native_input_capture(); - } - } - - pub(crate) fn update_render_surface(&self, surface: NativeRenderSurface) -> Result<(), String> { - self.video_liveness - .set_stats_overlay_visible(surface.visible && surface.show_stats); - self.render_state.set_surface(surface, &self.event_sender) - } - - pub(crate) fn stop(mut self) -> Result<(), String> { - if let Some(handle) = self.nvst_receive.take() { - handle.stop(); - } - self.skip_webrtc_video.store(false, Ordering::SeqCst); - self.video_liveness.set_stats_overlay_visible(false); - self.render_state.stop_external_renderer_window_guard(); - self.render_state.destroy_internal_renderer(); - #[cfg(target_os = "windows")] - if let Some(mut bridge) = self.native_window_input_bridge.take() { - bridge.stop(); - } - self.input_state.stop_heartbeat(); - self.video_liveness.stop(); - self.pipeline - .set_state(gst::State::Null) - .map(|_| ()) - .map_err(|error| format!("Failed to stop GStreamer pipeline: {error:?}")) - } -} - -pub(crate) fn resolve_gstreamer_stun_server(ice_servers: &[IceServer]) -> String { - ice_servers - .iter() - .flat_map(|server| server.urls.iter()) - .find_map(|url| { - let url = url.trim(); - if url.starts_with("stun://") { - Some(url.to_owned()) - } else { - url.strip_prefix("stun:") - .map(|endpoint| format!("stun://{endpoint}")) - } - }) - .unwrap_or_else(|| DEFAULT_GFN_STUN_SERVER.to_owned()) -} - -fn nice_stream_from_ice_transport( - transport: &gst_webrtc::WebRTCICETransport, -) -> Option { - if transport.type_().name() != "GstWebRTCNiceTransport" { - return None; - } - - unsafe { - let transport_ptr = transport.as_ptr() as *mut GstWebRTCNiceTransportCompat; - if transport_ptr.is_null() { - return None; - } - - let stream_ptr = (*transport_ptr).stream; - if stream_ptr.is_null() { - return None; - } - - Some(ActualNiceIceStream { - ptr: stream_ptr, - stream_id: (*stream_ptr).stream_id, - }) - } -} - -pub(crate) fn init_gstreamer() -> Result<(), String> { - gst::init().map_err(|error| format!("Failed to initialize GStreamer: {error}"))?; - #[cfg(target_os = "linux")] - { - static RTP_PLUGIN_REGISTRATION: OnceLock> = OnceLock::new(); - RTP_PLUGIN_REGISTRATION - .get_or_init(|| { - if gst::ElementFactory::find("rtpav1depay").is_some() { - return Ok(()); - } - gstrsrtp::plugin_register_static().map_err(|error| { - format!("Failed to register the bundled AV1 RTP plugin: {error}") - }) - }) - .clone() - } - #[cfg(not(target_os = "linux"))] - { - Ok(()) - } -} - -pub(crate) fn set_property_if_supported>( - element: &gst::Element, - name: &str, - value: T, -) { - if let Some(property) = element.find_property(name) { - if !property.flags().contains(glib::ParamFlags::WRITABLE) { - return; - } - - let value = value.into(); - let value_type = value.type_(); - let property_type = property.value_type(); - if value_type == property_type || value_type.is_a(property_type) { - element.set_property_from_value(name, &value); - } - } -} - -pub(crate) fn set_property_from_str_if_supported(element: &gst::Element, name: &str, value: &str) { - if element.find_property(name).is_some() { - element.set_property_from_str(name, value); - } -} - -pub(crate) fn configure_webrtc_low_latency(webrtc: &gst::Element) { - set_property_if_supported(webrtc, "latency", WEBRTC_LATENCY_MS); -} - -pub(crate) fn configure_queue_for_low_latency(element: &gst::Element, media_label: &str) { - let max_buffers = if media_label == "video" { - VIDEO_QUEUE_MAX_BUFFERS - } else { - AUDIO_QUEUE_MAX_BUFFERS - }; - - configure_queue(element, max_buffers, true); -} - -pub(crate) fn configure_queue(element: &gst::Element, max_buffers: u32, leaky_downstream: bool) { - set_property_if_supported(element, "max-size-buffers", max_buffers); - set_property_if_supported(element, "max-size-bytes", 0u32); - set_property_if_supported(element, "max-size-time", 0u64); - if leaky_downstream { - set_property_from_str_if_supported(element, "leaky", "downstream"); - } else { - set_property_from_str_if_supported(element, "leaky", "no"); - } -} - -pub(crate) fn configure_sink_for_low_latency(element: &gst::Element) { - // GFN-aligned present: never clock-sync or QoS-throttle the sink. Latency - // comes from decode + a depth-1 leaky post-decode queue + optional present - // limiter, not from GstBaseSink pacing. - set_property_if_supported(element, "sync", false); - set_property_if_supported(element, "async", false); - set_property_if_supported(element, "qos", false); - set_property_if_supported(element, "max-lateness", -1i64); - set_property_if_supported(element, "processing-deadline", 0u64); - set_property_if_supported(element, "render-delay", 0u64); - set_property_if_supported(element, "throttle-time", 0u64); - set_property_if_supported(element, "enable-last-sample", false); - set_property_if_supported(element, "show-preroll-frame", false); - set_property_if_supported(element, "redraw-on-update", true); - set_property_if_supported(element, "force-aspect-ratio", true); -} - -/// Configure d3d11/d3d12videosink for low-latency Internal/External present. -/// -/// GStreamer docs: `fullscreen` is ignored unless `fullscreen-toggle-mode` -/// includes `property`. Internal always keeps exclusive fullscreen off (caller -/// passes `d3d_fullscreen_sink=false`); External + Cloud G-Sync may enable it. -pub(crate) fn configure_d3d_video_sink(element: &gst::Element, d3d_fullscreen_sink: bool) { - configure_sink_for_low_latency(element); - // d3d12 only: attaching the swapchain directly to an external HWND can turn - // a present stall into upstream decode backpressure on the child-surface path. - set_property_if_supported(element, "direct-swapchain", false); - set_property_if_supported(element, "error-on-closed", false); - // RawInput owns mouse/keyboard; do not let the sink emit GstNavigation events. - set_property_if_supported(element, "enable-navigation-events", false); - set_property_if_supported(element, "fullscreen-on-alt-enter", false); - if d3d_fullscreen_sink { - set_property_from_str_if_supported(element, "fullscreen-toggle-mode", "property"); - set_property_if_supported(element, "fullscreen", true); - } else { - set_property_from_str_if_supported(element, "fullscreen-toggle-mode", "none"); - set_property_if_supported(element, "fullscreen", false); - } -} - -pub(crate) fn configure_stats_overlay_element(element: &gst::Element) { - set_property_if_supported(element, "visible", false); - set_property_if_supported(element, "text", ""); - set_property_if_supported(element, "auto-resize", true); - set_property_if_supported(element, "layout-x", 0.018f64); - set_property_if_supported(element, "layout-y", 0.018f64); - set_property_if_supported(element, "layout-width", 0.55f64); - set_property_if_supported(element, "layout-height", 0.18f64); - set_property_if_supported(element, "font-family", "Cascadia Mono"); - set_property_if_supported(element, "font-size", 18f32); - set_property_from_str_if_supported(element, "text-alignment", "leading"); - set_property_from_str_if_supported(element, "paragraph-alignment", "near"); - set_property_if_supported(element, "foreground-color", 0xF2FF_FFFFu32); - set_property_if_supported(element, "outline-color", 0xD000_0000u32); -} - -pub(crate) fn wait_for_promise(promise: &gst::Promise, operation: &str) -> Result<(), String> { - match promise.wait() { - gst::PromiseResult::Replied => { - if let Some(reply) = promise.get_reply() { - if reply.has_field("error") { - return Err(format!( - "GStreamer promise returned an error during {operation}: {}", - describe_structure(reply) - )); - } - } - Ok(()) - } - gst::PromiseResult::Interrupted => { - Err(format!("GStreamer promise interrupted during {operation}.")) - } - gst::PromiseResult::Expired => { - Err(format!("GStreamer promise expired during {operation}.")) - } - gst::PromiseResult::Pending => Err(format!( - "GStreamer promise still pending during {operation}." - )), - other => Err(format!( - "GStreamer promise failed during {operation}: {other:?}" - )), - } -} - -pub(crate) fn describe_structure(structure: &gst::StructureRef) -> String { - let fields = structure - .iter() - .map(|(name, value)| { - let rendered = value - .get::<&glib::Error>() - .map(|error| format!("{error:?}")) - .unwrap_or_else(|_| format!("{value:?}")); - format!("{}={rendered}", name.as_str()) - }) - .collect::>(); - - format!("{} {{{}}}", structure.name().as_str(), fields.join(", ")) -} - -fn wire_local_ice_events( - webrtc: &gst::Element, - event_sender: Option>, -) -> Result<(), String> { - let Some(event_sender) = event_sender else { - return Ok(()); - }; - - webrtc.connect("on-ice-candidate", false, move |values| { - let sdp_m_line_index = values.get(1).and_then(glib_value_to_u32).unwrap_or(0); - let candidate = values - .get(2) - .and_then(|value| value.get::().ok()) - .unwrap_or_default(); - - if !candidate.trim().is_empty() { - let _ = event_sender.send(Event::LocalIce { - candidate: IceCandidatePayload { - candidate, - sdp_mid: Some(sdp_m_line_index.to_string()), - sdp_m_line_index: Some(sdp_m_line_index), - username_fragment: None, - }, - }); - } - - None - }); - Ok(()) -} - -fn glib_value_to_u32(value: &glib::Value) -> Option { - let value_type = value.type_(); - if value_type == u32::static_type() { - return value.get::().ok(); - } - if value_type == i32::static_type() { - return value - .get::() - .ok() - .and_then(|value| u32::try_from(value).ok()); - } - if value_type == u64::static_type() { - return value - .get::() - .ok() - .and_then(|value| u32::try_from(value).ok()); - } - if value_type == i64::static_type() { - return value - .get::() - .ok() - .and_then(|value| u32::try_from(value).ok()); - } - None -} - -fn wire_webrtc_state_events(webrtc: &gst::Element, event_sender: Option>) { - wire_webrtc_property_event( - webrtc, - event_sender.clone(), - "ice-connection-state", - "ICE connection state", - ); - wire_webrtc_property_event( - webrtc, - event_sender.clone(), - "ice-gathering-state", - "ICE gathering state", - ); - wire_webrtc_property_event( - webrtc, - event_sender, - "connection-state", - "peer connection state", - ); -} - -fn wire_webrtc_property_event( - webrtc: &gst::Element, - event_sender: Option>, - property_name: &'static str, - label: &'static str, -) { - if event_sender.is_none() || webrtc.find_property(property_name).is_none() { - return; - } - - webrtc.connect_notify(Some(property_name), move |element, _| { - let value = element.property_value(property_name); - send_log( - &event_sender, - "debug", - format!("GStreamer WebRTC {label}: {value:?}."), - ); - }); -} - -fn start_gstreamer_bus_diagnostics( - pipeline: &gst::Pipeline, - event_sender: Option>, - stop: Arc, - video_liveness: VideoLivenessMonitor, -) { - let Some(bus) = pipeline.bus() else { - send_log( - &event_sender, - "warn", - "GStreamer pipeline has no bus; native diagnostics will be limited.".to_owned(), - ); - return; - }; - - thread::spawn(move || { - while !stop.load(Ordering::SeqCst) { - let Some(message) = bus.timed_pop_filtered( - gst::ClockTime::from_mseconds(250), - &[ - gst::MessageType::Error, - gst::MessageType::Warning, - gst::MessageType::Qos, - gst::MessageType::Latency, - gst::MessageType::StateChanged, - gst::MessageType::Eos, - ], - ) else { - continue; - }; - - match message.view() { - gst::MessageView::Error(error) => send_log( - &event_sender, - "error", - format!( - "GStreamer bus error from {}: {}; debug={:?}.", - message_src_name(&message), - error.error(), - error.debug() - ), - ), - gst::MessageView::Warning(warning) => send_log( - &event_sender, - "warn", - format!( - "GStreamer bus warning from {}: {}; debug={:?}.", - message_src_name(&message), - warning.error(), - warning.debug() - ), - ), - gst::MessageView::Qos(_) => send_log( - &event_sender, - "debug", - format!( - "GStreamer bus QoS from {}: {}.", - message_src_name(&message), - message_structure_summary(&message) - ), - ), - gst::MessageView::Latency(_) => send_log( - &event_sender, - "debug", - format!( - "GStreamer bus latency update from {}.", - message_src_name(&message) - ), - ), - gst::MessageView::StateChanged(state) => { - if message - .src() - .and_then(|src| src.clone().downcast::().ok()) - .is_some() - { - send_log( - &event_sender, - "debug", - format!( - "GStreamer pipeline state changed: {:?} -> {:?} pending {:?}.", - state.old(), - state.current(), - state.pending() - ), - ); - video_liveness.record_transition( - "pipeline-state-change", - "pipeline", - Some(format!("{:?}", state.old())), - Some(format!("{:?}", state.current())), - None, - None, - None, - None, - &event_sender, - ); - } - } - gst::MessageView::Eos(_) => send_log( - &event_sender, - "warn", - format!("GStreamer bus EOS from {}.", message_src_name(&message)), - ), - _ => {} - } - } - }); -} - -fn message_src_name(message: &gst::Message) -> String { - message - .src() - .map(|src| src.path_string().to_string()) - .unwrap_or_else(|| "unknown".to_owned()) -} - -fn message_structure_summary(message: &gst::Message) -> String { - message - .structure() - .map(|structure| structure.to_string()) - .unwrap_or_else(|| "no structure".to_owned()) -} - -fn wire_incoming_media_sink( - pipeline: &gst::Pipeline, - webrtc: &gst::Element, - event_sender: Option>, - render_state: GstreamerRenderState, - present_max_fps: Arc, - d3d_fullscreen_sink: Arc, - skip_webrtc_video: Arc, - video_liveness: VideoLivenessMonitor, -) { - let pipeline = pipeline.downgrade(); - let streaming_reported = Arc::new(AtomicBool::new(false)); - webrtc.connect_pad_added(move |_webrtc, src_pad| { - let Some(pipeline) = pipeline.upgrade() else { - return; - }; - let event_sender = event_sender.clone(); - - if !is_rtp_pad(src_pad) { - send_log( - &event_sender, - "debug", - format!( - "Ignoring non-RTP WebRTC pad with caps {:?}.", - pad_caps_name(src_pad) - ), - ); - return; - } - - if let Some(encoding) = rtp_video_encoding(src_pad) { - if skip_webrtc_video.load(Ordering::SeqCst) { - send_log( - &event_sender, - "info", - format!( - "Ignoring WebRTC RTP video pad ({encoding}); NVST classic UDP owns video." - ), - ); - if let Err(error) = - link_decoded_media_to_fakesink(&pipeline, src_pad, "ignored webrtc video") - { - send_log(&event_sender, "debug", error); - } - return; - } - match link_rtp_video_pad( - &pipeline, - src_pad, - &encoding, - &render_state, - &event_sender, - &streaming_reported, - present_max_fps.clone(), - d3d_fullscreen_sink.load(Ordering::SeqCst), - video_liveness.clone(), - ) { - Ok(()) => return, - Err(error) => send_log( - &event_sender, - "warn", - format!("{error}; falling back to decodebin."), - ), - } - } - - let decodebin = match make_element("decodebin") { - Ok(decodebin) => decodebin, - Err(error) => { - send_log(&event_sender, "warn", error); - return; - } - }; - - let decode_pipeline = pipeline.downgrade(); - let decode_sender = event_sender.clone(); - let decode_render_state = render_state.clone(); - let decode_streaming_reported = streaming_reported.clone(); - let decode_video_liveness = video_liveness.clone(); - decodebin.connect_pad_added(move |_decodebin, decoded_pad| { - let Some(pipeline) = decode_pipeline.upgrade() else { - return; - }; - let media_kind = decoded_media_kind(decoded_pad); - if let Err(error) = link_decoded_media_pad( - &pipeline, - decoded_pad, - &decode_render_state, - &decode_sender, - &decode_streaming_reported, - &decode_video_liveness, - ) { - send_log(&decode_sender, "warn", error); - if let Err(fallback_error) = - link_decoded_media_to_fakesink(&pipeline, decoded_pad, "decoded media fallback") - { - send_log(&decode_sender, "warn", fallback_error); - } - return; - } - - send_log( - &decode_sender, - "info", - format!( - "Linked decoded {} stream to native sink chain.", - media_kind.label() - ), - ); - }); - - if let Err(error) = pipeline.add(&decodebin) { - send_log( - &event_sender, - "warn", - format!("Failed to add decodebin: {error}"), - ); - return; - } - if let Err(error) = decodebin.sync_state_with_parent() { - send_log( - &event_sender, - "warn", - format!("Failed to sync decodebin state: {error}"), - ); - return; - } - - let Some(sink_pad) = decodebin.static_pad("sink") else { - send_log( - &event_sender, - "warn", - "decodebin has no sink pad.".to_owned(), - ); - return; - }; - if let Err(error) = src_pad.link(&sink_pad) { - send_log( - &event_sender, - "warn", - format!("Failed to link WebRTC RTP pad to decodebin: {error:?}"), - ); - } else if rtp_video_encoding(src_pad).is_some() { - video_liveness.set_rtp_video_src_pad(src_pad); - } - }); -} - -impl DecodedMediaKind { - fn label(self) -> &'static str { - match self { - Self::Audio => "audio", - Self::Video => "video", - Self::Unknown => "unknown", - } - } -} - -fn is_rtp_pad(pad: &gst::Pad) -> bool { - pad_caps_name(pad) - .as_deref() - .is_some_and(|name| name == "application/x-rtp") -} - -fn pad_caps_name(pad: &gst::Pad) -> Option { - let caps = pad.current_caps().unwrap_or_else(|| pad.query_caps(None)); - caps.structure(0) - .map(|structure| structure.name().to_string()) -} - -fn decoded_media_kind(pad: &gst::Pad) -> DecodedMediaKind { - match pad_caps_name(pad).as_deref() { - Some(name) if name.starts_with("video/") => DecodedMediaKind::Video, - Some(name) if name.starts_with("audio/") => DecodedMediaKind::Audio, - _ => DecodedMediaKind::Unknown, - } -} - -fn rtp_video_encoding(pad: &gst::Pad) -> Option { - let caps = pad.current_caps().unwrap_or_else(|| pad.query_caps(None)); - let structure = caps.structure(0)?; - if structure.name() != "application/x-rtp" { - return None; - } - - let media = structure.get::("media").ok()?; - if media != "video" { - return None; - } - - structure - .get::("encoding-name") - .ok() - .map(|encoding| encoding.to_ascii_uppercase()) -} - -fn rtp_video_depayloader_factory(codec: &str) -> Option<&'static str> { - match codec { - "H265" | "HEVC" => Some("rtph265depay"), - "H264" => Some("rtph264depay"), - "AV1" => Some("rtpav1depay"), - _ => None, - } -} - -fn rtp_video_parser_factory(codec: &str) -> Option<&'static str> { - match codec { - "H265" | "HEVC" => Some("h265parse"), - "H264" => Some("h264parse"), - "AV1" => Some("av1parse"), - _ => None, - } -} - -pub(crate) fn rtp_video_chain_definition( - encoding: &str, - video_api: RtpVideoApi, -) -> Option> { - let codec = encoding.to_ascii_uppercase(); - - #[cfg(target_os = "windows")] - if video_api == RtpVideoApi::Vulkan { - return windows_vulkan_present_chain_definition(codec.as_str()); - } - - let mut specs = vec![ - RtpVideoChainSpec::new( - rtp_video_depayloader_factory(codec.as_str())?, - RtpVideoChainRole::Depayloader, - ), - RtpVideoChainSpec::new( - rtp_video_parser_factory(codec.as_str())?, - RtpVideoChainRole::Parser, - ), - RtpVideoChainSpec::new("queue", RtpVideoChainRole::PreDecodeQueue), - RtpVideoChainSpec::new( - video_api.decoder_factory(codec.as_str())?, - RtpVideoChainRole::Decoder, - ), - ]; - - if let Some(memory_caps) = video_api.memory_caps() { - specs.push(RtpVideoChainSpec::with_caps( - "capsfilter", - RtpVideoChainRole::PostDecodeCapsFilter, - memory_caps, - )); - } - if let Some(converter) = video_api.post_decode_converter_factory() { - specs.push(RtpVideoChainSpec::new( - converter, - RtpVideoChainRole::PostDecodeConverter, - )); - } - if let Some(overlay) = video_api.stats_overlay_factory() { - specs.push(RtpVideoChainSpec::new( - overlay, - RtpVideoChainRole::StatsOverlay, - )); - } - specs.push(RtpVideoChainSpec::new( - "queue", - RtpVideoChainRole::PostDecodeQueue, - )); - specs.push(RtpVideoChainSpec::new( - video_api.sink_factory(), - RtpVideoChainRole::Sink, - )); - - Some(specs) -} - -/// Windows Vulkan path. -/// -/// Electron Internal hole-punch only composites DXGI swapchains on the child HWND. -/// A Win32 Vulkan surface on that HWND (or a GSTVULKAN child of it) presents black -/// even though vulkansink reports rendered frames. So: -/// - Internal: DXVA decode + `d3d12videosink` (D3D11 fallback; visible in Electron) -/// - External: DXVA decode + convert/upload + `vulkansink` (true Vulkan present) -/// -/// Native `vulkanh264dec` currently access-violates under NVIDIA Windows drivers. -#[cfg(target_os = "windows")] -fn windows_vulkan_present_chain_definition(codec: &str) -> Option> { - if use_internal_renderer() { - windows_vulkan_internal_present_chain_definition(codec) - } else { - windows_vulkan_external_present_chain_definition(codec) - } -} - -/// Internal Electron path: DXVA + D3D12 present (D3D11 fallback; DXGI hole-punch). -#[cfg(target_os = "windows")] -fn windows_vulkan_internal_present_chain_definition(codec: &str) -> Option> { - let decoder = RtpVideoApi::Vulkan.decoder_factory(codec)?; - let prefer_d3d12 = decoder.starts_with("d3d12"); - let sink = if prefer_d3d12 { - "d3d12videosink" - } else { - "d3d11videosink" - }; - let memory_api = if prefer_d3d12 { - RtpVideoApi::D3D12 - } else { - RtpVideoApi::D3D11 - }; - let mut specs = vec![ - RtpVideoChainSpec::new( - rtp_video_depayloader_factory(codec)?, - RtpVideoChainRole::Depayloader, - ), - RtpVideoChainSpec::new(rtp_video_parser_factory(codec)?, RtpVideoChainRole::Parser), - RtpVideoChainSpec::new("queue", RtpVideoChainRole::PreDecodeQueue), - RtpVideoChainSpec::new(decoder, RtpVideoChainRole::Decoder), - ]; - if let Some(memory_caps) = memory_api.memory_caps() { - specs.push(RtpVideoChainSpec::with_caps( - "capsfilter", - RtpVideoChainRole::PostDecodeCapsFilter, - memory_caps, - )); - } - specs.push(RtpVideoChainSpec::new( - "dwritetextoverlay", - RtpVideoChainRole::StatsOverlay, - )); - specs.push(RtpVideoChainSpec::new( - "queue", - RtpVideoChainRole::PostDecodeQueue, - )); - specs.push(RtpVideoChainSpec::new(sink, RtpVideoChainRole::Sink)); - Some(specs) -} - -/// External / capability path: DXVA + vulkanupload + vulkansink. -#[cfg(target_os = "windows")] -fn windows_vulkan_external_present_chain_definition(codec: &str) -> Option> { - let decoder = RtpVideoApi::Vulkan.decoder_factory(codec)?; - Some(vec![ - RtpVideoChainSpec::new( - rtp_video_depayloader_factory(codec)?, - RtpVideoChainRole::Depayloader, - ), - RtpVideoChainSpec::new(rtp_video_parser_factory(codec)?, RtpVideoChainRole::Parser), - RtpVideoChainSpec::new("queue", RtpVideoChainRole::PreDecodeQueue), - RtpVideoChainSpec::new(decoder, RtpVideoChainRole::Decoder), - // Composite diagnostics while frames are still in the DXVA/D3D path. - // dwritetextoverlay cannot consume VulkanImage memory after upload. - RtpVideoChainSpec::new("dwritetextoverlay", RtpVideoChainRole::StatsOverlay), - RtpVideoChainSpec::new("d3d11download", RtpVideoChainRole::PostDecodeConverter), - RtpVideoChainSpec::new("videoconvert", RtpVideoChainRole::PostDecodeConverter), - RtpVideoChainSpec::with_caps( - "capsfilter", - RtpVideoChainRole::PostDecodeCapsFilter, - "video/x-raw,format=RGBA", - ), - RtpVideoChainSpec::new("vulkanupload", RtpVideoChainRole::PostDecodeConverter), - RtpVideoChainSpec::new("queue", RtpVideoChainRole::PostDecodeQueue), - RtpVideoChainSpec::new(RtpVideoApi::Vulkan.sink_factory(), RtpVideoChainRole::Sink), - ]) -} - -fn preferred_rtp_video_apis(requested_fps: Option) -> Vec { - let requested = requested_video_backend(); - preferred_rtp_video_apis_for(requested.as_str(), requested_fps) -} - -pub(crate) fn preferred_rtp_video_apis_for( - requested: &str, - requested_fps: Option, -) -> Vec { - match requested { - "d3d11" => vec![RtpVideoApi::D3D11], - "d3d12" => vec![RtpVideoApi::D3D12], - "videotoolbox" | "vt" => vec![RtpVideoApi::VideoToolbox], - "nvdec" | "nvcodec" | "nvidia" => { - vec![RtpVideoApi::Nvdec, RtpVideoApi::Software] - } - "vaapi" | "va" => vec![RtpVideoApi::Vaapi, RtpVideoApi::Software], - "v4l2" | "v4l2stateless" => vec![RtpVideoApi::V4L2, RtpVideoApi::Software], - "vulkan" | "vk" => vec![RtpVideoApi::Vulkan, RtpVideoApi::Software], - "software" | "sw" => vec![RtpVideoApi::Software], - _ => default_rtp_video_api_priority(requested_fps), - } -} - -pub(crate) fn effective_present_max_fps( - configured_present_max_fps: u32, - requested_fps: Option, - video_api: RtpVideoApi, - display_hz: Option, -) -> u32 { - if configured_present_max_fps == PRESENT_LIMITER_VRR_SENTINEL { - if !matches!(video_api, RtpVideoApi::D3D11 | RtpVideoApi::D3D12) { - return 0; - } - return requested_fps - .filter(|fps| *fps > 0) - .map(|fps| vrr_present_max_fps(fps, display_hz)) - .unwrap_or(0); - } - - if configured_present_max_fps != PRESENT_LIMITER_AUTO_SENTINEL { - return configured_present_max_fps; - } - - // D3D11/D3D12 present (and Internal Vulkan→D3D) need the auto limiter so - // stream fps above display Hz does not stall the DXGI present path. - if !matches!(video_api, RtpVideoApi::D3D11 | RtpVideoApi::D3D12) - && !(cfg!(target_os = "windows") - && video_api == RtpVideoApi::Vulkan - && use_internal_renderer()) - { - return 0; - } - - requested_fps - .filter(|fps| *fps > 0) - .map(|fps| automatic_present_max_fps(fps, display_hz)) - .unwrap_or(0) -} - -pub(crate) fn default_rtp_video_api_priority(requested_fps: Option) -> Vec { - #[cfg(target_os = "windows")] - { - if should_prefer_d3d12_for_high_fps(requested_fps) { - return vec![ - RtpVideoApi::D3D12, - RtpVideoApi::D3D11, - RtpVideoApi::Software, - ]; - } - vec![ - RtpVideoApi::D3D11, - RtpVideoApi::D3D12, - RtpVideoApi::Software, - ] - } - #[cfg(target_os = "macos")] - { - let _ = requested_fps; - vec![RtpVideoApi::VideoToolbox, RtpVideoApi::Software] - } - #[cfg(all(target_os = "linux", target_arch = "aarch64"))] - { - let _ = requested_fps; - vec![ - RtpVideoApi::V4L2, - RtpVideoApi::Nvdec, - RtpVideoApi::Vaapi, - RtpVideoApi::Vulkan, - RtpVideoApi::Software, - ] - } - #[cfg(all(target_os = "linux", not(target_arch = "aarch64")))] - { - let _ = requested_fps; - vec![ - RtpVideoApi::Nvdec, - RtpVideoApi::Vaapi, - RtpVideoApi::Vulkan, - RtpVideoApi::V4L2, - RtpVideoApi::Software, - ] - } - #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] - { - let _ = requested_fps; - vec![RtpVideoApi::Software] - } -} - -fn should_prefer_d3d12_for_high_fps(requested_fps: Option) -> bool { - requested_fps.is_some_and(|fps| fps >= 200) -} - -fn rtp_video_chain_specs( - encoding: &str, - requested_fps: Option, -) -> Option<(RtpVideoApi, Vec)> { - preferred_rtp_video_apis(requested_fps) - .into_iter() - .find_map(|video_api| { - let codec = encoding.to_ascii_uppercase(); - let decoder = select_decoder_factory(video_api, codec.as_str())?; - let sink = select_sink_factory(video_api)?; - let mut specs = rtp_video_chain_definition(encoding, video_api)?; - for spec in &mut specs { - if spec.role == RtpVideoChainRole::Decoder { - spec.factory = decoder; - } else if spec.role == RtpVideoChainRole::Sink { - spec.factory = sink; - } - } - align_windows_vulkan_download_factory(&mut specs, decoder); - align_windows_vulkan_internal_present(&mut specs, decoder); - insert_requested_fps_capssetter(&mut specs, requested_fps); - specs.retain(|spec| { - spec.role != RtpVideoChainRole::StatsOverlay - || gst::ElementFactory::find(spec.factory).is_some() - }); - required_video_chain_elements_available(&specs).then_some((video_api, specs)) - }) -} - -fn align_windows_vulkan_download_factory(specs: &mut Vec, decoder: &str) { - #[cfg(target_os = "windows")] - { - let download = if decoder.starts_with("d3d12") { - Some("d3d12download") - } else if decoder.starts_with("d3d11") { - Some("d3d11download") - } else if decoder.starts_with("nv") { - // NVDEC Windows outputs system memory in our bundle; skip D3D download. - None - } else { - return; - }; - - match download { - Some(factory) => { - if let Some(spec) = specs.iter_mut().find(|spec| { - spec.role == RtpVideoChainRole::PostDecodeConverter - && (spec.factory == "d3d11download" || spec.factory == "d3d12download") - }) { - spec.factory = factory; - } - } - None => { - specs.retain(|spec| { - !(spec.role == RtpVideoChainRole::PostDecodeConverter - && (spec.factory == "d3d11download" || spec.factory == "d3d12download")) - }); - } - } - } - #[cfg(not(target_os = "windows"))] - { - let _ = (specs, decoder); - } -} - -/// Keep Internal Vulkan→D3D present matched to the selected DXVA decoder family. -#[cfg(target_os = "windows")] -fn align_windows_vulkan_internal_present(specs: &mut Vec, decoder: &str) { - if !use_internal_renderer() { - return; - } - let has_d3d_present = specs.iter().any(|spec| { - spec.role == RtpVideoChainRole::Sink - && (spec.factory == "d3d11videosink" || spec.factory == "d3d12videosink") - }); - if !has_d3d_present { - return; - } - - let (sink, memory_caps) = if decoder.starts_with("d3d12") - && gst::ElementFactory::find("d3d12videosink").is_some() - { - ("d3d12videosink", RtpVideoApi::D3D12.memory_caps()) - } else if decoder.starts_with("d3d11") - && gst::ElementFactory::find("d3d11videosink").is_some() - { - ("d3d11videosink", RtpVideoApi::D3D11.memory_caps()) - } else { - return; - }; - - if let Some(spec) = specs - .iter_mut() - .find(|spec| spec.role == RtpVideoChainRole::Sink) - { - spec.factory = sink; - } - if let Some(spec) = specs - .iter_mut() - .find(|spec| spec.role == RtpVideoChainRole::PostDecodeCapsFilter) - { - if let Some(caps) = memory_caps { - spec.caps = Some(caps.to_owned()); - } - } -} - -#[cfg(not(target_os = "windows"))] -fn align_windows_vulkan_internal_present(_specs: &mut Vec, _decoder: &str) {} - -fn insert_requested_fps_capssetter(specs: &mut Vec, requested_fps: Option) { - let Some(fps) = requested_fps.filter(|fps| *fps > 0) else { - return; - }; - if gst::ElementFactory::find("capssetter").is_none() { - return; - } - // Windows Vulkan hybrid / D3D present: forcing plain video/x-raw onto a D3D - // memory pad breaks caps negotiation. - if specs.iter().any(|spec| { - matches!( - spec.factory, - "d3d11download" - | "d3d12download" - | "vulkanupload" - | "d3d11videosink" - | "d3d12videosink" - | "d3d11h264dec" - | "d3d11h265dec" - | "d3d11av1dec" - | "d3d12h264dec" - | "d3d12h265dec" - | "d3d12av1dec" - ) - }) { - return; - } - let Some(decoder_index) = specs - .iter() - .position(|spec| spec.role == RtpVideoChainRole::Decoder) - else { - return; - }; - - specs.insert( - decoder_index + 1, - RtpVideoChainSpec::with_caps( - "capssetter", - RtpVideoChainRole::PostDecodeRateSetter, - format!("video/x-raw,framerate=(fraction){fps}/1"), - ), - ); -} - -fn select_decoder_factory(video_api: RtpVideoApi, codec: &str) -> Option<&'static str> { - let primary = video_api.decoder_factory(codec)?; - std::iter::once(primary) - .chain(video_api.fallback_decoder_factories(codec).iter().copied()) - .find(|factory| decoder_factory_usable(factory)) -} - -fn decoder_factory_usable(factory: &'static str) -> bool { - static DECODER_PROBES: OnceLock>> = OnceLock::new(); - let probes = DECODER_PROBES.get_or_init(|| Mutex::new(HashMap::new())); - if let Ok(probes) = probes.lock() { - if let Some(usable) = probes.get(factory) { - return *usable; - } - } - - let usable = gst::ElementFactory::make(factory) - .build() - .ok() - .is_some_and(|decoder| { - let usable = decoder.set_state(gst::State::Ready).is_ok(); - let _ = decoder.set_state(gst::State::Null); - usable - }); - if let Ok(mut probes) = probes.lock() { - probes.insert(factory, usable); - } - usable -} - -fn select_sink_factory(video_api: RtpVideoApi) -> Option<&'static str> { - // Internal Linux: never pick waylandsink for the X11 child overlay path. - #[cfg(target_os = "linux")] - if use_internal_renderer() { - let internal = video_api.internal_x11_sink_candidates(); - if let Some(factory) = internal - .iter() - .copied() - .find(|factory| gst::ElementFactory::find(factory).is_some()) - { - return Some(factory); - } - } - - // Internal Windows + Vulkan: Electron hole-punch cannot composite Win32 Vulkan - // swapchains; present with D3D12 (D3D11 fallback) VideoOverlay instead. - #[cfg(target_os = "windows")] - if use_internal_renderer() && video_api == RtpVideoApi::Vulkan { - return ["d3d12videosink", "d3d11videosink"] - .into_iter() - .find(|factory| gst::ElementFactory::find(factory).is_some()); - } - - select_capability_sink_factory(video_api) -} - -/// Sink advertised in capabilities / used when not overriding for Internal present. -fn select_capability_sink_factory(video_api: RtpVideoApi) -> Option<&'static str> { - std::iter::once(video_api.sink_factory()) - .chain(video_api.sink_fallback_factories().iter().copied()) - .find(|factory| gst::ElementFactory::find(factory).is_some()) -} - -fn required_video_chain_elements_available(specs: &[RtpVideoChainSpec]) -> bool { - specs - .iter() - .all(|spec| gst::ElementFactory::find(spec.factory).is_some()) -} - -fn all_rtp_video_apis() -> &'static [RtpVideoApi] { - &[ - RtpVideoApi::D3D12, - RtpVideoApi::D3D11, - RtpVideoApi::VideoToolbox, - RtpVideoApi::Nvdec, - RtpVideoApi::Vaapi, - RtpVideoApi::V4L2, - RtpVideoApi::Vulkan, - RtpVideoApi::Software, - ] -} - -fn all_video_codec_labels() -> &'static [&'static str] { - &["H264", "H265", "AV1"] -} - -pub(crate) fn current_platform_label() -> &'static str { - #[cfg(target_os = "windows")] - { - "windows" - } - #[cfg(target_os = "macos")] - { - "macos" - } - #[cfg(target_os = "linux")] - { - "linux" - } - #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] - { - "other" - } -} - -fn backend_runs_on_current_platform(video_api: RtpVideoApi) -> bool { - backend_runs_on_platform(video_api, current_platform_label()) -} - -pub(crate) fn backend_runs_on_platform(video_api: RtpVideoApi, platform: &str) -> bool { - match video_api { - RtpVideoApi::D3D11 | RtpVideoApi::D3D12 => platform == "windows", - RtpVideoApi::VideoToolbox => platform == "macos", - RtpVideoApi::Nvdec | RtpVideoApi::Vaapi | RtpVideoApi::V4L2 => platform == "linux", - RtpVideoApi::Vulkan => matches!(platform, "windows" | "linux"), - RtpVideoApi::Software => true, - } -} - -pub(crate) fn native_video_backend_capabilities() -> Vec { - all_rtp_video_apis() - .iter() - .copied() - .map(native_video_backend_capability) - .collect() -} - -fn native_video_backend_capability(video_api: RtpVideoApi) -> NativeVideoBackendCapability { - let platform_supported = backend_runs_on_current_platform(video_api); - // Advertise the true API sink (vulkansink). Internal Windows Vulkan may present - // via d3d12/d3d11videosink at session time for Electron hole-punch compatibility. - let sink_factory = platform_supported - .then(|| select_capability_sink_factory(video_api)) - .flatten(); - let codecs = all_video_codec_labels() - .iter() - .map(|codec| { - native_video_codec_capability(video_api, codec, platform_supported, sink_factory) - }) - .collect::>(); - let available = - platform_supported && sink_factory.is_some() && codecs.iter().any(|codec| codec.available); - let reason = if !platform_supported { - Some(format!( - "{} is a {} backend and does not run on {}.", - video_api.label(), - video_api.platform(), - current_platform_label() - )) - } else if sink_factory.is_none() { - Some(format!( - "{} sink is unavailable; install the platform GStreamer video sink plugins.", - video_api.label() - )) - } else if !available { - Some(format!( - "{} decoders are unavailable for H.264, H.265, and AV1.", - video_api.label() - )) - } else { - None - }; - - NativeVideoBackendCapability { - backend: video_api.capability_id().to_owned(), - platform: video_api.platform().to_owned(), - codecs, - zero_copy_modes: zero_copy_modes_for_backend(video_api), - sink: sink_factory.map(str::to_owned), - available, - reason, - } -} - -fn native_video_codec_capability( - video_api: RtpVideoApi, - codec: &str, - platform_supported: bool, - sink: Option<&'static str>, -) -> NativeVideoCodecCapability { - let depayloader = rtp_video_depayloader_factory(codec); - let parser = rtp_video_parser_factory(codec); - let decoder = platform_supported - .then(|| select_decoder_factory(video_api, codec)) - .flatten(); - // Capability checks the External Vulkan present chain so vulkansink/vulkanupload - // must be present even when Internal sessions present via D3D11. - let definition = { - #[cfg(target_os = "windows")] - { - if video_api == RtpVideoApi::Vulkan { - windows_vulkan_external_present_chain_definition(codec) - } else { - rtp_video_chain_definition(codec, video_api) - } - } - #[cfg(not(target_os = "windows"))] - { - rtp_video_chain_definition(codec, video_api) - } - }; - let available = platform_supported - && sink.is_some() - && decoder.is_some() - && depayloader.is_some_and(|factory| gst::ElementFactory::find(factory).is_some()) - && parser.is_some_and(|factory| gst::ElementFactory::find(factory).is_some()) - && definition.is_some_and(|mut specs| { - for spec in &mut specs { - if spec.role == RtpVideoChainRole::Decoder { - if let Some(decoder) = decoder { - spec.factory = decoder; - } - } else if spec.role == RtpVideoChainRole::Sink { - if let Some(sink) = sink { - spec.factory = sink; - } - } - } - specs.retain(|spec| { - spec.role != RtpVideoChainRole::StatsOverlay - || gst::ElementFactory::find(spec.factory).is_some() - }); - required_video_chain_elements_available(&specs) - }); - - let reason = if !platform_supported { - Some("Backend is not available on this platform.".to_owned()) - } else if depayloader.is_none() || parser.is_none() { - Some("RTP depayloader or parser is not mapped for this codec.".to_owned()) - } else if decoder.is_none() { - Some(format!( - "{} decoder for {codec} is not installed.", - video_api.label() - )) - } else if sink.is_none() { - Some(format!( - "{} video sink is not installed.", - video_api.label() - )) - } else if !available { - Some("Required GStreamer elements are not all available.".to_owned()) - } else { - None - }; - - NativeVideoCodecCapability { - codec: codec.to_ascii_lowercase(), - available, - decoder: decoder.map(str::to_owned), - parser: parser.map(str::to_owned), - depayloader: depayloader.map(str::to_owned), - reason, - } -} - -fn zero_copy_modes_for_backend(video_api: RtpVideoApi) -> Vec { - match video_api { - RtpVideoApi::D3D11 => vec!["D3D11Memory".to_owned()], - RtpVideoApi::D3D12 => vec!["D3D12Memory".to_owned()], - RtpVideoApi::VideoToolbox => vec!["GLMemory".to_owned()], - RtpVideoApi::Nvdec => Vec::new(), - RtpVideoApi::Vaapi => vec!["VAMemory".to_owned()], - // Linux keeps decoded frames as VulkanImage. Windows uses DXVA→upload, - // so there is no end-to-end VulkanImage zero-copy path yet. - RtpVideoApi::Vulkan if cfg!(target_os = "windows") => Vec::new(), - RtpVideoApi::Vulkan => vec!["VulkanImage".to_owned()], - RtpVideoApi::V4L2 => vec!["DMABuf".to_owned()], - RtpVideoApi::Software => Vec::new(), - } -} - -fn configure_rtp_video_chain_element( - element: &gst::Element, - spec: RtpVideoChainSpec, - video_api: RtpVideoApi, - d3d_fullscreen_sink: bool, -) { - match spec.role { - RtpVideoChainRole::Depayloader => { - set_property_if_supported(element, "request-keyframe", true); - // Hard-waiting after packet loss can freeze the visible frame while RTP is still flowing. - set_property_if_supported(element, "wait-for-keyframe", false); - } - RtpVideoChainRole::Parser => { - set_property_if_supported(element, "disable-passthrough", true); - set_property_if_supported(element, "config-interval", -1i32); - } - RtpVideoChainRole::PreDecodeQueue => { - configure_queue(element, VIDEO_COMPRESSED_QUEUE_MAX_BUFFERS, false); - } - RtpVideoChainRole::Decoder => { - set_property_if_supported(element, "automatic-request-sync-points", true); - set_property_if_supported(element, "discard-corrupted-frames", true); - set_property_if_supported(element, "min-force-key-unit-interval", 100_000_000u64); - set_property_if_supported(element, "qos", false); - } - RtpVideoChainRole::PostDecodeRateSetter => { - if let Some(caps) = spec - .caps - .as_deref() - .and_then(|caps| caps.parse::().ok()) - { - element.set_property("caps", &caps); - } - set_property_if_supported(element, "join", true); - set_property_if_supported(element, "replace", false); - set_property_if_supported(element, "qos", false); - } - RtpVideoChainRole::PostDecodeCapsFilter => { - if let Some(caps) = spec - .caps - .as_deref() - .and_then(|caps| caps.parse::().ok()) - { - element.set_property("caps", &caps); - } - } - RtpVideoChainRole::PostDecodeConverter => { - set_property_if_supported(element, "qos", false); - } - RtpVideoChainRole::StatsOverlay => { - configure_stats_overlay_element(element); - } - RtpVideoChainRole::PostDecodeQueue => { - configure_queue_for_low_latency(element, "video"); - } - RtpVideoChainRole::Sink => { - if matches!(video_api, RtpVideoApi::D3D11 | RtpVideoApi::D3D12) { - configure_d3d_video_sink(element, d3d_fullscreen_sink); - } else { - configure_sink_for_low_latency(element); - } - } - } -} - -fn link_rtp_video_pad( - pipeline: &gst::Pipeline, - src_pad: &gst::Pad, - encoding: &str, - render_state: &GstreamerRenderState, - event_sender: &Option>, - streaming_reported: &Arc, - present_max_fps: Arc, - d3d_fullscreen_sink: bool, - video_liveness: VideoLivenessMonitor, -) -> Result<(), String> { - if src_pad.is_linked() { - return Ok(()); - } - - let requested_fps = video_liveness.requested_fps(); - let (video_api, specs) = rtp_video_chain_specs(encoding, requested_fps).ok_or_else(|| { - format!( - "Explicit low-latency decode chain is unavailable for RTP {encoding}; install the platform GStreamer plugin packages or set {NATIVE_VIDEO_BACKEND_ENV}=software to force software decode." - ) - })?; - video_liveness.update_hardware_acceleration(format!("GStreamer {}", video_api.label())); - video_liveness.set_stats_overlay(None); - let mut elements = Vec::with_capacity(specs.len()); - - let result = (|| -> Result<(), String> { - send_log( - event_sender, - "info", - format_video_chain_selection(encoding, video_api, &specs), - ); - if video_api == RtpVideoApi::D3D12 { - send_log( - event_sender, - "info", - format_d3d12_selection_summary(requested_fps), - ); - } - let configured_present_max_fps = present_max_fps.load(Ordering::SeqCst); - let effective_present_max_fps = effective_present_max_fps( - configured_present_max_fps, - requested_fps, - video_api, - primary_display_refresh_hz(), - ); - present_max_fps.store(effective_present_max_fps, Ordering::SeqCst); - if effective_present_max_fps > 0 { - let reason = if configured_present_max_fps == PRESENT_LIMITER_AUTO_SENTINEL { - "auto-enabled for the D3D present path to prevent display-rate present backpressure" - .to_owned() - } else if configured_present_max_fps == PRESENT_LIMITER_VRR_SENTINEL { - "kept below the display refresh ceiling for VRR".to_owned() - } else { - format!("configured by {NATIVE_PRESENT_MAX_FPS_ENV}") - }; - send_log( - event_sender, - "info", - format!( - "Native present limiter enabled at {effective_present_max_fps} fps for {} video path; reason: {reason}.", - video_api.label() - ), - ); - } - if d3d_fullscreen_sink { - send_log( - event_sender, - "info", - format!( - "Native D3D sink fullscreen presentation enabled for Cloud G-Sync/VRR; set {NATIVE_D3D_FULLSCREEN_ENV}=0 to disable." - ), - ); - } - for spec in &specs { - let element = make_element(spec.factory)?; - configure_rtp_video_chain_element( - &element, - spec.clone(), - video_api, - d3d_fullscreen_sink, - ); - if spec.role == RtpVideoChainRole::StatsOverlay { - video_liveness.set_stats_overlay(Some(element.clone())); - } - pipeline.add(&element).map_err(|error| { - format!( - "Failed to add {} for RTP {encoding} video chain: {error}", - spec.factory - ) - })?; - elements.push(element); - } - - for pair in elements.windows(2) { - pair[0].link(&pair[1]).map_err(|error| { - format!( - "Failed to link {} -> {} for RTP {encoding} video chain: {error:?}", - element_factory_name(&pair[0]), - element_factory_name(&pair[1]) - ) - })?; - } - - let first = elements - .first() - .ok_or_else(|| format!("No elements created for RTP {encoding} video chain."))?; - let Some(first_sink_pad) = first.static_pad("sink") else { - return Err(format!( - "First RTP {encoding} video-chain element has no sink pad." - )); - }; - let sink = elements - .last() - .ok_or_else(|| format!("RTP {encoding} video chain has no sink element."))?; - if let Some(post_decode_queue) = - specs - .iter() - .zip(elements.iter()) - .find_map(|(spec, element)| { - (spec.role == RtpVideoChainRole::PostDecodeQueue).then_some(element) - }) - { - video_liveness.set_post_decode_queue(post_decode_queue.clone()); - watch_video_decoded_rate( - post_decode_queue, - event_sender, - Some(video_liveness.clone()), - ); - } - if let Some(pre_decode_queue) = - specs - .iter() - .zip(elements.iter()) - .find_map(|(spec, element)| { - (spec.role == RtpVideoChainRole::PreDecodeQueue).then_some(element) - }) - { - video_liveness.set_pre_decode_queue(pre_decode_queue.clone()); - } - if let Some(parser) = specs - .iter() - .zip(elements.iter()) - .find_map(|(spec, element)| (spec.role == RtpVideoChainRole::Parser).then_some(element)) - { - watch_video_caps_transitions(parser, "parser", event_sender, video_liveness.clone()); - } - if let Some(decoder) = specs - .iter() - .zip(elements.iter()) - .find_map(|(spec, element)| { - (spec.role == RtpVideoChainRole::Decoder).then_some(element) - }) - { - video_liveness.set_decoder(decoder.clone()); - watch_video_caps_transitions(decoder, "decoder", event_sender, video_liveness.clone()); - } - render_state - .set_video_sink(sink.clone(), event_sender) - .map_err(|error| { - format!("Failed to attach RTP {encoding} video sink to native surface: {error}") - })?; - install_present_limiter( - sink, - present_max_fps, - event_sender, - Some(video_liveness.clone()), - ); - watch_video_sink_caps_transitions(sink, event_sender, Some(video_liveness.clone())); - watch_first_sink_buffer(sink, "video", event_sender, streaming_reported); - watch_video_sink_rate(sink, event_sender, Some(video_liveness.clone())); - - for element in &elements { - element.sync_state_with_parent().map_err(|error| { - format!("Failed to sync RTP {encoding} video-chain element state: {error}") - })?; - } - src_pad - .link(&first_sink_pad) - .map_err(|error| format!("Failed to link RTP {encoding} video pad: {error:?}"))?; - video_liveness.set_rtp_video_src_pad(src_pad); - watch_rtp_video_bitrate(src_pad, video_liveness.clone(), event_sender); - video_liveness.start(pipeline.clone(), sink.clone(), event_sender.clone()); - - Ok(()) - })(); - - if result.is_err() { - for element in &elements { - let _ = element.set_state(gst::State::Null); - let _ = pipeline.remove(element); - } - } - - result?; - send_log( - event_sender, - "info", - format!( - "Linked RTP {encoding} video through explicit low-latency {} decode chain.", - video_api.label() - ), - ); - Ok(()) -} - -pub(crate) fn format_video_chain_selection( - encoding: &str, - video_api: RtpVideoApi, - specs: &[RtpVideoChainSpec], -) -> String { - let decoder = specs - .iter() - .find(|spec| spec.role == RtpVideoChainRole::Decoder) - .map(|spec| spec.factory) - .unwrap_or("unknown"); - let sink = specs - .iter() - .find(|spec| spec.role == RtpVideoChainRole::Sink) - .map(|spec| spec.factory) - .unwrap_or("unknown"); - let converter = specs - .iter() - .filter(|spec| spec.role == RtpVideoChainRole::PostDecodeConverter) - .map(|spec| spec.factory) - .collect::>() - .join("+"); - let converter = if converter.is_empty() { - "none".to_owned() - } else { - converter - }; - let memory = specs - .iter() - .find(|spec| spec.role == RtpVideoChainRole::PostDecodeCapsFilter) - .and_then(|spec| spec.caps.as_deref()) - .unwrap_or(if video_api.is_gpu_path() { - "auto-negotiated" - } else { - "system-memory" - }); - let acceleration = if video_api.is_gpu_path() { - "hardware" - } else { - "software" - }; - let path_note = if cfg!(target_os = "windows") && video_api == RtpVideoApi::Vulkan { - if sink == "d3d12videosink" { - " (DXVA decode + D3D12 present; Electron cannot composite Win32 vulkansink — use External for true Vulkan present)" - } else if sink == "d3d11videosink" { - " (DXVA decode + D3D11 present; Electron cannot composite Win32 vulkansink — use External for true Vulkan present)" - } else { - " (DXVA decode + Vulkan present; native vulkanh264dec is unstable on Windows)" - } - } else { - "" - }; - format!( - "Selected native {acceleration} video path for RTP {encoding}: backend={}, decoder={decoder}, converter={converter}, renderer={sink}, memory={memory}{path_note}.", - video_api.label() - ) -} - -fn format_d3d12_selection_summary(requested_fps: Option) -> String { - let backend_env = std::env::var(NATIVE_VIDEO_BACKEND_ENV).ok(); - let api_env = std::env::var(NATIVE_VIDEO_API_ENV).ok(); - let reason = if backend_env - .as_deref() - .is_some_and(|value| value.eq_ignore_ascii_case("d3d12")) - { - format!("forced by {NATIVE_VIDEO_BACKEND_ENV}=d3d12") - } else if api_env - .as_deref() - .is_some_and(|value| value.eq_ignore_ascii_case("d3d12")) - { - format!("forced by {NATIVE_VIDEO_API_ENV}=d3d12") - } else if should_prefer_d3d12_for_high_fps(requested_fps) { - format!( - "auto-selected for {} fps stream to avoid D3D11 display-rate present backpressure", - requested_fps - .map(|fps| fps.to_string()) - .unwrap_or_else(|| "high-FPS".to_owned()) - ) - } else { - "D3D11 was unavailable/probe failed".to_owned() - }; - - format!( - "Native D3D12 video path selected; reason: {reason}. env {NATIVE_VIDEO_BACKEND_ENV}={backend_env:?}, {NATIVE_VIDEO_API_ENV}={api_env:?}. If D3D12 stalls on a specific driver, force {NATIVE_VIDEO_BACKEND_ENV}=d3d11." - ) -} - -fn element_factory_name(element: &gst::Element) -> String { - element - .factory() - .map(|factory| factory.name().to_string()) - .unwrap_or_else(|| element.name().to_string()) -} - -fn link_decoded_media_pad( - pipeline: &gst::Pipeline, - src_pad: &gst::Pad, - render_state: &GstreamerRenderState, - event_sender: &Option>, - streaming_reported: &Arc, - video_liveness: &VideoLivenessMonitor, -) -> Result<(), String> { - if src_pad.is_linked() { - return Ok(()); - } - - match decoded_media_kind(src_pad) { - DecodedMediaKind::Video => link_media_chain( - pipeline, - src_pad, - &video_sink_factories(), - "video", - Some(render_state), - event_sender, - streaming_reported, - Some(video_liveness), - ), - DecodedMediaKind::Audio => link_media_chain( - pipeline, - src_pad, - &[ - ("queue", None), - ("audioconvert", None), - ("audioresample", None), - ("autoaudiosink", Some(false)), - ], - "audio", - None, - event_sender, - streaming_reported, - Some(video_liveness), - ), - DecodedMediaKind::Unknown => Err(format!( - "Unsupported decoded media caps {:?}; routing to fallback sink.", - pad_caps_name(src_pad) - )), - } -} - -fn video_sink_factories() -> Vec<(&'static str, Option)> { - #[cfg(target_os = "windows")] - { - let d3d_sink = ["d3d12videosink", "d3d11videosink"] - .into_iter() - .find(|factory| gst::ElementFactory::find(factory).is_some()); - if let Some(sink) = d3d_sink { - let mut factories = vec![("queue", None)]; - if gst::ElementFactory::find("dwritetextoverlay").is_some() { - factories.push(("dwritetextoverlay", None)); - } - factories.push((sink, Some(false))); - return factories; - } - } - - let mut factories = vec![("queue", None), ("videoconvert", None)]; - if gst::ElementFactory::find("dwritetextoverlay").is_some() { - factories.push(("dwritetextoverlay", None)); - } - factories.push(("autovideosink", Some(false))); - factories -} - -fn link_media_chain( - pipeline: &gst::Pipeline, - src_pad: &gst::Pad, - factories: &[(&str, Option)], - media_label: &str, - render_state: Option<&GstreamerRenderState>, - event_sender: &Option>, - streaming_reported: &Arc, - video_liveness: Option<&VideoLivenessMonitor>, -) -> Result<(), String> { - if media_label == "video" { - if let Some(video_liveness) = video_liveness { - video_liveness.set_stats_overlay(None); - } - } - - let mut elements = Vec::with_capacity(factories.len()); - for (factory, sync_property) in factories { - let factory = *factory; - let element = make_element(factory)?; - if factory == "queue" { - configure_queue_for_low_latency(&element, media_label); - } - if factory == "dwritetextoverlay" { - configure_stats_overlay_element(&element); - if media_label == "video" { - if let Some(video_liveness) = video_liveness { - video_liveness.set_stats_overlay(Some(element.clone())); - } - } - } - if sync_property.is_some() || factory.ends_with("sink") { - if factory == "d3d11videosink" || factory == "d3d12videosink" { - // Fallback decodebin path: never exclusive-fullscreen (Internal default). - configure_d3d_video_sink(&element, false); - } else { - configure_sink_for_low_latency(&element); - } - } - pipeline - .add(&element) - .map_err(|error| format!("Failed to add {factory} for {media_label}: {error}"))?; - elements.push(element); - } - - for pair in elements.windows(2) { - pair[0].link(&pair[1]).map_err(|error| { - format!( - "Failed to link {} -> {} for {media_label}: {error:?}", - pair[0] - .factory() - .map(|factory| factory.name()) - .unwrap_or_default(), - pair[1] - .factory() - .map(|factory| factory.name()) - .unwrap_or_default() - ) - })?; - } - - let first = elements - .first() - .ok_or_else(|| format!("No elements created for {media_label} sink chain."))?; - let Some(first_sink_pad) = first.static_pad("sink") else { - return Err(format!( - "First {media_label} sink-chain element has no sink pad." - )); - }; - src_pad - .link(&first_sink_pad) - .map_err(|error| format!("Failed to link decoded {media_label} pad: {error:?}"))?; - - if let Some(sink) = elements.last() { - if media_label == "video" { - if let Some(render_state) = render_state { - render_state - .set_video_sink(sink.clone(), event_sender) - .map_err(|error| { - format!("Failed to attach decoded video sink to native surface: {error}") - })?; - } - } - watch_first_sink_buffer(sink, media_label, event_sender, streaming_reported); - if media_label == "audio" { - if let Some(video_liveness) = video_liveness { - watch_audio_activity(sink, video_liveness); - } - } - if media_label == "video" { - if let Some(video_liveness) = video_liveness { - watch_video_sink_rate(sink, event_sender, Some(video_liveness.clone())); - video_liveness.start(pipeline.clone(), sink.clone(), event_sender.clone()); - } - } - } - - for element in &elements { - element.sync_state_with_parent().map_err(|error| { - format!("Failed to sync {media_label} sink-chain element state: {error}") - })?; - } - - Ok(()) -} - -fn link_decoded_media_to_fakesink( - pipeline: &gst::Pipeline, - src_pad: &gst::Pad, - label: &str, -) -> Result<(), String> { - if src_pad.is_linked() { - return Ok(()); - } - - let sink = gst::ElementFactory::make("fakesink") - .property("sync", false) - .property("async", false) - .build() - .map_err(|error| format!("Failed to create {label}: {error}"))?; - configure_sink_for_low_latency(&sink); - pipeline - .add(&sink) - .map_err(|error| format!("Failed to add {label}: {error}"))?; - sink.sync_state_with_parent() - .map_err(|error| format!("Failed to sync {label} state: {error}"))?; - - let Some(sink_pad) = sink.static_pad("sink") else { - return Err(format!("{label} has no sink pad.")); - }; - src_pad - .link(&sink_pad) - .map(|_| ()) - .map_err(|error| format!("Failed to link {label}: {error:?}")) -} - -fn make_element(factory: &str) -> Result { - gst::ElementFactory::make(factory) - .build() - .map_err(|error| format!("Failed to create GStreamer element {factory}: {error}")) -} diff --git a/native/opennow-streamer/src/gstreamer_platform.rs b/native/opennow-streamer/src/gstreamer_platform.rs deleted file mode 100644 index 1a936b760..000000000 --- a/native/opennow-streamer/src/gstreamer_platform.rs +++ /dev/null @@ -1,1705 +0,0 @@ -#[cfg(target_os = "windows")] -use crate::gstreamer_backend::send_log; -#[cfg(target_os = "windows")] -use crate::protocol::NativeRenderRect; -use crate::protocol::{Event, NativeRenderSurface, NativeStreamerShortcutBindings}; -#[cfg(target_os = "windows")] -use std::ffi::c_void; -use std::sync::atomic::AtomicBool; -#[cfg(target_os = "windows")] -use std::sync::atomic::Ordering; -use std::sync::mpsc::Sender; -use std::sync::Arc; -#[cfg(target_os = "windows")] -use std::thread; -#[cfg(target_os = "windows")] -use std::time::Duration; - -#[cfg(target_os = "windows")] -fn parse_window_handle(value: &str) -> Result { - let trimmed = value.trim(); - let hex = trimmed - .strip_prefix("0x") - .or_else(|| trimmed.strip_prefix("0X")); - let parsed = if let Some(hex) = hex { - usize::from_str_radix(hex, 16) - } else { - trimmed.parse::() - } - .map_err(|error| format!("Invalid native render window handle {value:?}: {error}"))?; - - if parsed == 0 { - return Err("Native render window handle is zero.".to_owned()); - } - - Ok(parsed) -} - -#[cfg(target_os = "windows")] -fn normalized_render_rect(rect: Option<&NativeRenderRect>) -> NativeRenderRect { - let Some(rect) = rect else { - return NativeRenderRect { - x: 0, - y: 0, - width: 2, - height: 2, - }; - }; - - NativeRenderRect { - x: rect.x.max(0), - y: rect.y.max(0), - width: rect.width.max(2), - height: rect.height.max(2), - } -} - -#[cfg(target_os = "windows")] -pub(crate) fn start_external_renderer_window_guard( - event_sender: Option>, - stop: Arc, -) { - thread::spawn(move || { - let mut logged = false; - while !stop.load(Ordering::SeqCst) { - if stop.load(Ordering::SeqCst) { - break; - } - - let configured = unsafe { win32_renderer_window::protect_process_renderer_window() }; - if configured && !logged { - send_log( - &event_sender, - "info", - "Configured external native renderer window for fullscreen DX11 input capture." - .to_owned(), - ); - logged = true; - } - thread::sleep(if logged { - Duration::from_millis(500) - } else { - Duration::from_millis(100) - }); - } - }); -} - -#[cfg(not(target_os = "windows"))] -pub(crate) fn start_external_renderer_window_guard( - _event_sender: Option>, - _stop: Arc, -) { -} - -#[cfg(target_os = "windows")] -pub(crate) fn set_native_shortcut_bindings(bindings: &NativeStreamerShortcutBindings) { - unsafe { - win32_renderer_window::set_shortcut_bindings(bindings.clone()); - } -} - -#[cfg(not(target_os = "windows"))] -pub(crate) fn set_native_shortcut_bindings(_bindings: &NativeStreamerShortcutBindings) {} - -#[cfg(target_os = "windows")] -pub(crate) fn clear_native_shortcut_bindings() { - unsafe { - win32_renderer_window::clear_shortcut_bindings(); - } -} - -#[cfg(not(target_os = "windows"))] -pub(crate) fn clear_native_shortcut_bindings() {} - -#[cfg(target_os = "windows")] -pub(crate) fn release_native_input_capture() { - unsafe { - win32_renderer_window::release_current_input_capture(); - } -} - -#[cfg(not(target_os = "windows"))] -pub(crate) fn release_native_input_capture() {} - -#[cfg(target_os = "windows")] -pub(crate) fn arm_internal_child_input(hwnd: usize) -> bool { - unsafe { win32_renderer_window::arm_internal_child_input(hwnd) } -} - -#[cfg(target_os = "windows")] -pub(crate) fn update_external_renderer_surface(surface: &NativeRenderSurface) { - let target = surface - .window_handle - .as_deref() - .and_then(|window_handle| parse_window_handle(window_handle).ok()) - .and_then(|window_handle| { - surface - .visible - .then_some(()) - .and(surface.rect.as_ref()) - .map(|rect| (window_handle, normalized_render_rect(Some(rect)))) - }); - - unsafe { - win32_renderer_window::set_render_target_surface(target); - } -} - -#[cfg(not(target_os = "windows"))] -pub(crate) fn update_external_renderer_surface(_surface: &NativeRenderSurface) {} - -#[cfg(target_os = "windows")] -pub(crate) mod win32_renderer_window { - use crate::gstreamer_input::NativeWindowInputEvent; - use crate::protocol::NativeRenderRect; - use crate::protocol::{NativeStreamerShortcutAction, NativeStreamerShortcutBindings}; - use crate::shortcuts::NativeShortcutMatcher; - use std::collections::{HashMap, HashSet}; - use std::ffi::c_void; - use std::ptr::{null, null_mut}; - use std::sync::atomic::{AtomicU64, Ordering}; - use std::sync::mpsc::Sender; - use std::sync::{Mutex, OnceLock}; - use std::thread; - use std::time::{Duration, Instant}; - - type Bool = i32; - type Dword = u32; - type Hcursor = *mut c_void; - type Hmonitor = *mut c_void; - type Hrawinput = *mut c_void; - type Hwnd = *mut c_void; - type Lparam = isize; - type Lresult = isize; - type Uint = u32; - type Wparam = usize; - - const GWL_STYLE: i32 = -16; - const GWL_EXSTYLE: i32 = -20; - const GWLP_WNDPROC: i32 = -4; - const GW_OWNER: Uint = 4; - const HTCLIENT: isize = 1; - const HWND_NOTOPMOST: Hwnd = -2isize as Hwnd; - const MA_ACTIVATE: isize = 1; - const MONITOR_DEFAULTTONEAREST: Dword = 0x0000_0002; - const RID_INPUT: Uint = 0x1000_0003; - const RIDEV_REMOVE: Dword = 0x0000_0001; - const RIDEV_NOLEGACY: Dword = 0x0000_0030; - // Receive WM_INPUT even when this HWND is not foreground. Required for the - // internal child surface: Electron stays the top-level foreground window, - // so keyboard RawInput never arrives without INPUTSINK. Mouse still works - // via RIDEV_CAPTUREMOUSE alone. - const RIDEV_INPUTSINK: Dword = 0x0000_0100; - const RIDEV_CAPTUREMOUSE: Dword = 0x0000_0200; - const RIM_TYPEMOUSE: Dword = 0; - const RIM_TYPEKEYBOARD: Dword = 1; - const RI_KEY_BREAK: u16 = 0x0001; - const RI_KEY_E0: u16 = 0x0002; - const RI_KEY_E1: u16 = 0x0004; - const RI_MOUSE_LEFT_BUTTON_DOWN: u16 = 0x0001; - const RI_MOUSE_LEFT_BUTTON_UP: u16 = 0x0002; - const RI_MOUSE_RIGHT_BUTTON_DOWN: u16 = 0x0004; - const RI_MOUSE_RIGHT_BUTTON_UP: u16 = 0x0008; - const RI_MOUSE_MIDDLE_BUTTON_DOWN: u16 = 0x0010; - const RI_MOUSE_MIDDLE_BUTTON_UP: u16 = 0x0020; - const RI_MOUSE_BUTTON_4_DOWN: u16 = 0x0040; - const RI_MOUSE_BUTTON_4_UP: u16 = 0x0080; - const RI_MOUSE_BUTTON_5_DOWN: u16 = 0x0100; - const RI_MOUSE_BUTTON_5_UP: u16 = 0x0200; - const RI_MOUSE_WHEEL: u16 = 0x0400; - const VK_SHIFT: u16 = 0x10; - const VK_ESCAPE: u16 = 0x1B; - const VK_V: u16 = 0x56; - const VK_TAB: u16 = 0x09; - const VK_CONTROL: u16 = 0x11; - const VK_MENU: u16 = 0x12; - const VK_CAPITAL: i32 = 0x14; - const VK_NUMLOCK: i32 = 0x90; - const VK_SCROLL: i32 = 0x91; - const VK_LSHIFT: u16 = 0xA0; - const VK_RSHIFT: u16 = 0xA1; - const VK_LCONTROL: u16 = 0xA2; - const VK_RCONTROL: u16 = 0xA3; - const VK_LMENU: u16 = 0xA4; - const VK_RMENU: u16 = 0xA5; - const VK_LWIN: u16 = 0x5B; - const VK_RWIN: u16 = 0x5C; - const WM_INPUT: Uint = 0x00FF; - const WM_NCHITTEST: Uint = 0x0084; - const WM_MOUSEACTIVATE: Uint = 0x0021; - const WM_SETCURSOR: Uint = 0x0020; - const WM_KILLFOCUS: Uint = 0x0008; - const WM_ACTIVATE: Uint = 0x0006; - const WA_INACTIVE: usize = 0; - const WM_KEYDOWN: Uint = 0x0100; - const WM_KEYUP: Uint = 0x0101; - const WM_SYSKEYDOWN: Uint = 0x0104; - const WM_SYSKEYUP: Uint = 0x0105; - const WM_LBUTTONDOWN: Uint = 0x0201; - const WM_LBUTTONUP: Uint = 0x0202; - const WM_RBUTTONDOWN: Uint = 0x0204; - const WM_RBUTTONUP: Uint = 0x0205; - const WM_MBUTTONDOWN: Uint = 0x0207; - const WM_MBUTTONUP: Uint = 0x0208; - const WM_XBUTTONDOWN: Uint = 0x020B; - const WM_XBUTTONUP: Uint = 0x020C; - const XBUTTON1: u16 = 0x0001; - const XBUTTON2: u16 = 0x0002; - const WS_CAPTION: isize = 0x00C0_0000; - const WS_MAXIMIZEBOX: isize = 0x0001_0000; - const WS_MINIMIZEBOX: isize = 0x0002_0000; - const WS_SYSMENU: isize = 0x0008_0000; - const WS_THICKFRAME: isize = 0x0004_0000; - const WS_EX_NOACTIVATE: isize = 0x0800_0000; - const WS_EX_TOOLWINDOW: isize = 0x0000_0080; - const WS_EX_TRANSPARENT: isize = 0x0000_0020; - const SWP_NOSIZE: u32 = 0x0001; - const SWP_NOMOVE: u32 = 0x0002; - const SWP_NOACTIVATE: u32 = 0x0010; - const SWP_FRAMECHANGED: u32 = 0x0020; - const SW_MINIMIZE: i32 = 6; - const ESCAPE_SCANCODE: u16 = 0x0001; - const ESCAPE_HOLD_TO_MINIMIZE: Duration = Duration::from_secs(5); - - struct EnumState { - process_id: u32, - candidates: Vec, - } - - #[derive(Clone, Copy)] - struct WindowCandidate { - hwnd: Hwnd, - area: i64, - } - - #[derive(Clone, Copy)] - struct RenderTargetSurface { - hwnd: isize, - client_rect: Rect, - } - - #[repr(C)] - #[derive(Clone, Copy)] - struct Rect { - left: i32, - top: i32, - right: i32, - bottom: i32, - } - - #[repr(C)] - #[derive(Clone, Copy)] - struct Point { - x: i32, - y: i32, - } - - #[repr(C)] - struct MonitorInfo { - cb_size: Dword, - rc_monitor: Rect, - rc_work: Rect, - dw_flags: Dword, - } - - #[repr(C)] - struct RawInputDevice { - us_usage_page: u16, - us_usage: u16, - dw_flags: Dword, - hwnd_target: Hwnd, - } - - #[repr(C)] - struct RawInputHeader { - dw_type: Dword, - dw_size: Dword, - h_device: *mut c_void, - w_param: Wparam, - } - - #[repr(C)] - #[derive(Clone, Copy)] - struct RawMouse { - us_flags: u16, - buttons: u32, - ul_raw_buttons: u32, - l_last_x: i32, - l_last_y: i32, - ul_extra_information: u32, - } - - #[repr(C)] - #[derive(Clone, Copy)] - struct RawKeyboard { - make_code: u16, - flags: u16, - reserved: u16, - vkey: u16, - message: Uint, - extra_information: u32, - } - - #[derive(Clone, Copy)] - struct PressedKey { - keycode: u16, - scancode: u16, - suppressed: bool, - } - - #[derive(Clone, Copy)] - struct EscapeKeyPress { - scancode: u16, - hold_timer_armed: bool, - } - - static INPUT_EVENT_SENDER: OnceLock>>> = - OnceLock::new(); - static ORIGINAL_WNDPROCS: OnceLock>> = OnceLock::new(); - static CAPTURED_HWND: OnceLock>> = OnceLock::new(); - static PROTECTED_HWND: OnceLock>> = OnceLock::new(); - static PRESSED_KEYS: OnceLock>> = OnceLock::new(); - static LAST_LOCK_KEYS_STATE: OnceLock> = OnceLock::new(); - static LEGACY_SUPPRESSED_KEYS: OnceLock>> = OnceLock::new(); - static STARTED_AT: OnceLock = OnceLock::new(); - static ESCAPE_HOLD_HWND: OnceLock>> = OnceLock::new(); - static ESCAPE_HOLD_TOKEN: OnceLock = OnceLock::new(); - static ESCAPE_KEY_PRESS: OnceLock>> = OnceLock::new(); - static SHORTCUT_MATCHER: OnceLock> = OnceLock::new(); - static RENDER_TARGET_SURFACE: OnceLock>> = OnceLock::new(); - - #[link(name = "user32")] - unsafe extern "system" { - fn CallWindowProcW( - previous: isize, - hwnd: Hwnd, - message: Uint, - wparam: Wparam, - lparam: Lparam, - ) -> Lresult; - fn ClientToScreen(hwnd: Hwnd, point: *mut Point) -> Bool; - fn ClipCursor(rect: *const Rect) -> Bool; - fn DefWindowProcW(hwnd: Hwnd, message: Uint, wparam: Wparam, lparam: Lparam) -> Lresult; - fn EnumWindows( - callback: Option Bool>, - lparam: Lparam, - ) -> Bool; - fn GetMonitorInfoW(monitor: Hmonitor, info: *mut MonitorInfo) -> Bool; - fn GetRawInputData( - raw_input: Hrawinput, - command: Uint, - data: *mut c_void, - size: *mut u32, - header_size: u32, - ) -> u32; - fn GetKeyState(virtual_key: i32) -> i16; - fn GetWindow(hwnd: Hwnd, command: Uint) -> Hwnd; - fn GetWindowLongPtrW(hwnd: Hwnd, index: i32) -> isize; - fn GetWindowRect(hwnd: Hwnd, rect: *mut Rect) -> Bool; - fn GetWindowThreadProcessId(hwnd: Hwnd, process_id: *mut u32) -> u32; - fn IsIconic(hwnd: Hwnd) -> Bool; - fn IsWindowVisible(hwnd: Hwnd) -> Bool; - fn MonitorFromWindow(hwnd: Hwnd, flags: Dword) -> Hmonitor; - fn RegisterRawInputDevices(devices: *const RawInputDevice, count: u32, size: u32) -> Bool; - fn ReleaseCapture() -> Bool; - fn SetCapture(hwnd: Hwnd) -> Hwnd; - fn SetCursor(cursor: Hcursor) -> Hcursor; - fn SetFocus(hwnd: Hwnd) -> Hwnd; - fn SetForegroundWindow(hwnd: Hwnd) -> Bool; - fn SetWindowLongPtrW(hwnd: Hwnd, index: i32, new_long: isize) -> isize; - fn SetWindowPos( - hwnd: Hwnd, - insert_after: Hwnd, - x: i32, - y: i32, - cx: i32, - cy: i32, - flags: u32, - ) -> Bool; - fn ShowWindow(hwnd: Hwnd, command: i32) -> Bool; - fn ShowCursor(show: Bool) -> i32; - } - - #[link(name = "kernel32")] - unsafe extern "system" { - fn GetCurrentProcessId() -> u32; - } - - pub unsafe fn set_render_target_surface(target: Option<(usize, NativeRenderRect)>) { - let target_surface = target.map(|(window_handle, rect)| RenderTargetSurface { - hwnd: window_handle as isize, - client_rect: Rect { - left: rect.x, - top: rect.y, - right: rect.x.saturating_add(rect.width.max(2)), - bottom: rect.y.saturating_add(rect.height.max(2)), - }, - }); - let slot = RENDER_TARGET_SURFACE.get_or_init(|| Mutex::new(None)); - if let Ok(mut current) = slot.lock() { - *current = target_surface; - } - } - - pub unsafe fn set_input_event_sender(sender: Option>) { - let input_stopped = sender.is_none(); - let slot = INPUT_EVENT_SENDER.get_or_init(|| Mutex::new(None)); - if let Ok(mut current) = slot.lock() { - *current = sender; - } - if input_stopped { - unregister_raw_input_devices(); - } - } - - pub unsafe fn set_shortcut_bindings(bindings: NativeStreamerShortcutBindings) { - let matcher = SHORTCUT_MATCHER.get_or_init(|| Mutex::new(NativeShortcutMatcher::default())); - if let Ok(mut current) = matcher.lock() { - *current = NativeShortcutMatcher::from_bindings(&bindings); - } - } - - pub unsafe fn clear_shortcut_bindings() { - let matcher = SHORTCUT_MATCHER.get_or_init(|| Mutex::new(NativeShortcutMatcher::default())); - if let Ok(mut current) = matcher.lock() { - *current = NativeShortcutMatcher::default(); - } - } - - pub unsafe fn release_current_input_capture() { - let Some(captured) = CAPTURED_HWND - .get() - .and_then(|captured| captured.lock().ok().and_then(|captured| *captured)) - else { - if !crate::gstreamer_config::use_internal_renderer() { - unregister_raw_input_devices(); - } - return; - }; - - release_input_capture(captured as Hwnd); - } - - /// Arm RawInput on the internal child HWND (sibling of Intermediate D3D). - /// Chains over the child's existing wndproc so SET_BOUNDS still works. - pub unsafe fn arm_internal_child_input(hwnd: usize) -> bool { - if hwnd == 0 { - return false; - } - let hwnd = hwnd as Hwnd; - let protected_slot = PROTECTED_HWND.get_or_init(|| Mutex::new(None)); - if let Ok(mut protected) = protected_slot.lock() { - *protected = Some(hwnd as isize); - } - let wndproc_installed = install_input_wndproc(hwnd); - let keyboard_registered = register_internal_raw_keyboard(hwnd); - wndproc_installed || keyboard_registered - } - - pub unsafe fn protect_process_renderer_window() -> bool { - let mut state = EnumState { - process_id: GetCurrentProcessId(), - candidates: Vec::new(), - }; - EnumWindows( - Some(collect_renderer_window_candidate), - &mut state as *mut EnumState as Lparam, - ); - - let Some(candidate) = state - .candidates - .into_iter() - .max_by_key(|candidate| candidate.area) - else { - return false; - }; - - protect_renderer_window(candidate.hwnd) - } - - unsafe extern "system" fn collect_renderer_window_candidate( - hwnd: Hwnd, - lparam: Lparam, - ) -> Bool { - let state = &mut *(lparam as *mut EnumState); - let mut process_id = 0; - GetWindowThreadProcessId(hwnd, &mut process_id); - if process_id != state.process_id || IsWindowVisible(hwnd) == 0 || IsIconic(hwnd) != 0 { - return 1; - } - - if !GetWindow(hwnd, GW_OWNER).is_null() { - return 1; - } - - let ex_style = GetWindowLongPtrW(hwnd, GWL_EXSTYLE); - if (ex_style & (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE)) != 0 { - return 1; - } - - let mut rect = Rect { - left: 0, - top: 0, - right: 0, - bottom: 0, - }; - if GetWindowRect(hwnd, &mut rect) == 0 { - return 1; - } - let width = rect.right.saturating_sub(rect.left); - let height = rect.bottom.saturating_sub(rect.top); - if width < 320 || height < 180 { - return 1; - } - - state.candidates.push(WindowCandidate { - hwnd, - area: i64::from(width) * i64::from(height), - }); - 1 - } - - unsafe fn protect_renderer_window(hwnd: Hwnd) -> bool { - let protected_slot = PROTECTED_HWND.get_or_init(|| Mutex::new(None)); - if let Ok(mut protected) = protected_slot.lock() { - *protected = Some(hwnd as isize); - } - - let mut configured = false; - let current = GetWindowLongPtrW(hwnd, GWL_EXSTYLE); - let desired = current & !(WS_EX_NOACTIVATE | WS_EX_TRANSPARENT); - if desired != current { - SetWindowLongPtrW(hwnd, GWL_EXSTYLE, desired); - configured = true; - } - - let current_style = GetWindowLongPtrW(hwnd, GWL_STYLE); - let fullscreen_style = current_style - & !(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU); - if fullscreen_style != current_style { - SetWindowLongPtrW(hwnd, GWL_STYLE, fullscreen_style); - configured = true; - } - - if install_input_wndproc(hwnd) { - SetForegroundWindow(hwnd); - SetFocus(hwnd); - configured = true; - } - - if let Some(rect) = target_renderer_rect().or_else(|| monitor_rect_for_window(hwnd)) { - SetWindowPos( - hwnd, - HWND_NOTOPMOST, - rect.left, - rect.top, - rect.right.saturating_sub(rect.left).max(2), - rect.bottom.saturating_sub(rect.top).max(2), - SWP_NOACTIVATE | SWP_FRAMECHANGED, - ); - configured = true; - } else { - SetWindowPos( - hwnd, - HWND_NOTOPMOST, - 0, - 0, - 0, - 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_FRAMECHANGED, - ); - } - - configured - } - - unsafe fn render_rect_to_screen_rect(hwnd: Hwnd, rect: Rect) -> Option { - if hwnd.is_null() { - return None; - } - let mut origin = Point { - x: rect.left, - y: rect.top, - }; - if ClientToScreen(hwnd, &mut origin) == 0 { - return None; - } - let width = rect.right.saturating_sub(rect.left).max(2); - let height = rect.bottom.saturating_sub(rect.top).max(2); - - Some(Rect { - left: origin.x, - top: origin.y, - right: origin.x.saturating_add(width), - bottom: origin.y.saturating_add(height), - }) - } - - unsafe fn install_input_wndproc(hwnd: Hwnd) -> bool { - let key = hwnd as isize; - let map = ORIGINAL_WNDPROCS.get_or_init(|| Mutex::new(HashMap::new())); - let Ok(mut map) = map.lock() else { - return false; - }; - if map.contains_key(&key) { - return false; - } - - let previous = SetWindowLongPtrW(hwnd, GWLP_WNDPROC, renderer_window_wndproc as isize); - if previous == 0 { - return false; - } - map.insert(key, previous); - true - } - - unsafe extern "system" fn renderer_window_wndproc( - hwnd: Hwnd, - message: Uint, - wparam: Wparam, - lparam: Lparam, - ) -> Lresult { - if message == WM_NCHITTEST { - return HTCLIENT; - } - if message == WM_MOUSEACTIVATE { - begin_input_capture(hwnd); - return MA_ACTIVATE; - } - if message == WM_SETCURSOR && is_input_captured(hwnd) { - SetCursor(null_mut()); - return 1; - } - if message == WM_INPUT { - handle_raw_input(lparam as Hrawinput); - return 0; - } - let handled_legacy_shortcut = is_keyboard_message(message) - && handle_legacy_shortcut_keyboard(message, wparam, lparam); - if handled_legacy_shortcut { - return 0; - } - if is_escape_keyboard_message(message, wparam) { - if !is_input_captured(hwnd) { - begin_input_capture(hwnd); - } - handle_legacy_escape_keyboard(message, lparam); - return 0; - } - if message == WM_KILLFOCUS || (message == WM_ACTIVATE && (wparam & 0xffff) == WA_INACTIVE) { - release_input_capture(hwnd); - } - if let Some((button, pressed)) = legacy_mouse_button(message, wparam) { - let was_captured = is_input_captured(hwnd); - if pressed && !was_captured { - begin_input_capture(hwnd); - emit_input_event(NativeWindowInputEvent::MouseButton { - pressed, - button, - timestamp_us: timestamp_us(), - }); - } - } - - let key = hwnd as isize; - let previous = ORIGINAL_WNDPROCS - .get() - .and_then(|map| map.lock().ok().and_then(|map| map.get(&key).copied())); - if let Some(previous) = previous { - return CallWindowProcW(previous, hwnd, message, wparam, lparam); - } - - DefWindowProcW(hwnd, message, wparam, lparam) - } - - unsafe fn monitor_rect_for_window(hwnd: Hwnd) -> Option { - let monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); - if monitor.is_null() { - return None; - } - - let mut info = MonitorInfo { - cb_size: std::mem::size_of::() as Dword, - rc_monitor: Rect { - left: 0, - top: 0, - right: 0, - bottom: 0, - }, - rc_work: Rect { - left: 0, - top: 0, - right: 0, - bottom: 0, - }, - dw_flags: 0, - }; - if GetMonitorInfoW(monitor, &mut info) == 0 { - return None; - } - - Some(info.rc_monitor) - } - - unsafe fn target_renderer_rect() -> Option { - let target = RENDER_TARGET_SURFACE - .get() - .and_then(|surface| surface.lock().ok().and_then(|surface| *surface))?; - let hwnd = target.hwnd as Hwnd; - render_rect_to_screen_rect(hwnd, target.client_rect) - .or_else(|| monitor_rect_for_window(hwnd)) - } - - unsafe fn begin_input_capture(hwnd: Hwnd) { - // External floating window: take OS focus so RawInput + ClipCursor work - // without INPUTSINK. Internal child: leave Electron as foreground so its - // shortcut keydown handlers keep working; keyboard arrives via INPUTSINK. - if !crate::gstreamer_config::use_internal_renderer() { - SetForegroundWindow(hwnd); - SetFocus(hwnd); - } - SetCapture(hwnd); - register_raw_input_devices(hwnd); - if let Some(rect) = target_renderer_rect().or_else(|| monitor_rect_for_window(hwnd)) { - ClipCursor(&rect); - } - hide_cursor(); - emit_input_capture_changed(true); - - let slot = CAPTURED_HWND.get_or_init(|| Mutex::new(None)); - if let Ok(mut captured) = slot.lock() { - *captured = Some(hwnd as isize); - } - sync_lock_keys_state(true); - } - - unsafe fn release_input_capture(hwnd: Hwnd) { - cancel_escape_hold_to_minimize_timer(); - clear_escape_key_press(); - let slot = CAPTURED_HWND.get_or_init(|| Mutex::new(None)); - let mut should_release = false; - if let Ok(mut captured) = slot.lock() { - should_release = captured.is_some_and(|captured| captured == hwnd as isize); - if should_release { - *captured = None; - } - } - - if !should_release { - return; - } - - release_pressed_keys(); - ReleaseCapture(); - ClipCursor(null()); - show_cursor(); - emit_input_capture_changed(false); - if crate::gstreamer_config::use_internal_renderer() { - // F10/F8 release relative mouse capture, but the internal stream - // must keep receiving keyboard input (especially Escape) while the - // Electron window remains foreground. - unregister_raw_mouse_device(); - register_internal_raw_keyboard(hwnd); - } else { - unregister_raw_input_devices(); - } - SetWindowPos( - hwnd, - HWND_NOTOPMOST, - 0, - 0, - 0, - 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE, - ); - } - - fn is_input_captured(hwnd: Hwnd) -> bool { - CAPTURED_HWND - .get() - .and_then(|captured| captured.lock().ok().and_then(|captured| *captured)) - .is_some_and(|captured| captured == hwnd as isize) - } - - fn captured_hwnd() -> Option { - CAPTURED_HWND - .get() - .and_then(|captured| captured.lock().ok().and_then(|captured| *captured)) - } - - fn protected_hwnd() -> Option { - PROTECTED_HWND - .get() - .and_then(|captured| captured.lock().ok().and_then(|captured| *captured)) - } - - unsafe fn start_escape_hold_to_minimize_timer() { - let Some(hwnd) = captured_hwnd() else { - return; - }; - - let token = ESCAPE_HOLD_TOKEN - .get_or_init(|| AtomicU64::new(0)) - .fetch_add(1, Ordering::SeqCst) - .wrapping_add(1); - let slot = ESCAPE_HOLD_HWND.get_or_init(|| Mutex::new(None)); - if let Ok(mut held_hwnd) = slot.lock() { - *held_hwnd = Some(hwnd); - } - - thread::spawn(move || { - thread::sleep(ESCAPE_HOLD_TO_MINIMIZE); - unsafe { - minimize_window_if_escape_still_held(hwnd, token); - } - }); - } - - fn cancel_escape_hold_to_minimize_timer() { - ESCAPE_HOLD_TOKEN - .get_or_init(|| AtomicU64::new(0)) - .fetch_add(1, Ordering::SeqCst); - let slot = ESCAPE_HOLD_HWND.get_or_init(|| Mutex::new(None)); - if let Ok(mut held_hwnd) = slot.lock() { - *held_hwnd = None; - } - } - - unsafe fn minimize_window_if_escape_still_held(hwnd: isize, token: u64) { - let current_token = ESCAPE_HOLD_TOKEN - .get_or_init(|| AtomicU64::new(0)) - .load(Ordering::SeqCst); - if current_token != token { - return; - } - - let still_held = ESCAPE_HOLD_HWND - .get() - .and_then(|held_hwnd| held_hwnd.lock().ok().and_then(|held_hwnd| *held_hwnd)) - .is_some_and(|held_hwnd| held_hwnd == hwnd); - if !still_held { - return; - } - - // Consume the held Escape so key-up does not also send a tap to GFN. - clear_escape_key_press(); - cancel_escape_hold_to_minimize_timer(); - - let hwnd = hwnd as Hwnd; - release_input_capture(hwnd); - - ShowWindow(hwnd, SW_MINIMIZE); - } - - unsafe fn register_raw_input_devices(hwnd: Hwnd) -> bool { - let keyboard_flags = if crate::gstreamer_config::use_internal_renderer() { - // Internal: Electron stays foreground and must keep receiving legacy - // WM_KEYDOWN for UI shortcuts. Do NOT set RIDEV_NOLEGACY on keyboard - // or Electron shortcuts die. INPUTSINK delivers WM_INPUT while Electron - // remains the top-level foreground window. - RIDEV_INPUTSINK - } else { - RIDEV_NOLEGACY - }; - let mouse_flags = if crate::gstreamer_config::use_internal_renderer() { - RIDEV_NOLEGACY | RIDEV_CAPTUREMOUSE | RIDEV_INPUTSINK - } else { - RIDEV_NOLEGACY | RIDEV_CAPTUREMOUSE - }; - let devices = [ - RawInputDevice { - us_usage_page: 0x01, - us_usage: 0x02, - dw_flags: mouse_flags, - hwnd_target: hwnd, - }, - RawInputDevice { - us_usage_page: 0x01, - us_usage: 0x06, - dw_flags: keyboard_flags, - hwnd_target: hwnd, - }, - ]; - - RegisterRawInputDevices( - devices.as_ptr(), - devices.len() as u32, - std::mem::size_of::() as u32, - ) != 0 - } - - unsafe fn register_internal_raw_keyboard(hwnd: Hwnd) -> bool { - let device = RawInputDevice { - us_usage_page: 0x01, - us_usage: 0x06, - dw_flags: RIDEV_INPUTSINK, - hwnd_target: hwnd, - }; - - RegisterRawInputDevices( - &device, - 1, - std::mem::size_of::() as u32, - ) != 0 - } - - unsafe fn unregister_raw_mouse_device() -> bool { - let device = RawInputDevice { - us_usage_page: 0x01, - us_usage: 0x02, - dw_flags: RIDEV_REMOVE, - hwnd_target: null_mut(), - }; - - RegisterRawInputDevices( - &device, - 1, - std::mem::size_of::() as u32, - ) != 0 - } - - unsafe fn unregister_raw_input_devices() -> bool { - let devices = [ - RawInputDevice { - us_usage_page: 0x01, - us_usage: 0x02, - dw_flags: RIDEV_REMOVE, - hwnd_target: null_mut(), - }, - RawInputDevice { - us_usage_page: 0x01, - us_usage: 0x06, - dw_flags: RIDEV_REMOVE, - hwnd_target: null_mut(), - }, - ]; - - RegisterRawInputDevices( - devices.as_ptr(), - devices.len() as u32, - std::mem::size_of::() as u32, - ) != 0 - } - - unsafe fn handle_raw_input(raw_input: Hrawinput) { - let mut size = 0u32; - let header_size = std::mem::size_of::() as u32; - let query = GetRawInputData(raw_input, RID_INPUT, null_mut(), &mut size, header_size); - if query == u32::MAX || size < header_size { - return; - } - - let mut buffer = vec![0u8; size as usize]; - let read = GetRawInputData( - raw_input, - RID_INPUT, - buffer.as_mut_ptr() as *mut c_void, - &mut size, - header_size, - ); - if read == u32::MAX || read == 0 || buffer.len() < header_size as usize { - return; - } - - let header = &*(buffer.as_ptr() as *const RawInputHeader); - let data = buffer.as_ptr().add(std::mem::size_of::()); - match header.dw_type { - RIM_TYPEMOUSE => handle_raw_mouse(&*(data as *const RawMouse)), - RIM_TYPEKEYBOARD => handle_raw_keyboard(&*(data as *const RawKeyboard)), - _ => {} - } - } - - unsafe fn handle_raw_mouse(raw: &RawMouse) { - if CAPTURED_HWND - .get() - .and_then(|captured| captured.lock().ok().and_then(|captured| *captured)) - .is_none() - { - return; - } - - let timestamp_us = timestamp_us(); - let dx = clamp_i32_to_i16(raw.l_last_x); - let dy = clamp_i32_to_i16(raw.l_last_y); - if dx != 0 || dy != 0 { - emit_input_event(NativeWindowInputEvent::MouseMove { - dx, - dy, - timestamp_us, - }); - } - - let button_flags = (raw.buttons & 0xffff) as u16; - let button_data = (raw.buttons >> 16) as u16; - emit_raw_mouse_button_events(button_flags, timestamp_us); - if (button_flags & RI_MOUSE_WHEEL) != 0 { - emit_input_event(NativeWindowInputEvent::MouseWheel { - delta: button_data as i16, - timestamp_us, - }); - } - } - - unsafe fn emit_raw_mouse_button_events(flags: u16, timestamp_us: u64) { - let pairs = [ - (RI_MOUSE_LEFT_BUTTON_DOWN, 1, true), - (RI_MOUSE_LEFT_BUTTON_UP, 1, false), - (RI_MOUSE_MIDDLE_BUTTON_DOWN, 2, true), - (RI_MOUSE_MIDDLE_BUTTON_UP, 2, false), - (RI_MOUSE_RIGHT_BUTTON_DOWN, 3, true), - (RI_MOUSE_RIGHT_BUTTON_UP, 3, false), - (RI_MOUSE_BUTTON_4_DOWN, 4, true), - (RI_MOUSE_BUTTON_4_UP, 4, false), - (RI_MOUSE_BUTTON_5_DOWN, 5, true), - (RI_MOUSE_BUTTON_5_UP, 5, false), - ]; - - for (flag, button, pressed) in pairs { - if (flags & flag) != 0 { - emit_input_event(NativeWindowInputEvent::MouseButton { - pressed, - button, - timestamp_us, - }); - } - } - } - - unsafe fn handle_raw_keyboard(raw: &RawKeyboard) { - if raw.vkey == 0xff { - return; - } - - let pressed = match raw.message { - WM_KEYDOWN | WM_SYSKEYDOWN => true, - WM_KEYUP | WM_SYSKEYUP => false, - _ => (raw.flags & RI_KEY_BREAK) == 0, - }; - let keycode = normalize_virtual_key(raw.vkey, raw.make_code, raw.flags); - let mut scancode = normalize_scancode(raw.make_code, raw.flags); - if keycode == VK_ESCAPE && scancode == 0 { - scancode = ESCAPE_SCANCODE; - } - if keycode == 0 || scancode == 0 { - return; - } - handle_keyboard_state(keycode, scancode, pressed); - } - - unsafe fn handle_legacy_escape_keyboard(message: Uint, lparam: Lparam) { - let pressed = matches!(message, WM_KEYDOWN | WM_SYSKEYDOWN); - let mut scancode = legacy_keyboard_scancode(lparam); - if scancode == 0 { - scancode = ESCAPE_SCANCODE; - } - handle_keyboard_state(VK_ESCAPE, scancode, pressed); - } - - fn is_escape_keyboard_message(message: Uint, wparam: Wparam) -> bool { - matches!(message, WM_KEYDOWN | WM_KEYUP | WM_SYSKEYDOWN | WM_SYSKEYUP) - && (wparam as u16) == VK_ESCAPE - } - - fn is_keyboard_message(message: Uint) -> bool { - matches!(message, WM_KEYDOWN | WM_KEYUP | WM_SYSKEYDOWN | WM_SYSKEYUP) - } - - fn legacy_keyboard_scancode(lparam: Lparam) -> u16 { - let scancode = ((lparam >> 16) & 0xff) as u16; - if scancode == 0 { - return 0; - } - if ((lparam >> 24) & 0x01) != 0 { - 0xe000 | scancode - } else { - scancode - } - } - - unsafe fn handle_legacy_shortcut_keyboard( - message: Uint, - wparam: Wparam, - lparam: Lparam, - ) -> bool { - let keycode = wparam as u16; - if keycode == VK_ESCAPE { - return false; - } - - let pressed = matches!(message, WM_KEYDOWN | WM_SYSKEYDOWN); - let scancode = legacy_keyboard_scancode(lparam); - let key_id = if scancode == 0 { keycode } else { scancode }; - let suppressed_keys = LEGACY_SUPPRESSED_KEYS.get_or_init(|| Mutex::new(HashSet::new())); - let Ok(mut suppressed_keys) = suppressed_keys.lock() else { - return false; - }; - - if !pressed { - return suppressed_keys.remove(&key_id); - } - - if suppressed_keys.contains(&key_id) { - return true; - } - - let modifiers = current_legacy_modifier_flags(); - if pressed && is_clipboard_paste_shortcut(keycode, modifiers) { - suppressed_keys.insert(key_id); - drop(suppressed_keys); - emit_clipboard_paste_request(); - return true; - } - - let Some(action) = shortcut_action_for_keypress(keycode, scancode, modifiers) else { - return false; - }; - - suppressed_keys.insert(key_id); - drop(suppressed_keys); - handle_shortcut_action(action); - true - } - - unsafe fn handle_keyboard_state(keycode: u16, scancode: u16, pressed: bool) { - sync_lock_keys_state(false); - - let keys = PRESSED_KEYS.get_or_init(|| Mutex::new(HashMap::new())); - let Ok(mut keys) = keys.lock() else { - return; - }; - if pressed && keycode == VK_TAB && is_alt_modifier_down(&keys) { - drop(keys); - release_current_input_capture(); - return; - } - if keycode == VK_ESCAPE { - drop(keys); - // In the internal renderer Electron must intercept the legacy Escape - // before Chromium exits fullscreen, then forward exactly one tap over - // IPC. RawInput still owns every other key in this mode. The external - // native window has no Electron interception and keeps this path. - if crate::gstreamer_config::use_internal_renderer() { - return; - } - handle_escape_keyboard_state(scancode, pressed); - return; - } - let previous = keys.get(&scancode).copied(); - if pressed { - if previous.is_some() { - return; - } - let modifiers = pressed_key_modifier_flags(&keys, keycode); - if is_clipboard_paste_shortcut(keycode, modifiers) { - keys.insert( - scancode, - PressedKey { - keycode, - scancode, - suppressed: true, - }, - ); - drop(keys); - emit_clipboard_paste_request(); - return; - } - if let Some(action) = shortcut_action_for_keypress(keycode, scancode, modifiers) { - keys.insert( - scancode, - PressedKey { - keycode, - scancode, - suppressed: true, - }, - ); - drop(keys); - handle_shortcut_action(action); - return; - } - keys.insert( - scancode, - PressedKey { - keycode, - scancode, - suppressed: false, - }, - ); - } else if let Some(previous) = keys.remove(&scancode) { - if previous.suppressed { - return; - } - } - let modifiers = pressed_key_modifier_flags(&keys, keycode); - drop(keys); - - emit_input_event(NativeWindowInputEvent::Key { - pressed, - keycode, - scancode, - modifiers, - timestamp_us: timestamp_us(), - }); - } - - unsafe fn handle_escape_keyboard_state(scancode: u16, pressed: bool) { - let slot = ESCAPE_KEY_PRESS.get_or_init(|| Mutex::new(None)); - let Ok(mut escape_press) = slot.lock() else { - return; - }; - - if pressed { - let should_start_hold_timer = if let Some(current) = escape_press.as_mut() { - let should_start = !crate::gstreamer_config::use_internal_renderer() - && !current.hold_timer_armed - && captured_hwnd().is_some(); - if should_start { - current.hold_timer_armed = true; - } - should_start - } else { - let hold_timer_armed = - !crate::gstreamer_config::use_internal_renderer() && captured_hwnd().is_some(); - *escape_press = Some(EscapeKeyPress { - scancode, - hold_timer_armed, - }); - hold_timer_armed - }; - drop(escape_press); - if should_start_hold_timer { - start_escape_hold_to_minimize_timer(); - } - return; - } - - let Some(escape_press) = escape_press.take() else { - cancel_escape_hold_to_minimize_timer(); - return; - }; - let scancode = escape_press.scancode; - - cancel_escape_hold_to_minimize_timer(); - send_escape_tap(scancode); - } - - fn clear_escape_key_press() { - let slot = ESCAPE_KEY_PRESS.get_or_init(|| Mutex::new(None)); - if let Ok(mut escape_press) = slot.lock() { - *escape_press = None; - } - } - - fn send_escape_tap(scancode: u16) { - let keydown_timestamp_us = timestamp_us(); - emit_input_event(NativeWindowInputEvent::Key { - pressed: true, - keycode: VK_ESCAPE, - scancode, - modifiers: 0, - timestamp_us: keydown_timestamp_us, - }); - emit_input_event(NativeWindowInputEvent::Key { - pressed: false, - keycode: VK_ESCAPE, - scancode, - modifiers: 0, - timestamp_us: timestamp_us(), - }); - } - - unsafe fn release_pressed_keys() { - let keys = PRESSED_KEYS.get_or_init(|| Mutex::new(HashMap::new())); - let Ok(mut keys) = keys.lock() else { - return; - }; - let pressed = keys.values().copied().collect::>(); - keys.clear(); - drop(keys); - - let timestamp_us = timestamp_us(); - for key in pressed { - if key.suppressed { - continue; - } - emit_input_event(NativeWindowInputEvent::Key { - pressed: false, - keycode: key.keycode, - scancode: key.scancode, - modifiers: 0, - timestamp_us, - }); - } - } - - fn normalize_virtual_key(vkey: u16, make_code: u16, flags: u16) -> u16 { - match vkey { - VK_SHIFT => match make_code { - 0x36 => VK_RSHIFT, - _ => VK_LSHIFT, - }, - VK_CONTROL => { - if (flags & RI_KEY_E0) != 0 { - VK_RCONTROL - } else { - VK_LCONTROL - } - } - VK_MENU => { - if (flags & RI_KEY_E0) != 0 { - VK_RMENU - } else { - VK_LMENU - } - } - _ => vkey, - } - } - - fn normalize_scancode(make_code: u16, flags: u16) -> u16 { - if make_code == 0 { - return 0; - } - if (flags & RI_KEY_E0) != 0 { - 0xe000 | make_code - } else if (flags & RI_KEY_E1) != 0 { - 0xe100 | make_code - } else { - make_code - } - } - - /// Lock-key bitmask for INPUT_LOCK_KEYS_SYNC (official GFN iS() on desktop Windows). - unsafe fn lock_keys_sync_state() -> u8 { - let mut state = 0x10; - if (GetKeyState(VK_CAPITAL) & 0x0001) != 0 { - state |= 0x01; - } - state |= 0x20; - state |= 0x40; - if (GetKeyState(VK_NUMLOCK) & 0x0001) != 0 { - state |= 0x02; - } - if (GetKeyState(VK_SCROLL) & 0x0001) != 0 { - state |= 0x04; - } - state - } - - unsafe fn sync_lock_keys_state(force: bool) { - let state = lock_keys_sync_state(); - let slot = LAST_LOCK_KEYS_STATE.get_or_init(|| Mutex::new(0)); - let Ok(mut last) = slot.lock() else { - return; - }; - if !force && *last == state { - return; - } - *last = state; - drop(last); - emit_input_event(NativeWindowInputEvent::LockKeysSync { state }); - } - - /// Per-key modifier byte from tracked pressed keys (official GFN yS()/Cb()). - /// Lock keys sync separately via INPUT_LOCK_KEYS_SYNC, not here. - unsafe fn pressed_key_modifier_flags( - keys: &HashMap, - active_keycode: u16, - ) -> u16 { - let mut modifiers = 0u16; - let mut shift_tracked = false; - let mut control_tracked = false; - let mut alt_tracked = false; - let mut win_tracked = false; - - for key in keys.values() { - if key.keycode == active_keycode { - continue; - } - match key.keycode { - VK_LSHIFT | VK_RSHIFT | VK_SHIFT => { - shift_tracked = true; - modifiers |= 0x01; - } - VK_LCONTROL | VK_RCONTROL | VK_CONTROL => { - control_tracked = true; - modifiers |= 0x02; - } - VK_LMENU | VK_RMENU | VK_MENU => { - alt_tracked = true; - modifiers |= 0x04; - } - VK_LWIN | VK_RWIN => { - win_tracked = true; - modifiers |= 0x08; - } - _ => {} - } - } - - if !matches!(active_keycode, VK_LSHIFT | VK_RSHIFT | VK_SHIFT) - && !shift_tracked - && (is_key_down(VK_SHIFT) || is_key_down(VK_LSHIFT) || is_key_down(VK_RSHIFT)) - { - modifiers |= 0x01; - } - if !matches!(active_keycode, VK_LCONTROL | VK_RCONTROL | VK_CONTROL) - && !control_tracked - && (is_key_down(VK_CONTROL) || is_key_down(VK_LCONTROL) || is_key_down(VK_RCONTROL)) - { - modifiers |= 0x02; - } - if !matches!(active_keycode, VK_LMENU | VK_RMENU | VK_MENU) - && !alt_tracked - && (is_key_down(VK_MENU) || is_key_down(VK_LMENU) || is_key_down(VK_RMENU)) - { - modifiers |= 0x04; - } - if !matches!(active_keycode, VK_LWIN | VK_RWIN) - && !win_tracked - && (is_key_down(VK_LWIN) || is_key_down(VK_RWIN)) - { - modifiers |= 0x08; - } - - modifiers - } - - /// Legacy fallback for shortcut matching before a key enters the pressed-key map. - unsafe fn keyboard_modifier_flags(active_keycode: u16) -> u16 { - let keys = PRESSED_KEYS.get_or_init(|| Mutex::new(HashMap::new())); - if let Ok(keys) = keys.lock() { - if !keys.is_empty() { - return pressed_key_modifier_flags(&keys, active_keycode); - } - } - - let mut modifiers = 0u16; - if !matches!(active_keycode, VK_LSHIFT | VK_RSHIFT | VK_SHIFT) - && (is_key_down(VK_SHIFT) || is_key_down(VK_LSHIFT) || is_key_down(VK_RSHIFT)) - { - modifiers |= 0x01; - } - if !matches!(active_keycode, VK_LCONTROL | VK_RCONTROL | VK_CONTROL) - && (is_key_down(VK_CONTROL) || is_key_down(VK_LCONTROL) || is_key_down(VK_RCONTROL)) - { - modifiers |= 0x02; - } - if !matches!(active_keycode, VK_LMENU | VK_RMENU | VK_MENU) - && (is_key_down(VK_MENU) || is_key_down(VK_LMENU) || is_key_down(VK_RMENU)) - { - modifiers |= 0x04; - } - if !matches!(active_keycode, VK_LWIN | VK_RWIN) - && (is_key_down(VK_LWIN) || is_key_down(VK_RWIN)) - { - modifiers |= 0x08; - } - modifiers - } - - unsafe fn current_legacy_modifier_flags() -> u16 { - let mut modifiers = 0u16; - if is_key_down(VK_SHIFT) || is_key_down(VK_LSHIFT) || is_key_down(VK_RSHIFT) { - modifiers |= 0x01; - } - if is_key_down(VK_CONTROL) || is_key_down(VK_LCONTROL) || is_key_down(VK_RCONTROL) { - modifiers |= 0x02; - } - if is_key_down(VK_MENU) || is_key_down(VK_LMENU) || is_key_down(VK_RMENU) { - modifiers |= 0x04; - } - if is_key_down(VK_LWIN) || is_key_down(VK_RWIN) { - modifiers |= 0x08; - } - if (GetKeyState(VK_CAPITAL) & 0x0001) != 0 { - modifiers |= 0x10; - } - if (GetKeyState(VK_NUMLOCK) & 0x0001) != 0 { - modifiers |= 0x20; - } - modifiers - } - - unsafe fn is_key_down(keycode: u16) -> bool { - ((GetKeyState(keycode as i32) as u16) & 0x8000) != 0 - } - - unsafe fn is_alt_modifier_down(keys: &HashMap) -> bool { - keys.values() - .any(|key| matches!(key.keycode, VK_LMENU | VK_RMENU | VK_MENU)) - || ((GetKeyState(VK_MENU as i32) as u16) & 0x8000) != 0 - } - - fn shortcut_action_for_keypress( - keycode: u16, - scancode: u16, - modifiers: u16, - ) -> Option { - SHORTCUT_MATCHER - .get() - .and_then(|matcher| matcher.lock().ok()) - .and_then(|matcher| matcher.match_keydown(keycode, scancode, modifiers)) - } - - unsafe fn handle_shortcut_action(action: NativeStreamerShortcutAction) { - match action { - NativeStreamerShortcutAction::TogglePointerLock => { - if let Some(hwnd) = captured_hwnd().or_else(protected_hwnd) { - let hwnd = hwnd as Hwnd; - if is_input_captured(hwnd) { - release_input_capture(hwnd); - } else { - begin_input_capture(hwnd); - } - } - // Internal: Electron's own keydown owns the UI shortcut; only - // toggle RawInput capture here and keep the key out of GFN. - if crate::gstreamer_config::use_internal_renderer() { - return; - } - } - _ => { - if shortcut_action_releases_input_capture(action) { - release_current_input_capture(); - } - // Internal: Electron already owns UI shortcuts via keydown. - // Suppress the key from GFN (caller marks suppressed) without - // emitting Shortcut, or Electron would double-fire. - if crate::gstreamer_config::use_internal_renderer() { - return; - } - emit_input_event(NativeWindowInputEvent::Shortcut { action }); - } - } - } - - fn shortcut_action_releases_input_capture(action: NativeStreamerShortcutAction) -> bool { - matches!( - action, - NativeStreamerShortcutAction::ToggleFullscreen - | NativeStreamerShortcutAction::StopStream - ) - } - - fn legacy_mouse_button(message: Uint, wparam: Wparam) -> Option<(u8, bool)> { - match message { - WM_LBUTTONDOWN => Some((1, true)), - WM_LBUTTONUP => Some((1, false)), - WM_MBUTTONDOWN => Some((2, true)), - WM_MBUTTONUP => Some((2, false)), - WM_RBUTTONDOWN => Some((3, true)), - WM_RBUTTONUP => Some((3, false)), - WM_XBUTTONDOWN | WM_XBUTTONUP => { - let xbutton = ((wparam >> 16) & 0xffff) as u16; - let button = match xbutton { - XBUTTON1 => 4, - XBUTTON2 => 5, - _ => return None, - }; - Some((button, message == WM_XBUTTONDOWN)) - } - _ => None, - } - } - - fn emit_input_event(event: NativeWindowInputEvent) { - let Some(sender) = INPUT_EVENT_SENDER - .get() - .and_then(|sender| sender.lock().ok().and_then(|sender| sender.clone())) - else { - return; - }; - let _ = sender.send(event); - } - - fn is_clipboard_paste_shortcut(keycode: u16, modifiers: u16) -> bool { - keycode == VK_V - && ((modifiers & 0x02) != 0 || unsafe { is_ctrl_modifier_down() }) - && (modifiers & 0x04) == 0 - } - - unsafe fn is_ctrl_modifier_down() -> bool { - is_key_down(VK_CONTROL) || is_key_down(VK_LCONTROL) || is_key_down(VK_RCONTROL) - } - - fn emit_clipboard_paste_request() { - let Some(sender) = INPUT_EVENT_SENDER - .get() - .and_then(|sender| sender.lock().ok().and_then(|sender| sender.clone())) - else { - return; - }; - let _ = sender.send(NativeWindowInputEvent::ClipboardPaste); - } - - fn emit_input_capture_changed(captured: bool) { - // Electron maps this to notifyPointerLockChange so main-process Escape - // interception stays in sync with RawInput capture (tap→GFN, hold→exit). - let Some(sender) = INPUT_EVENT_SENDER - .get() - .and_then(|sender| sender.lock().ok().and_then(|sender| sender.clone())) - else { - return; - }; - let _ = sender.send(NativeWindowInputEvent::InputCaptureChanged { captured }); - } - - fn clamp_i32_to_i16(value: i32) -> i16 { - value.clamp(i16::MIN as i32, i16::MAX as i32) as i16 - } - - fn timestamp_us() -> u64 { - STARTED_AT - .get_or_init(Instant::now) - .elapsed() - .as_micros() - .min(u128::from(u64::MAX)) as u64 - } - - unsafe fn hide_cursor() { - while ShowCursor(0) >= 0 {} - } - - unsafe fn show_cursor() { - while ShowCursor(1) < 0 {} - } -} - -// The old BrowserWindow-HWND GstVideoOverlay path was removed. Internal mode -// uses `crate::internal_renderer::InternalRenderer` (child surface owned by the -// streamer). External mode uses the floating GStreamer window + window guard. - -#[cfg(target_os = "windows")] -pub(crate) fn primary_display_refresh_hz() -> Option { - const VREFRESH: i32 = 116; - - #[link(name = "user32")] - extern "system" { - fn GetDC(hwnd: *mut c_void) -> *mut c_void; - fn ReleaseDC(hwnd: *mut c_void, hdc: *mut c_void) -> i32; - } - - #[link(name = "gdi32")] - extern "system" { - fn GetDeviceCaps(hdc: *mut c_void, index: i32) -> i32; - } - - let hdc = unsafe { GetDC(std::ptr::null_mut()) }; - if hdc.is_null() { - return None; - } - - let refresh = unsafe { GetDeviceCaps(hdc, VREFRESH) }; - unsafe { - ReleaseDC(std::ptr::null_mut(), hdc); - } - - (refresh > 1).then_some(refresh as u32) -} - -#[cfg(not(target_os = "windows"))] -pub(crate) fn primary_display_refresh_hz() -> Option { - None -} diff --git a/native/opennow-streamer/src/gstreamer_transitions.rs b/native/opennow-streamer/src/gstreamer_transitions.rs deleted file mode 100644 index 0392bc0a7..000000000 --- a/native/opennow-streamer/src/gstreamer_transitions.rs +++ /dev/null @@ -1,111 +0,0 @@ -use crate::protocol::{NativeQueueMode, StreamSettings, VideoTransitionEvent}; - -pub(crate) const DEFAULT_VIDEO_QUEUE_DEPTH: u32 = 1; - -#[derive(Debug, Clone)] -pub(crate) struct TransitionSnapshot { - pub(crate) transition_type: String, - pub(crate) source: String, - pub(crate) at_ms: u64, - pub(crate) old_caps: Option, - pub(crate) new_caps: Option, - pub(crate) old_framerate: Option, - pub(crate) new_framerate: Option, - pub(crate) old_memory_mode: Option, - pub(crate) new_memory_mode: Option, - pub(crate) render_gap_ms: Option, - pub(crate) requested_fps: Option, - pub(crate) caps_framerate: Option, - pub(crate) high_fps_risk: bool, - pub(crate) queue_mode: NativeQueueMode, - pub(crate) summary: String, -} - -impl TransitionSnapshot { - pub(crate) fn to_event(&self) -> VideoTransitionEvent { - VideoTransitionEvent { - transition_type: self.transition_type.clone(), - source: self.source.clone(), - at_ms: self.at_ms, - old_caps: self.old_caps.clone(), - new_caps: self.new_caps.clone(), - old_framerate: self.old_framerate.clone(), - new_framerate: self.new_framerate.clone(), - old_memory_mode: self.old_memory_mode.clone(), - new_memory_mode: self.new_memory_mode.clone(), - render_gap_ms: self.render_gap_ms, - requested_fps: self.requested_fps, - caps_framerate: self.caps_framerate.clone(), - high_fps_risk: self.high_fps_risk, - queue_mode: self.queue_mode.as_str().to_owned(), - summary: self.summary.clone(), - } - } -} - -#[derive(Debug, Clone)] -pub(crate) struct TransitionTelemetry { - pub(crate) queue_mode: NativeQueueMode, - pub(crate) queue_depth: u32, - pub(crate) queue_depth_changes: u32, - pub(crate) present_pacing_changes: u32, - pub(crate) partial_flush_count: u32, - pub(crate) complete_flush_count: u32, - pub(crate) last_transition: Option, -} - -impl Default for TransitionTelemetry { - fn default() -> Self { - Self { - queue_mode: NativeQueueMode::Auto, - queue_depth: DEFAULT_VIDEO_QUEUE_DEPTH, - queue_depth_changes: 0, - present_pacing_changes: 0, - partial_flush_count: 0, - complete_flush_count: 0, - last_transition: None, - } - } -} - -pub(crate) fn resolve_queue_mode(settings: &StreamSettings) -> NativeQueueMode { - if let Some(force_queue_mode) = settings - .native_transition_diagnostics - .as_ref() - .and_then(|diagnostics| diagnostics.force_queue_mode) - { - return force_queue_mode; - } - - if settings.enable_cloud_gsync { - return NativeQueueMode::Vrr; - } - if settings.fps >= 240 { - return NativeQueueMode::Adaptive; - } - NativeQueueMode::Fixed -} - -pub(crate) fn format_transition_summary( - transition_type: &str, - source: &str, - requested_fps: Option, - old_framerate: Option<&str>, - new_framerate: Option<&str>, - high_fps_risk: bool, -) -> String { - let fps_summary = match (old_framerate, new_framerate) { - (Some(old), Some(new)) if old != new => format!("framerate {old} -> {new}"), - (_, Some(new)) => format!("framerate {new}"), - _ => "framerate unchanged/unknown".to_owned(), - }; - if high_fps_risk { - return format!( - "{transition_type} on {source}: {fps_summary} while requestedFps={} (high-fps transition risk).", - requested_fps - .map(|value| value.to_string()) - .unwrap_or_else(|| "unknown".to_owned()) - ); - } - format!("{transition_type} on {source}: {fps_summary}.") -} diff --git a/native/opennow-streamer/src/input.rs b/native/opennow-streamer/src/input.rs deleted file mode 100644 index 50a43cf22..000000000 --- a/native/opennow-streamer/src/input.rs +++ /dev/null @@ -1,775 +0,0 @@ -#![allow(dead_code)] - -use std::collections::HashMap; - -pub const INPUT_HEARTBEAT: u32 = 2; -pub const INPUT_KEY_DOWN: u32 = 3; -pub const INPUT_KEY_UP: u32 = 4; -pub const INPUT_MOUSE_REL: u32 = 7; -pub const INPUT_MOUSE_BUTTON_DOWN: u32 = 8; -pub const INPUT_MOUSE_BUTTON_UP: u32 = 9; -pub const INPUT_MOUSE_WHEEL: u32 = 10; -pub const INPUT_GAMEPAD: u32 = 12; -pub const INPUT_LOCK_KEYS_SYNC: u32 = 19; - -pub const GAMEPAD_MAX_CONTROLLERS: u8 = 4; -pub const GAMEPAD_PACKET_SIZE: usize = 38; -pub const PARTIALLY_RELIABLE_GAMEPAD_MASK_ALL: u32 = (1 << GAMEPAD_MAX_CONTROLLERS) - 1; -pub const PARTIALLY_RELIABLE_HID_DEVICE_MASK_ALL: u32 = 0xFFFF_FFFF; - -const WRAPPER_LEGACY_INPUT: u8 = 0x21; -const WRAPPER_SINGLE_INPUT: u8 = 0x22; -const WRAPPER_PARTIALLY_RELIABLE_INPUT: u8 = 0x26; -const WRAPPER_VERSION_MARKER: u8 = 0x23; -const WRAPPER_VERSION_HEADER_BYTES: usize = 9; -const WRAPPER_SINGLE_BODY_OFFSET: usize = WRAPPER_VERSION_HEADER_BYTES + 1; -const GAMEPAD_PAYLOAD_SIZE: u16 = 26; -const GAMEPAD_INNER_SIZE: u16 = 20; -const GAMEPAD_RESERVED_MARKER: u16 = 85; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct KeyboardPayload { - pub keycode: u16, - pub scancode: u16, - pub modifiers: u16, - pub timestamp_us: u64, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct MouseMovePayload { - pub dx: i16, - pub dy: i16, - pub timestamp_us: u64, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct MouseButtonPayload { - pub button: u8, - pub timestamp_us: u64, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct MouseWheelPayload { - pub delta: i16, - pub timestamp_us: u64, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct GamepadInput { - pub controller_id: u8, - pub buttons: u16, - pub left_trigger: u8, - pub right_trigger: u8, - pub left_stick_x: i16, - pub left_stick_y: i16, - pub right_stick_x: i16, - pub right_stick_y: i16, - pub connected: bool, - pub timestamp_us: u64, -} - -#[derive(Debug, Clone)] -pub struct InputEncoder { - protocol_version: u8, - gamepad_sequences: HashMap, -} - -impl Default for InputEncoder { - fn default() -> Self { - Self { - protocol_version: 2, - gamepad_sequences: HashMap::new(), - } - } -} - -impl InputEncoder { - pub fn new(protocol_version: u8) -> Self { - Self { - protocol_version, - gamepad_sequences: HashMap::new(), - } - } - - pub fn protocol_version(&self) -> u8 { - self.protocol_version - } - - pub fn set_protocol_version(&mut self, protocol_version: u8) { - self.protocol_version = protocol_version; - } - - pub fn reset_gamepad_sequences(&mut self) { - self.gamepad_sequences.clear(); - } - - pub fn encode_heartbeat(&self) -> Vec { - let mut payload = Vec::with_capacity(4); - put_u32_le(&mut payload, INPUT_HEARTBEAT); - payload - } - - pub fn encode_key_down(&self, payload: KeyboardPayload) -> Vec { - self.encode_keyboard(INPUT_KEY_DOWN, payload) - } - - pub fn encode_key_up(&self, payload: KeyboardPayload) -> Vec { - self.encode_keyboard(INPUT_KEY_UP, payload) - } - - pub fn encode_lock_keys_sync(&self, state: u8) -> Vec { - let mut bytes = Vec::with_capacity(5); - put_u32_le(&mut bytes, INPUT_LOCK_KEYS_SYNC); - bytes.push(state); - wrap_single_input(self.protocol_version, 0, &bytes) - } - - pub fn encode_mouse_move(&self, payload: MouseMovePayload) -> Vec { - let mut bytes = Vec::with_capacity(22); - put_u32_le(&mut bytes, INPUT_MOUSE_REL); - put_i16_be(&mut bytes, payload.dx); - put_i16_be(&mut bytes, payload.dy); - put_u16_be(&mut bytes, 0); - put_u32_be(&mut bytes, 0); - put_u64_be(&mut bytes, payload.timestamp_us); - wrap_legacy_input(self.protocol_version, payload.timestamp_us, &bytes) - } - - pub fn encode_mouse_button_down(&self, payload: MouseButtonPayload) -> Vec { - self.encode_mouse_button(INPUT_MOUSE_BUTTON_DOWN, payload) - } - - pub fn encode_mouse_button_up(&self, payload: MouseButtonPayload) -> Vec { - self.encode_mouse_button(INPUT_MOUSE_BUTTON_UP, payload) - } - - pub fn encode_mouse_wheel(&self, payload: MouseWheelPayload) -> Vec { - let mut bytes = Vec::with_capacity(22); - put_u32_le(&mut bytes, INPUT_MOUSE_WHEEL); - put_i16_be(&mut bytes, 0); - put_i16_be(&mut bytes, payload.delta); - put_u16_be(&mut bytes, 0); - put_u32_be(&mut bytes, 0); - put_u64_be(&mut bytes, payload.timestamp_us); - wrap_single_input(self.protocol_version, payload.timestamp_us, &bytes) - } - - pub fn encode_gamepad_state( - &mut self, - bitmap: u16, - input: GamepadInput, - use_partially_reliable: bool, - ) -> Vec { - let payload = encode_gamepad_payload(bitmap, input); - if !use_partially_reliable { - return wrap_legacy_input(self.protocol_version, input.timestamp_us, &payload); - } - - let sequence = self.next_gamepad_sequence(input.controller_id); - wrap_partially_reliable_input( - self.protocol_version, - input.timestamp_us, - input.controller_id, - sequence, - &payload, - ) - } - - fn encode_keyboard(&self, input_type: u32, payload: KeyboardPayload) -> Vec { - let mut bytes = Vec::with_capacity(18); - put_u32_le(&mut bytes, input_type); - put_u16_be(&mut bytes, payload.keycode); - put_u16_be(&mut bytes, payload.modifiers); - put_u16_be(&mut bytes, payload.scancode); - put_u64_be(&mut bytes, payload.timestamp_us); - wrap_single_input(self.protocol_version, payload.timestamp_us, &bytes) - } - - fn encode_mouse_button(&self, input_type: u32, payload: MouseButtonPayload) -> Vec { - let mut bytes = Vec::with_capacity(18); - put_u32_le(&mut bytes, input_type); - bytes.push(payload.button); - bytes.push(0); - put_u32_be(&mut bytes, 0); - put_u64_be(&mut bytes, payload.timestamp_us); - wrap_single_input(self.protocol_version, payload.timestamp_us, &bytes) - } - - fn next_gamepad_sequence(&mut self, controller_id: u8) -> u16 { - let current = *self.gamepad_sequences.get(&controller_id).unwrap_or(&1); - self.gamepad_sequences - .insert(controller_id, current.wrapping_add(1)); - current - } -} - -/// Rewrite the protocol v3 `[0x23][timestamp]` header to the send-time session clock. -pub fn restamp_protocol_v3_outer_timestamp(packet: &mut [u8], timestamp_us: u64) -> bool { - if packet.len() < WRAPPER_VERSION_HEADER_BYTES || packet[0] != WRAPPER_VERSION_MARKER { - return false; - } - - packet[1..WRAPPER_VERSION_HEADER_BYTES].copy_from_slice(×tamp_us.to_be_bytes()); - true -} - -/// Coalesce protocol v3 single-input packets into one datachannel payload. -/// Official GFN batches multiple `[0x22][body]` frames under one `[0x23][timestamp]` header -/// stamped with the send-time session clock (`ed()`), not per-event capture timestamps. -/// Returns `None` when payloads cannot be safely coalesced (for example protocol v2). -pub fn combine_single_input_packets( - payloads: &[Vec], - send_timestamp_us: u64, -) -> Option> { - if payloads.is_empty() { - return None; - } - if payloads.len() == 1 { - let mut packet = payloads[0].clone(); - restamp_protocol_v3_outer_timestamp(&mut packet, send_timestamp_us); - return Some(packet); - } - - let mut combined_bodies = Vec::new(); - - for payload in payloads { - if payload.len() >= WRAPPER_SINGLE_BODY_OFFSET - && payload[0] == WRAPPER_VERSION_MARKER - && payload[WRAPPER_VERSION_HEADER_BYTES] == WRAPPER_SINGLE_INPUT - { - combined_bodies.push(WRAPPER_SINGLE_INPUT); - combined_bodies.extend_from_slice(&payload[WRAPPER_SINGLE_BODY_OFFSET..]); - continue; - } - - return None; - } - - let mut bytes = Vec::with_capacity(WRAPPER_VERSION_HEADER_BYTES + combined_bodies.len()); - bytes.push(WRAPPER_VERSION_MARKER); - bytes.extend_from_slice(&send_timestamp_us.to_be_bytes()); - bytes.extend_from_slice(&combined_bodies); - Some(bytes) -} - -/// Finalize reliable keyboard/button packets for send, restamping v3 headers at send time. -pub fn finalize_reliable_single_input_packets( - payloads: &[Vec], - send_timestamp_us: u64, -) -> Vec> { - if payloads.is_empty() { - return Vec::new(); - } - - if let Some(combined) = combine_single_input_packets(payloads, send_timestamp_us) { - return vec![combined]; - } - - payloads - .iter() - .map(|payload| { - let mut packet = payload.clone(); - restamp_protocol_v3_outer_timestamp(&mut packet, send_timestamp_us); - packet - }) - .collect() -} - -pub fn partially_reliable_hid_mask_for_input_type(input_type: u32) -> u32 { - if input_type > 31 { - return 0; - } - 1_u32 << input_type -} - -pub fn is_partially_reliable_hid_transfer_eligible(input_type: u32) -> bool { - input_type == INPUT_MOUSE_REL -} - -pub(crate) fn layout_mapped_keyboard_scancode(physical_scancode: u16) -> u16 { - // GFN keyboard events use the selected remote layout plus VK; sending the local physical - // scancode makes QWERTZ-only keys such as Y/Z resolve as their US physical positions. - // Escape is the exception: Chromium's synthetic/pointer-lock path sends scan code 0x01, - // and GFN ignores native Escape taps when that scan code is discarded. - if physical_scancode == 0x0001 { - physical_scancode - } else { - 0 - } -} - -pub(crate) fn layout_mapped_keyboard_keycode(fallback_keycode: u16, physical_scancode: u16) -> u16 { - // Set 1 scancode -> official GFN browser position-dependent VK map (vendor Jr). - match physical_scancode { - 0x0001 => 0x1B, - 0x0002 => 0x31, - 0x0003 => 0x32, - 0x0004 => 0x33, - 0x0005 => 0x34, - 0x0006 => 0x35, - 0x0007 => 0x36, - 0x0008 => 0x37, - 0x0009 => 0x38, - 0x000A => 0x39, - 0x000B => 0x30, - 0x000C => 0xBD, - 0x000D => 0xBB, - 0x000E => 0x08, - 0x000F => 0x09, - 0x0010 => 0x51, - 0x0011 => 0x57, - 0x0012 => 0x45, - 0x0013 => 0x52, - 0x0014 => 0x54, - 0x0015 => 0x59, - 0x0016 => 0x55, - 0x0017 => 0x49, - 0x0018 => 0x4F, - 0x0019 => 0x50, - 0x001A => 0xDB, - 0x001B => 0xDD, - 0x001C => 0x0D, - 0x001D => 0xA2, - 0x001E => 0x41, - 0x001F => 0x53, - 0x0020 => 0x44, - 0x0021 => 0x46, - 0x0022 => 0x47, - 0x0023 => 0x48, - 0x0024 => 0x4A, - 0x0025 => 0x4B, - 0x0026 => 0x4C, - 0x0027 => 0xBA, - 0x0028 => 0xDE, - 0x0029 => 0xC0, - 0x002A => 0xA0, - 0x002B => 0xDC, - 0x002C => 0x5A, - 0x002D => 0x58, - 0x002E => 0x43, - 0x002F => 0x56, - 0x0030 => 0x42, - 0x0031 => 0x4E, - 0x0032 => 0x4D, - 0x0033 => 0xBC, - 0x0034 => 0xBE, - 0x0035 => 0xBF, - 0x0036 => 0xA1, - 0x0037 => 0x6A, - 0x0038 => 0xA4, - 0x0039 => 0x20, - 0x003A => 0x14, - 0x003B => 0x70, - 0x003C => 0x71, - 0x003D => 0x72, - 0x003E => 0x73, - 0x003F => 0x74, - 0x0040 => 0x75, - 0x0041 => 0x76, - 0x0042 => 0x77, - 0x0043 => 0x78, - 0x0044 => 0x79, - 0x0045 => fallback_keycode, - 0x0046 => 0x91, - 0x0047 => 0x67, - 0x0048 => 0x68, - 0x0049 => 0x69, - 0x004A => 0x6D, - 0x004B => 0x64, - 0x004C => 0x65, - 0x004D => 0x66, - 0x004E => 0x6B, - 0x004F => 0x61, - 0x0050 => 0x62, - 0x0051 => 0x63, - 0x0052 => 0x60, - 0x0053 => 0x6E, - 0x0056 => 0xE2, - 0x0057 => 0x7A, - 0x0058 => 0x7B, - 0x0059 => 0xBB, - 0x0064 => 0x7C, - 0x0070 => 0xE9, - 0x0073 => 0xC2, - 0x0079 => 0xEA, - 0x007B => 0xEB, - 0x007D => 0xC1, - 0x007E => 0xBC, - 0xE01C => 0x0D, - 0xE01D => 0xA3, - 0xE035 => 0x6F, - 0xE037 => 0x2A, - 0xE038 => 0xA5, - 0xE045 => 0x90, - 0xE047 => 0x24, - 0xE048 => 0x26, - 0xE049 => 0x21, - 0xE04B => 0x25, - 0xE04D => 0x27, - 0xE04F => 0x23, - 0xE050 => 0x28, - 0xE051 => 0x22, - 0xE052 => 0x2D, - 0xE053 => 0x2E, - 0xE05B => 0x5B, - 0xE05C => 0x5C, - 0xE05D => 0x5D, - _ => fallback_keycode, - } -} - -fn encode_gamepad_payload(bitmap: u16, input: GamepadInput) -> Vec { - let mut payload = Vec::with_capacity(GAMEPAD_PACKET_SIZE); - put_u32_le(&mut payload, INPUT_GAMEPAD); - put_u16_le(&mut payload, GAMEPAD_PAYLOAD_SIZE); - put_u16_le(&mut payload, input.controller_id as u16); - put_u16_le(&mut payload, bitmap); - put_u16_le(&mut payload, GAMEPAD_INNER_SIZE); - put_u16_le(&mut payload, input.buttons); - put_u16_le( - &mut payload, - input.left_trigger as u16 | ((input.right_trigger as u16) << 8), - ); - put_i16_le(&mut payload, input.left_stick_x); - put_i16_le(&mut payload, input.left_stick_y); - put_i16_le(&mut payload, input.right_stick_x); - put_i16_le(&mut payload, input.right_stick_y); - put_u16_le(&mut payload, 0); - put_u16_le(&mut payload, GAMEPAD_RESERVED_MARKER); - put_u16_le(&mut payload, 0); - put_u64_le(&mut payload, input.timestamp_us); - payload -} - -fn wrap_single_input(protocol_version: u8, timestamp_us: u64, payload: &[u8]) -> Vec { - if protocol_version < 3 { - return payload.to_vec(); - } - - let mut bytes = Vec::with_capacity(10 + payload.len()); - bytes.push(WRAPPER_VERSION_MARKER); - put_u64_be(&mut bytes, timestamp_us); - bytes.push(WRAPPER_SINGLE_INPUT); - bytes.extend_from_slice(payload); - bytes -} - -fn wrap_legacy_input(protocol_version: u8, timestamp_us: u64, payload: &[u8]) -> Vec { - if protocol_version < 3 { - return payload.to_vec(); - } - - let mut bytes = Vec::with_capacity(12 + payload.len()); - bytes.push(WRAPPER_VERSION_MARKER); - put_u64_be(&mut bytes, timestamp_us); - bytes.push(WRAPPER_LEGACY_INPUT); - put_u16_be(&mut bytes, payload.len() as u16); - bytes.extend_from_slice(payload); - bytes -} - -fn wrap_partially_reliable_input( - protocol_version: u8, - timestamp_us: u64, - controller_id: u8, - sequence: u16, - payload: &[u8], -) -> Vec { - if protocol_version < 3 { - return payload.to_vec(); - } - - let mut bytes = Vec::with_capacity(15 + payload.len()); - bytes.push(WRAPPER_VERSION_MARKER); - put_u64_be(&mut bytes, timestamp_us); - bytes.push(WRAPPER_PARTIALLY_RELIABLE_INPUT); - bytes.push(controller_id); - put_u16_be(&mut bytes, sequence); - bytes.push(WRAPPER_LEGACY_INPUT); - put_u16_be(&mut bytes, payload.len() as u16); - bytes.extend_from_slice(payload); - bytes -} - -fn put_u16_be(bytes: &mut Vec, value: u16) { - bytes.extend_from_slice(&value.to_be_bytes()); -} - -fn put_u16_le(bytes: &mut Vec, value: u16) { - bytes.extend_from_slice(&value.to_le_bytes()); -} - -fn put_i16_be(bytes: &mut Vec, value: i16) { - bytes.extend_from_slice(&value.to_be_bytes()); -} - -fn put_i16_le(bytes: &mut Vec, value: i16) { - bytes.extend_from_slice(&value.to_le_bytes()); -} - -fn put_u32_be(bytes: &mut Vec, value: u32) { - bytes.extend_from_slice(&value.to_be_bytes()); -} - -fn put_u32_le(bytes: &mut Vec, value: u32) { - bytes.extend_from_slice(&value.to_le_bytes()); -} - -fn put_u64_be(bytes: &mut Vec, value: u64) { - bytes.extend_from_slice(&value.to_be_bytes()); -} - -fn put_u64_le(bytes: &mut Vec, value: u64) { - bytes.extend_from_slice(&value.to_le_bytes()); -} - -#[cfg(test)] -mod combine_tests { - use super::*; - - #[test] - fn combines_protocol_v3_single_input_packets() { - let encoder = InputEncoder::new(3); - let first = encoder.encode_key_down(KeyboardPayload { - keycode: 0x0041, - scancode: 0, - modifiers: 0, - timestamp_us: 10, - }); - let second = encoder.encode_key_down(KeyboardPayload { - keycode: 0x0042, - scancode: 0, - modifiers: 0, - timestamp_us: 20, - }); - - let combined = combine_single_input_packets(&[first.clone(), second.clone()], 20) - .expect("v3 keyboard packets should combine"); - - assert_eq!(combined[0], WRAPPER_VERSION_MARKER); - assert_eq!(&combined[1..9], &20u64.to_be_bytes()); - assert_eq!(combined[9], WRAPPER_SINGLE_INPUT); - assert_eq!(&combined[10..14], &[0x03, 0, 0, 0]); - assert_eq!(combined[28], WRAPPER_SINGLE_INPUT); - assert_eq!(&combined[29..33], &[0x03, 0, 0, 0]); - } - - #[test] - fn leaves_protocol_v2_packets_uncombined() { - let encoder = InputEncoder::new(2); - let first = encoder.encode_key_down(KeyboardPayload { - keycode: 0x0041, - scancode: 0, - modifiers: 0, - timestamp_us: 10, - }); - let second = encoder.encode_key_up(KeyboardPayload { - keycode: 0x0041, - scancode: 0, - modifiers: 0, - timestamp_us: 11, - }); - - assert!(combine_single_input_packets(&[first, second], 11).is_none()); - } - - #[test] - fn restamps_single_v3_packet_at_send_time() { - let encoder = InputEncoder::new(3); - let mut packet = encoder.encode_key_down(KeyboardPayload { - keycode: 0x0041, - scancode: 0, - modifiers: 0, - timestamp_us: 10, - }); - - assert!(restamp_protocol_v3_outer_timestamp(&mut packet, 99)); - assert_eq!(&packet[1..9], &99u64.to_be_bytes()); - } - - #[test] - fn encodes_lock_keys_sync_as_single_input() { - let encoder = InputEncoder::new(3); - let payload = encoder.encode_lock_keys_sync(0x73); - - assert_eq!(payload.len(), 15); - assert_eq!(payload[0], WRAPPER_VERSION_MARKER); - assert_eq!(payload[9], WRAPPER_SINGLE_INPUT); - assert_eq!(&payload[10..14], &[0x13, 0, 0, 0]); - assert_eq!(payload[14], 0x73); - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn encodes_heartbeat_as_raw_little_endian_type() { - let encoder = InputEncoder::default(); - assert_eq!(encoder.encode_heartbeat(), vec![2, 0, 0, 0]); - } - - #[test] - fn encodes_protocol_v2_keyboard_without_wrapper() { - let encoder = InputEncoder::new(2); - let payload = encoder.encode_key_down(KeyboardPayload { - keycode: 0x0041, - scancode: 0x001e, - modifiers: 0x0002, - timestamp_us: 0x0102_0304_0506_0708, - }); - - assert_eq!(payload.len(), 18); - assert_eq!( - payload, - vec![ - 0x03, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x02, 0x00, 0x1e, 0x01, 0x02, 0x03, 0x04, - 0x05, 0x06, 0x07, 0x08, - ], - ); - } - - #[test] - fn wraps_protocol_v3_keyboard_as_single_input() { - let encoder = InputEncoder::new(3); - let payload = encoder.encode_key_up(KeyboardPayload { - keycode: 0x0041, - scancode: 0x001e, - modifiers: 0, - timestamp_us: 7, - }); - - assert_eq!(payload.len(), 28); - assert_eq!(payload[0], WRAPPER_VERSION_MARKER); - assert_eq!(&payload[1..9], &[0, 0, 0, 0, 0, 0, 0, 7]); - assert_eq!(payload[9], WRAPPER_SINGLE_INPUT); - assert_eq!(&payload[10..14], &[0x04, 0x00, 0x00, 0x00]); - } - - #[test] - fn wraps_protocol_v3_mouse_move_with_payload_size() { - let encoder = InputEncoder::new(3); - let payload = encoder.encode_mouse_move(MouseMovePayload { - dx: -2, - dy: 300, - timestamp_us: 9, - }); - - assert_eq!(payload.len(), 34); - assert_eq!(payload[0], WRAPPER_VERSION_MARKER); - assert_eq!(payload[9], WRAPPER_LEGACY_INPUT); - assert_eq!(&payload[10..12], &[0, 22]); - assert_eq!(&payload[12..16], &[0x07, 0x00, 0x00, 0x00]); - assert_eq!(&payload[16..18], &(-2_i16).to_be_bytes()); - assert_eq!(&payload[18..20], &300_i16.to_be_bytes()); - } - - #[test] - fn encodes_mouse_button_and_wheel_payloads() { - let encoder = InputEncoder::new(2); - let button = encoder.encode_mouse_button_down(MouseButtonPayload { - button: 1, - timestamp_us: 5, - }); - assert_eq!(button.len(), 18); - assert_eq!(&button[0..4], &[0x08, 0, 0, 0]); - assert_eq!(button[4], 1); - assert_eq!(&button[10..18], &[0, 0, 0, 0, 0, 0, 0, 5]); - - let wheel = encoder.encode_mouse_wheel(MouseWheelPayload { - delta: -120, - timestamp_us: 6, - }); - assert_eq!(wheel.len(), 22); - assert_eq!(&wheel[0..4], &[0x0a, 0, 0, 0]); - assert_eq!(&wheel[6..8], &(-120_i16).to_be_bytes()); - assert_eq!(&wheel[14..22], &[0, 0, 0, 0, 0, 0, 0, 6]); - } - - #[test] - fn encodes_gamepad_payload_and_wrappers() { - let mut encoder = InputEncoder::new(3); - let input = GamepadInput { - controller_id: 2, - buttons: 0x1001, - left_trigger: 12, - right_trigger: 34, - left_stick_x: -100, - left_stick_y: 100, - right_stick_x: -200, - right_stick_y: 200, - connected: true, - timestamp_us: 11, - }; - - let reliable = encoder.encode_gamepad_state(0x00ff, input, false); - assert_eq!(reliable.len(), 50); - assert_eq!(reliable[9], WRAPPER_LEGACY_INPUT); - assert_eq!(&reliable[10..12], &[0, GAMEPAD_PACKET_SIZE as u8]); - let raw = &reliable[12..]; - assert_eq!(&raw[0..4], &[0x0c, 0, 0, 0]); - assert_eq!(&raw[4..6], &GAMEPAD_PAYLOAD_SIZE.to_le_bytes()); - assert_eq!(&raw[6..8], &2_u16.to_le_bytes()); - assert_eq!(&raw[8..10], &0x00ff_u16.to_le_bytes()); - assert_eq!(&raw[12..14], &0x1001_u16.to_le_bytes()); - assert_eq!(&raw[14..16], &(12_u16 | (34_u16 << 8)).to_le_bytes()); - assert_eq!(&raw[16..18], &(-100_i16).to_le_bytes()); - assert_eq!(&raw[24..26], &0_u16.to_le_bytes()); - assert_eq!(&raw[26..28], &GAMEPAD_RESERVED_MARKER.to_le_bytes()); - assert_eq!(&raw[30..38], &11_u64.to_le_bytes()); - - let partially_reliable = encoder.encode_gamepad_state(0x00ff, input, true); - assert_eq!(partially_reliable.len(), 54); - assert_eq!(partially_reliable[9], WRAPPER_PARTIALLY_RELIABLE_INPUT); - assert_eq!(partially_reliable[10], 2); - assert_eq!(&partially_reliable[11..13], &1_u16.to_be_bytes()); - assert_eq!(partially_reliable[13], WRAPPER_LEGACY_INPUT); - assert_eq!(&partially_reliable[14..16], &[0, GAMEPAD_PACKET_SIZE as u8]); - - let next = encoder.encode_gamepad_state(0x00ff, input, true); - assert_eq!(&next[11..13], &2_u16.to_be_bytes()); - - encoder.reset_gamepad_sequences(); - let reset = encoder.encode_gamepad_state(0x00ff, input, true); - assert_eq!(&reset[11..13], &1_u16.to_be_bytes()); - } - - #[test] - fn computes_partially_reliable_hid_masks() { - assert_eq!( - partially_reliable_hid_mask_for_input_type(INPUT_MOUSE_REL), - 1 << 7 - ); - assert_eq!(partially_reliable_hid_mask_for_input_type(32), 0); - assert!(is_partially_reliable_hid_transfer_eligible(INPUT_MOUSE_REL)); - assert!(!is_partially_reliable_hid_transfer_eligible(INPUT_KEY_DOWN)); - } - - #[test] - fn layout_mapped_keyboard_input_omits_physical_scancodes() { - assert_eq!(layout_mapped_keyboard_scancode(0x0015), 0); - assert_eq!(layout_mapped_keyboard_scancode(0x002c), 0); - } - - #[test] - fn layout_mapped_keyboard_input_preserves_escape_scancode() { - assert_eq!(layout_mapped_keyboard_scancode(0x0001), 0x0001); - } - - #[test] - fn layout_mapped_keyboard_input_uses_official_position_keycodes() { - assert_eq!(layout_mapped_keyboard_keycode(0x0059, 0x002c), 0x005a); - assert_eq!(layout_mapped_keyboard_keycode(0x00ba, 0x001a), 0x00db); - assert_eq!(layout_mapped_keyboard_keycode(0x00c0, 0x0027), 0x00ba); - assert_eq!(layout_mapped_keyboard_keycode(0x00dc, 0x0029), 0x00c0); - assert_eq!(layout_mapped_keyboard_keycode(0x00bd, 0x0035), 0x00bf); - assert_eq!(layout_mapped_keyboard_keycode(0x0010, 0x0036), 0x00a1); - assert_eq!(layout_mapped_keyboard_keycode(0x0090, 0x0045), 0x0090); - assert_eq!(layout_mapped_keyboard_keycode(0x0013, 0x0045), 0x0013); - assert_eq!(layout_mapped_keyboard_keycode(0x00f2, 0x0070), 0x00e9); - assert_eq!(layout_mapped_keyboard_keycode(0x001c, 0x0079), 0x00ea); - assert_eq!(layout_mapped_keyboard_keycode(0x001d, 0x007b), 0x00eb); - assert_eq!(layout_mapped_keyboard_keycode(0x1234, 0xffff), 0x1234); - } -} diff --git a/native/opennow-streamer/src/internal_renderer.rs b/native/opennow-streamer/src/internal_renderer.rs deleted file mode 100644 index 4a15e2e0c..000000000 --- a/native/opennow-streamer/src/internal_renderer.rs +++ /dev/null @@ -1,1495 +0,0 @@ -//! Dedicated child native surface for the internal (single-window) renderer. -//! -//! GStreamer paints into a streamer-owned child surface that is parented into -//! the Electron window. The Electron BrowserWindow handle is never used as a -//! GstVideoOverlay target. - -use crate::protocol::{NativeRenderRect, NativeRenderSurface}; -use gstreamer as gst; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Mutex; - -#[cfg(any(target_os = "windows", target_os = "linux"))] -fn parse_native_handle(value: &str) -> Result { - let trimmed = value.trim(); - let hex = trimmed - .strip_prefix("0x") - .or_else(|| trimmed.strip_prefix("0X")); - let parsed = if let Some(hex) = hex { - usize::from_str_radix(hex, 16) - } else { - trimmed.parse::() - } - .map_err(|error| format!("Invalid native parent window handle {value:?}: {error}"))?; - - if parsed == 0 { - return Err("Native parent window handle is zero.".to_owned()); - } - - Ok(parsed) -} - -fn normalized_rect(rect: Option<&NativeRenderRect>) -> NativeRenderRect { - let Some(rect) = rect else { - return NativeRenderRect { - x: 0, - y: 0, - width: 2, - height: 2, - }; - }; - - NativeRenderRect { - x: rect.x.max(0), - y: rect.y.max(0), - width: rect.width.max(2), - height: rect.height.max(2), - } -} - -/// Platform child surface that GStreamer presents into. -#[derive(Debug)] -pub(crate) struct InternalRenderer { - inner: Mutex, - /// Child window handle for prepare-window-handle (avoids locking during sink setup). - child_handle: AtomicUsize, - child_width: std::sync::atomic::AtomicI32, - child_height: std::sync::atomic::AtomicI32, -} - -// Child window handles are owned exclusively by this process and only mutated -// under the mutex; GStreamer callbacks require Send + Sync on render state. -unsafe impl Send for InternalRenderer {} -unsafe impl Sync for InternalRenderer {} - -#[derive(Debug)] -struct InternalRendererState { - surface: Option, - last_parent: Option, - last_bounds: Option, - last_visible: bool, - video_sink: Option, -} - -impl InternalRenderer { - pub(crate) fn new() -> Self { - Self { - inner: Mutex::new(InternalRendererState { - surface: None, - last_parent: None, - last_bounds: None, - last_visible: false, - video_sink: None, - }), - child_handle: AtomicUsize::new(0), - child_width: std::sync::atomic::AtomicI32::new(2), - child_height: std::sync::atomic::AtomicI32::new(2), - } - } - - fn publish_child_handle(&self, handle: usize, bounds: &NativeRenderRect) { - self.child_handle.store(handle, Ordering::SeqCst); - self.child_width.store(bounds.width, Ordering::SeqCst); - self.child_height.store(bounds.height, Ordering::SeqCst); - } - - fn clear_child_handle(&self) { - self.child_handle.store(0, Ordering::SeqCst); - self.child_width.store(2, Ordering::SeqCst); - self.child_height.store(2, Ordering::SeqCst); - } - - #[cfg(target_os = "windows")] - pub(crate) fn child_handle(&self) -> usize { - self.child_handle.load(Ordering::SeqCst) - } - - pub(crate) fn set_video_sink(&self, sink: gst::Element) -> Result<(), String> { - let mut state = self - .inner - .lock() - .map_err(|_| "Internal renderer lock poisoned.".to_owned())?; - state.video_sink = Some(sink); - Self::rebind_overlay_locked(self, &mut state) - } - - pub(crate) fn apply_surface(&self, surface: &NativeRenderSurface) -> Result<(), String> { - let mut state = self - .inner - .lock() - .map_err(|_| "Internal renderer lock poisoned.".to_owned())?; - - let parent = match surface.window_handle.as_deref() { - Some(handle) => Some(parse_parent_handle(handle)?), - None => None, - }; - - if !surface.visible || parent.is_none() || surface.rect.is_none() { - if let Some(child) = state.surface.as_mut() { - child.set_visible(false)?; - } - state.last_visible = false; - return Ok(()); - } - - let parent = parent.expect("checked above"); - let bounds = normalized_rect(surface.rect.as_ref()); - - let needs_recreate = match state.last_parent { - Some(existing) => existing != parent || state.surface.is_none(), - None => true, - }; - - if needs_recreate { - if let Some(mut previous) = state.surface.take() { - previous.destroy(); - } - let child = PlatformChildSurface::create(parent, &bounds)?; - self.publish_child_handle(child.handle(), &bounds); - state.surface = Some(child); - state.last_parent = Some(parent); - state.last_bounds = Some(bounds.clone()); - state.last_visible = true; - Self::rebind_overlay_locked(self, &mut state)?; - } else { - let bounds_changed = state.last_bounds.as_ref() != Some(&bounds); - let was_visible = state.last_visible; - if let Some(child) = state.surface.as_mut() { - if bounds_changed { - child.set_bounds(&bounds)?; - } - if !was_visible { - child.set_visible(true)?; - } - self.publish_child_handle(child.handle(), &bounds); - } - state.last_bounds = Some(bounds); - state.last_visible = true; - if bounds_changed || !was_visible { - Self::rebind_overlay_locked(self, &mut state)?; - } - } - - Ok(()) - } - - pub(crate) fn destroy(&self) { - if let Ok(mut state) = self.inner.lock() { - if let Some(mut surface) = state.surface.take() { - surface.destroy(); - } - state.last_parent = None; - state.last_bounds = None; - state.last_visible = false; - state.video_sink = None; - } - self.clear_child_handle(); - } - - fn rebind_overlay_locked( - renderer: &InternalRenderer, - state: &mut InternalRendererState, - ) -> Result<(), String> { - let (Some(child), Some(sink)) = (state.surface.as_ref(), state.video_sink.as_ref()) else { - return Ok(()); - }; - let bounds = state.last_bounds.clone().unwrap_or_else(|| NativeRenderRect { - x: 0, - y: 0, - width: renderer.child_width.load(Ordering::SeqCst).max(2), - height: renderer.child_height.load(Ordering::SeqCst).max(2), - }); - bind_overlay_to_child(sink, child.handle(), Some(&bounds)) - } -} - -impl Drop for InternalRenderer { - fn drop(&mut self) { - self.destroy(); - } -} - -fn parse_parent_handle(value: &str) -> Result { - #[cfg(any(target_os = "windows", target_os = "linux"))] - { - parse_native_handle(value) - } - #[cfg(target_os = "macos")] - { - parse_native_handle_macos(value) - } - #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] - { - let _ = value; - Err("Internal renderer is not supported on this platform.".to_owned()) - } -} - -#[cfg(target_os = "macos")] -fn parse_native_handle_macos(value: &str) -> Result { - let trimmed = value.trim(); - let hex = trimmed - .strip_prefix("0x") - .or_else(|| trimmed.strip_prefix("0X")); - let parsed = if let Some(hex) = hex { - usize::from_str_radix(hex, 16) - } else { - trimmed.parse::() - } - .map_err(|error| format!("Invalid native parent view handle {value:?}: {error}"))?; - - if parsed == 0 { - return Err("Native parent view handle is zero.".to_owned()); - } - - Ok(parsed) -} - -fn bind_overlay_to_child( - sink: &gst::Element, - child_handle: usize, - bounds: Option<&NativeRenderRect>, -) -> Result<(), String> { - #[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] - { - use gst_video::prelude::*; - use gstreamer_video as gst_video; - - let overlay = sink - .clone() - .dynamic_cast::() - .map_err(|_| { - format!( - "Native render sink {} does not implement GstVideoOverlay.", - sink.name() - ) - })?; - - // SAFETY: child_handle is a platform window/view created by this process - // (or an X11 window id we own) and remains valid while the surface lives. - // Win32 vulkansink: our patched gstvkwindow presents on the GSTVULKAN child - // hwnd while parenting that child under this overlay handle (no floating window). - unsafe { - overlay.set_window_handle(child_handle); - } - overlay.handle_events(false); - // Child surface is already sized to the StreamView rect; present into the - // full client area so D3D sinks do not wait on an empty render rectangle. - let rect = normalized_rect(bounds); - let _ = overlay.set_render_rectangle(0, 0, rect.width, rect.height); - overlay.expose(); - Ok(()) - } - #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] - { - let _ = (sink, child_handle, bounds); - Err("Internal renderer overlay binding is not supported on this platform.".to_owned()) - } -} - -#[derive(Debug)] -struct PlatformChildSurface { - #[cfg(target_os = "windows")] - win: windows_child::ChildWindow, - #[cfg(target_os = "macos")] - view: usize, - #[cfg(target_os = "linux")] - window: linux_child::XWindow, - #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] - _unused: (), -} - -impl PlatformChildSurface { - fn create(parent: usize, bounds: &NativeRenderRect) -> Result { - #[cfg(target_os = "windows")] - { - Ok(Self { - win: windows_child::ChildWindow::create(parent, bounds)?, - }) - } - #[cfg(target_os = "macos")] - { - let view = macos_child::create_child(parent, bounds)?; - Ok(Self { - view: view as usize, - }) - } - #[cfg(target_os = "linux")] - { - let window = linux_child::create_child(parent, bounds)?; - Ok(Self { window }) - } - #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] - { - let _ = (parent, bounds); - Err("Internal renderer child surfaces are not supported on this platform.".to_owned()) - } - } - - fn handle(&self) -> usize { - #[cfg(target_os = "windows")] - { - self.win.hwnd() - } - #[cfg(target_os = "macos")] - { - self.view - } - #[cfg(target_os = "linux")] - { - self.window.window as usize - } - #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] - { - 0 - } - } - - fn set_bounds(&mut self, bounds: &NativeRenderRect) -> Result<(), String> { - #[cfg(target_os = "windows")] - { - self.win.set_bounds(bounds) - } - #[cfg(target_os = "macos")] - { - macos_child::set_bounds(self.view as macos_child::NsViewPtr, bounds) - } - #[cfg(target_os = "linux")] - { - linux_child::set_bounds(&self.window, bounds) - } - #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] - { - let _ = bounds; - Ok(()) - } - } - - fn set_visible(&mut self, visible: bool) -> Result<(), String> { - #[cfg(target_os = "windows")] - { - self.win.set_visible(visible) - } - #[cfg(target_os = "macos")] - { - macos_child::set_visible(self.view as macos_child::NsViewPtr, visible) - } - #[cfg(target_os = "linux")] - { - linux_child::set_visible(&self.window, visible) - } - #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] - { - let _ = visible; - Ok(()) - } - } - - fn destroy(&mut self) { - #[cfg(target_os = "windows")] - { - self.win.destroy(); - } - #[cfg(target_os = "macos")] - { - macos_child::destroy(self.view as macos_child::NsViewPtr); - self.view = 0; - } - #[cfg(target_os = "linux")] - { - linux_child::destroy(&mut self.window); - } - } -} - -#[cfg(target_os = "windows")] -mod windows_child { - use crate::protocol::NativeRenderRect; - use std::ffi::c_void; - use std::ptr::{null, null_mut}; - use std::sync::atomic::{AtomicBool, Ordering}; - - pub(super) type Hwnd = *mut c_void; - - type Atom = u16; - type Bool = i32; - type Hinstance = *mut c_void; - type Hmenu = *mut c_void; - type Lparam = isize; - type Lresult = isize; - type Wparam = usize; - - const CS_HREDRAW: u32 = 0x0002; - const CS_OWNDC: u32 = 0x0020; - const CS_VREDRAW: u32 = 0x0001; - // Sibling of Chromium Intermediate D3D: sit on top for present, force - // Intermediate D3D WS_CLIPSIBLINGS so it punches a paint hole. Input is - // owned by RawInput on this HWND (not Electron click-through). - const HWND_TOP: Hwnd = std::ptr::null_mut(); - const GWL_STYLE: i32 = -16; - const GWL_EXSTYLE: i32 = -20; - const SWP_NOSIZE: u32 = 0x0001; - const SWP_NOMOVE: u32 = 0x0002; - const SWP_NOACTIVATE: u32 = 0x0010; - const SWP_FRAMECHANGED: u32 = 0x0020; - const SWP_SHOWWINDOW: u32 = 0x0040; - const SWP_HIDEWINDOW: u32 = 0x0080; - const SWP_NOCOPYBITS: u32 = 0x0100; - const SWP_NOZORDER: u32 = 0x0004; - const SWP_NOSENDCHANGING: u32 = 0x0400; - const SW_HIDE: i32 = 0; - const SW_SHOWNOACTIVATE: i32 = 4; - const WM_DESTROY: u32 = 0x0002; - const WM_ERASEBKGND: u32 = 0x0014; - const WM_MOUSEACTIVATE: u32 = 0x0021; - const WM_PAINT: u32 = 0x000F; - const WS_CHILD: u32 = 0x4000_0000; - const WS_CLIPCHILDREN: u32 = 0x0200_0000; - const WS_CLIPSIBLINGS: u32 = 0x0400_0000; - const WS_VISIBLE: u32 = 0x1000_0000; - const WS_POPUP: u32 = 0x8000_0000; - const WS_CAPTION: u32 = 0x00C0_0000; - const WS_THICKFRAME: u32 = 0x0004_0000; - const WS_MINIMIZEBOX: u32 = 0x0002_0000; - const WS_MAXIMIZEBOX: u32 = 0x0001_0000; - const WS_SYSMENU: u32 = 0x0008_0000; - const WS_BORDER: u32 = 0x0080_0000; - const WS_EX_APPWINDOW: u32 = 0x0004_0000; - const WS_EX_TOOLWINDOW: u32 = 0x0000_0080; - const WS_EX_NOACTIVATE: u32 = 0x0800_0000; - const MA_ACTIVATE: isize = 1; - const BLACK_BRUSH: i32 = 4; - - #[repr(C)] - struct WndClassExW { - cb_size: u32, - style: u32, - lpfn_wnd_proc: Option Lresult>, - cb_cls_extra: i32, - cb_wnd_extra: i32, - h_instance: Hinstance, - h_icon: *mut c_void, - h_cursor: *mut c_void, - h_br_background: *mut c_void, - lpsz_menu_name: *const u16, - lpsz_class_name: *const u16, - h_icon_sm: *mut c_void, - } - - #[link(name = "user32")] - extern "system" { - fn CreateWindowExW( - dw_ex_style: u32, - lp_class_name: *const u16, - lp_window_name: *const u16, - dw_style: u32, - x: i32, - y: i32, - n_width: i32, - n_height: i32, - h_wnd_parent: Hwnd, - h_menu: Hmenu, - h_instance: Hinstance, - lp_param: *mut c_void, - ) -> Hwnd; - fn DefWindowProcW(h_wnd: Hwnd, msg: u32, w_param: Wparam, l_param: Lparam) -> Lresult; - fn DestroyWindow(h_wnd: Hwnd) -> Bool; - fn EnumChildWindows( - h_wnd_parent: Hwnd, - lp_enum_func: Option Bool>, - l_param: Lparam, - ) -> Bool; - fn EnumWindows( - lp_enum_func: Option Bool>, - l_param: Lparam, - ) -> Bool; - fn GetClassNameW(h_wnd: Hwnd, lp_class_name: *mut u16, n_max_count: i32) -> i32; - fn GetModuleHandleW(lp_module_name: *const u16) -> Hinstance; - fn GetParent(h_wnd: Hwnd) -> Hwnd; - fn GetWindowLongPtrW(h_wnd: Hwnd, n_index: i32) -> isize; - fn GetWindowThreadProcessId(h_wnd: Hwnd, process_id: *mut u32) -> u32; - fn RegisterClassExW(class: *const WndClassExW) -> Atom; - fn SetParent(h_wnd_child: Hwnd, h_wnd_new_parent: Hwnd) -> Hwnd; - fn SetWindowLongPtrW(h_wnd: Hwnd, n_index: i32, dw_new_long: isize) -> isize; - fn SetWindowPos( - h_wnd: Hwnd, - h_wnd_insert_after: Hwnd, - x: i32, - y: i32, - cx: i32, - cy: i32, - flags: u32, - ) -> Bool; - fn ShowWindow(h_wnd: Hwnd, n_cmd_show: i32) -> Bool; - fn ValidateRect(h_wnd: Hwnd, lp_rect: *const c_void) -> Bool; - fn GetMessageW(lp_msg: *mut Msg, h_wnd: Hwnd, w_msg_filter_min: u32, w_msg_filter_max: u32) -> Bool; - fn TranslateMessage(lp_msg: *const Msg) -> Bool; - fn DispatchMessageW(lp_msg: *const Msg) -> Lresult; - fn PostMessageW(h_wnd: Hwnd, msg: u32, w_param: Wparam, l_param: Lparam) -> Bool; - fn PostThreadMessageW(id_thread: u32, msg: u32, w_param: Wparam, l_param: Lparam) -> Bool; - fn GetCurrentThreadId() -> u32; - } - - #[link(name = "kernel32")] - extern "system" { - fn GetCurrentProcessId() -> u32; - } - - #[repr(C)] - struct Msg { - hwnd: Hwnd, - message: u32, - w_param: Wparam, - l_param: Lparam, - time: u32, - pt_x: i32, - pt_y: i32, - } - - const WM_QUIT: u32 = 0x0012; - const WM_USER_SET_BOUNDS: u32 = 0x0400; - const WM_USER_SET_VISIBLE: u32 = 0x0401; - - #[link(name = "gdi32")] - extern "system" { - fn GetStockObject(index: i32) -> *mut c_void; - } - - static CLASS_REGISTERED: AtomicBool = AtomicBool::new(false); - const CLASS_NAME: &[u16] = &[ - b'O' as u16, b'p' as u16, b'e' as u16, b'n' as u16, b'N' as u16, b'O' as u16, b'W' as u16, - b'I' as u16, b'n' as u16, b't' as u16, b'e' as u16, b'r' as u16, b'n' as u16, b'a' as u16, - b'l' as u16, b'V' as u16, b'i' as u16, b'd' as u16, b'e' as u16, b'o' as u16, 0, - ]; - - unsafe extern "system" fn wnd_proc( - hwnd: Hwnd, - msg: u32, - w_param: Wparam, - l_param: Lparam, - ) -> Lresult { - match msg { - WM_USER_SET_BOUNDS => { - let x = (l_param & 0xFFFF) as i16 as i32; - let y = ((l_param >> 16) & 0xFFFF) as i16 as i32; - let w = (w_param & 0xFFFF) as i32; - let h = ((w_param >> 16) & 0xFFFF) as i32; - let parent = GetParent(hwnd); - if !parent.is_null() { - enable_clip_styles(parent, find_chromium_content_hwnd(parent)); - } - SetWindowPos( - hwnd, - HWND_TOP, - x, - y, - w.max(2), - h.max(2), - SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOSENDCHANGING, - ); - 0 - } - WM_USER_SET_VISIBLE => { - let visible = w_param != 0; - ShowWindow(hwnd, if visible { SW_SHOWNOACTIVATE } else { SW_HIDE }); - SetWindowPos( - hwnd, - HWND_TOP, - 0, - 0, - 0, - 0, - SWP_NOACTIVATE - | SWP_NOZORDER - | SWP_NOSIZE - | SWP_NOMOVE - | if visible { - SWP_SHOWWINDOW - } else { - SWP_HIDEWINDOW - }, - ); - 0 - } - // Activation / RawInput capture is handled by the chained platform - // wndproc installed after create (see arm_internal_child_input). - WM_MOUSEACTIVATE => MA_ACTIVATE, - WM_ERASEBKGND => 1, - WM_PAINT => { - ValidateRect(hwnd, null()); - 0 - } - WM_DESTROY => 0, - _ => DefWindowProcW(hwnd, msg, w_param, l_param), - } - } - - unsafe extern "system" fn collect_chromium_child(hwnd: Hwnd, l_param: Lparam) -> Bool { - let out = &mut *(l_param as *mut Hwnd); - if !out.is_null() { - return 1; - } - let mut class_name = [0u16; 64]; - let len = GetClassNameW(hwnd, class_name.as_mut_ptr(), class_name.len() as i32); - if len <= 0 { - return 1; - } - // Chromium's Intermediate D3D / content HWND class names. - let name: String = String::from_utf16_lossy(&class_name[..len as usize]); - if name.contains("Intermediate D3D") - || name.contains("Chrome_RenderWidgetHostHWND") - || name.contains("Chrome_WidgetWin_") - { - *out = hwnd; - return 0; - } - 1 - } - - unsafe fn find_chromium_content_hwnd(parent: Hwnd) -> Option { - let mut found: Hwnd = null_mut(); - EnumChildWindows( - parent, - Some(collect_chromium_child), - &mut found as *mut Hwnd as Lparam, - ); - if found.is_null() { - None - } else { - Some(found) - } - } - - unsafe extern "system" fn collect_gst_vulkan_child(hwnd: Hwnd, l_param: Lparam) -> Bool { - let out = &mut *(l_param as *mut Hwnd); - if !out.is_null() { - return 1; - } - if class_name_is_gst_vulkan(hwnd) { - *out = hwnd; - return 0; - } - 1 - } - - unsafe extern "system" fn collect_gst_vulkan_top_level(hwnd: Hwnd, l_param: Lparam) -> Bool { - let state = &mut *(l_param as *mut (u32, Hwnd)); - if !state.1.is_null() { - return 1; - } - let mut process_id = 0u32; - GetWindowThreadProcessId(hwnd, &mut process_id); - if process_id != state.0 { - return 1; - } - if class_name_is_gst_vulkan(hwnd) { - state.1 = hwnd; - return 0; - } - 1 - } - - unsafe fn class_name_is_gst_vulkan(hwnd: Hwnd) -> bool { - let mut class_name = [0u16; 64]; - let len = GetClassNameW(hwnd, class_name.as_mut_ptr(), class_name.len() as i32); - if len <= 0 { - return false; - } - String::from_utf16_lossy(&class_name[..len as usize]) == "GSTVULKAN" - } - - unsafe fn find_gst_vulkan_under_parent(parent: Hwnd) -> Option { - let mut found: Hwnd = null_mut(); - EnumChildWindows( - parent, - Some(collect_gst_vulkan_child), - &mut found as *mut Hwnd as Lparam, - ); - if found.is_null() { - None - } else { - Some(found) - } - } - - unsafe fn find_process_gst_vulkan_window() -> Option { - let mut state = (GetCurrentProcessId(), null_mut::()); - EnumWindows( - Some(collect_gst_vulkan_top_level), - &mut state as *mut (u32, Hwnd) as Lparam, - ); - if state.1.is_null() { - None - } else { - Some(state.1) - } - } - - /// Hide any top-level GSTVULKAN windows so they never float over Electron. - pub(super) fn suppress_top_level_gst_vulkan_windows() { - unsafe { - let mut state = (GetCurrentProcessId(), 0u32); - EnumWindows( - Some(suppress_top_level_gst_vulkan), - &mut state as *mut (u32, u32) as Lparam, - ); - } - } - - unsafe extern "system" fn suppress_top_level_gst_vulkan(hwnd: Hwnd, l_param: Lparam) -> Bool { - let state = &mut *(l_param as *mut (u32, u32)); - let mut process_id = 0u32; - GetWindowThreadProcessId(hwnd, &mut process_id); - if process_id != state.0 || !class_name_is_gst_vulkan(hwnd) { - return 1; - } - // Already embedded under some parent — leave alone. - if !GetParent(hwnd).is_null() { - return 1; - } - ShowWindow(hwnd, SW_HIDE); - let ex = GetWindowLongPtrW(hwnd, GWL_EXSTYLE); - let desired_ex = (ex | WS_EX_TOOLWINDOW as isize | WS_EX_NOACTIVATE as isize) - & !(WS_EX_APPWINDOW as isize); - if desired_ex != ex { - SetWindowLongPtrW(hwnd, GWL_EXSTYLE, desired_ex); - } - SetWindowPos( - hwnd, - HWND_TOP, - -32_000, - -32_000, - 2, - 2, - SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOSENDCHANGING, - ); - state.1 = state.1.saturating_add(1); - 1 - } - - /// Reparent vulkansink's GSTVULKAN hwnd into our Internal child and size it. - /// Keeps the window hidden while top-level so nothing floats over Electron. - pub(super) fn embed_gst_vulkan_window(parent: Hwnd, width: i32, height: i32) -> bool { - if parent.is_null() { - return false; - } - let width = width.max(2); - let height = height.max(2); - unsafe { - suppress_top_level_gst_vulkan_windows(); - - let Some(vulkan) = find_gst_vulkan_under_parent(parent) - .or_else(|| find_process_gst_vulkan_window()) - else { - return false; - }; - - // Never show as a top-level window — hide first, then reparent, then show. - if GetParent(vulkan) != parent { - ShowWindow(vulkan, SW_HIDE); - SetParent(vulkan, parent); - } - - let style = GetWindowLongPtrW(vulkan, GWL_STYLE); - let cleared = (WS_POPUP - | WS_CAPTION - | WS_THICKFRAME - | WS_MINIMIZEBOX - | WS_MAXIMIZEBOX - | WS_SYSMENU - | WS_BORDER) as isize; - let desired = (style & !cleared) - | (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN) as isize; - if desired != style { - SetWindowLongPtrW(vulkan, GWL_STYLE, desired); - } - - let ex = GetWindowLongPtrW(vulkan, GWL_EXSTYLE); - let desired_ex = ex & !(WS_EX_APPWINDOW as isize | WS_EX_TOOLWINDOW as isize); - if desired_ex != ex { - SetWindowLongPtrW(vulkan, GWL_EXSTYLE, desired_ex); - } - - SetWindowPos( - vulkan, - HWND_TOP, - 0, - 0, - width, - height, - SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOCOPYBITS, - ); - ShowWindow(vulkan, SW_SHOWNOACTIVATE); - true - } - } - - unsafe fn enable_clip_styles(parent: Hwnd, chromium: Option) { - let parent_style = GetWindowLongPtrW(parent, GWL_STYLE); - let desired_parent = parent_style | (WS_CLIPCHILDREN as isize); - if desired_parent != parent_style { - SetWindowLongPtrW(parent, GWL_STYLE, desired_parent); - } - if let Some(chrome) = chromium { - let chrome_style = GetWindowLongPtrW(chrome, GWL_STYLE); - let desired_chrome = chrome_style | (WS_CLIPSIBLINGS as isize); - if desired_chrome != chrome_style { - SetWindowLongPtrW(chrome, GWL_STYLE, desired_chrome); - } - } - } - - fn ensure_class() -> Result<(), String> { - if CLASS_REGISTERED.load(Ordering::SeqCst) { - return Ok(()); - } - - unsafe { - let instance = GetModuleHandleW(null()); - if instance.is_null() { - return Err("GetModuleHandleW failed for internal renderer class.".to_owned()); - } - - let class = WndClassExW { - cb_size: std::mem::size_of::() as u32, - style: CS_HREDRAW | CS_VREDRAW | CS_OWNDC, - lpfn_wnd_proc: Some(wnd_proc), - cb_cls_extra: 0, - cb_wnd_extra: 0, - h_instance: instance, - h_icon: null_mut(), - h_cursor: null_mut(), - h_br_background: GetStockObject(BLACK_BRUSH), - lpsz_menu_name: null(), - lpsz_class_name: CLASS_NAME.as_ptr(), - h_icon_sm: null_mut(), - }; - - let atom = RegisterClassExW(&class); - if atom == 0 { - // Another thread may have won the race; treat as success if already registered. - if !CLASS_REGISTERED.load(Ordering::SeqCst) { - // ERROR_CLASS_ALREADY_EXISTS == 1410 - // Still mark registered so we do not loop. - } - } - CLASS_REGISTERED.store(true, Ordering::SeqCst); - } - - Ok(()) - } - - pub(super) struct ChildWindow { - hwnd: usize, - thread_id: u32, - join: Option>, - } - - impl std::fmt::Debug for ChildWindow { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("ChildWindow") - .field("hwnd", &self.hwnd) - .field("thread_id", &self.thread_id) - .finish() - } - } - - impl ChildWindow { - pub(super) fn create(parent: usize, bounds: &NativeRenderRect) -> Result { - ensure_class()?; - let parent_hwnd = parent as Hwnd; - if parent_hwnd.is_null() { - return Err("Internal renderer parent HWND is null.".to_owned()); - } - - let (tx, rx) = std::sync::mpsc::channel::>(); - let bounds = bounds.clone(); - let parent_handle = parent; - let join = std::thread::Builder::new() - .name("opennow-internal-video".to_owned()) - .spawn(move || { - let created = - unsafe { create_child_on_thread(parent_handle as Hwnd, &bounds) }; - match created { - Ok(hwnd) => { - let thread_id = unsafe { GetCurrentThreadId() }; - let _ = tx.send(Ok((hwnd as usize, thread_id))); - run_message_loop(hwnd); - } - Err(error) => { - let _ = tx.send(Err(error)); - } - } - }) - .map_err(|error| format!("Failed to spawn internal renderer UI thread: {error}"))?; - - let (hwnd, thread_id) = rx - .recv() - .map_err(|_| "Internal renderer UI thread exited before creating HWND.".to_owned())? - ?; - - Ok(Self { - hwnd, - thread_id, - join: Some(join), - }) - } - - pub(super) fn hwnd(&self) -> usize { - self.hwnd - } - - pub(super) fn set_bounds(&self, bounds: &NativeRenderRect) -> Result<(), String> { - if self.hwnd == 0 { - return Ok(()); - } - // Pack x/y into lParam (signed 16-bit each) and w/h into wParam. - let x = bounds.x.clamp(i16::MIN as i32, i16::MAX as i32) as u16 as u32; - let y = bounds.y.clamp(i16::MIN as i32, i16::MAX as i32) as u16 as u32; - let l_param = ((y as Lparam) << 16) | (x as Lparam); - let w = bounds.width.max(2).min(u16::MAX as i32) as u16 as usize; - let h = bounds.height.max(2).min(u16::MAX as i32) as u16 as usize; - let w_param = (h << 16) | w; - unsafe { - if PostMessageW( - self.hwnd as Hwnd, - WM_USER_SET_BOUNDS, - w_param, - l_param, - ) == 0 - { - return Err("PostMessageW(SET_BOUNDS) failed for internal renderer.".to_owned()); - } - } - Ok(()) - } - - pub(super) fn set_visible(&self, visible: bool) -> Result<(), String> { - if self.hwnd == 0 { - return Ok(()); - } - unsafe { - if PostMessageW( - self.hwnd as Hwnd, - WM_USER_SET_VISIBLE, - if visible { 1 } else { 0 }, - 0, - ) == 0 - { - return Err("PostMessageW(SET_VISIBLE) failed for internal renderer.".to_owned()); - } - } - Ok(()) - } - - pub(super) fn destroy(&mut self) { - if self.hwnd != 0 { - unsafe { - // DestroyWindow posts WM_DESTROY; then quit the UI thread loop. - DestroyWindow(self.hwnd as Hwnd); - PostThreadMessageW(self.thread_id, WM_QUIT, 0, 0); - } - self.hwnd = 0; - } - if let Some(join) = self.join.take() { - let _ = join.join(); - } - } - } - - impl Drop for ChildWindow { - fn drop(&mut self) { - self.destroy(); - } - } - - unsafe fn create_child_on_thread(parent_hwnd: Hwnd, bounds: &NativeRenderRect) -> Result { - let instance = GetModuleHandleW(null()); - let chromium = find_chromium_content_hwnd(parent_hwnd); - enable_clip_styles(parent_hwnd, chromium); - - // Sibling above Intermediate D3D for present. Clip styles punch a hole - // so Chromium does not paint over us. Input uses RawInput on this HWND - // (Electron click-through is unreliable across process boundaries). - // Do not use WS_EX_NOACTIVATE: the first click must activate so RawInput - // capture can arm (same as the floating external renderer window). - let hwnd = CreateWindowExW( - 0, - CLASS_NAME.as_ptr(), - null(), - WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, - bounds.x, - bounds.y, - bounds.width, - bounds.height, - parent_hwnd, - null_mut(), - instance, - null_mut(), - ); - - if hwnd.is_null() { - return Err("CreateWindowExW failed for internal renderer child HWND.".to_owned()); - } - - SetWindowPos( - hwnd, - HWND_TOP, - bounds.x, - bounds.y, - bounds.width, - bounds.height, - SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOSENDCHANGING, - ); - - Ok(hwnd) - } - - fn run_message_loop(_hwnd: Hwnd) { - unsafe { - let mut msg = Msg { - hwnd: null_mut(), - message: 0, - w_param: 0, - l_param: 0, - time: 0, - pt_x: 0, - pt_y: 0, - }; - // D3D11 videosink present requires a live message pump on the - // thread that owns the child HWND. Without this, sink stays at 0 fps. - while GetMessageW(&mut msg, null_mut(), 0, 0) > 0 { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - } - } - - // ChildWindow owns create/bounds/visible/destroy + UI thread lifecycle. -} - -#[cfg(target_os = "macos")] -mod macos_child { - use crate::protocol::NativeRenderRect; - use std::ffi::c_void; - use std::sync::OnceLock; - - pub(super) type NsViewPtr = *mut c_void; - - #[link(name = "objc")] - extern "C" { - fn sel_registerName(name: *const i8) -> *const c_void; - fn objc_getClass(name: *const i8) -> *mut c_void; - fn objc_msgSend(); - } - - // objc_msgSend is variadic; call via transmute per selector signature. - type MsgSend0 = unsafe extern "C" fn(*mut c_void, *const c_void) -> *mut c_void; - type MsgSend1Ptr = unsafe extern "C" fn(*mut c_void, *const c_void, *mut c_void) -> *mut c_void; - type MsgSendRect = unsafe extern "C" fn(*mut c_void, *const c_void, NsRect) -> *mut c_void; - type MsgSendBool = unsafe extern "C" fn(*mut c_void, *const c_void, bool); - type MsgSendVoidPtr = unsafe extern "C" fn(*mut c_void, *const c_void, *mut c_void); - - #[repr(C)] - #[derive(Clone, Copy)] - struct NsPoint { - x: f64, - y: f64, - } - - #[repr(C)] - #[derive(Clone, Copy)] - struct NsSize { - width: f64, - height: f64, - } - - #[repr(C)] - #[derive(Clone, Copy)] - struct NsRect { - origin: NsPoint, - size: NsSize, - } - - struct Selectors { - alloc: *const c_void, - init_with_frame: *const c_void, - add_subview: *const c_void, - set_frame: *const c_void, - set_hidden: *const c_void, - set_wants_layer: *const c_void, - set_autoresizes_subviews: *const c_void, - release: *const c_void, - bounds: *const c_void, - } - - // Objective-C selectors are process-global, immutable runtime tokens returned by - // sel_registerName. Sharing these non-null tokens does not share pointed-to data. - unsafe impl Send for Selectors {} - unsafe impl Sync for Selectors {} - - fn selectors() -> &'static Selectors { - static SELECTORS: OnceLock = OnceLock::new(); - SELECTORS.get_or_init(|| unsafe { - Selectors { - alloc: sel_registerName(b"alloc\0".as_ptr().cast()), - init_with_frame: sel_registerName(b"initWithFrame:\0".as_ptr().cast()), - add_subview: sel_registerName(b"addSubview:\0".as_ptr().cast()), - set_frame: sel_registerName(b"setFrame:\0".as_ptr().cast()), - set_hidden: sel_registerName(b"setHidden:\0".as_ptr().cast()), - set_wants_layer: sel_registerName(b"setWantsLayer:\0".as_ptr().cast()), - set_autoresizes_subviews: sel_registerName( - b"setAutoresizesSubviews:\0".as_ptr().cast(), - ), - release: sel_registerName(b"release\0".as_ptr().cast()), - bounds: sel_registerName(b"bounds\0".as_ptr().cast()), - } - }) - } - - fn msg_send_0(obj: *mut c_void, sel: *const c_void) -> *mut c_void { - unsafe { - let f: MsgSend0 = std::mem::transmute(objc_msgSend as *const ()); - f(obj, sel) - } - } - - fn parent_bounds(parent: NsViewPtr) -> NsRect { - // bounds returns NSRect by value; on x86_64/arm64 macOS this is returned in registers / - // as a struct. Use a dedicated trampoline via objc_msgSend_stret is obsolete on arm64. - type MsgSendBounds = unsafe extern "C" fn(*mut c_void, *const c_void) -> NsRect; - unsafe { - let f: MsgSendBounds = std::mem::transmute(objc_msgSend as *const ()); - f(parent, selectors().bounds) - } - } - - fn to_ns_rect(bounds: &NativeRenderRect, parent: NsViewPtr) -> NsRect { - // Electron reports top-left client coords in device pixels. NSView is bottom-left - // in points; approximate by treating incoming coords as points relative to parent - // bounds (Electron already DPI-scales the rect we receive). - let parent_bounds = parent_bounds(parent); - let height = bounds.height as f64; - let y = parent_bounds.size.height - (bounds.y as f64) - height; - NsRect { - origin: NsPoint { - x: bounds.x as f64, - y: y.max(0.0), - }, - size: NsSize { - width: bounds.width as f64, - height, - }, - } - } - - pub(super) fn create_child(parent: usize, bounds: &NativeRenderRect) -> Result { - let parent_view = parent as NsViewPtr; - if parent_view.is_null() { - return Err("Internal renderer parent NSView is null.".to_owned()); - } - - unsafe { - let class = objc_getClass(b"NSView\0".as_ptr().cast()); - if class.is_null() { - return Err("objc_getClass(NSView) failed.".to_owned()); - } - - let sels = selectors(); - let alloc = msg_send_0(class, sels.alloc); - if alloc.is_null() { - return Err("NSView alloc failed.".to_owned()); - } - - let frame = to_ns_rect(bounds, parent_view); - let init: MsgSendRect = std::mem::transmute(objc_msgSend as *const ()); - let view = init(alloc, sels.init_with_frame, frame); - if view.is_null() { - return Err("NSView initWithFrame failed.".to_owned()); - } - - let set_bool: MsgSendBool = std::mem::transmute(objc_msgSend as *const ()); - set_bool(view, sels.set_wants_layer, true); - set_bool(view, sels.set_autoresizes_subviews, false); - set_bool(view, sels.set_hidden, false); - - let add: MsgSend1Ptr = std::mem::transmute(objc_msgSend as *const ()); - add(parent_view, sels.add_subview, view); - - Ok(view) - } - } - - pub(super) fn set_bounds(view: NsViewPtr, bounds: &NativeRenderRect) -> Result<(), String> { - if view.is_null() { - return Ok(()); - } - // Parent is needed for Y-flip; store is not available here — use frame in parent - // coordinates assuming the same parent. Read superview. - unsafe { - let sels = selectors(); - let superview_sel = sel_registerName(b"superview\0".as_ptr().cast()); - let parent = msg_send_0(view, superview_sel); - let frame = if parent.is_null() { - NsRect { - origin: NsPoint { - x: bounds.x as f64, - y: bounds.y as f64, - }, - size: NsSize { - width: bounds.width as f64, - height: bounds.height as f64, - }, - } - } else { - to_ns_rect(bounds, parent) - }; - let set_frame: MsgSendRect = std::mem::transmute(objc_msgSend as *const ()); - set_frame(view, sels.set_frame, frame); - } - Ok(()) - } - - pub(super) fn set_visible(view: NsViewPtr, visible: bool) -> Result<(), String> { - if view.is_null() { - return Ok(()); - } - unsafe { - let set_bool: MsgSendBool = std::mem::transmute(objc_msgSend as *const ()); - set_bool(view, selectors().set_hidden, !visible); - } - Ok(()) - } - - pub(super) fn destroy(view: NsViewPtr) { - if view.is_null() { - return; - } - unsafe { - let sels = selectors(); - let remove_sel = sel_registerName(b"removeFromSuperview\0".as_ptr().cast()); - let _ = msg_send_0(view, remove_sel); - let _ = msg_send_0(view, sels.release); - } - } -} - -#[cfg(target_os = "linux")] -mod linux_child { - use crate::protocol::NativeRenderRect; - use std::ffi::c_void; - use std::ptr::null_mut; - - #[derive(Debug)] - pub(super) struct XWindow { - pub(super) display: usize, - pub(super) window: u64, - parent: u64, - } - - // Minimal X11 FFI — enough to create a child window for GstVideoOverlay. - #[repr(C)] - struct XSetWindowAttributes { - background_pixmap: u64, - background_pixel: u64, - border_pixmap: u64, - border_pixel: u64, - bit_gravity: i32, - win_gravity: i32, - backing_store: i32, - backing_planes: u64, - backing_pixel: u64, - save_under: i32, - event_mask: i64, - do_not_propagate_mask: i64, - override_redirect: i32, - colormap: u64, - cursor: u64, - } - - #[link(name = "X11")] - extern "C" { - fn XOpenDisplay(display_name: *const i8) -> *mut c_void; - fn XDefaultScreen(display: *mut c_void) -> i32; - fn XDefaultVisual(display: *mut c_void, screen: i32) -> *mut c_void; - fn XDefaultDepth(display: *mut c_void, screen: i32) -> i32; - fn XDefaultColormap(display: *mut c_void, screen: i32) -> u64; - fn XBlackPixel(display: *mut c_void, screen: i32) -> u64; - fn XCreateWindow( - display: *mut c_void, - parent: u64, - x: i32, - y: i32, - width: u32, - height: u32, - border_width: u32, - depth: i32, - class: u32, - visual: *mut c_void, - valuemask: u64, - attributes: *mut XSetWindowAttributes, - ) -> u64; - fn XMapWindow(display: *mut c_void, window: u64) -> i32; - fn XUnmapWindow(display: *mut c_void, window: u64) -> i32; - fn XMoveResizeWindow( - display: *mut c_void, - window: u64, - x: i32, - y: i32, - width: u32, - height: u32, - ) -> i32; - fn XRaiseWindow(display: *mut c_void, window: u64) -> i32; - fn XClearWindow(display: *mut c_void, window: u64) -> i32; - fn XDestroyWindow(display: *mut c_void, window: u64) -> i32; - fn XFlush(display: *mut c_void) -> i32; - fn XSync(display: *mut c_void, discard: i32) -> i32; - fn XSelectInput(display: *mut c_void, window: u64, event_mask: i64) -> i32; - } - - const INPUT_OUTPUT: u32 = 1; - const CW_BACK_PIXEL: u64 = 0x0002; - const CW_EVENT_MASK: u64 = 0x0800; - const CW_COLORMAP: u64 = 0x2000; - // Exposure + StructureNotify so GstVideoOverlay can redraw after map/resize. - // No pointer/keyboard masks — Electron owns input in internal mode. - const EXPOSURE_MASK: i64 = 0x0000_8000; - const STRUCTURE_NOTIFY_MASK: i64 = 0x0002_0000; - const EVENT_MASK: i64 = EXPOSURE_MASK | STRUCTURE_NOTIFY_MASK; - - fn wayland_session_active() -> bool { - std::env::var_os("WAYLAND_DISPLAY") - .filter(|value| !value.is_empty()) - .is_some() - } - - fn x11_unavailable_message() -> String { - if wayland_session_active() { - "Native internal renderer requires X11 or XWayland. Pure Wayland embedding is not supported yet — launch under X11, or set GDK_BACKEND=x11 / use an XWayland session." - .to_owned() - } else { - "XOpenDisplay failed; native internal renderer requires a working X11 display (DISPLAY unset or unreachable)." - .to_owned() - } - } - - pub(super) fn create_child(parent: usize, bounds: &NativeRenderRect) -> Result { - unsafe { - let display = XOpenDisplay(null_mut()); - if display.is_null() { - return Err(x11_unavailable_message()); - } - - let screen = XDefaultScreen(display); - let visual = XDefaultVisual(display, screen); - let depth = XDefaultDepth(display, screen); - let mut attrs = XSetWindowAttributes { - background_pixmap: 0, - background_pixel: XBlackPixel(display, screen), - border_pixmap: 0, - border_pixel: 0, - bit_gravity: 0, - win_gravity: 0, - backing_store: 0, - backing_planes: 0, - backing_pixel: 0, - save_under: 0, - event_mask: EVENT_MASK, - do_not_propagate_mask: 0, - override_redirect: 0, - colormap: XDefaultColormap(display, screen), - cursor: 0, - }; - - let window = XCreateWindow( - display, - parent as u64, - bounds.x, - bounds.y, - bounds.width.max(2) as u32, - bounds.height.max(2) as u32, - 0, - depth, - INPUT_OUTPUT, - visual, - CW_BACK_PIXEL | CW_EVENT_MASK | CW_COLORMAP, - &mut attrs, - ); - - if window == 0 { - return Err("XCreateWindow failed for internal renderer child.".to_owned()); - } - - XSelectInput(display, window, EVENT_MASK); - XMapWindow(display, window); - XRaiseWindow(display, window); - // Ensure the child is mapped and sized before GstVideoOverlay binds. - XSync(display, 0); - XClearWindow(display, window); - XFlush(display); - - Ok(XWindow { - display: display as usize, - window, - parent: parent as u64, - }) - } - } - - pub(super) fn set_bounds(window: &XWindow, bounds: &NativeRenderRect) -> Result<(), String> { - if window.display == 0 || window.window == 0 { - return Ok(()); - } - let display = window.display as *mut c_void; - unsafe { - XMoveResizeWindow( - display, - window.window, - bounds.x, - bounds.y, - bounds.width.max(2) as u32, - bounds.height.max(2) as u32, - ); - XRaiseWindow(display, window.window); - XSync(display, 0); - XFlush(display); - } - let _ = window.parent; - Ok(()) - } - - pub(super) fn set_visible(window: &XWindow, visible: bool) -> Result<(), String> { - if window.display == 0 || window.window == 0 { - return Ok(()); - } - let display = window.display as *mut c_void; - unsafe { - if visible { - XMapWindow(display, window.window); - XRaiseWindow(display, window.window); - XClearWindow(display, window.window); - } else { - XUnmapWindow(display, window.window); - } - XSync(display, 0); - XFlush(display); - } - Ok(()) - } - - pub(super) fn destroy(window: &mut XWindow) { - if window.display == 0 { - return; - } - let display = window.display as *mut c_void; - unsafe { - if window.window != 0 { - XDestroyWindow(display, window.window); - window.window = 0; - } - // Intentionally keep the display open for process lifetime; closing here - // can race with other X users in the same process. - XFlush(display); - } - } -} diff --git a/native/opennow-streamer/src/main.rs b/native/opennow-streamer/src/main.rs deleted file mode 100644 index abf8216a9..000000000 --- a/native/opennow-streamer/src/main.rs +++ /dev/null @@ -1,178 +0,0 @@ -#![cfg_attr(all(windows, not(debug_assertions)), windows_subsystem = "windows")] - -mod backend; -#[cfg(feature = "gstreamer")] -mod gstreamer_backend; -// Present/input policy helpers are pure Rust and stay available for unit tests -// even when the optional GStreamer feature is off. -mod gstreamer_config; -#[cfg(feature = "gstreamer")] -mod gstreamer_input; -#[cfg(feature = "gstreamer")] -mod gstreamer_liveness; -#[cfg(feature = "gstreamer")] -mod gstreamer_pipeline; -#[cfg(feature = "gstreamer")] -mod gstreamer_platform; -#[cfg(feature = "gstreamer")] -mod gstreamer_transitions; -#[cfg(feature = "gstreamer")] -mod internal_renderer; -mod input; -mod nvst_video; -mod protocol; -mod shortcuts; -mod sdp; -#[cfg(target_os = "windows")] -mod windows_dpi; - -use serde::Serialize; -use serde_json::Value; -use std::io::{self, BufRead, Write}; -use std::sync::mpsc; -use std::thread; - -use backend::{create_backend, BackendReply, NativeStreamerBackend}; -use protocol::{parse_command, CommandEnvelope, Event, Response, PROTOCOL_VERSION}; - -fn write_json(value: &T) -> io::Result<()> { - let mut stdout = io::stdout().lock(); - serde_json::to_writer(&mut stdout, value)?; - writeln!(stdout)?; - stdout.flush() -} - -fn write_response(response: &Response) -> io::Result<()> { - write_json(response) -} - -fn write_event(event: &Event) -> io::Result<()> { - write_json(event) -} - -fn write_error(id: Option, code: &str, message: impl Into) -> io::Result<()> { - write_response(&Response::Error { - id, - code: code.to_owned(), - message: message.into(), - }) -} - -fn write_reply(reply: BackendReply) -> io::Result { - for event in &reply.events { - write_event(event)?; - } - if let Some(response) = &reply.response { - write_response(response)?; - } - Ok(reply.should_continue) -} - -fn handle_command( - command: CommandEnvelope, - backend: &mut dyn NativeStreamerBackend, -) -> io::Result { - match command.command_type.as_str() { - "hello" => { - let requested = command.protocol_version.unwrap_or(0); - if requested != PROTOCOL_VERSION { - write_error( - Some(command.id), - "protocol-version-mismatch", - "Unsupported native streamer protocol version.", - )?; - return Ok(true); - } - - write_response(&Response::Ready { - id: command.id, - capabilities: backend.capabilities(), - })?; - } - "start" => { - return write_reply(backend.start(command)); - } - "offer" => { - return write_reply(backend.handle_offer(command)); - } - "remote-ice" => { - return write_reply(backend.add_remote_ice(command)); - } - "input" => { - return write_reply(backend.send_input(command)); - } - "input-paused" => { - return write_reply(backend.set_input_paused(command)); - } - "surface" => { - return write_reply(backend.update_render_surface(command)); - } - "bitrate" => { - return write_reply(backend.update_bitrate_limit(command)); - } - "update-shortcuts" => { - return write_reply(backend.update_shortcuts(command)); - } - "stop" => { - return write_reply(backend.stop(command)); - } - other => { - write_error( - Some(command.id), - "unknown-command", - format!("Unknown command: {other}"), - )?; - } - } - - Ok(true) -} - -fn main() -> io::Result<()> { - #[cfg(target_os = "windows")] - windows_dpi::enable_per_monitor_awareness(); - - let stdin = io::stdin(); - let (event_sender, event_receiver) = mpsc::channel::(); - let event_writer = thread::spawn(move || { - for event in event_receiver { - if let Err(error) = write_event(&event) { - eprintln!("[NativeStreamer] Failed to write async event: {error}"); - break; - } - } - }); - let mut backend = create_backend(Some(event_sender)); - - for line in stdin.lock().lines() { - let line = line?; - let trimmed = line.trim(); - if trimmed.is_empty() { - continue; - } - - let value: Value = match serde_json::from_str(trimmed) { - Ok(value) => value, - Err(error) => { - write_error(None, "invalid-json", error.to_string())?; - continue; - } - }; - - let command = match parse_command(value) { - Ok(command) => command, - Err(error) => { - write_error(None, "invalid-command", error)?; - continue; - } - }; - - if !handle_command(command, backend.as_mut())? { - break; - } - } - - drop(backend); - let _ = event_writer.join(); - Ok(()) -} diff --git a/native/opennow-streamer/src/nvst_video.rs b/native/opennow-streamer/src/nvst_video.rs deleted file mode 100644 index 3415d24ab..000000000 --- a/native/opennow-streamer/src/nvst_video.rs +++ /dev/null @@ -1,537 +0,0 @@ -//! Classic NVST / Mjolnir UDP video receive scaffold (GO-with-Moonlight-hypothesis). -//! -//! Pipeline (intended): -//! UDP bind → hole-punch PING → (SRTP decrypt) → RTP(+ext) → NV_VIDEO_PACKET → -//! assemble AUs on FLAG_EOF → appsrc (Annex-B) → h265parse/h264parse → decoder → sink -//! -//! SRTP: master = AES-256 key[32] || salt[12] where salt = key_id as BE u32 zero-padded -//! to 12 bytes (`%024x`). Prefer AEAD_AES_256_GCM. This scaffold does **not** link -//! libsrtp; when decrypt is unavailable it logs once and parses cleartext RTP so the -//! receive/assemble/appsrc path can be exercised. A GStreamer `srtpdec` branch can be -//! added later once the wire profile is confirmed on a live pcap. - -#![cfg_attr(not(feature = "gstreamer"), allow(dead_code))] - -#[cfg(feature = "gstreamer")] -use crate::gstreamer_backend::send_log; -#[cfg(feature = "gstreamer")] -use crate::protocol::{Event, NvstVideoSession}; -#[cfg(feature = "gstreamer")] -use gstreamer as gst; -#[cfg(feature = "gstreamer")] -use gstreamer::prelude::*; -#[cfg(feature = "gstreamer")] -use std::io; -#[cfg(feature = "gstreamer")] -use std::net::{SocketAddr, UdpSocket}; -#[cfg(feature = "gstreamer")] -use std::sync::atomic::{AtomicBool, Ordering}; -#[cfg(feature = "gstreamer")] -use std::sync::mpsc::Sender; -#[cfg(feature = "gstreamer")] -use std::sync::Arc; -#[cfg(feature = "gstreamer")] -use std::thread::{self, JoinHandle}; -#[cfg(feature = "gstreamer")] -use std::time::Duration; - -/// Moonlight / GameStream `NV_VIDEO_PACKET` size (little-endian fields). -pub const NV_VIDEO_PACKET_LEN: usize = 16; -/// `FLAG_EOF` — last packet of a frame (assemble AU). -pub const FLAG_EOF: u8 = 0x02; -/// `FLAG_SOF` — first packet of a frame. -#[allow(dead_code)] -pub const FLAG_SOF: u8 = 0x04; -/// `FLAG_CONTAINS_PIC_DATA`. -#[allow(dead_code)] -pub const FLAG_CONTAINS_PIC_DATA: u8 = 0x01; - -/// Pack AES-256 key + key ID into the 44-byte libsrtp master key||salt. -/// -/// Salt is `key_id` as a big-endian u32, zero-padded to 12 bytes (`printf`-style `%024x`). -pub fn pack_srtp_master_key_salt(aes_key: &[u8; 32], key_id: u32) -> [u8; 44] { - let mut out = [0u8; 44]; - out[..32].copy_from_slice(aes_key); - out[40..44].copy_from_slice(&key_id.to_be_bytes()); - out -} - -/// Decode a 64-hex AES-256 key string into 32 bytes. -pub fn parse_aes_key_hex(hex: &str) -> Result<[u8; 32], String> { - let trimmed = hex.trim(); - if trimmed.len() != 64 { - return Err(format!( - "srtpAesKeyHex must be 64 hex chars, got {}", - trimmed.len() - )); - } - let mut out = [0u8; 32]; - for (i, chunk) in trimmed.as_bytes().chunks(2).enumerate() { - let s = std::str::from_utf8(chunk).map_err(|e| e.to_string())?; - out[i] = u8::from_str_radix(s, 16) - .map_err(|e| format!("Invalid hex in srtpAesKeyHex at byte {i}: {e}"))?; - } - Ok(out) -} - -/// Parsed Moonlight-hypothesis `NV_VIDEO_PACKET` (LE). -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct NvVideoPacket { - pub stream_packet_index: u32, - pub frame_index: u32, - pub flags: u8, - pub extra_flags: u8, - pub multi_fec_flags: u8, - pub multi_fec_blocks: u8, - pub fec_info: u32, -} - -impl NvVideoPacket { - pub fn parse(bytes: &[u8]) -> Option { - if bytes.len() < NV_VIDEO_PACKET_LEN { - return None; - } - Some(Self { - stream_packet_index: u32::from_le_bytes(bytes[0..4].try_into().ok()?), - frame_index: u32::from_le_bytes(bytes[4..8].try_into().ok()?), - flags: bytes[8], - extra_flags: bytes[9], - multi_fec_flags: bytes[10], - multi_fec_blocks: bytes[11], - fec_info: u32::from_le_bytes(bytes[12..16].try_into().ok()?), - }) - } - - /// FEC / non-picture packets use `flags == 0` in the Moonlight hypothesis. - pub fn is_fec_or_empty(&self) -> bool { - self.flags == 0 - } - - pub fn is_eof(&self) -> bool { - self.flags & FLAG_EOF != 0 - } -} - -/// Strip standard RTP header (+ optional 4-byte extension pad when X is set) and -/// return the payload starting at `NV_VIDEO_PACKET`. -/// -/// Layout hypothesis (post-SRTP): `12B RTP + 4B ext pad if X + 16B NV_VIDEO_PACKET + payload`. -pub fn strip_rtp_header(packet: &[u8]) -> Option<&[u8]> { - if packet.len() < 12 { - return None; - } - let v_pxcc = packet[0]; - let version = v_pxcc >> 6; - if version != 2 { - return None; - } - let has_padding = (v_pxcc & 0x20) != 0; - let has_extension = (v_pxcc & 0x10) != 0; - let csrc_count = (v_pxcc & 0x0f) as usize; - let mut offset = 12 + csrc_count * 4; - if packet.len() < offset { - return None; - } - if has_extension { - // Moonlight-hypothesis: fixed 4-byte extension pad (not full RFC 5285 walk). - offset = offset.checked_add(4)?; - if packet.len() < offset { - return None; - } - } - - let mut payload = &packet[offset..]; - if has_padding { - let pad_len = *payload.last()? as usize; - if pad_len == 0 || pad_len > payload.len() { - return None; - } - payload = &payload[..payload.len() - pad_len]; - } - Some(payload) -} - -/// Parse RTP → NV_VIDEO_PACKET → media payload. Returns `None` for FEC (`flags==0`) -/// or malformed packets. -pub fn parse_nvst_rtp_payload(packet: &[u8]) -> Option<(NvVideoPacket, &[u8])> { - let after_rtp = strip_rtp_header(packet)?; - let header = NvVideoPacket::parse(after_rtp)?; - if header.is_fec_or_empty() { - return None; - } - let media = after_rtp.get(NV_VIDEO_PACKET_LEN..)?; - Some((header, media)) -} - -/// Assembles Annex-B access units from NVST RTP payloads (Moonlight hypothesis). -#[derive(Debug, Default)] -pub struct NvstFrameAssembler { - current_frame: Option, - buffer: Vec, -} - -impl NvstFrameAssembler { - pub fn new() -> Self { - Self::default() - } - - /// Push one media packet. Returns a completed AU when `FLAG_EOF` is set. - pub fn push(&mut self, header: &NvVideoPacket, payload: &[u8]) -> Option> { - if header.is_fec_or_empty() { - return None; - } - - match self.current_frame { - Some(frame) if frame != header.frame_index => { - self.buffer.clear(); - self.current_frame = Some(header.frame_index); - } - None => { - self.current_frame = Some(header.frame_index); - } - _ => {} - } - - self.buffer.extend_from_slice(payload); - - if header.is_eof() { - let au = std::mem::take(&mut self.buffer); - self.current_frame = None; - if au.is_empty() { - None - } else { - Some(au) - } - } else { - None - } - } -} - -/// Caps string for Annex-B appsrc feeding `h265parse` / `h264parse`. -pub fn annexb_appsrc_caps(codec: &str) -> &'static str { - match codec.to_ascii_uppercase().as_str() { - "H264" => "video/x-h264,stream-format=byte-stream,alignment=au", - _ => "video/x-h265,stream-format=byte-stream,alignment=au", - } -} - -/// Build description for a GStreamer branch that would decrypt SRTP then feed RTP -/// into an appsrc-style path. Documented for future `srtpdec` wiring; the live -/// scaffold currently decrypts (or skips) in the UDP thread and pushes Annex-B AUs. -pub fn srtpdec_pipeline_branch_hint(codec: &str) -> String { - let caps = annexb_appsrc_caps(codec); - let parser = match codec.to_ascii_uppercase().as_str() { - "H264" => "h264parse", - _ => "h265parse", - }; - format!( - "appsrc name=nvst-annexb caps=\"{caps}\" is-live=true format=time ! \ - {parser} ! …decoder… ! …sink… \ - (SRTP: prefer libsrtp AEAD_AES_256_GCM with pack_srtp_master_key_salt; \ - GStreamer srtpdec may be wired later — do not use appsrc caps=application/x-rtp \ - named nvst-rtp for assembled AUs)" - ) -} - -#[cfg(feature = "gstreamer")] -pub(crate) struct NvstVideoReceiveHandle { - stop: Arc, - join: Option>, -} - -#[cfg(feature = "gstreamer")] -impl std::fmt::Debug for NvstVideoReceiveHandle { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("NvstVideoReceiveHandle") - .field("stop", &self.stop.load(Ordering::SeqCst)) - .field("join", &self.join.as_ref().map(|_| "JoinHandle")) - .finish() - } -} - -#[cfg(feature = "gstreamer")] -impl NvstVideoReceiveHandle { - pub(crate) fn stop(mut self) { - self.stop.store(true, Ordering::SeqCst); - if let Some(join) = self.join.take() { - let _ = join.join(); - } - } -} - -#[cfg(feature = "gstreamer")] -impl Drop for NvstVideoReceiveHandle { - fn drop(&mut self) { - self.stop.store(true, Ordering::SeqCst); - if let Some(join) = self.join.take() { - let _ = join.join(); - } - } -} - -/// Spawn UDP bind → PING hole-punch → recv → parse → push Annex-B AUs into `appsrc`. -#[cfg(feature = "gstreamer")] -pub(crate) fn spawn_nvst_udp_receive( - session: NvstVideoSession, - appsrc: gst::Element, - event_sender: Option>, -) -> Result { - let aes_key = parse_aes_key_hex(&session.srtp_aes_key_hex)?; - let master = pack_srtp_master_key_salt(&aes_key, session.srtp_key_id); - let _ = master; // reserved for future libsrtp / srtpdec install - - let peer: SocketAddr = format!("{}:{}", session.video_peer_ip, session.video_peer_port) - .parse() - .map_err(|e| format!("Invalid nvstVideo peer address: {e}"))?; - - let bind_addr = SocketAddr::from(([0, 0, 0, 0], session.client_udp_port)); - let socket = UdpSocket::bind(bind_addr) - .map_err(|e| format!("Failed to bind NVST UDP {bind_addr}: {e}"))?; - socket - .set_read_timeout(Some(Duration::from_millis(250))) - .map_err(|e| format!("Failed to set NVST UDP read timeout: {e}"))?; - - let ping = session - .ping_payload - .as_deref() - .filter(|s| !s.is_empty()) - .unwrap_or("PING"); - match socket.send_to(ping.as_bytes(), peer) { - Ok(_) => send_log( - &event_sender, - "info", - format!( - "NVST video hole-punch sent ({ping_len} B) to {peer} from {bind_addr}.", - ping_len = ping.len() - ), - ), - Err(e) => send_log( - &event_sender, - "warn", - format!("NVST video hole-punch to {peer} failed: {e}"), - ), - } - - send_log( - &event_sender, - "info", - format!( - "NVST SRTP scaffold: master key/salt packed (44 B) for keyId {}; \ - libsrtp/srtpdec not linked — parsing cleartext RTP if packets arrive undecrypted. {}", - session.srtp_key_id, - srtpdec_pipeline_branch_hint(session.codec.as_deref().unwrap_or("H265")) - ), - ); - - let stop = Arc::new(AtomicBool::new(false)); - let stop_flag = stop.clone(); - let join = thread::Builder::new() - .name("nvst-udp-video".to_owned()) - .spawn(move || { - nvst_udp_recv_loop(socket, appsrc, event_sender, stop_flag); - }) - .map_err(|e| format!("Failed to spawn NVST UDP thread: {e}"))?; - - Ok(NvstVideoReceiveHandle { - stop, - join: Some(join), - }) -} - -#[cfg(feature = "gstreamer")] -fn nvst_udp_recv_loop( - socket: UdpSocket, - appsrc: gst::Element, - event_sender: Option>, - stop: Arc, -) { - let mut buf = [0u8; 2048]; - let mut assembler = NvstFrameAssembler::new(); - let mut first_packet_logged = false; - let mut first_au_logged = false; - let mut decrypt_fail_logged = false; - let mut cleartext_notice_logged = false; - - while !stop.load(Ordering::SeqCst) { - match socket.recv_from(&mut buf) { - Ok((len, _from)) => { - if !first_packet_logged { - first_packet_logged = true; - send_log( - &event_sender, - "info", - format!("NVST UDP received first packet ({len} B)."), - ); - } - if !cleartext_notice_logged { - cleartext_notice_logged = true; - send_log( - &event_sender, - "info", - "NVST SRTP decrypt unavailable in scaffold; attempting cleartext RTP parse." - .to_owned(), - ); - } - - let packet = &buf[..len]; - if packet.first().map(|b| b >> 6) != Some(2) { - if !decrypt_fail_logged { - decrypt_fail_logged = true; - send_log( - &event_sender, - "warn", - "NVST UDP packet does not look like cleartext RTP (version != 2); \ - SRTP decrypt required — continuing to listen." - .to_owned(), - ); - } - continue; - } - - let Some((header, payload)) = parse_nvst_rtp_payload(packet) else { - continue; - }; - let Some(au) = assembler.push(&header, payload) else { - continue; - }; - if !first_au_logged { - first_au_logged = true; - send_log( - &event_sender, - "info", - format!( - "NVST assembled first Annex-B AU ({} B, frameIndex={}).", - au.len(), - header.frame_index - ), - ); - } - if let Err(err) = push_au_to_appsrc(&appsrc, &au) { - send_log( - &event_sender, - "warn", - format!("NVST appsrc push failed: {err}"), - ); - } - } - Err(e) if e.kind() == io::ErrorKind::WouldBlock || e.kind() == io::ErrorKind::TimedOut => { - continue; - } - Err(e) => { - if !stop.load(Ordering::SeqCst) { - send_log( - &event_sender, - "warn", - format!("NVST UDP recv error: {e}"), - ); - } - break; - } - } - } -} - -#[cfg(feature = "gstreamer")] -fn push_au_to_appsrc(appsrc: &gst::Element, au: &[u8]) -> Result<(), String> { - let mut buffer = gst::Buffer::from_mut_slice(au.to_vec()); - { - let buffer = buffer - .get_mut() - .ok_or_else(|| "NVST appsrc buffer not writable".to_owned())?; - buffer.set_pts(gst::ClockTime::NONE); - buffer.set_dts(gst::ClockTime::NONE); - } - let flow = appsrc.emit_by_name::("push-buffer", &[&buffer]); - if flow != gst::FlowReturn::Ok { - return Err(format!("appsrc push-buffer returned {flow:?}")); - } - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn pack_srtp_master_key_salt_matches_docs_key_id() { - // Docs: key_id 2664076126 → salt ends 9ECA935E (`%024x` → 00000000000000009ECA935E). - let key = [0xABu8; 32]; - let packed = pack_srtp_master_key_salt(&key, 2664076126); - assert_eq!(&packed[..32], &key); - assert_eq!(&packed[32..40], &[0u8; 8]); - assert_eq!(&packed[40..44], &[0x9E, 0xCA, 0x93, 0x5E]); - } - - #[test] - fn pack_srtp_additional_doc_key_ids() { - let key = [0u8; 32]; - let a = pack_srtp_master_key_salt(&key, 1664590642); - assert_eq!(&a[40..44], &[0x63, 0x37, 0xA3, 0x32]); - let b = pack_srtp_master_key_salt(&key, 2478780175); - assert_eq!(&b[40..44], &[0x93, 0xBF, 0x2F, 0x0F]); - } - - #[test] - fn parse_nv_video_packet_synthetic() { - let mut bytes = [0u8; 16]; - bytes[0..4].copy_from_slice(&0x11223344u32.to_le_bytes()); - bytes[4..8].copy_from_slice(&7u32.to_le_bytes()); - bytes[8] = FLAG_SOF | FLAG_EOF | FLAG_CONTAINS_PIC_DATA; - bytes[9] = 0x10; - bytes[10] = 0x20; - bytes[11] = 0x30; - bytes[12..16].copy_from_slice(&0xAABBCCDDu32.to_le_bytes()); - - let pkt = NvVideoPacket::parse(&bytes).expect("parse"); - assert_eq!(pkt.stream_packet_index, 0x11223344); - assert_eq!(pkt.frame_index, 7); - assert!(pkt.is_eof()); - assert!(!pkt.is_fec_or_empty()); - assert_eq!(pkt.extra_flags, 0x10); - assert_eq!(pkt.fec_info, 0xAABBCCDD); - } - - #[test] - fn fec_flags_zero_ignored_by_parser() { - let mut packet = vec![0x80u8, 0x60, 0x00, 0x01, 0, 0, 0, 0, 0, 0, 0, 0]; - packet.extend_from_slice(&[0u8; 16]); - packet.extend_from_slice(&[0xDE, 0xAD]); - assert!(parse_nvst_rtp_payload(&packet).is_none()); - } - - #[test] - fn assemble_frame_on_eof() { - let mut asm = NvstFrameAssembler::new(); - let sof = NvVideoPacket { - stream_packet_index: 1, - frame_index: 3, - flags: FLAG_SOF | FLAG_CONTAINS_PIC_DATA, - extra_flags: 0, - multi_fec_flags: 0, - multi_fec_blocks: 0, - fec_info: 0, - }; - let eof = NvVideoPacket { - flags: FLAG_EOF | FLAG_CONTAINS_PIC_DATA, - stream_packet_index: 2, - ..sof - }; - assert!(asm.push(&sof, b"AA").is_none()); - let au = asm.push(&eof, b"BB").expect("AU"); - assert_eq!(au, b"AABB"); - } - - #[test] - fn strip_rtp_with_extension_pad() { - let mut packet = vec![0x90u8, 0x60, 0x00, 0x02, 0, 0, 0, 0, 0, 0, 0, 0]; - packet.extend_from_slice(&[0xBE, 0xDE, 0x00, 0x00]); - let mut nv = [0u8; 16]; - nv[8] = FLAG_EOF | FLAG_CONTAINS_PIC_DATA; - packet.extend_from_slice(&nv); - packet.extend_from_slice(b"NAL"); - let (hdr, payload) = parse_nvst_rtp_payload(&packet).expect("parse"); - assert!(hdr.is_eof()); - assert_eq!(payload, b"NAL"); - } -} diff --git a/native/opennow-streamer/src/protocol.rs b/native/opennow-streamer/src/protocol.rs deleted file mode 100644 index a3f79b572..000000000 --- a/native/opennow-streamer/src/protocol.rs +++ /dev/null @@ -1,739 +0,0 @@ -use base64::{engine::general_purpose::STANDARD as BASE64_STANDARD, Engine as _}; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use std::borrow::Cow; - -pub const PROTOCOL_VERSION: u64 = 4; - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CommandEnvelope { - pub id: String, - #[serde(rename = "type")] - pub command_type: String, - #[serde(default)] - pub protocol_version: Option, - #[serde(default)] - pub context: Option, - #[serde(default)] - pub sdp: Option, - #[serde(default)] - pub candidate: Option, - #[serde(default)] - pub input: Option, - #[serde(default)] - pub paused: Option, - #[serde(default)] - pub surface: Option, - #[serde(default)] - pub max_bitrate_kbps: Option, - #[serde(default)] - pub reason: Option, - #[serde(default)] - pub shortcuts: Option, -} - -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct NativeStreamerSessionContext { - pub session: SessionInfo, - pub settings: StreamSettings, - #[serde(default)] - pub shortcuts: NativeStreamerShortcutBindings, - /// Classic Mjolnir UDP video (post-SETUP peer + SRTP material). When set, - /// the GStreamer backend receives video over UDP while keeping webrtcbin - /// for SCTP datachannels / input. - #[serde(default, rename = "nvstVideo")] - pub nvst_video: Option, -} - -/// Classic NVST UDP video session parameters (Moonlight-hypothesis scaffold). -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -#[cfg_attr(not(feature = "gstreamer"), allow(dead_code))] -pub struct NvstVideoSession { - pub client_udp_port: u16, - pub video_peer_ip: String, - pub video_peer_port: u16, - /// 64 hex chars = 32-byte AES-256 key. - pub srtp_aes_key_hex: String, - pub srtp_key_id: u32, - /// Optional SETUP `X-Nv-Ping-Payload` token; when absent, hole-punch sends `PING`. - #[serde(default)] - pub ping_payload: Option, - /// `H265` / `H264` (defaults to session settings codec when omitted). - #[serde(default)] - pub codec: Option, -} - -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SessionInfo { - pub session_id: String, - pub server_ip: String, - #[serde(default)] - pub ice_servers: Vec, - #[serde(default)] - pub media_connection_info: Option, - #[allow(dead_code)] - #[serde(default)] - pub negotiated_stream_profile: Option, - #[cfg_attr(not(feature = "gstreamer"), allow(dead_code))] - #[serde(default)] - pub requested_streaming_features: Option, - #[cfg_attr(not(feature = "gstreamer"), allow(dead_code))] - #[serde(default)] - pub finalized_streaming_features: Option, -} - -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct IceServer { - pub urls: Vec, - #[allow(dead_code)] - #[serde(default)] - pub username: Option, - #[allow(dead_code)] - #[serde(default)] - pub credential: Option, -} - -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct MediaConnectionInfo { - pub ip: String, - pub port: u16, - #[serde(default)] - pub usage: Option, -} - -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct StreamSettings { - pub resolution: String, - pub fps: u32, - pub max_bitrate_mbps: u32, - pub codec: VideoCodec, - pub color_quality: ColorQuality, - #[serde(default)] - #[allow(dead_code)] - pub enable_cloud_gsync: bool, - #[cfg_attr(not(feature = "gstreamer"), allow(dead_code))] - #[serde(default)] - pub native_transition_diagnostics: Option, -} - -#[derive(Debug, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct StreamingFeatures { - #[serde(default)] - pub reflex: Option, - #[serde(default)] - pub bit_depth: Option, - #[serde(default)] - pub cloud_gsync: Option, - #[serde(default)] - pub chroma_format: Option, - #[serde(default)] - pub enabled_l4s: Option, - #[serde(default)] - pub true_hdr: Option, -} - -#[cfg_attr(not(feature = "gstreamer"), allow(dead_code))] -impl StreamingFeatures { - pub fn summary(&self) -> String { - let mut parts = Vec::new(); - if let Some(reflex) = self.reflex { - parts.push(format!("reflex={reflex}")); - } - if let Some(bit_depth) = self.bit_depth { - parts.push(format!("bitDepth={bit_depth}")); - } - if let Some(cloud_gsync) = self.cloud_gsync { - parts.push(format!("cloudGsync={cloud_gsync}")); - } - if let Some(chroma_format) = self.chroma_format { - parts.push(format!("chroma={chroma_format}")); - } - if let Some(enabled_l4s) = self.enabled_l4s { - parts.push(format!("l4s={enabled_l4s}")); - } - if let Some(true_hdr) = self.true_hdr { - parts.push(format!("trueHdr={true_hdr}")); - } - if parts.is_empty() { - "none".to_owned() - } else { - parts.join(", ") - } - } -} - -#[derive(Debug, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct NegotiatedStreamProfile { - #[serde(default)] - pub resolution: Option, - #[serde(default)] - pub fps: Option, - #[serde(default)] - pub codec: Option, -} - -#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)] -#[serde(rename_all = "lowercase")] -pub enum NativeQueueMode { - #[default] - Auto, - Fixed, - Adaptive, - Vrr, -} - -#[cfg_attr(not(feature = "gstreamer"), allow(dead_code))] -impl NativeQueueMode { - pub fn as_str(self) -> &'static str { - match self { - Self::Auto => "auto", - Self::Fixed => "fixed", - Self::Adaptive => "adaptive", - Self::Vrr => "vrr", - } - } -} - -#[derive(Debug, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct NativeTransitionDiagnosticsSettings { - #[serde(default)] - pub disable_dynamic_split_encode_updates: bool, - #[serde(default)] - pub force_queue_mode: Option, - #[serde(default)] - pub disable_transition_flush_escalation: bool, -} - -#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)] -pub enum VideoCodec { - H264, - H265, - AV1, -} - -impl VideoCodec { - #[allow(dead_code)] - pub fn as_str(self) -> &'static str { - match self { - Self::H264 => "H264", - Self::H265 => "H265", - Self::AV1 => "AV1", - } - } -} - -#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)] -pub enum ColorQuality { - #[serde(rename = "8bit_420")] - EightBit420, - #[serde(rename = "8bit_444")] - EightBit444, - #[serde(rename = "10bit_420")] - TenBit420, - #[serde(rename = "10bit_444")] - TenBit444, -} - -impl ColorQuality { - pub fn bit_depth(self) -> u8 { - match self { - Self::EightBit420 | Self::EightBit444 => 8, - Self::TenBit420 | Self::TenBit444 => 10, - } - } -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct IceCandidatePayload { - pub candidate: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub sdp_mid: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub sdp_m_line_index: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub username_fragment: Option, -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct NativeInputPacket { - #[serde(default)] - pub payload: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub payload_base64: Option, - #[serde(default)] - pub partially_reliable: bool, -} - -impl NativeInputPacket { - pub fn payload_bytes(&self) -> Result, String> { - let Some(payload_base64) = self.payload_base64.as_deref() else { - return Ok(Cow::Borrowed(&self.payload)); - }; - - BASE64_STANDARD - .decode(payload_base64) - .map(Cow::Owned) - .map_err(|error| format!("Invalid base64 input payload: {error}")) - } -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct NativeRenderSurface { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub window_handle: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub rect: Option, - #[serde(default)] - pub visible: bool, - #[serde(default)] - pub device_scale_factor: f64, - #[serde(default)] - pub show_stats: bool, -} - -#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct NativeRenderRect { - pub x: i32, - pub y: i32, - pub width: i32, - pub height: i32, -} - -#[derive(Debug, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct NativeStreamerShortcutBindings { - #[serde(default)] - pub toggle_stats: String, - #[serde(default)] - pub toggle_pointer_lock: String, - #[serde(default)] - pub toggle_fullscreen: String, - #[serde(default)] - pub stop_stream: String, - #[serde(default)] - pub toggle_anti_afk: String, - #[serde(default)] - pub toggle_microphone: String, - #[serde(default)] - pub screenshot: String, - #[serde(default)] - pub toggle_recording: String, -} - -#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)] -#[serde(rename_all = "camelCase")] -pub enum NativeStreamerShortcutAction { - ToggleStats, - TogglePointerLock, - ToggleFullscreen, - StopStream, - ToggleAntiAfk, - ToggleMicrophone, - Screenshot, - ToggleRecording, -} - -#[derive(Debug, Clone, Serialize)] -pub struct NativeStreamerCapabilities { - #[serde(rename = "protocolVersion")] - pub protocol_version: u64, - pub backend: &'static str, - #[serde(rename = "requestedBackend", skip_serializing_if = "Option::is_none")] - pub requested_backend: Option, - #[serde(rename = "fallbackReason", skip_serializing_if = "Option::is_none")] - pub fallback_reason: Option, - #[serde(rename = "supportsOfferAnswer")] - pub supports_offer_answer: bool, - #[serde(rename = "supportsRemoteIce")] - pub supports_remote_ice: bool, - #[serde(rename = "supportsLocalIce")] - pub supports_local_ice: bool, - #[serde(rename = "supportsInput")] - pub supports_input: bool, - #[serde( - rename = "videoBackends", - default, - skip_serializing_if = "Vec::is_empty" - )] - pub video_backends: Vec, -} - -#[derive(Debug, Clone, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct NativeVideoBackendCapability { - pub backend: String, - pub platform: String, - pub codecs: Vec, - #[serde(rename = "zeroCopyModes")] - pub zero_copy_modes: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - pub sink: Option, - pub available: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub reason: Option, -} - -#[derive(Debug, Clone, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct NativeVideoCodecCapability { - pub codec: String, - pub available: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub decoder: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub parser: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub depayloader: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub reason: Option, -} - -#[derive(Debug, Clone, Serialize)] -#[allow(dead_code)] -#[serde(tag = "type")] -pub enum Response { - #[serde(rename = "ready")] - Ready { - id: String, - capabilities: NativeStreamerCapabilities, - }, - #[serde(rename = "ok")] - Ok { id: String }, - #[serde(rename = "answer")] - Answer { - id: String, - answer: SendAnswerRequest, - }, - #[serde(rename = "error")] - Error { - #[serde(skip_serializing_if = "Option::is_none")] - id: Option, - code: String, - message: String, - }, -} - -#[derive(Debug, Clone, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SendAnswerRequest { - pub sdp: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub nvst_sdp: Option, -} - -#[derive(Debug, Clone, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct VideoStallEvent { - pub stall_ms: u64, - pub encoded_kbps: f64, - pub decoded_fps: f64, - pub sink_fps: f64, - #[serde(skip_serializing_if = "Option::is_none")] - pub encoded_age_ms: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub decoded_age_ms: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub sink_age_ms: Option, - pub likely_stage: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub sink_rendered: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub sink_dropped: Option, - pub memory_mode: String, - pub zero_copy: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub requested_fps: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub caps_framerate: Option, - pub queue_mode: String, - pub partial_flush_count: u32, - pub complete_flush_count: u32, - #[serde(skip_serializing_if = "Option::is_none")] - pub last_transition_type: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub last_transition_at_ms: Option, - pub requested_streaming_features_summary: String, - pub finalized_streaming_features_summary: String, - pub zero_copy_d3d11: bool, - pub zero_copy_d3d12: bool, - pub recovery_attempt: u8, -} - -#[derive(Debug, Clone, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct VideoTransitionEvent { - pub transition_type: String, - pub source: String, - pub at_ms: u64, - #[serde(skip_serializing_if = "Option::is_none")] - pub old_caps: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub new_caps: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub old_framerate: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub new_framerate: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub old_memory_mode: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub new_memory_mode: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub render_gap_ms: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub requested_fps: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub caps_framerate: Option, - pub high_fps_risk: bool, - pub queue_mode: String, - pub summary: String, -} - -#[derive(Debug, Clone, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct NativeStatsEvent { - pub codec: String, - pub resolution: String, - pub hardware_acceleration: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub requested_fps: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub caps_framerate: Option, - pub bitrate_kbps: u32, - pub target_bitrate_kbps: u32, - pub bitrate_performance_percent: f64, - pub decoded_fps: f64, - pub render_fps: f64, - pub frames_decoded: u64, - pub frames_rendered: u64, - pub frames_pending_to_present: u64, - #[serde(skip_serializing_if = "Option::is_none")] - pub sink_rendered: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub sink_dropped: Option, - pub memory_mode: String, - pub zero_copy: bool, - pub queue_mode: String, - pub queue_depth_changes: u32, - pub present_pacing_changes: u32, - pub partial_flush_count: u32, - pub complete_flush_count: u32, - #[serde(skip_serializing_if = "Option::is_none")] - pub last_transition_type: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub last_transition_at_ms: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub last_transition_summary: Option, - pub requested_streaming_features_summary: String, - pub finalized_streaming_features_summary: String, - pub zero_copy_d3d11: bool, - pub zero_copy_d3d12: bool, -} - -#[derive(Debug, Clone, Serialize)] -#[allow(dead_code)] -#[serde(tag = "type")] -pub enum Event { - #[serde(rename = "log")] - Log { - level: &'static str, - message: String, - }, - #[serde(rename = "status")] - Status { - status: &'static str, - #[serde(skip_serializing_if = "Option::is_none")] - message: Option, - }, - #[serde(rename = "local-ice")] - LocalIce { candidate: IceCandidatePayload }, - #[serde(rename = "input-ready")] - InputReady { - #[serde(rename = "protocolVersion")] - protocol_version: u16, - }, - #[serde(rename = "shortcut")] - Shortcut { - action: NativeStreamerShortcutAction, - }, - #[serde(rename = "clipboard-paste")] - ClipboardPaste, - #[serde(rename = "input-capture-changed")] - InputCaptureChanged { - captured: bool, - }, - #[serde(rename = "video-stall")] - VideoStall(VideoStallEvent), - #[serde(rename = "video-transition")] - VideoTransition { transition: VideoTransitionEvent }, - #[serde(rename = "stats")] - Stats { stats: NativeStatsEvent }, - #[serde(rename = "error")] - Error { code: String, message: String }, -} - -pub fn parse_command(value: Value) -> Result { - serde_json::from_value(value).map_err(|error| error.to_string()) -} - -pub fn missing_field(id: &str, field: &str) -> Response { - Response::Error { - id: Some(id.to_owned()), - code: "missing-field".to_owned(), - message: format!("Command is missing required field: {field}"), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn input_packet_prefers_base64_payload() { - let packet = NativeInputPacket { - payload: vec![1, 2, 3], - payload_base64: Some("BAUG".to_owned()), - partially_reliable: true, - }; - - assert_eq!( - packet.payload_bytes().expect("valid base64").as_ref(), - &[4, 5, 6] - ); - } - - #[test] - fn input_packet_keeps_legacy_byte_array_payload() { - let packet = NativeInputPacket { - payload: vec![7, 8, 9], - payload_base64: None, - partially_reliable: false, - }; - - assert_eq!( - packet.payload_bytes().expect("legacy payload").as_ref(), - &[7, 8, 9] - ); - } - - #[test] - fn video_stall_event_serializes_as_flat_native_event() { - let event = Event::VideoStall(VideoStallEvent { - stall_ms: 2_500, - encoded_kbps: 0.0, - decoded_fps: 0.0, - sink_fps: 0.0, - encoded_age_ms: Some(2_500), - decoded_age_ms: Some(2_500), - sink_age_ms: Some(2_500), - likely_stage: "video-output-stalled".to_owned(), - sink_rendered: Some(42), - sink_dropped: Some(1), - memory_mode: "D3D11Memory".to_owned(), - zero_copy: true, - requested_fps: Some(240), - caps_framerate: Some("60/1".to_owned()), - queue_mode: "adaptive".to_owned(), - partial_flush_count: 1, - complete_flush_count: 0, - last_transition_type: Some("high-fps-transition-risk".to_owned()), - last_transition_at_ms: Some(2_250), - requested_streaming_features_summary: "reflex=true, bitDepth=10".to_owned(), - finalized_streaming_features_summary: "reflex=true, bitDepth=8".to_owned(), - zero_copy_d3d11: true, - zero_copy_d3d12: false, - recovery_attempt: 1, - }); - let value = serde_json::to_value(event).expect("serializes"); - - assert_eq!(value["type"], "video-stall"); - assert_eq!(value["stallMs"], 2_500); - assert_eq!(value["encodedAgeMs"], 2_500); - assert_eq!(value["likelyStage"], "video-output-stalled"); - assert_eq!(value["sinkRendered"], 42); - assert_eq!(value["recoveryAttempt"], 1); - assert_eq!(value["queueMode"], "adaptive"); - assert_eq!(value["lastTransitionType"], "high-fps-transition-risk"); - } - - #[test] - fn video_transition_event_serializes_as_nested_transition_payload() { - let event = Event::VideoTransition { - transition: VideoTransitionEvent { - transition_type: "sink-caps-change".to_owned(), - source: "sink".to_owned(), - at_ms: 3_100, - old_caps: Some( - "video/x-raw(memory:D3D11Memory),framerate=(fraction)240/1".to_owned(), - ), - new_caps: Some( - "video/x-raw(memory:D3D11Memory),framerate=(fraction)60/1".to_owned(), - ), - old_framerate: Some("240/1".to_owned()), - new_framerate: Some("60/1".to_owned()), - old_memory_mode: Some("D3D11Memory".to_owned()), - new_memory_mode: Some("D3D11Memory".to_owned()), - render_gap_ms: Some(900), - requested_fps: Some(240), - caps_framerate: Some("60/1".to_owned()), - high_fps_risk: true, - queue_mode: "adaptive".to_owned(), - summary: "sink caps moved from 240/1 to 60/1 while 240 FPS was requested" - .to_owned(), - }, - }; - let value = serde_json::to_value(event).expect("serializes"); - - assert_eq!(value["type"], "video-transition"); - assert_eq!(value["transition"]["transitionType"], "sink-caps-change"); - assert_eq!(value["transition"]["highFpsRisk"], true); - } - - #[test] - fn nvst_video_session_deserializes_camel_case() { - let value = serde_json::json!({ - "session": { - "sessionId": "s1", - "serverIp": "1.2.3.4" - }, - "settings": { - "resolution": "1920x1080", - "fps": 60, - "maxBitrateMbps": 50, - "codec": "H265", - "colorQuality": "8bit_420", - "enableCloudGsync": false - }, - "shortcuts": {}, - "nvstVideo": { - "clientUdpPort": 49005, - "videoPeerIp": "10.0.0.1", - "videoPeerPort": 5004, - "srtpAesKeyHex": "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff", - "srtpKeyId": 2664076126u32, - "pingPayload": "token", - "codec": "H265" - } - }); - let ctx: NativeStreamerSessionContext = - serde_json::from_value(value).expect("deserialize"); - let nvst = ctx.nvst_video.expect("nvstVideo present"); - assert_eq!(nvst.client_udp_port, 49005); - assert_eq!(nvst.video_peer_port, 5004); - assert_eq!(nvst.srtp_key_id, 2664076126); - assert_eq!(nvst.ping_payload.as_deref(), Some("token")); - } -} diff --git a/native/opennow-streamer/src/sdp.rs b/native/opennow-streamer/src/sdp.rs deleted file mode 100644 index 5517d27bf..000000000 --- a/native/opennow-streamer/src/sdp.rs +++ /dev/null @@ -1,1416 +0,0 @@ -#![allow(dead_code)] - -use regex::Regex; -use std::collections::{HashMap, HashSet}; - -use crate::input::{PARTIALLY_RELIABLE_GAMEPAD_MASK_ALL, PARTIALLY_RELIABLE_HID_DEVICE_MASK_ALL}; -use crate::protocol::{ColorQuality, VideoCodec}; - -// Match the official web client's 240 FPS profile. Disabling split encode at -// this frame rate can leave H265 streams smeared because the server/client -// repair and frame-state assumptions no longer line up. -// Official Nvsc dumps set adjustStreamingFpsDuringOutOfFocus:1 (matches TS builder). -const ENABLE_OUT_OF_FOCUS_FPS_ADJUSTMENT: bool = true; -const ENABLE_240_FPS_SPLIT_ENCODE: bool = true; -const ENABLE_DYNAMIC_SPLIT_ENCODE_UPDATES: bool = true; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct IceCredentials { - pub ufrag: String, - pub pwd: String, - pub fingerprint: String, -} - -#[derive(Debug, Clone)] -pub struct NvstParams { - pub width: u32, - pub height: u32, - pub fps: u32, - pub max_bitrate_kbps: u32, - pub partial_reliable_threshold_ms: u32, - pub codec: VideoCodec, - pub color_quality: ColorQuality, - pub credentials: IceCredentials, - pub hid_device_mask: Option, - pub enable_partially_reliable_transfer_gamepad: Option, - pub enable_partially_reliable_transfer_hid: Option, -} - -#[derive(Debug, Clone, Copy)] -pub struct PreferCodecOptions { - pub prefer_hevc_profile_id: Option, -} - -pub fn parse_resolution(value: &str) -> Option<(u32, u32)> { - let (width, height) = value.split_once('x')?; - let width = width.parse().ok()?; - let height = height.parse().ok()?; - Some((width, height)) -} - -pub fn extract_public_ip(host_or_ip: &str) -> Option { - if host_or_ip.is_empty() { - return None; - } - - let ipv4 = Regex::new(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$").expect("valid regex"); - if ipv4.is_match(host_or_ip) { - return Some(host_or_ip.to_owned()); - } - - let first_label = host_or_ip.split('.').next().unwrap_or_default(); - let parts: Vec<&str> = first_label.split('-').collect(); - if parts.len() == 4 - && parts.iter().all(|part| { - !part.is_empty() && part.len() <= 3 && part.as_bytes().iter().all(u8::is_ascii_digit) - }) - { - return Some(parts.join(".")); - } - - None -} - -pub fn fix_server_ip(sdp: &str, server_ip: &str) -> String { - let Some(ip) = extract_public_ip(server_ip) else { - return sdp.to_owned(); - }; - - let fixed = sdp.replace("c=IN IP4 0.0.0.0", &format!("c=IN IP4 {ip}")); - let candidate_re = - Regex::new(r"(a=candidate:\S+\s+\d+\s+\w+\s+\d+\s+)0\.0\.0\.0(\s+)").expect("valid regex"); - candidate_re - .replace_all(&fixed, format!("${{1}}{ip}${{2}}")) - .into_owned() -} - -pub fn rewrite_ice_candidate_endpoint( - candidate: &str, - ip: &str, - port: u16, -) -> (String, bool) { - let ip = ip.trim(); - if ip.is_empty() || port == 0 { - return (candidate.to_owned(), false); - } - - let mut parts: Vec = candidate.split_whitespace().map(ToOwned::to_owned).collect(); - if parts.len() < 6 - || !(parts[0].starts_with("candidate:") || parts[0].starts_with("a=candidate:")) - { - return (candidate.to_owned(), false); - } - - if parts[4] == ip && parts[5] == port.to_string() { - return (candidate.to_owned(), false); - } - - parts[4] = ip.to_owned(); - parts[5] = port.to_string(); - let rewritten = parts.join(" "); - (rewritten, true) -} - -pub fn rewrite_sdp_ice_candidate_endpoints( - sdp: &str, - ip: &str, - port: u16, -) -> (String, usize) { - let ending = line_ending(sdp); - let mut replacements = 0usize; - let lines = split_lines_lossless(sdp) - .into_iter() - .map(|line| { - if !line.starts_with("a=candidate:") { - return line.to_owned(); - } - let (rewritten, changed) = rewrite_ice_candidate_endpoint(line, ip, port); - if changed { - replacements += 1; - } - rewritten - }) - .collect::>(); - - (lines.join(ending), replacements) -} - -pub fn duplicate_session_webrtc_attributes_to_media(sdp: &str) -> String { - let ending = line_ending(sdp); - let lines = split_lines_lossless(sdp); - let first_media_index = lines.iter().position(|line| line.starts_with("m=")); - let Some(first_media_index) = first_media_index else { - return sdp.to_owned(); - }; - - let session_attributes: Vec<&str> = lines[..first_media_index] - .iter() - .copied() - .filter(|line| { - line.starts_with("a=ice-ufrag:") - || line.starts_with("a=ice-pwd:") - || line.starts_with("a=ice-options:") - || line.starts_with("a=fingerprint:") - || line.starts_with("a=setup:") - }) - .collect(); - - if session_attributes.is_empty() { - return sdp.to_owned(); - } - - let mut output: Vec = lines[..first_media_index] - .iter() - .filter(|line| !is_media_transport_attribute(line)) - .map(|line| (*line).to_owned()) - .collect(); - - let mut index = first_media_index; - while index < lines.len() { - let section_start = index; - index += 1; - while index < lines.len() && !lines[index].starts_with("m=") { - index += 1; - } - let section = &lines[section_start..index]; - let insert_index = section - .iter() - .position(|line| line.starts_with("a=")) - .unwrap_or(section.len()); - - for line in §ion[..insert_index] { - output.push((*line).to_owned()); - } - for attribute in &session_attributes { - let prefix = attribute - .split_once(':') - .map(|(prefix, _)| format!("{prefix}:")) - .unwrap_or_else(|| (*attribute).to_owned()); - if !section.iter().any(|line| line.starts_with(&prefix)) { - output.push((*attribute).to_owned()); - } - } - for line in §ion[insert_index..] { - output.push((*line).to_owned()); - } - } - - output.join(ending) -} - -pub fn summarize_media_transport_attributes(sdp: &str) -> String { - let lines = split_lines_lossless(sdp); - let session_has_fingerprint = lines - .iter() - .take_while(|line| !line.starts_with("m=")) - .any(|line| line.starts_with("a=fingerprint:")); - - let mut media_count = 0usize; - let mut fingerprint_count = 0usize; - let mut setup_count = 0usize; - let mut ice_ufrag_count = 0usize; - let mut ice_pwd_count = 0usize; - - let mut index = 0usize; - while index < lines.len() { - if !lines[index].starts_with("m=") { - index += 1; - continue; - } - - media_count += 1; - index += 1; - let mut has_fingerprint = false; - let mut has_setup = false; - let mut has_ice_ufrag = false; - let mut has_ice_pwd = false; - while index < lines.len() && !lines[index].starts_with("m=") { - has_fingerprint |= lines[index].starts_with("a=fingerprint:"); - has_setup |= lines[index].starts_with("a=setup:"); - has_ice_ufrag |= lines[index].starts_with("a=ice-ufrag:"); - has_ice_pwd |= lines[index].starts_with("a=ice-pwd:"); - index += 1; - } - - fingerprint_count += usize::from(has_fingerprint); - setup_count += usize::from(has_setup); - ice_ufrag_count += usize::from(has_ice_ufrag); - ice_pwd_count += usize::from(has_ice_pwd); - } - - format!( - "mediaSections={media_count}, mediaFingerprints={fingerprint_count}, mediaSetup={setup_count}, mediaIceUfrag={ice_ufrag_count}, mediaIcePwd={ice_pwd_count}, sessionFingerprint={session_has_fingerprint}" - ) -} - -pub fn sanitize_ice_pwd_for_gstreamer(sdp: &str) -> (String, usize) { - let ending = line_ending(sdp); - let mut replacements = 0usize; - let lines = split_lines_lossless(sdp) - .into_iter() - .map(|line| { - let Some(value) = line.strip_prefix("a=ice-pwd:") else { - return line.to_owned(); - }; - - let sanitized = sanitize_ice_pwd_value(value); - if sanitized == value { - return line.to_owned(); - } - - replacements += 1; - format!("a=ice-pwd:{sanitized}") - }) - .collect::>(); - - (lines.join(ending), replacements) -} - -fn sanitize_ice_pwd_value(value: &str) -> String { - value - .chars() - .filter(|character| { - character.is_ascii_alphanumeric() || *character == '+' || *character == '/' - }) - .collect() -} - -fn is_media_transport_attribute(line: &str) -> bool { - line.starts_with("a=ice-ufrag:") - || line.starts_with("a=ice-pwd:") - || line.starts_with("a=fingerprint:") - || line.starts_with("a=setup:") -} - -pub fn extract_ice_ufrag_from_offer(sdp: &str) -> String { - sdp.lines() - .find_map(|line| line.strip_prefix("a=ice-ufrag:")) - .map(str::trim) - .unwrap_or_default() - .to_owned() -} - -pub fn extract_ice_credentials(sdp: &str) -> IceCredentials { - let mut ufrag = String::new(); - let mut pwd = String::new(); - let mut fingerprint = String::new(); - - for line in sdp.lines() { - if ufrag.is_empty() { - if let Some(value) = line.strip_prefix("a=ice-ufrag:") { - ufrag = value.trim().to_owned(); - continue; - } - } - if pwd.is_empty() { - if let Some(value) = line.strip_prefix("a=ice-pwd:") { - pwd = value.trim().to_owned(); - continue; - } - } - if fingerprint.is_empty() { - if let Some(value) = extract_fingerprint_value(line) { - fingerprint = value.to_owned(); - } - } - - if !ufrag.is_empty() && !pwd.is_empty() && !fingerprint.is_empty() { - break; - } - } - - IceCredentials { - ufrag, - pwd, - fingerprint, - } -} - -fn extract_fingerprint_value(line: &str) -> Option<&str> { - let value = line.strip_prefix("a=fingerprint:")?; - let (_, fingerprint) = value.trim().split_once(' ')?; - let fingerprint = fingerprint.trim(); - if fingerprint.is_empty() { - None - } else { - Some(fingerprint) - } -} - -pub fn build_nvst_sdp_for_answer(params: &NvstParams, answer_sdp: &str) -> Result { - let credentials = extract_ice_credentials(answer_sdp); - if credentials.ufrag.is_empty() - || credentials.pwd.is_empty() - || credentials.fingerprint.is_empty() - { - return Err( - "Local answer SDP is missing ICE ufrag, ICE password, or DTLS fingerprint.".to_owned(), - ); - } - - let mut answer_params = params.clone(); - answer_params.credentials = credentials; - if let Some(codec) = extract_negotiated_video_codec(answer_sdp) { - answer_params.codec = codec; - } - Ok(build_nvst_sdp(&answer_params)) -} - -pub fn extract_negotiated_video_codec(sdp: &str) -> Option { - let lines = split_lines_lossless(sdp); - let mut in_video_section = false; - let mut video_payloads = Vec::new(); - let mut codec_by_payload_type: HashMap = HashMap::new(); - - for line in &lines { - if line.starts_with("m=video") { - in_video_section = true; - video_payloads = line.split_whitespace().skip(3).map(str::to_owned).collect(); - continue; - } - if line.starts_with("m=") && in_video_section { - in_video_section = false; - } - if !in_video_section || !line.starts_with("a=rtpmap:") { - continue; - } - - let rest = line.strip_prefix("a=rtpmap:").unwrap_or_default(); - let mut parts = rest.split_whitespace(); - let Some(pt) = parts.next() else { - continue; - }; - let Some(codec_part) = parts.next() else { - continue; - }; - let codec_name = normalize_codec(codec_part.split('/').next().unwrap_or_default()); - if !codec_name.is_empty() { - codec_by_payload_type.insert(pt.to_owned(), codec_name); - } - } - - video_payloads - .iter() - .filter_map(|pt| codec_by_payload_type.get(pt)) - .find_map(|codec| match codec.as_str() { - "H264" => Some(VideoCodec::H264), - "H265" => Some(VideoCodec::H265), - "AV1" => Some(VideoCodec::AV1), - _ => None, - }) -} - -fn line_ending(sdp: &str) -> &'static str { - if sdp.contains("\r\n") { - "\r\n" - } else { - "\n" - } -} - -fn normalize_codec(name: &str) -> String { - let upper = name.to_ascii_uppercase(); - if upper == "HEVC" { - "H265".to_owned() - } else { - upper - } -} - -fn split_lines_lossless(sdp: &str) -> Vec<&str> { - sdp.split(['\r', '\n']) - .filter(|line| !line.is_empty()) - .collect() -} - -pub fn prefer_codec(sdp: &str, codec: VideoCodec, options: PreferCodecOptions) -> String { - let ending = line_ending(sdp); - let lines = split_lines_lossless(sdp); - let target_codec = codec.as_str(); - let mut in_video_section = false; - let mut payload_types_by_codec: HashMap> = HashMap::new(); - let mut codec_by_payload_type: HashMap = HashMap::new(); - let mut rtx_apt_by_payload_type: HashMap = HashMap::new(); - let mut fmtp_by_payload_type: HashMap = HashMap::new(); - - for line in &lines { - if line.starts_with("m=video") { - in_video_section = true; - continue; - } - if line.starts_with("m=") && in_video_section { - in_video_section = false; - } - if !in_video_section || !line.starts_with("a=rtpmap:") { - continue; - } - - let rest = line.strip_prefix("a=rtpmap:").unwrap_or_default(); - let mut parts = rest.split_whitespace(); - let Some(pt) = parts.next() else { - continue; - }; - let Some(codec_part) = parts.next() else { - continue; - }; - let codec_name = normalize_codec(codec_part.split('/').next().unwrap_or_default()); - if codec_name.is_empty() { - continue; - } - payload_types_by_codec - .entry(codec_name.clone()) - .or_default() - .push(pt.to_owned()); - codec_by_payload_type.insert(pt.to_owned(), codec_name); - } - - in_video_section = false; - let apt_re = Regex::new(r"(?i)(?:^|;)\s*apt=(\d+)").expect("valid regex"); - for line in &lines { - if line.starts_with("m=video") { - in_video_section = true; - continue; - } - if line.starts_with("m=") && in_video_section { - in_video_section = false; - } - if !in_video_section || !line.starts_with("a=fmtp:") { - continue; - } - - let rest = line - .split_once(':') - .map(|(_, rest)| rest) - .unwrap_or_default(); - let mut parts = rest.splitn(2, char::is_whitespace); - let Some(pt) = parts.next() else { - continue; - }; - let params = parts.next().unwrap_or_default().trim(); - if pt.is_empty() || params.is_empty() { - continue; - } - - if let Some(captures) = apt_re.captures(params) { - if let Some(apt) = captures.get(1) { - rtx_apt_by_payload_type.insert(pt.to_owned(), apt.as_str().to_owned()); - } - } - fmtp_by_payload_type.insert(pt.to_owned(), params.to_owned()); - } - - let Some(preferred_payloads) = payload_types_by_codec.get(target_codec) else { - return sdp.to_owned(); - }; - if preferred_payloads.is_empty() { - return sdp.to_owned(); - } - - let mut ordered_preferred_payloads = preferred_payloads.clone(); - if codec == VideoCodec::H265 { - if let Some(preferred_profile) = options.prefer_hevc_profile_id { - ordered_preferred_payloads.sort_by_key(|pt| { - let fmtp = fmtp_by_payload_type - .get(pt) - .map(String::as_str) - .unwrap_or_default(); - let profile = capture_numeric_param(fmtp, "profile-id"); - if profile == Some(preferred_profile as u32) { - 0 - } else if profile.is_none() { - 1 - } else { - 2 - } - }); - } - } - - let preferred: HashSet = ordered_preferred_payloads.iter().cloned().collect(); - let mut allowed = preferred.clone(); - - for (rtx_pt, apt) in rtx_apt_by_payload_type { - if preferred.contains(&apt) - && codec_by_payload_type - .get(&rtx_pt) - .is_some_and(|name| name == "RTX") - { - allowed.insert(rtx_pt); - } - } - - for (pt, codec_name) in &codec_by_payload_type { - if matches!(codec_name.as_str(), "FLEXFEC-03") { - allowed.insert(pt.clone()); - } - } - - let mut filtered = Vec::new(); - in_video_section = false; - - for line in lines { - if line.starts_with("m=video") { - in_video_section = true; - let parts: Vec<&str> = line.split_whitespace().collect(); - let header = &parts[..parts.len().min(3)]; - let available: Vec<&str> = parts - .iter() - .skip(3) - .copied() - .filter(|pt| allowed.contains(*pt)) - .collect(); - let mut ordered = Vec::new(); - - for pt in &ordered_preferred_payloads { - if available.contains(&pt.as_str()) { - ordered.push(pt.as_str()); - } - } - for pt in available { - if !preferred.contains(pt) { - ordered.push(pt); - } - } - - if ordered.is_empty() { - filtered.push(line.to_owned()); - } else { - filtered.push( - header - .iter() - .chain(ordered.iter()) - .copied() - .collect::>() - .join(" "), - ); - } - continue; - } - - if line.starts_with("m=") && in_video_section { - in_video_section = false; - } - - if in_video_section - && (line.starts_with("a=rtpmap:") - || line.starts_with("a=fmtp:") - || line.starts_with("a=rtcp-fb:")) - { - let rest = line - .split_once(':') - .map(|(_, rest)| rest) - .unwrap_or_default(); - let pt = rest.split_whitespace().next().unwrap_or_default(); - if !pt.is_empty() && !allowed.contains(pt) { - continue; - } - } - - filtered.push(line.to_owned()); - } - - filtered.join(ending) -} - -fn capture_numeric_param(params: &str, key: &str) -> Option { - for part in params.split(';') { - let trimmed = part.trim(); - let Some((candidate_key, value)) = trimmed.split_once('=') else { - continue; - }; - if candidate_key.eq_ignore_ascii_case(key) { - return value.trim().parse().ok(); - } - } - None -} - -pub fn munge_answer_sdp(sdp: &str, max_bitrate_kbps: u32) -> String { - let ending = line_ending(sdp); - let lines = split_lines_lossless(sdp); - let mut result = Vec::new(); - - for (index, line) in lines.iter().enumerate() { - let mut current = (*line).to_owned(); - if current.starts_with("a=fmtp:") - && current.contains("minptime=") - && !current.contains("stereo=1") - { - current.push_str(";stereo=1"); - } - result.push(current); - - if line.starts_with("m=video") || line.starts_with("m=audio") { - let bitrate = if line.starts_with("m=video") { - max_bitrate_kbps - } else { - 128 - }; - let next_line = lines.get(index + 1).copied().unwrap_or_default(); - if !next_line.starts_with("b=") { - result.push(format!("b=AS:{bitrate}")); - } - } - } - - result.join(ending) -} - -pub fn build_nvst_sdp(params: &NvstParams) -> String { - // Align bitrate floor/startup with the TS WebRTC companion builder - // (official web client uses a 4 Mbps floor and ~max/4 startup). - const OFFICIAL_MIN_BITRATE_KBPS: u32 = 4000; - let max_bitrate = params.max_bitrate_kbps.max(OFFICIAL_MIN_BITRATE_KBPS); - let min_bitrate = OFFICIAL_MIN_BITRATE_KBPS; - let initial_bitrate = OFFICIAL_MIN_BITRATE_KBPS.max(max_bitrate / 4); - let is_high_fps = params.fps > 60; - let is_at_least_120_fps = params.fps >= 120; - let is_90_fps = params.fps == 90; - let is_120_fps = params.fps == 120; - let is_240_fps = params.fps == 240; - let is_av1 = params.codec == VideoCodec::AV1; - let bit_depth = params.color_quality.bit_depth(); - let hid_device_mask = params - .hid_device_mask - .unwrap_or(PARTIALLY_RELIABLE_HID_DEVICE_MASK_ALL); - let enable_partially_reliable_transfer_gamepad = params - .enable_partially_reliable_transfer_gamepad - .unwrap_or(PARTIALLY_RELIABLE_GAMEPAD_MASK_ALL); - let enable_partially_reliable_transfer_hid = params - .enable_partially_reliable_transfer_hid - .unwrap_or(hid_device_mask); - let min_target_frame_time_us = (1_000_000u32.saturating_mul(95) - / params.fps.max(1).saturating_mul(100)) - .max(1000); - - let mut lines = vec![ - "v=0".to_owned(), - "o=SdpTest test_id_13 14 IN IPv4 127.0.0.1".to_owned(), - "s=-".to_owned(), - "t=0 0".to_owned(), - format!("a=general.icePassword:{}", params.credentials.pwd), - format!("a=general.iceUserNameFragment:{}", params.credentials.ufrag), - format!( - "a=general.dtlsFingerprint:{}", - params.credentials.fingerprint - ), - "m=video 0 RTP/AVP".to_owned(), - "a=msid:fbc-video-0".to_owned(), - "a=vqos.fec.rateDropWindow:10".to_owned(), - "a=vqos.fec.minRequiredFecPackets:2".to_owned(), - "a=vqos.fec.repairMinPercent:5".to_owned(), - "a=vqos.fec.repairPercent:5".to_owned(), - "a=vqos.fec.repairMaxPercent:35".to_owned(), - "a=vqos.bllFec.enable:0".to_owned(), - "a=vqos.dynamicStreamingMode:0".to_owned(), - "a=vqos.drc.enable:0".to_owned(), - "a=vqos.calculateAvgVideoStreamingBitrate:1".to_owned(), - "a=video.dx9EnableNv12:1".to_owned(), - "a=video.dx9EnableHdr:1".to_owned(), - "a=vqos.qpg.enable:1".to_owned(), - "a=vqos.resControl.qp.qpg.featureSetting:7".to_owned(), - "a=video.adaptiveQuantization.spatialAQSetting:7".to_owned(), - "a=video.adaptiveQuantization.temporalAQSetting:0".to_owned(), - "a=video.adaptiveQuantization.spatialAQStrength:12".to_owned(), - "a=video.adaptiveQuantization.qpThresholdAdjPercent:2".to_owned(), - "a=video.adaptiveQuantization.saqAdaptMinQpThresholdPercent:40".to_owned(), - "a=video.adaptiveQuantization.saqAdaptMaxQpThresholdPercent:100".to_owned(), - "a=video.adaptiveQuantization.saqAdaptDecayStrengthX100:250".to_owned(), - "a=video.adaptiveQuantization.perfAdjEnablement:1".to_owned(), - "a=video.framePacing.mode:2".to_owned(), - format!("a=video.framePacing.pid.minTargetFrameTimeUs:{min_target_frame_time_us}"), - "a=bwe.useOwdCongestionControl:1".to_owned(), - "a=video.enableRtpNack:1".to_owned(), - "a=vqos.bw.txRxLag.minFeedbackTxDeltaMs:200".to_owned(), - "a=vqos.drc.bitrateIirFilterFactor:18".to_owned(), - "a=video.packetSize:1140".to_owned(), - "a=packetPacing.version:3".to_owned(), - "a=packetPacing.mode:1".to_owned(), - "a=packetPacing.minNumPacketsPerGroup:15".to_owned(), - "a=packetPacing.enableAccurateSleep:1".to_owned(), - "a=packetPacing.enableSmoothTransition:1".to_owned(), - "a=packetPacing.allowFpsBasedToggle:1".to_owned(), - "a=vqos.relaxMaxBitrate.overrideAvgBitrateThresholdPercent:4".to_owned(), - "a=vqos.relaxMaxBitrate.customAvgBitrateThresholdPercent:65".to_owned(), - "a=vqos.relaxMaxBitrate.overrideAvgQpThresholdPercent:7".to_owned(), - "a=vqos.relaxMaxBitrate.customAvgQpThresholdPercent:51".to_owned(), - "a=vqos.relaxMaxBitrate.iirFilterFactor:120".to_owned(), - "a=vqos.qpDelta.qpDeltaMaxPercent:10".to_owned(), - "a=vqos.qpDelta.qpDeltaSurfaceAdjustmentStrengthPercent:70".to_owned(), - "a=vqos.qpDelta.qpDeltaVbvUsageFactorPercentH264:100".to_owned(), - "a=vqos.qpDelta.qpDeltaVbvUsageFactorPercentH265:100".to_owned(), - "a=vqos.qpDelta.qpDeltaVbvUsageFactorPercentAv1:100".to_owned(), - "a=vqos.qpDelta.qpDeltaMinPercent:60".to_owned(), - "a=vqos.qpDelta.qpDeltaIirFactor:60".to_owned(), - "a=vqos.qpDelta.qpDeltaThrottlePercent:100".to_owned(), - ]; - - if is_high_fps { - lines.extend([ - "a=vqos.dfc.enable:1".to_owned(), - "a=vqos.dfc.decodeFpsAdjPercent:85".to_owned(), - "a=vqos.dfc.targetDownCooldownMs:250".to_owned(), - format!( - "a=vqos.dfc.dfcAlgoVersion:{}", - if is_at_least_120_fps { 2 } else { 1 } - ), - format!( - "a=vqos.dfc.minTargetFps:{}", - if is_at_least_120_fps { 100 } else { 60 } - ), - "a=vqos.resControl.dfc.useClientFpsPerf:0".to_owned(), - "a=vqos.dfc.adjustResAndFps:0".to_owned(), - ]); - lines.extend([ - "a=bwe.iirFilterFactor:8".to_owned(), - "a=video.encoderFeatureSetting:47".to_owned(), - "a=video.encoderPreset:6".to_owned(), - ]); - let fps_specific_capture_tuning = if is_90_fps { - Some((9, 11)) - } else if is_120_fps { - Some((6, 9)) - } else if is_240_fps { - Some((18, 9)) - } else { - None - }; - if let Some((grab_timeout_ms, decode_threshold_ms)) = fps_specific_capture_tuning { - lines.push(format!( - "a=video.fbcDynamicFpsGrabTimeoutMs:{grab_timeout_ms}" - )); - lines.push(format!( - "a=vqos.resControl.cpmRtc.decodeTimeThresholdMs:{decode_threshold_ms}" - )); - } - } else { - lines.extend([ - "a=vqos.dfc.enable:0".to_owned(), - "a=vqos.dfc.adjustResAndFps:0".to_owned(), - ]); - } - - if is_240_fps { - lines.extend([ - "a=video.enableNextCaptureMode:1".to_owned(), - "a=vqos.maxStreamFpsEstimate:240".to_owned(), - ]); - if ENABLE_240_FPS_SPLIT_ENCODE { - let strips_per_frame = - if is_av1 && params.width.saturating_mul(params.height) >= 2_764_800 { - 63 - } else { - 3 - }; - lines.push(format!( - "a=video.videoSplitEncodeStripsPerFrame:{strips_per_frame}" - )); - lines.push(format!( - "a=video.updateSplitEncodeStateDynamically:{}", - if ENABLE_DYNAMIC_SPLIT_ENCODE_UPDATES { - 1 - } else { - 0 - } - )); - lines.push("a=vqos.rtcPreemptiveIdrSettings.minBurstNackSize:65535".to_owned()); - lines - .push("a=vqos.rtcPreemptiveIdrSettings.minNackPacketCaptureAgeMs:65535".to_owned()); - } - } - - lines.extend([ - format!( - "a=vqos.adjustStreamingFpsDuringOutOfFocus:{}", - if ENABLE_OUT_OF_FOCUS_FPS_ADJUSTMENT { - 1 - } else { - 0 - } - ), - "a=vqos.resControl.cpmRtc.ignoreOutOfFocusWindowState:1".to_owned(), - "a=vqos.resControl.perfHistory.rtcIgnoreOutOfFocusWindowState:1".to_owned(), - "a=vqos.resControl.cpmRtc.featureMask:0".to_owned(), - "a=vqos.resControl.cpmRtc.enable:0".to_owned(), - "a=vqos.resControl.cpmRtc.minResolutionPercent:100".to_owned(), - "a=vqos.resControl.cpmRtc.resolutionChangeHoldonMs:999999".to_owned(), - format!( - "a=packetPacing.numGroups:{}", - if is_120_fps { 3 } else { 5 } - ), - "a=packetPacing.maxDelayUs:1000".to_owned(), - "a=packetPacing.minNumPacketsFrame:10".to_owned(), - "a=video.rtpNackQueueLength:1024".to_owned(), - "a=video.rtpNackQueueMaxPackets:512".to_owned(), - "a=video.rtpNackMaxPacketCount:25".to_owned(), - "a=vqos.drc.qpMaxResThresholdAdj:4".to_owned(), - "a=vqos.grc.qpMaxResThresholdAdj:4".to_owned(), - "a=vqos.drc.iirFilterFactor:100".to_owned(), - ]); - - if is_av1 { - lines.extend([ - "a=vqos.drc.minQpHeadroom:20".to_owned(), - "a=vqos.drc.lowerQpThreshold:100".to_owned(), - "a=vqos.drc.upperQpThreshold:200".to_owned(), - "a=vqos.drc.minAdaptiveQpThreshold:180".to_owned(), - "a=vqos.drc.qpCodecThresholdAdj:0".to_owned(), - "a=vqos.drc.qpMaxResThresholdAdj:20".to_owned(), - "a=vqos.dfc.minQpHeadroom:20".to_owned(), - "a=vqos.dfc.qpLowerLimit:100".to_owned(), - "a=vqos.dfc.qpMaxUpperLimit:200".to_owned(), - "a=vqos.dfc.qpMinUpperLimit:180".to_owned(), - "a=vqos.dfc.qpMaxResThresholdAdj:20".to_owned(), - "a=vqos.dfc.qpCodecThresholdAdj:0".to_owned(), - "a=vqos.grc.minQpHeadroom:20".to_owned(), - "a=vqos.grc.lowerQpThreshold:100".to_owned(), - "a=vqos.grc.upperQpThreshold:200".to_owned(), - "a=vqos.grc.minAdaptiveQpThreshold:180".to_owned(), - "a=vqos.grc.qpMaxResThresholdAdj:20".to_owned(), - "a=vqos.grc.qpCodecThresholdAdj:0".to_owned(), - "a=video.minQp:25".to_owned(), - "a=video.enableAv1RcPrecisionFactor:1".to_owned(), - ]); - } - - lines.extend([ - format!("a=video.clientViewportWd:{}", params.width), - format!("a=video.clientViewportHt:{}", params.height), - format!("a=video.maxFPS:{}", params.fps), - format!("a=video.initialBitrateKbps:{initial_bitrate}"), - format!("a=video.initialPeakBitrateKbps:{initial_bitrate}"), - format!("a=vqos.bw.maximumBitrateKbps:{max_bitrate}"), - format!("a=vqos.bw.minimumBitrateKbps:{min_bitrate}"), - format!("a=vqos.bw.peakBitrateKbps:{max_bitrate}"), - format!("a=vqos.bw.serverPeakBitrateKbps:{max_bitrate}"), - "a=vqos.bw.enableBandwidthEstimation:1".to_owned(), - "a=vqos.bw.disableBitrateLimit:0".to_owned(), - format!("a=vqos.grc.maximumBitrateKbps:{max_bitrate}"), - "a=vqos.grc.enable:0".to_owned(), - "a=video.maxNumReferenceFrames:4".to_owned(), - "a=video.mapRtpTimestampsToFrames:1".to_owned(), - "a=video.encoderCscMode:3".to_owned(), - "a=video.dynamicRangeMode:0".to_owned(), - format!("a=video.bitDepth:{bit_depth}"), - format!("a=video.scalingFeature1:{}", if is_av1 { 1 } else { 0 }), - "a=video.prefilterParams.prefilterModel:0".to_owned(), - "m=audio 0 RTP/AVP".to_owned(), - "a=msid:audio".to_owned(), - "a=aqos.enableRedundancy:1".to_owned(), - "a=aqos.redundancyLevel:2".to_owned(), - "a=aqos.enableRedundancyForMic:1".to_owned(), - "a=aqos.redundancyLevelForMic:3".to_owned(), - "a=audio.enableDynamicAudioConfig:1".to_owned(), - "a=audio.enableTimestampAudioBuffer:1".to_owned(), - "m=mic 0 RTP/AVP".to_owned(), - "a=msid:mic".to_owned(), - "a=rtpmap:0 PCMU/8000".to_owned(), - "m=application 0 RTP/AVP".to_owned(), - "a=msid:input_1".to_owned(), - format!( - "a=ri.partialReliableThresholdMs:{}", - params.partial_reliable_threshold_ms - ), - format!("a=ri.hidDeviceMask:{hid_device_mask}"), - format!( - "a=ri.enablePartiallyReliableTransferGamepad:{enable_partially_reliable_transfer_gamepad}" - ), - format!( - "a=ri.enablePartiallyReliableTransferHid:{enable_partially_reliable_transfer_hid}" - ), - "a=ri.timestampsEnabled:1".to_owned(), - "a=ri.useMultipleGamepads:1".to_owned(), - String::new(), - ]); - - lines.join("\n") -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn extracts_public_ip_from_host_or_ip() { - assert_eq!( - extract_public_ip("80-250-97-40.cloudmatchbeta.nvidiagrid.net").as_deref(), - Some("80.250.97.40"), - ); - assert_eq!( - extract_public_ip("161.248.11.132").as_deref(), - Some("161.248.11.132") - ); - assert_eq!(extract_public_ip("not-an-ip.example.com"), None); - } - - #[test] - fn fixes_connection_and_candidate_ips() { - let offer = "v=0\nc=IN IP4 0.0.0.0\na=candidate:1 1 udp 1 0.0.0.0 49000 typ host\n"; - let fixed = fix_server_ip(offer, "80-250-97-40.cloudmatchbeta.nvidiagrid.net"); - assert!(fixed.contains("c=IN IP4 80.250.97.40")); - assert!(fixed.contains("a=candidate:1 1 udp 1 80.250.97.40 49000 typ host")); - } - - #[test] - fn rewrites_sdp_ice_candidate_endpoints() { - let offer = [ - "v=0", - "c=IN IP4 0.0.0.0", - "a=candidate:1 1 udp 2122260223 203.0.113.10 47998 typ host", - "a=candidate:2 1 tcp 1518214911 203.0.113.10 9 typ host tcptype active", - ] - .join("\r\n"); - - let (rewritten, replacements) = - rewrite_sdp_ice_candidate_endpoints(&offer, "198.51.100.55", 18784); - - assert_eq!(replacements, 2); - assert!(rewritten - .contains("a=candidate:1 1 udp 2122260223 198.51.100.55 18784 typ host")); - assert!(rewritten.contains( - "a=candidate:2 1 tcp 1518214911 198.51.100.55 18784 typ host tcptype active" - )); - assert!(rewritten.contains("c=IN IP4 0.0.0.0")); - assert!(rewritten.contains("\r\n")); - } - - #[test] - fn rewrites_trickled_ice_candidate_endpoint() { - let candidate = "candidate:1 1 udp 2122260223 203.0.113.10 47998 typ host"; - - let (rewritten, changed) = - rewrite_ice_candidate_endpoint(candidate, "198.51.100.55", 18784); - - assert!(changed); - assert_eq!( - rewritten, - "candidate:1 1 udp 2122260223 198.51.100.55 18784 typ host" - ); - } - - #[test] - fn duplicates_session_webrtc_attributes_into_media_sections() { - let offer = [ - "v=0", - "a=ice-options:trickle", - "a=ice-ufrag:user", - "a=ice-pwd:pass", - "a=fingerprint:sha-256 AA:BB", - "a=setup:actpass", - "m=audio 9 UDP/TLS/RTP/SAVPF 111", - "c=IN IP4 10.0.0.1", - "a=mid:0", - "m=video 9 UDP/TLS/RTP/SAVPF 96", - "c=IN IP4 10.0.0.1", - "a=mid:1", - ] - .join("\n"); - - let normalized = duplicate_session_webrtc_attributes_to_media(&offer); - let session_part = normalized.split("\nm=").next().expect("session section"); - let media_sections = normalized - .split("\nm=") - .skip(1) - .map(|section| format!("m={section}")) - .collect::>(); - - assert_eq!(media_sections.len(), 2); - for section in media_sections { - assert!(section.contains("a=ice-options:trickle")); - assert!(section.contains("a=ice-ufrag:user")); - assert!(section.contains("a=ice-pwd:pass")); - assert!(section.contains("a=fingerprint:sha-256 AA:BB")); - assert!(section.contains("a=setup:actpass")); - } - assert!(!session_part.contains("a=ice-ufrag:user")); - assert!(!session_part.contains("a=ice-pwd:pass")); - assert!(!session_part.contains("a=fingerprint:sha-256 AA:BB")); - assert!(!session_part.contains("a=setup:actpass")); - } - - #[test] - fn keeps_existing_media_webrtc_attributes() { - let offer = [ - "v=0", - "a=ice-ufrag:session", - "a=ice-pwd:session-pass", - "m=audio 9 UDP/TLS/RTP/SAVPF 111", - "a=ice-ufrag:media", - "a=ice-pwd:media-pass", - "a=mid:0", - ] - .join("\n"); - - let normalized = duplicate_session_webrtc_attributes_to_media(&offer); - - assert!(normalized.contains("a=ice-ufrag:media")); - assert!(normalized.contains("a=ice-pwd:media-pass")); - assert_eq!(normalized.matches("a=ice-ufrag:session").count(), 0); - assert_eq!(normalized.matches("a=ice-pwd:session-pass").count(), 0); - } - - #[test] - fn summarizes_media_transport_attributes() { - let offer = [ - "v=0", - "a=group:BUNDLE 0 1", - "m=audio 9 UDP/TLS/RTP/SAVPF 111", - "a=fingerprint:sha-256 AA:BB", - "a=setup:actpass", - "a=ice-ufrag:user", - "a=ice-pwd:pass", - "m=video 9 UDP/TLS/RTP/SAVPF 96", - "a=setup:actpass", - ] - .join("\n"); - - assert_eq!( - summarize_media_transport_attributes(&offer), - "mediaSections=2, mediaFingerprints=1, mediaSetup=2, mediaIceUfrag=1, mediaIcePwd=1, sessionFingerprint=false" - ); - } - - #[test] - fn sanitizes_nonstandard_ice_password_for_gstreamer() { - let sdp = [ - "v=0", - "m=audio 9 UDP/TLS/RTP/SAVPF 111", - "a=ice-pwd:48ca4c4b-199a-454c-b58a-3d14739335a3", - "m=video 9 UDP/TLS/RTP/SAVPF 96", - "a=ice-pwd:alreadyValidPassword123456", - ] - .join("\n"); - - let (sanitized, replacements) = sanitize_ice_pwd_for_gstreamer(&sdp); - - assert_eq!(replacements, 1); - assert!(sanitized.contains("a=ice-pwd:48ca4c4b199a454cb58a3d14739335a3")); - assert!(sanitized.contains("a=ice-pwd:alreadyValidPassword123456")); - } - - #[test] - fn extracts_ice_credentials() { - let sdp = "a=ice-ufrag:user\r\na=ice-pwd:pass\r\na=fingerprint:sha-256 AA:BB\r\na=ice-ufrag:other\r\na=ice-pwd:other-pass\r\na=fingerprint:sha-256 CC:DD\r\n"; - assert_eq!(extract_ice_ufrag_from_offer(sdp), "user"); - assert_eq!( - extract_ice_credentials(sdp), - IceCredentials { - ufrag: "user".to_owned(), - pwd: "pass".to_owned(), - fingerprint: "AA:BB".to_owned(), - }, - ); - } - - #[test] - fn builds_nvst_sdp_with_local_answer_credentials() { - let params = NvstParams { - width: 1920, - height: 1080, - fps: 60, - max_bitrate_kbps: 75_000, - partial_reliable_threshold_ms: 16, - codec: VideoCodec::H265, - color_quality: ColorQuality::EightBit420, - credentials: IceCredentials { - ufrag: "remote-user".to_owned(), - pwd: "remote-password".to_owned(), - fingerprint: "AA:BB".to_owned(), - }, - hid_device_mask: None, - enable_partially_reliable_transfer_gamepad: None, - enable_partially_reliable_transfer_hid: None, - }; - let answer_sdp = [ - "v=0", - "m=audio 9 UDP/TLS/RTP/SAVPF 111", - "a=ice-ufrag:local-user", - "a=ice-pwd:local-password", - "a=fingerprint:sha-256 CC:DD", - "m=video 9 UDP/TLS/RTP/SAVPF 96", - "a=ice-ufrag:video-user", - "a=ice-pwd:video-password", - "a=fingerprint:sha-256 EE:FF", - ] - .join("\n"); - - let nvst = build_nvst_sdp_for_answer(¶ms, &answer_sdp).expect("nvst sdp"); - - assert!(nvst.contains("a=general.icePassword:local-password")); - assert!(nvst.contains("a=general.iceUserNameFragment:local-user")); - assert!(nvst.contains("a=general.dtlsFingerprint:CC:DD")); - assert!(!nvst.contains("remote-password")); - assert!(!nvst.contains("video-password")); - } - - fn nvst_params_for_fps(fps: u32) -> NvstParams { - NvstParams { - width: 1920, - height: 1080, - fps, - max_bitrate_kbps: 75_000, - partial_reliable_threshold_ms: 16, - codec: VideoCodec::H265, - color_quality: ColorQuality::EightBit420, - credentials: IceCredentials { - ufrag: "user".to_owned(), - pwd: "password".to_owned(), - fingerprint: "AA:BB".to_owned(), - }, - hid_device_mask: None, - enable_partially_reliable_transfer_gamepad: None, - enable_partially_reliable_transfer_hid: None, - } - } - - #[test] - fn builds_nvst_sdp_disables_dynamic_streaming_for_normal_fps() { - let nvst = build_nvst_sdp(&nvst_params_for_fps(60)); - - assert!(nvst.contains("a=vqos.dynamicStreamingMode:0")); - assert!(nvst.contains("a=vqos.dfc.adjustResAndFps:0")); - assert!(nvst.contains("a=vqos.dfc.enable:0")); - assert!(!nvst.contains("a=vqos.dfc.decodeFpsAdjPercent:85")); - assert!(!nvst.contains("a=vqos.resControl.dfc.useClientFpsPerf:0")); - } - - #[test] - fn builds_nvst_sdp_disables_dynamic_streaming_for_high_fps() { - for fps in [90, 120, 144, 165, 240, 360] { - let nvst = build_nvst_sdp(&nvst_params_for_fps(fps)); - - assert!(nvst.contains("a=vqos.dynamicStreamingMode:0")); - assert!(nvst.contains("a=vqos.dfc.adjustResAndFps:0")); - assert!(nvst.contains("a=vqos.dfc.enable:1")); - assert!(nvst.contains("a=vqos.resControl.dfc.useClientFpsPerf:0")); - if fps >= 120 { - assert!(nvst.contains("a=vqos.dfc.dfcAlgoVersion:2")); - assert!(nvst.contains("a=vqos.dfc.minTargetFps:100")); - } else { - assert!(nvst.contains("a=vqos.dfc.dfcAlgoVersion:1")); - assert!(nvst.contains("a=vqos.dfc.minTargetFps:60")); - } - assert!(!nvst.contains("a=vqos.dfc.enable:0")); - } - } - - #[test] - fn applies_only_official_fps_specific_capture_tuning() { - let cases = [ - (90, Some((9, 11))), - (120, Some((6, 9))), - (144, None), - (165, None), - (240, Some((18, 9))), - (360, None), - ]; - - for (fps, expected) in cases { - let nvst = build_nvst_sdp(&nvst_params_for_fps(fps)); - match expected { - Some((grab_timeout_ms, decode_threshold_ms)) => { - assert!(nvst.contains(&format!( - "a=video.fbcDynamicFpsGrabTimeoutMs:{grab_timeout_ms}" - ))); - assert!(nvst.contains(&format!( - "a=vqos.resControl.cpmRtc.decodeTimeThresholdMs:{decode_threshold_ms}" - ))); - } - None => { - assert!(!nvst.contains("a=video.fbcDynamicFpsGrabTimeoutMs:")); - assert!(!nvst.contains("a=vqos.resControl.cpmRtc.decodeTimeThresholdMs:")); - } - } - } - } - - #[test] - fn reserves_240_fps_capture_profile_for_exact_240_fps() { - let nvst_240 = build_nvst_sdp(&nvst_params_for_fps(240)); - let nvst_360 = build_nvst_sdp(&nvst_params_for_fps(360)); - - assert!(nvst_240.contains("a=vqos.maxStreamFpsEstimate:240")); - assert!(nvst_240.contains("a=video.enableNextCaptureMode:1")); - assert!(!nvst_360.contains("a=vqos.maxStreamFpsEstimate:240")); - assert!(!nvst_360.contains("a=video.enableNextCaptureMode:1")); - assert!(!nvst_360.contains("a=video.videoSplitEncodeStripsPerFrame:")); - } - - #[test] - fn extracts_negotiated_video_codec_from_answer_payload_order() { - let answer_sdp = [ - "v=0", - "m=audio 9 UDP/TLS/RTP/SAVPF 111", - "a=rtpmap:111 OPUS/48000/2", - "m=video 9 UDP/TLS/RTP/SAVPF 101 102", - "a=rtpmap:101 AV1/90000", - "a=rtpmap:102 rtx/90000", - "a=fmtp:102 apt=101", - ] - .join("\n"); - - assert_eq!( - extract_negotiated_video_codec(&answer_sdp), - Some(VideoCodec::AV1) - ); - } - - #[test] - fn builds_nvst_sdp_for_answer_uses_negotiated_av1_codec() { - let params = NvstParams { - width: 2560, - height: 1440, - fps: 120, - max_bitrate_kbps: 150_000, - partial_reliable_threshold_ms: 16, - codec: VideoCodec::H265, - color_quality: ColorQuality::EightBit420, - credentials: IceCredentials { - ufrag: "remote-user".to_owned(), - pwd: "remote-password".to_owned(), - fingerprint: "AA:BB".to_owned(), - }, - hid_device_mask: None, - enable_partially_reliable_transfer_gamepad: None, - enable_partially_reliable_transfer_hid: None, - }; - let answer_sdp = [ - "v=0", - "m=audio 9 UDP/TLS/RTP/SAVPF 111", - "a=ice-ufrag:local-user", - "a=ice-pwd:local-password", - "a=fingerprint:sha-256 CC:DD", - "m=video 9 UDP/TLS/RTP/SAVPF 101", - "a=rtpmap:101 AV1/90000", - ] - .join("\n"); - - let nvst = build_nvst_sdp_for_answer(¶ms, &answer_sdp).expect("nvst sdp"); - - assert!(nvst.contains("a=video.scalingFeature1:1")); - assert!(nvst.contains("a=video.enableAv1RcPrecisionFactor:1")); - assert!(nvst.contains("a=vqos.drc.minQpHeadroom:20")); - } - - #[test] - fn munges_answer_bitrate_and_opus_stereo() { - let sdp = "m=video 9 UDP/TLS/RTP/SAVPF 96\nm=audio 9 UDP/TLS/RTP/SAVPF 111\na=fmtp:111 minptime=10;useinbandfec=1"; - let munged = munge_answer_sdp(sdp, 75000); - assert!(munged.contains("m=video 9 UDP/TLS/RTP/SAVPF 96\nb=AS:75000")); - assert!(munged.contains("m=audio 9 UDP/TLS/RTP/SAVPF 111\nb=AS:128")); - assert!(munged.contains("a=fmtp:111 minptime=10;useinbandfec=1;stereo=1")); - } - - #[test] - fn filters_video_codec_and_keeps_matching_rtx() { - let sdp = [ - "v=0", - "m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101", - "a=rtpmap:96 H264/90000", - "a=rtpmap:97 rtx/90000", - "a=fmtp:97 apt=96", - "a=rtpmap:98 H265/90000", - "a=fmtp:98 profile-id=1;level-id=186", - "a=rtpmap:99 rtx/90000", - "a=fmtp:99 apt=98", - "a=rtpmap:100 AV1/90000", - "a=rtpmap:101 flexfec-03/90000", - "m=audio 9 UDP/TLS/RTP/SAVPF 111", - ] - .join("\n"); - let filtered = prefer_codec( - &sdp, - VideoCodec::H265, - PreferCodecOptions { - prefer_hevc_profile_id: Some(1), - }, - ); - assert!(filtered.contains("m=video 9 UDP/TLS/RTP/SAVPF 98 99 101")); - assert!(!filtered.contains("a=rtpmap:96 H264/90000")); - assert!(filtered.contains("a=rtpmap:99 rtx/90000")); - assert!(filtered.contains("a=rtpmap:101 flexfec-03/90000")); - assert!(filtered.contains("m=audio 9 UDP/TLS/RTP/SAVPF 111")); - } - - #[test] - fn builds_nvst_sdp_with_core_attributes() { - let nvst = build_nvst_sdp(&NvstParams { - width: 1920, - height: 1080, - fps: 120, - max_bitrate_kbps: 75_000, - partial_reliable_threshold_ms: 16, - codec: VideoCodec::H265, - color_quality: ColorQuality::TenBit420, - credentials: IceCredentials { - ufrag: "ufrag".to_owned(), - pwd: "pwd".to_owned(), - fingerprint: "AA:BB".to_owned(), - }, - hid_device_mask: None, - enable_partially_reliable_transfer_gamepad: None, - enable_partially_reliable_transfer_hid: None, - }); - - assert!(nvst.contains("a=general.icePassword:pwd")); - assert!(nvst.contains("a=video.clientViewportWd:1920")); - assert!(nvst.contains("a=video.clientViewportHt:1080")); - assert!(nvst.contains("a=video.maxFPS:120")); - assert!(nvst.contains("a=video.bitDepth:10")); - assert!(nvst.contains("a=packetPacing.numGroups:3")); - assert!(nvst.contains("a=packetPacing.enableAccurateSleep:1")); - assert!(nvst.contains("a=packetPacing.minNumPacketsPerGroup:15")); - assert!(nvst.contains("a=video.framePacing.mode:2")); - assert!(nvst.contains("a=vqos.fec.repairPercent:5")); - assert!(nvst.contains("a=vqos.fec.repairMaxPercent:35")); - assert!(nvst.contains("a=vqos.bllFec.enable:0")); - assert!(nvst.contains("a=video.rtpNackQueueLength:1024")); - assert!(nvst.contains("a=video.rtpNackQueueMaxPackets:512")); - assert!(nvst.contains("a=video.rtpNackMaxPacketCount:25")); - assert!(nvst.contains("a=aqos.enableRedundancy:1")); - assert!(nvst.contains("a=vqos.adjustStreamingFpsDuringOutOfFocus:1")); - assert!(!nvst.contains("a=video.updateSplitEncodeStateDynamically:1")); - assert!(nvst.contains("a=ri.partialReliableThresholdMs:16")); - assert!(nvst.ends_with('\n')); - } - - #[test] - fn advertises_official_240_fps_split_encode_profile() { - let nvst = build_nvst_sdp(&NvstParams { - width: 1920, - height: 1080, - fps: 240, - max_bitrate_kbps: 75_000, - partial_reliable_threshold_ms: 16, - codec: VideoCodec::H265, - color_quality: ColorQuality::EightBit420, - credentials: IceCredentials { - ufrag: "ufrag".to_owned(), - pwd: "pwd".to_owned(), - fingerprint: "AA:BB".to_owned(), - }, - hid_device_mask: None, - enable_partially_reliable_transfer_gamepad: None, - enable_partially_reliable_transfer_hid: None, - }); - - assert!(nvst.contains("a=vqos.maxStreamFpsEstimate:240")); - assert!(nvst.contains("a=video.videoSplitEncodeStripsPerFrame:3")); - assert!(nvst.contains("a=video.updateSplitEncodeStateDynamically:1")); - assert!(nvst.contains("a=video.framePacing.pid.minTargetFrameTimeUs:3958")); - assert!(nvst.contains("a=vqos.rtcPreemptiveIdrSettings.minBurstNackSize:65535")); - assert!(nvst.contains("a=vqos.rtcPreemptiveIdrSettings.minNackPacketCaptureAgeMs:65535")); - } - - #[test] - fn uses_wide_split_encode_only_for_high_resolution_av1() { - let mut params = nvst_params_for_fps(240); - params.codec = VideoCodec::AV1; - params.width = 2560; - params.height = 1440; - - let nvst = build_nvst_sdp(¶ms); - - assert!(nvst.contains("a=video.videoSplitEncodeStripsPerFrame:63")); - } -} diff --git a/native/opennow-streamer/src/shortcuts.rs b/native/opennow-streamer/src/shortcuts.rs deleted file mode 100644 index 271b9e419..000000000 --- a/native/opennow-streamer/src/shortcuts.rs +++ /dev/null @@ -1,355 +0,0 @@ -use crate::protocol::{NativeStreamerShortcutAction, NativeStreamerShortcutBindings}; - -const MODIFIER_SHIFT: u16 = 0x01; -const MODIFIER_CTRL: u16 = 0x02; -const MODIFIER_ALT: u16 = 0x04; -const MODIFIER_META: u16 = 0x08; -const SHORTCUT_MODIFIER_MASK: u16 = MODIFIER_SHIFT | MODIFIER_CTRL | MODIFIER_ALT | MODIFIER_META; - -const VK_BACK: u16 = 0x08; -const VK_TAB: u16 = 0x09; -const VK_RETURN: u16 = 0x0D; -const VK_PAUSE: u16 = 0x13; -const VK_CAPITAL: u16 = 0x14; -const VK_ESCAPE: u16 = 0x1B; -const VK_SPACE: u16 = 0x20; -const VK_PRIOR: u16 = 0x21; -const VK_NEXT: u16 = 0x22; -const VK_END: u16 = 0x23; -const VK_HOME: u16 = 0x24; -const VK_LEFT: u16 = 0x25; -const VK_UP: u16 = 0x26; -const VK_RIGHT: u16 = 0x27; -const VK_DOWN: u16 = 0x28; -const VK_INSERT: u16 = 0x2D; -const VK_DELETE: u16 = 0x2E; -const VK_PRINT: u16 = 0x2C; -const VK_LWIN: u16 = 0x5B; -const VK_RWIN: u16 = 0x5C; -const VK_APPS: u16 = 0x5D; -const VK_NUMPAD0: u16 = 0x60; -const VK_MULTIPLY: u16 = 0x6A; -const VK_ADD: u16 = 0x6B; -const VK_SEPARATOR: u16 = 0x6C; -const VK_SUBTRACT: u16 = 0x6D; -const VK_DECIMAL: u16 = 0x6E; -const VK_DIVIDE: u16 = 0x6F; -const VK_F1: u16 = 0x70; -const VK_NUMLOCK: u16 = 0x90; -const VK_SCROLL: u16 = 0x91; -const VK_OEM_1: u16 = 0xBA; -const VK_OEM_PLUS: u16 = 0xBB; -const VK_OEM_COMMA: u16 = 0xBC; -const VK_OEM_MINUS: u16 = 0xBD; -const VK_OEM_PERIOD: u16 = 0xBE; -const VK_OEM_2: u16 = 0xBF; -const VK_OEM_3: u16 = 0xC0; -const VK_OEM_4: u16 = 0xDB; -const VK_OEM_5: u16 = 0xDC; -const VK_OEM_6: u16 = 0xDD; -const VK_OEM_7: u16 = 0xDE; -const SCANCODE_ENTER: u16 = 0x001C; -const SCANCODE_NUMPAD_ENTER: u16 = 0xE01C; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct ShortcutBinding { - action: NativeStreamerShortcutAction, - keycode: u16, - scancode: Option, - modifiers: u16, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct ParsedKey { - keycode: u16, - scancode: Option, -} - -#[derive(Debug, Clone, Default)] -pub(crate) struct NativeShortcutMatcher { - bindings: Vec, -} - -impl NativeShortcutMatcher { - pub(crate) fn from_bindings(bindings: &NativeStreamerShortcutBindings) -> Self { - let mut parsed = Vec::new(); - append_binding( - &mut parsed, - NativeStreamerShortcutAction::ToggleStats, - &bindings.toggle_stats, - ); - append_binding( - &mut parsed, - NativeStreamerShortcutAction::TogglePointerLock, - &bindings.toggle_pointer_lock, - ); - append_binding( - &mut parsed, - NativeStreamerShortcutAction::ToggleFullscreen, - &bindings.toggle_fullscreen, - ); - append_binding( - &mut parsed, - NativeStreamerShortcutAction::StopStream, - &bindings.stop_stream, - ); - append_binding( - &mut parsed, - NativeStreamerShortcutAction::ToggleAntiAfk, - &bindings.toggle_anti_afk, - ); - append_binding( - &mut parsed, - NativeStreamerShortcutAction::ToggleMicrophone, - &bindings.toggle_microphone, - ); - append_binding( - &mut parsed, - NativeStreamerShortcutAction::Screenshot, - &bindings.screenshot, - ); - append_binding( - &mut parsed, - NativeStreamerShortcutAction::ToggleRecording, - &bindings.toggle_recording, - ); - Self { bindings: parsed } - } - - pub(crate) fn match_keydown( - &self, - keycode: u16, - scancode: u16, - modifiers: u16, - ) -> Option { - let modifiers = modifiers & SHORTCUT_MODIFIER_MASK; - self.bindings - .iter() - .find(|binding| { - binding.keycode == keycode - && binding.modifiers == modifiers - && binding.scancode.map_or(true, |expected| expected == scancode) - }) - .map(|binding| binding.action) - } -} - -fn append_binding( - bindings: &mut Vec, - action: NativeStreamerShortcutAction, - raw: &str, -) { - if let Some(binding) = parse_binding(action, raw) { - bindings.push(binding); - } -} - -fn parse_binding(action: NativeStreamerShortcutAction, raw: &str) -> Option { - let mut modifiers = 0u16; - let mut key = None; - - for token in raw.split('+').map(str::trim).filter(|token| !token.is_empty()) { - match token.to_ascii_uppercase().as_str() { - "CTRL" | "CONTROL" => modifiers |= MODIFIER_CTRL, - "ALT" | "OPTION" => modifiers |= MODIFIER_ALT, - "SHIFT" => modifiers |= MODIFIER_SHIFT, - "META" | "CMD" | "COMMAND" => modifiers |= MODIFIER_META, - _ => { - if key.is_some() { - return None; - } - key = parse_key_token(token); - } - } - } - - let key = key?; - Some(ShortcutBinding { - action, - keycode: key.keycode, - scancode: key.scancode, - modifiers, - }) -} - -fn parsed_key(keycode: u16) -> Option { - Some(ParsedKey { - keycode, - scancode: None, - }) -} - -fn parsed_scancode_key(keycode: u16, scancode: u16) -> Option { - Some(ParsedKey { - keycode, - scancode: Some(scancode), - }) -} - -fn parse_key_token(token: &str) -> Option { - let upper = token.trim().to_ascii_uppercase(); - if upper.len() == 1 { - let byte = upper.as_bytes()[0]; - return match byte { - b'A'..=b'Z' | b'0'..=b'9' => parsed_key(u16::from(byte)), - b',' => parsed_key(VK_OEM_COMMA), - b'.' => parsed_key(VK_OEM_PERIOD), - b'/' => parsed_key(VK_OEM_2), - b';' => parsed_key(VK_OEM_1), - b'\'' => parsed_key(VK_OEM_7), - b'[' => parsed_key(VK_OEM_4), - b']' => parsed_key(VK_OEM_6), - b'\\' => parsed_key(VK_OEM_5), - b'-' => parsed_key(VK_OEM_MINUS), - b'=' => parsed_key(VK_OEM_PLUS), - b'`' => parsed_key(VK_OEM_3), - _ => None, - }; - } - - if let Some(function_index) = upper - .strip_prefix('F') - .and_then(|value| value.parse::().ok()) - { - if (1..=24).contains(&function_index) { - return parsed_key(VK_F1 + function_index - 1); - } - } - - if let Some(numpad_index) = upper - .strip_prefix("NUMPAD") - .and_then(|value| value.parse::().ok()) - { - if numpad_index <= 9 { - return parsed_key(VK_NUMPAD0 + numpad_index); - } - } - - match upper.as_str() { - "BACKSPACE" => parsed_key(VK_BACK), - "TAB" => parsed_key(VK_TAB), - "ENTER" => parsed_scancode_key(VK_RETURN, SCANCODE_ENTER), - "NUMPADENTER" => parsed_scancode_key(VK_RETURN, SCANCODE_NUMPAD_ENTER), - "PAUSE" => parsed_key(VK_PAUSE), - "CAPSLOCK" => parsed_key(VK_CAPITAL), - "ESCAPE" => parsed_key(VK_ESCAPE), - "SPACE" => parsed_key(VK_SPACE), - "PAGEUP" => parsed_key(VK_PRIOR), - "PAGEDOWN" => parsed_key(VK_NEXT), - "END" => parsed_key(VK_END), - "HOME" => parsed_key(VK_HOME), - "ARROWLEFT" => parsed_key(VK_LEFT), - "ARROWUP" => parsed_key(VK_UP), - "ARROWRIGHT" => parsed_key(VK_RIGHT), - "ARROWDOWN" => parsed_key(VK_DOWN), - "INSERT" => parsed_key(VK_INSERT), - "DELETE" => parsed_key(VK_DELETE), - "PRINTSCREEN" => parsed_key(VK_PRINT), - "APPS" | "MENU" => parsed_key(VK_APPS), - "METALEFT" => parsed_key(VK_LWIN), - "METARIGHT" => parsed_key(VK_RWIN), - "NUMPADMULTIPLY" => parsed_key(VK_MULTIPLY), - "NUMPADADD" => parsed_key(VK_ADD), - "NUMPADSEPARATOR" => parsed_key(VK_SEPARATOR), - "NUMPADSUBTRACT" => parsed_key(VK_SUBTRACT), - "NUMPADDECIMAL" => parsed_key(VK_DECIMAL), - "NUMPADDIVIDE" => parsed_key(VK_DIVIDE), - "NUMLOCK" => parsed_key(VK_NUMLOCK), - "SCROLLLOCK" => parsed_key(VK_SCROLL), - "SEMICOLON" => parsed_key(VK_OEM_1), - "EQUAL" => parsed_key(VK_OEM_PLUS), - "COMMA" => parsed_key(VK_OEM_COMMA), - "MINUS" => parsed_key(VK_OEM_MINUS), - "PERIOD" => parsed_key(VK_OEM_PERIOD), - "SLASH" => parsed_key(VK_OEM_2), - "BACKQUOTE" => parsed_key(VK_OEM_3), - "BRACKETLEFT" => parsed_key(VK_OEM_4), - "BACKSLASH" => parsed_key(VK_OEM_5), - "BRACKETRIGHT" => parsed_key(VK_OEM_6), - "QUOTE" => parsed_key(VK_OEM_7), - _ => None, - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn bindings() -> NativeStreamerShortcutBindings { - NativeStreamerShortcutBindings { - toggle_stats: "F3".to_owned(), - toggle_pointer_lock: "F8".to_owned(), - toggle_fullscreen: "F10".to_owned(), - stop_stream: "Ctrl+Shift+Q".to_owned(), - toggle_anti_afk: "Ctrl+Shift+K".to_owned(), - toggle_microphone: "Ctrl+Shift+M".to_owned(), - screenshot: "F11".to_owned(), - toggle_recording: "F12".to_owned(), - } - } - - #[test] - fn matches_function_key_shortcuts_without_modifiers() { - let matcher = NativeShortcutMatcher::from_bindings(&bindings()); - - assert_eq!( - matcher.match_keydown(VK_F1 + 2, 0, 0), - Some(NativeStreamerShortcutAction::ToggleStats) - ); - assert_eq!( - matcher.match_keydown(VK_F1 + 10, 0, 0), - Some(NativeStreamerShortcutAction::Screenshot) - ); - } - - #[test] - fn matches_exact_modifier_combinations() { - let matcher = NativeShortcutMatcher::from_bindings(&bindings()); - - assert_eq!( - matcher.match_keydown(u16::from(b'Q'), 0, MODIFIER_CTRL | MODIFIER_SHIFT), - Some(NativeStreamerShortcutAction::StopStream) - ); - assert_eq!(matcher.match_keydown(u16::from(b'Q'), 0, MODIFIER_CTRL), None); - assert_eq!( - matcher.match_keydown( - u16::from(b'Q'), - 0, - MODIFIER_CTRL | MODIFIER_SHIFT | MODIFIER_ALT - ), - None - ); - } - - #[test] - fn ignores_invalid_bindings() { - let matcher = NativeShortcutMatcher::from_bindings(&NativeStreamerShortcutBindings { - toggle_stats: "Ctrl+Shift".to_owned(), - ..bindings() - }); - - assert_eq!(matcher.match_keydown(VK_F1 + 2, 0, 0), None); - assert_eq!( - matcher.match_keydown(VK_F1 + 7, 0, 0), - Some(NativeStreamerShortcutAction::TogglePointerLock) - ); - } - - #[test] - fn keeps_regular_enter_and_numpad_enter_distinct() { - let matcher = NativeShortcutMatcher::from_bindings(&NativeStreamerShortcutBindings { - toggle_stats: "Enter".to_owned(), - toggle_pointer_lock: "NumpadEnter".to_owned(), - ..bindings() - }); - - assert_eq!( - matcher.match_keydown(VK_RETURN, SCANCODE_ENTER, 0), - Some(NativeStreamerShortcutAction::ToggleStats) - ); - assert_eq!( - matcher.match_keydown(VK_RETURN, SCANCODE_NUMPAD_ENTER, 0), - Some(NativeStreamerShortcutAction::TogglePointerLock) - ); - } -} diff --git a/native/opennow-streamer/src/windows_dpi.rs b/native/opennow-streamer/src/windows_dpi.rs deleted file mode 100644 index fdf2fcf16..000000000 --- a/native/opennow-streamer/src/windows_dpi.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Windows DPI policy for native renderer windows. -//! -//! Electron publishes native render-surface bounds in physical pixels. The -//! streamer must use the same coordinate space or Windows DPI virtualization -//! can offset or shrink the video window on scaled and mixed-DPI displays. - -use std::ffi::c_void; - -type DpiAwarenessContext = *mut c_void; - -// DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 from winuser.h. -const PER_MONITOR_AWARE_V2: DpiAwarenessContext = -4_isize as DpiAwarenessContext; - -#[link(name = "user32")] -extern "system" { - fn SetProcessDpiAwarenessContext(value: DpiAwarenessContext) -> i32; - fn SetProcessDPIAware() -> i32; -} - -/// Opt the streamer into physical-pixel coordinates before GStreamer or any -/// renderer thread can create a window. The legacy fallback keeps coordinates -/// unvirtualized on Windows versions that reject the per-monitor-v2 context. -pub(crate) fn enable_per_monitor_awareness() { - unsafe { - if SetProcessDpiAwarenessContext(PER_MONITOR_AWARE_V2) == 0 { - let _ = SetProcessDPIAware(); - } - } -} diff --git a/native/opennow-streamer/vendor/audiopus-sys/.github/workflows/ci.yml b/native/opennow-streamer/vendor/audiopus-sys/.github/workflows/ci.yml new file mode 100644 index 000000000..76d11ae6e --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/.github/workflows/ci.yml @@ -0,0 +1,72 @@ +name: CI + +on: [push, pull_request] + +jobs: + test: + runs-on: ${{ matrix.os || 'ubuntu-latest' }} + + strategy: + fail-fast: false + matrix: + name: + - stable + - beta + - nightly + - macOS + - Windows + + include: + - name: beta + toolchain: beta + - name: nightly + toolchain: nightly + - name: macOS + os: macOS-latest + - name: Windows + os: windows-latest + + steps: + - name: Checkout sources + uses: actions/checkout@v2 + with: + submodules: 'recursive' + + - name: Install toolchain + id: tc + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.toolchain || 'stable' }} + profile: minimal + override: true + + - name: Install dependencies + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y libopus-dev + + - name: Setup cache + if: runner.os != 'macOS' + uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ matrix.os }}-test-${{ steps.tc.outputs.rustc_hash }}-${{ hashFiles('**/Cargo.toml') }} + + - name: Build static + run: cargo build --features "static" + + - name: Build dynamic + run: cargo build --features "dynamic" + + # TODO: Fix for CI environment. + #- name: Generate bindings + # run: cargo build --features "generate_binding" + + - name: Test all features + # TODO: Once "generate_binding" is fixed, replace with `--all-features` + # again. + run: cargo test --features "static dynamic" diff --git a/native/opennow-streamer/vendor/audiopus-sys/.gitignore b/native/opennow-streamer/vendor/audiopus-sys/.gitignore new file mode 100644 index 000000000..693699042 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/.gitignore @@ -0,0 +1,3 @@ +/target +**/*.rs.bk +Cargo.lock diff --git a/native/opennow-streamer/vendor/audiopus-sys/.gitmodules b/native/opennow-streamer/vendor/audiopus-sys/.gitmodules new file mode 100644 index 000000000..ba5e9dacc --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/.gitmodules @@ -0,0 +1,3 @@ +[submodule "opus"] + path = opus + url = https://github.com/xiph/opus/ diff --git a/native/opennow-streamer/vendor/audiopus-sys/CHANGELOG.md b/native/opennow-streamer/vendor/audiopus-sys/CHANGELOG.md new file mode 100644 index 000000000..b32c749ab --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/CHANGELOG.md @@ -0,0 +1,60 @@ +# Change Log + +An overview of changes: + +## [0.2.0] + +* Now requires `cmake`. +* Windows will build via `cmake` too. +* Windows pre-built binaries have been removed. +* Updated `bindgen` to version `0.58`. + +## [0.1.8] + +This release adds build support for FreeBSD. + +## [0.1.7] + +Add missing `opus`-folder. + +## [0.1.6] + +This release removes the `bindgen`-dependency from the default features. +Additionally, the `bindgen`-feature has been added in order to generate a new binding. + +## [0.1.4 and 0.1.5] + +v0.1.4: +This release fixes a problem where `audiopus_sys` could not find the +Opus folder. + +v0.1.5: +Convert Unix-relevant files' EOLs from CRLF to LF inside the opus-folder. + +### **Fix** +* Bundle the Opus project again. +* Added missing `cfg` on `find_via_pkg_config`. + +## [0.1.3] + +Fixes build-issues related to `pkg-config`. + +## [0.1.2] + +This release adds the ability to bypass `pkg-config`. + +### **Added:** + +* Ignore `pkg-config` when `LIBOPUS_NO_PKG` or `OPUS_NO_PKG` is set. +* Print the dynamic/static build cause via `cargo:info`. +* Add missing repository-link in `Cargo.toml`. + +## [0.1.1] + +### **Added:** + +* Copy Opus' source to `OUT_DIR` before building to avoid modifying and generating files outside of `OUT_DIR`. + +### **Fixed:** +* Convert Unix-relevant files' EOLs from `CRLF` to `LF` inside the `opus`-folder. +* Resolve unused import warnings when building with Unix. diff --git a/native/opennow-streamer/vendor/audiopus-sys/CONTRIBUTING.md b/native/opennow-streamer/vendor/audiopus-sys/CONTRIBUTING.md new file mode 100644 index 000000000..e61f23f9d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/CONTRIBUTING.md @@ -0,0 +1,62 @@ +# Contributing + +Everyone is welcome to get involved, may it be a pull request, suggestion, bug +report, or a textual improvement! : ) + +The language applied in this repository is British English. + +## Contributions + +Contributions to `audiopus_sys` should be first discussed up via an issue and then +implemented via pull request. +Issues display development-plans or required brainstorming, feel free to ask, +suggest, and discuss! +The `master`-branch contains the latest release. + +## Comments & Documentation Style + +- Comments are placed the lines before the related code line, not on the same +line. + +- Write full sentences in British English. + +- `unsafe` must always be reasoned and their soundness must be proven via a +comment. + +- Use Rust intra-doc-links paths to refer Rust items in documentation: +`[name](crate::module::struct::method)`. + +- If code ends up difficult, try to simplify it, if unavoidable, explain code +with comments. Prefer explicit variable naming instead of abbreviations. + +## Commit Style + +Write full sentences in British English. + +Commits should describe the action being peformed. + +Example: +- *Fix deadlock for events.* +- *Correct grammar in `command`-example.* + +## Pull Request Checklist + +- Make sure to open an issue prior working on a problem or ask on existing +issue be assigned. + +- If a pull requests breaks the current API, use the `breaking-changes`-branch, +otherwise `stable-changes`. + +- Commits shall be as small as possible, compile, and pass all tests. + +- Make sure your code is formatted with `rustfmt` and free of lints, +run `cargo fmt` and `cargo clippy`. + +- If you fixed a bug, add a test for that bug. Unit tests belong inside the +same file's `mod` named `tests`, integrational tests belong inside the +`tests`-folder. + +- Last but not least, make sure your planned pull request merges cleanly, +if it does not, rebase your changes. + +If you have any questions left, please reach out via the issue system : ) diff --git a/native/opennow-streamer/vendor/audiopus-sys/Cargo.toml b/native/opennow-streamer/vendor/audiopus-sys/Cargo.toml new file mode 100644 index 000000000..2eb3d64d9 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/Cargo.toml @@ -0,0 +1,44 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "audiopus_sys" +version = "0.2.2" +authors = ["Lakelezz "] +description = "FFI-Binding to Opus, dynamically or statically linked for Windows and UNIX." +documentation = "https://docs.rs/audiopus_sys" +readme = "README.md" +keywords = ["audio", "opus", "codec"] +categories = ["api-bindings", "compression", "encoding", "multimedia::audio", "multimedia::encoding"] +license = "ISC" +repository = "https://github.com/lakelezz/audiopus_sys.git" + +[dependencies] +[build-dependencies.bindgen] +version = "0.58" +optional = true + +[build-dependencies.cmake] +version = "0.1" + +[build-dependencies.log] +version = "0.4" + +[build-dependencies.pkg-config] +version = "0.3" + +[features] +default = [] +dynamic = [] +generate_binding = ["bindgen"] +static = [] diff --git a/native/opennow-streamer/vendor/audiopus-sys/Cargo.toml.orig b/native/opennow-streamer/vendor/audiopus-sys/Cargo.toml.orig new file mode 100644 index 000000000..227d110eb --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/Cargo.toml.orig @@ -0,0 +1,30 @@ +[package] +name = "audiopus_sys" +version = "0.2.2" +license = "ISC" +repository = "https://github.com/lakelezz/audiopus_sys.git" +authors = ["Lakelezz "] +keywords = ["audio", "opus", "codec"] +categories = ["api-bindings", "compression", "encoding", + "multimedia::audio", "multimedia::encoding"] +description = "FFI-Binding to Opus, dynamically or statically linked for Windows and UNIX." +readme = "README.md" +documentation = "https://docs.rs/audiopus_sys" +edition = "2018" + +[dependencies] + +[build-dependencies] +log = "0.4" +pkg-config = "0.3" +cmake = "0.1" + +[build-dependencies.bindgen] +version = "0.58" +optional = true + +[features] +default = [] +dynamic = [] +static = [] +generate_binding = ["bindgen"] diff --git a/native/opennow-streamer/vendor/audiopus-sys/LICENSE.md b/native/opennow-streamer/vendor/audiopus-sys/LICENSE.md new file mode 100644 index 000000000..a861f02de --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/LICENSE.md @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2019, Lakelezz + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/native/opennow-streamer/vendor/audiopus-sys/README.md b/native/opennow-streamer/vendor/audiopus-sys/README.md new file mode 100644 index 000000000..c60b256e8 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/README.md @@ -0,0 +1,81 @@ +[![ci-badge][]][ci] [![docs-badge][]][docs] [![rust version badge]][rust version link] [![crates.io version]][crates.io link] + +# About + +`audiopus_sys` is an FFI-Rust-binding to [`Opus`] version 1.3. + +Orginally, this sys-crate was made to empower the [`serenity`]-crate to build audio features on Windows, Linux, and Mac. However, it's not limited to that. + +Everyone is welcome to contribute, +check out the [`CONTRIBUTING.md`](CONTRIBUTING.md) for further guidance. + +# Building + +## Requirements +If you want to build Opus, you will need `cmake`. + +If you have `pkg-config`, it will attempt to use that before building. + +You can also link a pre-installed Opus, see [**Pre-installed Opus**](#Pre-installed-Opus) +below. + +This crate provides a pre-built binding. In case you want to generate the +binding yourself, you will need [`Clang`](https://rust-lang.github.io/rust-bindgen/requirements.html#clang), +see [**Pre-installed Opus**](#Generating-The-Binding) below for further +instructions. + +## Linking +`audiopus_sys` links to Opus 1.3 and supports Windows, Linux, and MacOS +By default, we statically link to Windows, MacOS, and if you use the +`musl`-environment. We will link dynamically for Linux except when using +mentioned `musl`. + +This can be altered by compiling with the `static` or `dynamic` feature having +effects respective to their names. If both features are enabled, +we will pick your system's default. + +Environment variables named `LIBOPUS_STATIC` or `OPUS_STATIC` will take +precedence over features thus overriding the behaviour. The value of these +environment variables have no influence of the result: If one of them is set, +statically linking will be picked. + +## Pkg-Config +By default, `audiopus_sys` will use `pkg-config` on Unix or GNU. +Setting the environment variable `LIBOPUS_NO_PKG` or `OPUS_NO_PKG` will bypass +probing for Opus via `pkg-config`. + +## Pre-installed Opus +If you have Opus pre-installed, you can set `LIBOPUS_LIB_DIR` or +`OPUS_LIB_DIR` to the directory containing Opus. + +Be aware that using an Opus other than version 1.3 may not work. + +# Generating The Binding +If you want to generate the binding yourself, you can use the +`generate_binding`-feature. + +Be aware, `bindgen` requires Clang and its `LIBCLANG_PATH` +environment variable to be specified. + +# Installation +Add this to your `Cargo.toml`: + +```toml +[dependencies] +audiopus_sys = "0.2" +``` +[`serenity`]: https://crates.io/crates/serenity + +[`Opus`]: https://www.opus-codec.org/ + +[ci-badge]: https://img.shields.io/github/workflow/status/Lakelezz/audiopus_sys/CI?style=flat-square +[ci]: https://github.com/Lakelezz/audiopus_sys/actions + +[docs-badge]: https://img.shields.io/badge/docs-online-5023dd.svg?style=flat-square&colorB=32b6b7 +[docs]: https://docs.rs/audiopus_sys + +[rust version badge]: https://img.shields.io/badge/rust-1.51+-93450a.svg?style=flat-square&colorB=ff9a0d +[rust version link]: https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html + +[crates.io link]: https://crates.io/crates/audiopus_sys +[crates.io version]: https://img.shields.io/crates/v/audiopus_sys.svg?style=flat-square&colorB=b73732 diff --git a/native/opennow-streamer/vendor/audiopus-sys/build.rs b/native/opennow-streamer/vendor/audiopus-sys/build.rs new file mode 100644 index 000000000..d963f1e1c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/build.rs @@ -0,0 +1,157 @@ +#![deny(rust_2018_idioms)] + +#[cfg(feature = "generate_binding")] +use std::path::PathBuf; +use std::{env, fmt::Display, path::Path}; + +/// Outputs the library-file's prefix as word usable for actual arguments on +/// commands or paths. +const fn rustc_linking_word(is_static_link: bool) -> &'static str { + if is_static_link { + "static" + } else { + "dylib" + } +} + +/// Generates a new binding at `src/lib.rs` using `src/wrapper.h`. +#[cfg(feature = "generate_binding")] +fn generate_binding() { + const ALLOW_UNCONVENTIONALS: &'static str = "#![allow(non_upper_case_globals)]\n\ + #![allow(non_camel_case_types)]\n\ + #![allow(non_snake_case)]\n"; + + let bindings = bindgen::Builder::default() + .header("src/wrapper.h") + .raw_line(ALLOW_UNCONVENTIONALS) + .generate() + .expect("Unable to generate binding"); + + let binding_target_path = PathBuf::new().join("src").join("lib.rs"); + + bindings + .write_to_file(binding_target_path) + .expect("Could not write binding to the file at `src/lib.rs`"); + + println!("cargo:info=Successfully generated binding."); +} + +fn build_opus(is_static: bool) { + let opus_path = Path::new("opus"); + + println!( + "cargo:info=Opus source path used: {:?}.", + opus_path + .canonicalize() + .expect("Could not canonicalise to absolute path") + ); + + println!("cargo:info=Building Opus via CMake."); + let opus_build_dir = cmake::build(opus_path); + link_opus(is_static, opus_build_dir.display()) +} + +fn link_opus(is_static: bool, opus_build_dir: impl Display) { + let is_static_text = rustc_linking_word(is_static); + + println!( + "cargo:info=Linking Opus as {} lib: {}", + is_static_text, opus_build_dir + ); + println!("cargo:rustc-link-lib={}=opus", is_static_text); + println!("cargo:rustc-link-search=native={}/lib", opus_build_dir); +} + +#[cfg(any(unix, target_env = "gnu"))] +fn find_via_pkg_config(is_static: bool) -> bool { + pkg_config::Config::new() + .statik(is_static) + .probe("opus") + .is_ok() +} + +/// Based on the OS or target environment we are building for, +/// this function will return an expected default library linking method. +/// +/// If we build for Windows, MacOS, or Linux with musl, we will link statically. +/// However, if you build for Linux without musl, we will link dynamically. +/// +/// **Info**: +/// This is a helper-function and may not be called if +/// if the `static`-feature is enabled, the environment variable +/// `LIBOPUS_STATIC` or `OPUS_STATIC` is set. +fn default_library_linking() -> bool { + #[cfg(any(windows, target_os = "macos", target_env = "musl"))] + { + true + } + #[cfg(any(target_os = "freebsd", all(unix, target_env = "gnu")))] + { + false + } +} + +fn find_installed_opus() -> Option { + if let Ok(lib_directory) = env::var("LIBOPUS_LIB_DIR") { + Some(lib_directory) + } else if let Ok(lib_directory) = env::var("OPUS_LIB_DIR") { + Some(lib_directory) + } else { + None + } +} + +fn is_static_build() -> bool { + if cfg!(feature = "static") && cfg!(feature = "dynamic") { + default_library_linking() + } else if cfg!(feature = "static") + || env::var("LIBOPUS_STATIC").is_ok() + || env::var("OPUS_STATIC").is_ok() + { + println!("cargo:info=Static feature or environment variable found."); + + true + } else if cfg!(feature = "dynamic") { + println!("cargo:info=Dynamic feature enabled."); + + false + } else { + println!("cargo:info=No feature or environment variable found, linking by default."); + + default_library_linking() + } +} + +fn main() { + #[cfg(feature = "generate_binding")] + generate_binding(); + + let is_static = is_static_build(); + + // The streamer is distributed as a self-contained executable. When the + // static feature is selected, always compile the vendored Opus sources so + // pkg-config cannot silently introduce a runtime dependency on libopus. + if is_static { + build_opus(true); + return; + } + + #[cfg(any(unix, target_env = "gnu"))] + { + if std::env::var("LIBOPUS_NO_PKG").is_ok() || std::env::var("OPUS_NO_PKG").is_ok() { + println!("cargo:info=Bypassed `pkg-config`."); + } else if find_via_pkg_config(is_static) { + println!("cargo:info=Found `Opus` via `pkg_config`."); + + return; + } else { + println!("cargo:info=`pkg_config` could not find `Opus`."); + } + } + + if let Some(installed_opus) = find_installed_opus() { + link_opus(is_static, installed_opus); + } else { + build_opus(is_static); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/.appveyor.yml b/native/opennow-streamer/vendor/audiopus-sys/opus/.appveyor.yml new file mode 100644 index 000000000..a0f4a776e --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/.appveyor.yml @@ -0,0 +1,37 @@ +image: Visual Studio 2015 +configuration: +- Debug +- DebugDLL +- DebugDLL_fixed +- Release +- ReleaseDLL +- ReleaseDLL_fixed + +platform: +- Win32 +- x64 + +environment: + api_key: + secure: kR3Ac0NjGwFnTmXdFrR8d6VXjdk5F7L4F/BilC4nvaM= + +build: + project: win32\VS2015\opus.sln + parallel: true + verbosity: minimal + +after_build: +- cd %APPVEYOR_BUILD_FOLDER% +- 7z a opus.zip win32\VS2015\%PLATFORM%\%CONFIGURATION%\opus.??? include\*.h + +test_script: +- cd %APPVEYOR_BUILD_FOLDER%\win32\VS2015\%PLATFORM%\%CONFIGURATION% +- test_opus_api.exe +- test_opus_decode.exe +- test_opus_encode.exe + +artifacts: +- path: opus.zip + +on_success: +- ps: if ($env:api_key -and "$env:configuration/$env:platform" -eq "ReleaseDLL_fixed/x64") { Start-AppveyorBuild -ApiKey $env:api_key -ProjectSlug 'opus-tools' } diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/.gitattributes b/native/opennow-streamer/vendor/audiopus-sys/opus/.gitattributes new file mode 100644 index 000000000..649c81005 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/.gitattributes @@ -0,0 +1,10 @@ +.gitignore export-ignore +.gitattributes export-ignore + +update_version export-ignore + +*.bat eol=crlf +*.sln eol=crlf +*.vcxproj eol=crlf +*.vcxproj.filters eol=crlf +common.props eol=crlf diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/.gitignore b/native/opennow-streamer/vendor/audiopus-sys/opus/.gitignore new file mode 100644 index 000000000..837619f9c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/.gitignore @@ -0,0 +1,90 @@ +Doxyfile +Makefile +Makefile.in +TAGS +aclocal.m4 +autom4te.cache +*.kdevelop.pcs +*.kdevses +compile +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +depcomp +INSTALL +install-sh +.deps +.libs +.dirstamp +*.a +*.exe +*.la +*-gnu.S +testcelt +libtool +ltmain.sh +missing +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +opus_compare +opus_demo +repacketizer_demo +stamp-h1 +test-driver +trivial_example +*.sw* +*.o +*.lo +*.pc +*.tar.gz +*~ +tests/*test +tests/test_opus_api +tests/test_opus_decode +tests/test_opus_encode +tests/test_opus_padding +tests/test_opus_projection +celt/arm/armopts.s +celt/dump_modes/dump_modes +celt/tests/test_unit_cwrs32 +celt/tests/test_unit_dft +celt/tests/test_unit_entropy +celt/tests/test_unit_laplace +celt/tests/test_unit_mathops +celt/tests/test_unit_mdct +celt/tests/test_unit_rotation +celt/tests/test_unit_types +doc/doxygen_sqlite3.db +doc/doxygen-build.stamp +doc/html +doc/latex +doc/man +package_version +version.h +celt/Debug +celt/Release +celt/x64 +silk/Debug +silk/Release +silk/x64 +silk/fixed/Debug +silk/fixed/Release +silk/fixed/x64 +silk/float/Debug +silk/float/Release +silk/float/x64 +silk/tests/test_unit_LPC_inv_pred_gain +src/Debug +src/Release +src/x64 +/*[Bb]uild*/ +.vs/ +.vscode/ +CMakeSettings.json diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/.gitlab-ci.yml b/native/opennow-streamer/vendor/audiopus-sys/opus/.gitlab-ci.yml new file mode 100644 index 000000000..01b033fda --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/.gitlab-ci.yml @@ -0,0 +1,61 @@ +include: + - template: 'Workflows/Branch-Pipelines.gitlab-ci.yml' + +default: + tags: + - docker + # Image from https://hub.docker.com/_/gcc/ based on Debian + image: gcc:9 + +whitespace: + stage: test + script: + - git diff-tree --check origin/master HEAD + +autoconf: + stage: build + before_script: + - apt-get update && + apt-get install -y zip doxygen + script: + - ./autogen.sh + - ./configure + - make -j4 + - make distcheck + cache: + paths: + - "src/*.o" + - "src/.libs/*.o" + - "silk/*.o" + - "silk/.libs/*.o" + - "celt/*.o" + - "celt/.libs/*.o" + +cmake: + stage: build + before_script: + - apt-get update && + apt-get install -y cmake ninja-build + script: + - mkdir build + - cmake -S . -B build -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DOPUS_BUILD_TESTING=ON -DOPUS_BUILD_PROGRAMS=ON + - cmake --build build + - cd build && ctest --output-on-failure + +meson: + stage: build + before_script: + - apt-get update && + apt-get install -y python3-pip ninja-build doxygen + - export XDG_CACHE_HOME=$PWD/pip-cache + - pip3 install --user meson + script: + - export PATH=$PATH:$HOME/.local/bin + - mkdir builddir + - meson setup --werror -Dtests=enabled -Ddocs=enabled -Dbuildtype=release builddir + - meson compile -C builddir + - meson test -C builddir + #- meson dist --no-tests -C builddir + cache: + paths: + - 'pip-cache/*' diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/.travis.yml b/native/opennow-streamer/vendor/audiopus-sys/opus/.travis.yml new file mode 100644 index 000000000..821c813ec --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/.travis.yml @@ -0,0 +1,21 @@ +language: c + +compiler: + - gcc + - clang + +os: + - linux + - osx + +env: + - CONFIG="" + - CONFIG="--enable-assertions" + - CONFIG="--enable-fixed-point" + - CONFIG="--enable-fixed-point --disable-float-api" + - CONFIG="--enable-fixed-point --enable-assertions" + +script: + - ./autogen.sh + - ./configure $CONFIG + - make distcheck diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/AUTHORS b/native/opennow-streamer/vendor/audiopus-sys/opus/AUTHORS new file mode 100644 index 000000000..b3d22a20c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/AUTHORS @@ -0,0 +1,6 @@ +Jean-Marc Valin (jmvalin@jmvalin.ca) +Koen Vos (koenvos74@gmail.com) +Timothy Terriberry (tterribe@xiph.org) +Karsten Vandborg Sorensen (karsten.vandborg.sorensen@skype.net) +Soren Skak Jensen (ssjensen@gn.com) +Gregory Maxwell (greg@xiph.org) diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/CMakeLists.txt b/native/opennow-streamer/vendor/audiopus-sys/opus/CMakeLists.txt new file mode 100644 index 000000000..94a5880a3 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/CMakeLists.txt @@ -0,0 +1,618 @@ +cmake_minimum_required(VERSION 3.5...4.0) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +include(OpusPackageVersion) +get_package_version(PACKAGE_VERSION PROJECT_VERSION) + +project(Opus LANGUAGES C VERSION ${PROJECT_VERSION}) + +include(OpusFunctions) +include(OpusBuildtype) +include(OpusConfig) +include(OpusSources) +include(GNUInstallDirs) +include(CMakeDependentOption) +include(FeatureSummary) + +set(OPUS_BUILD_SHARED_LIBRARY_HELP_STR "build shared library.") +option(OPUS_BUILD_SHARED_LIBRARY ${OPUS_BUILD_SHARED_LIBRARY_HELP_STR} OFF) +if(OPUS_BUILD_SHARED_LIBRARY OR BUILD_SHARED_LIBS OR OPUS_BUILD_FRAMEWORK) + # Global flag to cause add_library() to create shared libraries if on. + set(BUILD_SHARED_LIBS ON) + set(OPUS_BUILD_SHARED_LIBRARY ON) +endif() +add_feature_info(OPUS_BUILD_SHARED_LIBRARY OPUS_BUILD_SHARED_LIBRARY ${OPUS_BUILD_SHARED_LIBRARY_HELP_STR}) + +set(OPUS_BUILD_TESTING_HELP_STR "build tests.") +option(OPUS_BUILD_TESTING ${OPUS_BUILD_TESTING_HELP_STR} OFF) +if(OPUS_BUILD_TESTING OR BUILD_TESTING) + set(OPUS_BUILD_TESTING ON) + set(BUILD_TESTING ON) +endif() +add_feature_info(OPUS_BUILD_TESTING OPUS_BUILD_TESTING ${OPUS_BUILD_TESTING_HELP_STR}) + +set(OPUS_CUSTOM_MODES_HELP_STR "enable non-Opus modes, e.g. 44.1 kHz & 2^n frames.") +option(OPUS_CUSTOM_MODES ${OPUS_CUSTOM_MODES_HELP_STR} OFF) +add_feature_info(OPUS_CUSTOM_MODES OPUS_CUSTOM_MODES ${OPUS_CUSTOM_MODES_HELP_STR}) + +set(OPUS_BUILD_PROGRAMS_HELP_STR "build programs.") +option(OPUS_BUILD_PROGRAMS ${OPUS_BUILD_PROGRAMS_HELP_STR} OFF) +add_feature_info(OPUS_BUILD_PROGRAMS OPUS_BUILD_PROGRAMS ${OPUS_BUILD_PROGRAMS_HELP_STR}) + +set(OPUS_DISABLE_INTRINSICS_HELP_STR "disable all intrinsics optimizations.") +option(OPUS_DISABLE_INTRINSICS ${OPUS_DISABLE_INTRINSICS_HELP_STR} OFF) +add_feature_info(OPUS_DISABLE_INTRINSICS OPUS_DISABLE_INTRINSICS ${OPUS_DISABLE_INTRINSICS_HELP_STR}) + +set(OPUS_FIXED_POINT_HELP_STR "compile as fixed-point (for machines without a fast enough FPU).") +option(OPUS_FIXED_POINT ${OPUS_FIXED_POINT_HELP_STR} OFF) +add_feature_info(OPUS_FIXED_POINT OPUS_FIXED_POINT ${OPUS_FIXED_POINT_HELP_STR}) + +set(OPUS_ENABLE_FLOAT_API_HELP_STR "compile with the floating point API (for machines with float library).") +option(OPUS_ENABLE_FLOAT_API ${OPUS_ENABLE_FLOAT_API_HELP_STR} ON) +add_feature_info(OPUS_ENABLE_FLOAT_API OPUS_ENABLE_FLOAT_API ${OPUS_ENABLE_FLOAT_API_HELP_STR}) + +set(OPUS_FLOAT_APPROX_HELP_STR "enable floating point approximations (Ensure your platform supports IEEE 754 before enabling).") +option(OPUS_FLOAT_APPROX ${OPUS_FLOAT_APPROX_HELP_STR} OFF) +add_feature_info(OPUS_FLOAT_APPROX OPUS_FLOAT_APPROX ${OPUS_FLOAT_APPROX_HELP_STR}) + +set(OPUS_ASSERTIONS_HELP_STR "additional software error checking.") +option(OPUS_ASSERTIONS ${OPUS_ASSERTIONS_HELP_STR} OFF) +add_feature_info(OPUS_ASSERTIONS OPUS_ASSERTIONS ${OPUS_ASSERTIONS_HELP_STR}) + +set(OPUS_HARDENING_HELP_STR "run-time checks that are cheap and safe for use in production.") +option(OPUS_HARDENING ${OPUS_HARDENING_HELP_STR} ON) +add_feature_info(OPUS_HARDENING OPUS_HARDENING ${OPUS_HARDENING_HELP_STR}) + +set(OPUS_FUZZING_HELP_STR "causes the encoder to make random decisions (do not use in production).") +option(OPUS_FUZZING ${OPUS_FUZZING_HELP_STR} OFF) +add_feature_info(OPUS_FUZZING OPUS_FUZZING ${OPUS_FUZZING_HELP_STR}) + +set(OPUS_CHECK_ASM_HELP_STR "enable bit-exactness checks between optimized and c implementations.") +option(OPUS_CHECK_ASM ${OPUS_CHECK_ASM_HELP_STR} OFF) +add_feature_info(OPUS_CHECK_ASM OPUS_CHECK_ASM ${OPUS_CHECK_ASM_HELP_STR}) + +set(OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR "install pkg-config module.") +option(OPUS_INSTALL_PKG_CONFIG_MODULE ${OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR} ON) +add_feature_info(OPUS_INSTALL_PKG_CONFIG_MODULE OPUS_INSTALL_PKG_CONFIG_MODULE ${OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR}) + +set(OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR "install CMake package config module.") +option(OPUS_INSTALL_CMAKE_CONFIG_MODULE ${OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR} ON) +add_feature_info(OPUS_INSTALL_CMAKE_CONFIG_MODULE OPUS_INSTALL_CMAKE_CONFIG_MODULE ${OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR}) + +if(APPLE) + set(OPUS_BUILD_FRAMEWORK_HELP_STR "build Framework bundle for Apple systems.") + option(OPUS_BUILD_FRAMEWORK ${OPUS_BUILD_FRAMEWORK_HELP_STR} OFF) + add_feature_info(OPUS_BUILD_FRAMEWORK OPUS_BUILD_FRAMEWORK ${OPUS_BUILD_FRAMEWORK_HELP_STR}) +endif() + +set(OPUS_FIXED_POINT_DEBUG_HELP_STR "debug fixed-point implementation.") +cmake_dependent_option(OPUS_FIXED_POINT_DEBUG + ${OPUS_FIXED_POINT_DEBUG_HELP_STR} + ON + "OPUS_FIXED_POINT; OPUS_FIXED_POINT_DEBUG" + OFF) +add_feature_info(OPUS_FIXED_POINT_DEBUG OPUS_FIXED_POINT_DEBUG ${OPUS_FIXED_POINT_DEBUG_HELP_STR}) + +set(OPUS_VAR_ARRAYS_HELP_STR "use variable length arrays for stack arrays.") +cmake_dependent_option(OPUS_VAR_ARRAYS + ${OPUS_VAR_ARRAYS_HELP_STR} + ON + "VLA_SUPPORTED; NOT OPUS_USE_ALLOCA; NOT OPUS_NONTHREADSAFE_PSEUDOSTACK" + OFF) +add_feature_info(OPUS_VAR_ARRAYS OPUS_VAR_ARRAYS ${OPUS_VAR_ARRAYS_HELP_STR}) + +set(OPUS_USE_ALLOCA_HELP_STR "use alloca for stack arrays (on non-C99 compilers).") +cmake_dependent_option(OPUS_USE_ALLOCA + ${OPUS_USE_ALLOCA_HELP_STR} + ON + "USE_ALLOCA_SUPPORTED; NOT OPUS_VAR_ARRAYS; NOT OPUS_NONTHREADSAFE_PSEUDOSTACK" + OFF) +add_feature_info(OPUS_USE_ALLOCA OPUS_USE_ALLOCA ${OPUS_USE_ALLOCA_HELP_STR}) + +set(OPUS_NONTHREADSAFE_PSEUDOSTACK_HELP_STR "use a non threadsafe pseudostack when neither variable length arrays or alloca is supported.") +cmake_dependent_option(OPUS_NONTHREADSAFE_PSEUDOSTACK + ${OPUS_NONTHREADSAFE_PSEUDOSTACK_HELP_STR} + ON + "NOT OPUS_VAR_ARRAYS; NOT OPUS_USE_ALLOCA" + OFF) +add_feature_info(OPUS_NONTHREADSAFE_PSEUDOSTACK OPUS_NONTHREADSAFE_PSEUDOSTACK ${OPUS_NONTHREADSAFE_PSEUDOSTACK_HELP_STR}) + +set(OPUS_FAST_MATH_HELP_STR "enable fast math (unsupported and discouraged use, as code is not well tested with this build option).") +cmake_dependent_option(OPUS_FAST_MATH + ${OPUS_FAST_MATH_HELP_STR} + ON + "OPUS_FLOAT_APPROX; OPUS_FAST_MATH; FAST_MATH_SUPPORTED" + OFF) +add_feature_info(OPUS_FAST_MATH OPUS_FAST_MATH ${OPUS_FAST_MATH_HELP_STR}) + +set(OPUS_STACK_PROTECTOR_HELP_STR "use stack protection.") +cmake_dependent_option(OPUS_STACK_PROTECTOR + ${OPUS_STACK_PROTECTOR_HELP_STR} + ON + "STACK_PROTECTOR_SUPPORTED" + OFF) +add_feature_info(OPUS_STACK_PROTECTOR OPUS_STACK_PROTECTOR ${OPUS_STACK_PROTECTOR_HELP_STR}) + +if(NOT MSVC) + set(OPUS_FORTIFY_SOURCE_HELP_STR "add protection against buffer overflows.") + cmake_dependent_option(OPUS_FORTIFY_SOURCE + ${OPUS_FORTIFY_SOURCE_HELP_STR} + ON + "FORTIFY_SOURCE_SUPPORTED" + OFF) + add_feature_info(OPUS_FORTIFY_SOURCE OPUS_FORTIFY_SOURCE ${OPUS_FORTIFY_SOURCE_HELP_STR}) +endif() + +if(MINGW AND (OPUS_FORTIFY_SOURCE OR OPUS_STACK_PROTECTOR)) + # ssp lib is needed for security features for MINGW + list(APPEND OPUS_REQUIRED_LIBRARIES ssp) +endif() + +if(OPUS_CPU_X86 OR OPUS_CPU_X64) + set(OPUS_X86_MAY_HAVE_SSE_HELP_STR "does runtime check for SSE1 support.") + cmake_dependent_option(OPUS_X86_MAY_HAVE_SSE + ${OPUS_X86_MAY_HAVE_SSE_HELP_STR} + ON + "SSE1_SUPPORTED; NOT OPUS_DISABLE_INTRINSICS" + OFF) + add_feature_info(OPUS_X86_MAY_HAVE_SSE OPUS_X86_MAY_HAVE_SSE ${OPUS_X86_MAY_HAVE_SSE_HELP_STR}) + + set(OPUS_X86_MAY_HAVE_SSE2_HELP_STR "does runtime check for SSE2 support.") + cmake_dependent_option(OPUS_X86_MAY_HAVE_SSE2 + ${OPUS_X86_MAY_HAVE_SSE2_HELP_STR} + ON + "SSE2_SUPPORTED; NOT OPUS_DISABLE_INTRINSICS" + OFF) + add_feature_info(OPUS_X86_MAY_HAVE_SSE2 OPUS_X86_MAY_HAVE_SSE2 ${OPUS_X86_MAY_HAVE_SSE2_HELP_STR}) + + set(OPUS_X86_MAY_HAVE_SSE4_1_HELP_STR "does runtime check for SSE4.1 support.") + cmake_dependent_option(OPUS_X86_MAY_HAVE_SSE4_1 + ${OPUS_X86_MAY_HAVE_SSE4_1_HELP_STR} + ON + "SSE4_1_SUPPORTED; NOT OPUS_DISABLE_INTRINSICS" + OFF) + add_feature_info(OPUS_X86_MAY_HAVE_SSE4_1 OPUS_X86_MAY_HAVE_SSE4_1 ${OPUS_X86_MAY_HAVE_SSE4_1_HELP_STR}) + + set(OPUS_X86_MAY_HAVE_AVX_HELP_STR "does runtime check for AVX support.") + cmake_dependent_option(OPUS_X86_MAY_HAVE_AVX + ${OPUS_X86_MAY_HAVE_AVX_HELP_STR} + ON + "AVX_SUPPORTED; NOT OPUS_DISABLE_INTRINSICS" + OFF) + add_feature_info(OPUS_X86_MAY_HAVE_AVX OPUS_X86_MAY_HAVE_AVX ${OPUS_X86_MAY_HAVE_AVX_HELP_STR}) + + # PRESUME depends on MAY HAVE, but PRESUME will override runtime detection + set(OPUS_X86_PRESUME_SSE_HELP_STR "assume target CPU has SSE1 support (override runtime check).") + set(OPUS_X86_PRESUME_SSE2_HELP_STR "assume target CPU has SSE2 support (override runtime check).") + if(OPUS_CPU_X64) # Assume x86_64 has up to SSE2 support + cmake_dependent_option(OPUS_X86_PRESUME_SSE + ${OPUS_X86_PRESUME_SSE_HELP_STR} + ON + "OPUS_X86_MAY_HAVE_SSE; NOT OPUS_DISABLE_INTRINSICS" + OFF) + + cmake_dependent_option(OPUS_X86_PRESUME_SSE2 + ${OPUS_X86_PRESUME_SSE2_HELP_STR} + ON + "OPUS_X86_MAY_HAVE_SSE2; NOT OPUS_DISABLE_INTRINSICS" + OFF) + else() + cmake_dependent_option(OPUS_X86_PRESUME_SSE + ${OPUS_X86_PRESUME_SSE_HELP_STR} + OFF + "OPUS_X86_MAY_HAVE_SSE; NOT OPUS_DISABLE_INTRINSICS" + OFF) + + cmake_dependent_option(OPUS_X86_PRESUME_SSE2 + ${OPUS_X86_PRESUME_SSE2_HELP_STR} + OFF + "OPUS_X86_MAY_HAVE_SSE2; NOT OPUS_DISABLE_INTRINSICS" + OFF) + endif() + add_feature_info(OPUS_X86_PRESUME_SSE OPUS_X86_PRESUME_SSE ${OPUS_X86_PRESUME_SSE_HELP_STR}) + add_feature_info(OPUS_X86_PRESUME_SSE2 OPUS_X86_PRESUME_SSE2 ${OPUS_X86_PRESUME_SSE2_HELP_STR}) + + set(OPUS_X86_PRESUME_SSE4_1_HELP_STR "assume target CPU has SSE4.1 support (override runtime check).") + cmake_dependent_option(OPUS_X86_PRESUME_SSE4_1 + ${OPUS_X86_PRESUME_SSE4_1_HELP_STR} + OFF + "OPUS_X86_MAY_HAVE_SSE4_1; NOT OPUS_DISABLE_INTRINSICS" + OFF) + add_feature_info(OPUS_X86_PRESUME_SSE4_1 OPUS_X86_PRESUME_SSE4_1 ${OPUS_X86_PRESUME_SSE4_1_HELP_STR}) + + set(OPUS_X86_PRESUME_AVX_HELP_STR "assume target CPU has AVX support (override runtime check).") + cmake_dependent_option(OPUS_X86_PRESUME_AVX + ${OPUS_X86_PRESUME_AVX_HELP_STR} + OFF + "OPUS_X86_MAY_HAVE_AVX; NOT OPUS_DISABLE_INTRINSICS" + OFF) + add_feature_info(OPUS_X86_PRESUME_AVX OPUS_X86_PRESUME_AVX ${OPUS_X86_PRESUME_AVX_HELP_STR}) +endif() + +feature_summary(WHAT ALL) + +set_package_properties(Git + PROPERTIES + TYPE + REQUIRED + DESCRIPTION + "fast, scalable, distributed revision control system" + URL + "https://git-scm.com/" + PURPOSE + "required to set up package version") + +set(Opus_PUBLIC_HEADER + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_defines.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_multistream.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_projection.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_types.h) + +if(OPUS_CUSTOM_MODES) + list(APPEND Opus_PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_custom.h) +endif() + +add_library(opus ${opus_headers} ${opus_sources} ${opus_sources_float} ${Opus_PUBLIC_HEADER}) +add_library(Opus::opus ALIAS opus) + +get_library_version(OPUS_LIBRARY_VERSION OPUS_LIBRARY_VERSION_MAJOR) +message(DEBUG "Opus library version: ${OPUS_LIBRARY_VERSION}") + +set_target_properties(opus + PROPERTIES SOVERSION + ${OPUS_LIBRARY_VERSION_MAJOR} + VERSION + ${OPUS_LIBRARY_VERSION} + PUBLIC_HEADER + "${Opus_PUBLIC_HEADER}") + +target_include_directories( + opus + PUBLIC $ + $ + $ + PRIVATE ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + celt + silk) + +target_link_libraries(opus PRIVATE ${OPUS_REQUIRED_LIBRARIES}) +target_compile_definitions(opus PRIVATE OPUS_BUILD) + +if(OPUS_FIXED_POINT_DEBUG) + target_compile_definitions(opus PRIVATE FIXED_DEBUG) +endif() + +if(OPUS_FORTIFY_SOURCE AND NOT MSVC) + target_compile_definitions(opus PRIVATE + $<$>:_FORTIFY_SOURCE=2>) +endif() + +if(OPUS_FLOAT_APPROX) + target_compile_definitions(opus PRIVATE FLOAT_APPROX) +endif() + +if(OPUS_ASSERTIONS) + target_compile_definitions(opus PRIVATE ENABLE_ASSERTIONS) +endif() + +if(OPUS_HARDENING) + target_compile_definitions(opus PRIVATE ENABLE_HARDENING) +endif() + +if(OPUS_FUZZING) + target_compile_definitions(opus PRIVATE FUZZING) +endif() + +if(OPUS_CHECK_ASM) + target_compile_definitions(opus PRIVATE OPUS_CHECK_ASM) +endif() + +if(OPUS_VAR_ARRAYS) + target_compile_definitions(opus PRIVATE VAR_ARRAYS) +elseif(OPUS_USE_ALLOCA) + target_compile_definitions(opus PRIVATE USE_ALLOCA) +elseif(OPUS_NONTHREADSAFE_PSEUDOSTACK) + target_compile_definitions(opus PRIVATE NONTHREADSAFE_PSEUDOSTACK) +else() + message(ERROR "Need to set a define for stack allocation") +endif() + +if(OPUS_CUSTOM_MODES) + target_compile_definitions(opus PRIVATE CUSTOM_MODES) +endif() + +if(OPUS_FAST_MATH) + if(MSVC) + target_compile_options(opus PRIVATE /fp:fast) + else() + target_compile_options(opus PRIVATE -ffast-math) + endif() +endif() + +if(OPUS_STACK_PROTECTOR) + if(MSVC) + target_compile_options(opus PRIVATE /GS) + else() + target_compile_options(opus PRIVATE -fstack-protector-strong) + endif() +elseif(STACK_PROTECTOR_DISABLED_SUPPORTED) + target_compile_options(opus PRIVATE /GS-) +endif() + +if(BUILD_SHARED_LIBS) + if(WIN32) + target_compile_definitions(opus PRIVATE DLL_EXPORT) + elseif(HIDDEN_VISIBILITY_SUPPORTED) + set_target_properties(opus PROPERTIES C_VISIBILITY_PRESET hidden) + endif() +endif() + +add_sources_group(opus silk ${silk_headers} ${silk_sources}) +add_sources_group(opus celt ${celt_headers} ${celt_sources}) + +if(OPUS_FIXED_POINT) + add_sources_group(opus silk ${silk_sources_fixed}) + target_include_directories(opus PRIVATE silk/fixed) + target_compile_definitions(opus PRIVATE FIXED_POINT=1) +else() + add_sources_group(opus silk ${silk_sources_float}) + target_include_directories(opus PRIVATE silk/float) +endif() + +if(NOT OPUS_ENABLE_FLOAT_API) + target_compile_definitions(opus PRIVATE DISABLE_FLOAT_API) +endif() + +if(NOT OPUS_DISABLE_INTRINSICS) + if((OPUS_X86_MAY_HAVE_SSE AND NOT OPUS_X86_PRESUME_SSE) OR + (OPUS_X86_MAY_HAVE_SSE2 AND NOT OPUS_X86_PRESUME_SSE2) OR + (OPUS_X86_MAY_HAVE_SSE4_1 AND NOT OPUS_X86_PRESUME_SSE4_1) OR + (OPUS_X86_MAY_HAVE_AVX AND NOT OPUS_X86_PRESUME_AVX)) + target_compile_definitions(opus PRIVATE OPUS_HAVE_RTCD) + endif() + + if(SSE1_SUPPORTED) + if(OPUS_X86_MAY_HAVE_SSE) + add_sources_group(opus celt ${celt_sources_sse}) + target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_SSE) + if(NOT MSVC) + set_source_files_properties(${celt_sources_sse} PROPERTIES COMPILE_FLAGS -msse) + endif() + endif() + if(OPUS_X86_PRESUME_SSE) + target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_SSE) + if(NOT MSVC) + target_compile_options(opus PRIVATE -msse) + endif() + endif() + endif() + + if(SSE2_SUPPORTED) + if(OPUS_X86_MAY_HAVE_SSE2) + add_sources_group(opus celt ${celt_sources_sse2}) + target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_SSE2) + if(NOT MSVC) + set_source_files_properties(${celt_sources_sse2} PROPERTIES COMPILE_FLAGS -msse2) + endif() + endif() + if(OPUS_X86_PRESUME_SSE2) + target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_SSE2) + if(NOT MSVC) + target_compile_options(opus PRIVATE -msse2) + endif() + endif() + endif() + + if(SSE4_1_SUPPORTED) + if(OPUS_X86_MAY_HAVE_SSE4_1) + add_sources_group(opus celt ${celt_sources_sse4_1}) + add_sources_group(opus silk ${silk_sources_sse4_1}) + target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_SSE4_1) + if(NOT MSVC) + set_source_files_properties(${celt_sources_sse4_1} ${silk_sources_sse4_1} PROPERTIES COMPILE_FLAGS -msse4.1) + endif() + + if(OPUS_FIXED_POINT) + add_sources_group(opus silk ${silk_sources_fixed_sse4_1}) + if(NOT MSVC) + set_source_files_properties(${silk_sources_fixed_sse4_1} PROPERTIES COMPILE_FLAGS -msse4.1) + endif() + endif() + endif() + if(OPUS_X86_PRESUME_SSE4_1) + target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_SSE4_1) + if(NOT MSVC) + target_compile_options(opus PRIVATE -msse4.1) + endif() + endif() + endif() + + if(AVX_SUPPORTED) + # mostly placeholder in case of avx intrinsics is added + if(OPUS_X86_MAY_HAVE_AVX) + target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_AVX) + endif() + if(OPUS_X86_PRESUME_AVX) + target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_AVX) + if(NOT MSVC) + target_compile_options(opus PRIVATE -mavx) + endif() + endif() + endif() + + if(MSVC) + if(AVX_SUPPORTED AND OPUS_X86_PRESUME_AVX) # on 64 bit and 32 bits + add_definitions(/arch:AVX) + elseif(OPUS_CPU_X86) # if AVX not supported then set SSE flag + if((SSE4_1_SUPPORTED AND OPUS_X86_PRESUME_SSE4_1) + OR (SSE2_SUPPORTED AND OPUS_X86_PRESUME_SSE2)) + target_compile_definitions(opus PRIVATE /arch:SSE2) + elseif(SSE1_SUPPORTED AND OPUS_X86_PRESUME_SSE) + target_compile_definitions(opus PRIVATE /arch:SSE) + endif() + endif() + endif() + + if(CMAKE_SYSTEM_PROCESSOR MATCHES "(arm|aarch64)") + add_sources_group(opus celt ${celt_sources_arm}) + endif() + + if(COMPILER_SUPPORT_NEON) + if(OPUS_MAY_HAVE_NEON) + if(RUNTIME_CPU_CAPABILITY_DETECTION) + message(STATUS "OPUS_MAY_HAVE_NEON enabling runtime detection") + target_compile_definitions(opus PRIVATE OPUS_HAVE_RTCD) + else() + message(ERROR "Runtime cpu capability detection needed for MAY_HAVE_NEON") + endif() + # Do runtime check for NEON + target_compile_definitions(opus + PRIVATE + OPUS_ARM_MAY_HAVE_NEON + OPUS_ARM_MAY_HAVE_NEON_INTR) + endif() + + add_sources_group(opus celt ${celt_sources_arm_neon_intr}) + add_sources_group(opus silk ${silk_sources_arm_neon_intr}) + + # silk arm neon depends on main_Fix.h + target_include_directories(opus PRIVATE silk/fixed) + + if(OPUS_FIXED_POINT) + add_sources_group(opus silk ${silk_sources_fixed_arm_neon_intr}) + endif() + + if(OPUS_PRESUME_NEON) + target_compile_definitions(opus + PRIVATE + OPUS_ARM_PRESUME_NEON + OPUS_ARM_PRESUME_NEON_INTR) + endif() + endif() +endif() + +target_compile_definitions(opus + PRIVATE + $<$:HAVE_LRINT> + $<$:HAVE_LRINTF>) + +if(OPUS_BUILD_FRAMEWORK) + set_target_properties(opus PROPERTIES + FRAMEWORK TRUE + FRAMEWORK_VERSION ${PROJECT_VERSION} + MACOSX_FRAMEWORK_IDENTIFIER org.xiph.opus + MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PROJECT_VERSION} + MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION} + XCODE_ATTRIBUTE_INSTALL_PATH "@rpath" + OUTPUT_NAME Opus) +endif() + +install(TARGETS opus + EXPORT OpusTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + FRAMEWORK DESTINATION ${CMAKE_INSTALL_PREFIX} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/opus) + +if(OPUS_INSTALL_PKG_CONFIG_MODULE) + set(prefix ${CMAKE_INSTALL_PREFIX}) + set(exec_prefix ${CMAKE_INSTALL_PREFIX}) + set(libdir ${CMAKE_INSTALL_FULL_LIBDIR}) + set(includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR}) + set(VERSION ${PACKAGE_VERSION}) + if(HAVE_LIBM) + set(LIBM "-lm") + endif() + configure_file(opus.pc.in opus.pc) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/opus.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +endif() + +if(OPUS_INSTALL_CMAKE_CONFIG_MODULE) + set(CPACK_GENERATOR TGZ) + include(CPack) + set(CMAKE_INSTALL_PACKAGEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) + install(EXPORT OpusTargets + NAMESPACE Opus:: + DESTINATION ${CMAKE_INSTALL_PACKAGEDIR}) + + include(CMakePackageConfigHelpers) + + set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}) + configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/OpusConfig.cmake.in + OpusConfig.cmake + INSTALL_DESTINATION + ${CMAKE_INSTALL_PACKAGEDIR} + PATH_VARS + INCLUDE_INSTALL_DIR + INSTALL_PREFIX + ${CMAKE_INSTALL_PREFIX}) + write_basic_package_version_file(OpusConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/OpusConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/OpusConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_PACKAGEDIR}) +endif() + +if(OPUS_BUILD_PROGRAMS) + # demo + if(OPUS_CUSTOM_MODES) + add_executable(opus_custom_demo ${opus_custom_demo_sources}) + target_include_directories(opus_custom_demo + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(opus_custom_demo PRIVATE opus) + endif() + + add_executable(opus_demo ${opus_demo_sources}) + target_include_directories(opus_demo PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_include_directories(opus_demo PRIVATE silk) # debug.h + target_include_directories(opus_demo PRIVATE celt) # arch.h + target_link_libraries(opus_demo PRIVATE opus ${OPUS_REQUIRED_LIBRARIES}) + + # compare + add_executable(opus_compare ${opus_compare_sources}) + target_include_directories(opus_compare PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(opus_compare PRIVATE opus ${OPUS_REQUIRED_LIBRARIES}) +endif() + +if(BUILD_TESTING) + enable_testing() + + # tests + add_executable(test_opus_decode ${test_opus_decode_sources}) + target_include_directories(test_opus_decode + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(test_opus_decode PRIVATE opus) + if(OPUS_FIXED_POINT) + target_compile_definitions(test_opus_decode PRIVATE DISABLE_FLOAT_API) + endif() + add_test(NAME test_opus_decode COMMAND $ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + + add_executable(test_opus_padding ${test_opus_padding_sources}) + target_include_directories(test_opus_padding + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(test_opus_padding PRIVATE opus) + add_test(NAME test_opus_padding COMMAND $ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + + if(NOT BUILD_SHARED_LIBS) + # disable tests that depends on private API when building shared lib + add_executable(test_opus_api ${test_opus_api_sources}) + target_include_directories(test_opus_api + PRIVATE ${CMAKE_CURRENT_BINARY_DIR} celt) + target_link_libraries(test_opus_api PRIVATE opus) + if(OPUS_FIXED_POINT) + target_compile_definitions(test_opus_api PRIVATE DISABLE_FLOAT_API) + endif() + add_test(NAME test_opus_api COMMAND $ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + + add_executable(test_opus_encode ${test_opus_encode_sources}) + target_include_directories(test_opus_encode + PRIVATE ${CMAKE_CURRENT_BINARY_DIR} celt) + target_link_libraries(test_opus_encode PRIVATE opus) + add_test(NAME test_opus_encode COMMAND $ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + endif() +endif() diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/COPYING b/native/opennow-streamer/vendor/audiopus-sys/opus/COPYING new file mode 100644 index 000000000..9c739c34a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/COPYING @@ -0,0 +1,44 @@ +Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic, + Jean-Marc Valin, Timothy B. Terriberry, + CSIRO, Gregory Maxwell, Mark Borgerding, + Erik de Castro Lopo + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- 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. + +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER +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. + +Opus is subject to the royalty-free patent licenses which are +specified at: + +Xiph.Org Foundation: +https://datatracker.ietf.org/ipr/1524/ + +Microsoft Corporation: +https://datatracker.ietf.org/ipr/1914/ + +Broadcom Corporation: +https://datatracker.ietf.org/ipr/1526/ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/ChangeLog b/native/opennow-streamer/vendor/audiopus-sys/opus/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/LICENSE_PLEASE_READ.txt b/native/opennow-streamer/vendor/audiopus-sys/opus/LICENSE_PLEASE_READ.txt new file mode 100644 index 000000000..bc88efa6c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/LICENSE_PLEASE_READ.txt @@ -0,0 +1,22 @@ +Contributions to the collaboration shall not be considered confidential. + +Each contributor represents and warrants that it has the right and +authority to license copyright in its contributions to the collaboration. + +Each contributor agrees to license the copyright in the contributions +under the Modified (2-clause or 3-clause) BSD License or the Clear BSD License. + +Please see the IPR statements submitted to the IETF for the complete +patent licensing details: + +Xiph.Org Foundation: +https://datatracker.ietf.org/ipr/1524/ + +Microsoft Corporation: +https://datatracker.ietf.org/ipr/1914/ + +Skype Limited: +https://datatracker.ietf.org/ipr/1602/ + +Broadcom Corporation: +https://datatracker.ietf.org/ipr/1526/ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/Makefile.am b/native/opennow-streamer/vendor/audiopus-sys/opus/Makefile.am new file mode 100644 index 000000000..83beaa3f1 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/Makefile.am @@ -0,0 +1,371 @@ +# Provide the full test output for failed tests when using the parallel +# test suite (which is enabled by default with automake 1.13+). +export VERBOSE = yes + +AUTOMAKE_OPTIONS = subdir-objects +ACLOCAL_AMFLAGS = -I m4 + +lib_LTLIBRARIES = libopus.la + +DIST_SUBDIRS = doc + +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/celt -I$(top_srcdir)/silk \ + -I$(top_srcdir)/silk/float -I$(top_srcdir)/silk/fixed $(NE10_CFLAGS) + +include celt_sources.mk +include silk_sources.mk +include opus_sources.mk + +if FIXED_POINT +SILK_SOURCES += $(SILK_SOURCES_FIXED) +if HAVE_SSE4_1 +SILK_SOURCES += $(SILK_SOURCES_SSE4_1) $(SILK_SOURCES_FIXED_SSE4_1) +endif +if HAVE_ARM_NEON_INTR +SILK_SOURCES += $(SILK_SOURCES_FIXED_ARM_NEON_INTR) +endif +else +SILK_SOURCES += $(SILK_SOURCES_FLOAT) +if HAVE_SSE4_1 +SILK_SOURCES += $(SILK_SOURCES_SSE4_1) +endif +endif + +if DISABLE_FLOAT_API +else +OPUS_SOURCES += $(OPUS_SOURCES_FLOAT) +endif + +if HAVE_SSE +CELT_SOURCES += $(CELT_SOURCES_SSE) +endif +if HAVE_SSE2 +CELT_SOURCES += $(CELT_SOURCES_SSE2) +endif +if HAVE_SSE4_1 +CELT_SOURCES += $(CELT_SOURCES_SSE4_1) +endif + +if CPU_ARM +CELT_SOURCES += $(CELT_SOURCES_ARM) +SILK_SOURCES += $(SILK_SOURCES_ARM) + +if HAVE_ARM_NEON_INTR +CELT_SOURCES += $(CELT_SOURCES_ARM_NEON_INTR) +SILK_SOURCES += $(SILK_SOURCES_ARM_NEON_INTR) +endif + +if HAVE_ARM_NE10 +CELT_SOURCES += $(CELT_SOURCES_ARM_NE10) +endif + +if OPUS_ARM_EXTERNAL_ASM +noinst_LTLIBRARIES = libarmasm.la +libarmasm_la_SOURCES = $(CELT_SOURCES_ARM_ASM:.s=-gnu.S) +BUILT_SOURCES = $(CELT_SOURCES_ARM_ASM:.s=-gnu.S) \ + $(CELT_AM_SOURCES_ARM_ASM:.s.in=.s) \ + $(CELT_AM_SOURCES_ARM_ASM:.s.in=-gnu.S) +endif +endif + +CLEANFILES = $(CELT_SOURCES_ARM_ASM:.s=-gnu.S) \ + $(CELT_AM_SOURCES_ARM_ASM:.s.in=-gnu.S) + +include celt_headers.mk +include silk_headers.mk +include opus_headers.mk + +libopus_la_SOURCES = $(CELT_SOURCES) $(SILK_SOURCES) $(OPUS_SOURCES) +libopus_la_LDFLAGS = -no-undefined -version-info @OPUS_LT_CURRENT@:@OPUS_LT_REVISION@:@OPUS_LT_AGE@ +libopus_la_LIBADD = $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +libopus_la_LIBADD += libarmasm.la +endif + +pkginclude_HEADERS = include/opus.h include/opus_multistream.h include/opus_types.h include/opus_defines.h include/opus_projection.h + +noinst_HEADERS = $(OPUS_HEAD) $(SILK_HEAD) $(CELT_HEAD) + +if EXTRA_PROGRAMS +noinst_PROGRAMS = celt/tests/test_unit_cwrs32 \ + celt/tests/test_unit_dft \ + celt/tests/test_unit_entropy \ + celt/tests/test_unit_laplace \ + celt/tests/test_unit_mathops \ + celt/tests/test_unit_mdct \ + celt/tests/test_unit_rotation \ + celt/tests/test_unit_types \ + opus_compare \ + opus_demo \ + repacketizer_demo \ + silk/tests/test_unit_LPC_inv_pred_gain \ + tests/test_opus_api \ + tests/test_opus_decode \ + tests/test_opus_encode \ + tests/test_opus_padding \ + tests/test_opus_projection \ + trivial_example + +TESTS = celt/tests/test_unit_cwrs32 \ + celt/tests/test_unit_dft \ + celt/tests/test_unit_entropy \ + celt/tests/test_unit_laplace \ + celt/tests/test_unit_mathops \ + celt/tests/test_unit_mdct \ + celt/tests/test_unit_rotation \ + celt/tests/test_unit_types \ + silk/tests/test_unit_LPC_inv_pred_gain \ + tests/test_opus_api \ + tests/test_opus_decode \ + tests/test_opus_encode \ + tests/test_opus_padding \ + tests/test_opus_projection + +opus_demo_SOURCES = src/opus_demo.c + +opus_demo_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +repacketizer_demo_SOURCES = src/repacketizer_demo.c + +repacketizer_demo_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +opus_compare_SOURCES = src/opus_compare.c +opus_compare_LDADD = $(LIBM) + +trivial_example_SOURCES = doc/trivial_example.c +trivial_example_LDADD = libopus.la $(LIBM) + +tests_test_opus_api_SOURCES = tests/test_opus_api.c tests/test_opus_common.h +tests_test_opus_api_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +tests_test_opus_encode_SOURCES = tests/test_opus_encode.c tests/opus_encode_regressions.c tests/test_opus_common.h +tests_test_opus_encode_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +tests_test_opus_decode_SOURCES = tests/test_opus_decode.c tests/test_opus_common.h +tests_test_opus_decode_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +tests_test_opus_padding_SOURCES = tests/test_opus_padding.c tests/test_opus_common.h +tests_test_opus_padding_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +CELT_OBJ = $(CELT_SOURCES:.c=.lo) +SILK_OBJ = $(SILK_SOURCES:.c=.lo) +OPUS_OBJ = $(OPUS_SOURCES:.c=.lo) + +tests_test_opus_projection_SOURCES = tests/test_opus_projection.c tests/test_opus_common.h +tests_test_opus_projection_LDADD = $(OPUS_OBJ) $(SILK_OBJ) $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +tests_test_opus_projection_LDADD += libarmasm.la +endif + +silk_tests_test_unit_LPC_inv_pred_gain_SOURCES = silk/tests/test_unit_LPC_inv_pred_gain.c +silk_tests_test_unit_LPC_inv_pred_gain_LDADD = $(SILK_OBJ) $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +silk_tests_test_unit_LPC_inv_pred_gain_LDADD += libarmasm.la +endif + +celt_tests_test_unit_cwrs32_SOURCES = celt/tests/test_unit_cwrs32.c +celt_tests_test_unit_cwrs32_LDADD = $(LIBM) + +celt_tests_test_unit_dft_SOURCES = celt/tests/test_unit_dft.c +celt_tests_test_unit_dft_LDADD = $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +celt_tests_test_unit_dft_LDADD += libarmasm.la +endif + +celt_tests_test_unit_entropy_SOURCES = celt/tests/test_unit_entropy.c +celt_tests_test_unit_entropy_LDADD = $(LIBM) + +celt_tests_test_unit_laplace_SOURCES = celt/tests/test_unit_laplace.c +celt_tests_test_unit_laplace_LDADD = $(LIBM) + +celt_tests_test_unit_mathops_SOURCES = celt/tests/test_unit_mathops.c +celt_tests_test_unit_mathops_LDADD = $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +celt_tests_test_unit_mathops_LDADD += libarmasm.la +endif + +celt_tests_test_unit_mdct_SOURCES = celt/tests/test_unit_mdct.c +celt_tests_test_unit_mdct_LDADD = $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +celt_tests_test_unit_mdct_LDADD += libarmasm.la +endif + +celt_tests_test_unit_rotation_SOURCES = celt/tests/test_unit_rotation.c +celt_tests_test_unit_rotation_LDADD = $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +celt_tests_test_unit_rotation_LDADD += libarmasm.la +endif + +celt_tests_test_unit_types_SOURCES = celt/tests/test_unit_types.c +celt_tests_test_unit_types_LDADD = $(LIBM) +endif + +if CUSTOM_MODES +pkginclude_HEADERS += include/opus_custom.h +if EXTRA_PROGRAMS +noinst_PROGRAMS += opus_custom_demo +opus_custom_demo_SOURCES = celt/opus_custom_demo.c +opus_custom_demo_LDADD = libopus.la $(LIBM) +endif +endif + +EXTRA_DIST = opus.pc.in \ + opus-uninstalled.pc.in \ + opus.m4 \ + Makefile.mips \ + Makefile.unix \ + CMakeLists.txt \ + cmake/CFeatureCheck.cmake \ + cmake/OpusBuildtype.cmake \ + cmake/OpusConfig.cmake \ + cmake/OpusConfig.cmake.in \ + cmake/OpusFunctions.cmake \ + cmake/OpusPackageVersion.cmake \ + cmake/OpusSources.cmake \ + cmake/config.h.cmake.in \ + cmake/vla.c \ + meson/get-version.py \ + meson/read-sources-list.py \ + meson.build \ + meson_options.txt \ + include/meson.build \ + celt/meson.build \ + celt/tests/meson.build \ + silk/meson.build \ + silk/tests/meson.build \ + src/meson.build \ + tests/meson.build \ + doc/meson.build \ + tests/run_vectors.sh \ + celt/arm/arm2gnu.pl \ + celt/arm/celt_pitch_xcorr_arm.s \ + win32/VS2015/opus.vcxproj \ + win32/VS2015/test_opus_encode.vcxproj.filters \ + win32/VS2015/test_opus_encode.vcxproj \ + win32/VS2015/opus_demo.vcxproj \ + win32/VS2015/test_opus_api.vcxproj.filters \ + win32/VS2015/test_opus_api.vcxproj \ + win32/VS2015/test_opus_decode.vcxproj.filters \ + win32/VS2015/opus_demo.vcxproj.filters \ + win32/VS2015/opus.vcxproj.filters \ + win32/VS2015/test_opus_decode.vcxproj \ + win32/VS2015/opus.sln \ + win32/VS2015/common.props \ + win32/genversion.bat \ + win32/config.h + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = opus.pc + +m4datadir = $(datadir)/aclocal +m4data_DATA = opus.m4 + +# Targets to build and install just the library without the docs +opus check-opus install-opus: export NO_DOXYGEN = 1 + +opus: all +check-opus: check +install-opus: install + + +# Or just the docs +docs: + ( cd doc && $(MAKE) $(AM_MAKEFLAGS) ) + +install-docs: + ( cd doc && $(MAKE) $(AM_MAKEFLAGS) install ) + + +# Or everything (by default) +all-local: + @[ -n "$(NO_DOXYGEN)" ] || ( cd doc && $(MAKE) $(AM_MAKEFLAGS) ) + +install-data-local: + @[ -n "$(NO_DOXYGEN)" ] || ( cd doc && $(MAKE) $(AM_MAKEFLAGS) install ) + +clean-local: + -( cd doc && $(MAKE) $(AM_MAKEFLAGS) clean ) + +uninstall-local: + ( cd doc && $(MAKE) $(AM_MAKEFLAGS) uninstall ) + + +# We check this every time make is run, with configure.ac being touched to +# trigger an update of the build system files if update_version changes the +# current PACKAGE_VERSION (or if package_version was modified manually by a +# user with either AUTO_UPDATE=no or no update_version script present - the +# latter being the normal case for tarball releases). +# +# We can't just add the package_version file to CONFIGURE_DEPENDENCIES since +# simply running autoconf will not actually regenerate configure for us when +# the content of that file changes (due to autoconf dependency checking not +# knowing about that without us creating yet another file for it to include). +# +# The MAKECMDGOALS check is a gnu-make'ism, but will degrade 'gracefully' for +# makes that don't support it. The only loss of functionality is not forcing +# an update of package_version for `make dist` if AUTO_UPDATE=no, but that is +# unlikely to be a real problem for any real user. +$(top_srcdir)/configure.ac: force + @case "$(MAKECMDGOALS)" in \ + dist-hook) exit 0 ;; \ + dist-* | dist | distcheck | distclean) _arg=release ;; \ + esac; \ + if ! $(top_srcdir)/update_version $$_arg 2> /dev/null; then \ + if [ ! -e $(top_srcdir)/package_version ]; then \ + echo 'PACKAGE_VERSION="unknown"' > $(top_srcdir)/package_version; \ + fi; \ + . $(top_srcdir)/package_version || exit 1; \ + [ "$(PACKAGE_VERSION)" != "$$PACKAGE_VERSION" ] || exit 0; \ + fi; \ + touch $@ + +force: + +# Create a minimal package_version file when make dist is run. +dist-hook: + echo 'PACKAGE_VERSION="$(PACKAGE_VERSION)"' > $(top_distdir)/package_version + + +.PHONY: opus check-opus install-opus docs install-docs + +# automake doesn't do dependency tracking for asm files, that I can tell +$(CELT_SOURCES_ARM_ASM:%.s=%-gnu.S): celt/arm/armopts-gnu.S +$(CELT_SOURCES_ARM_ASM:%.s=%-gnu.S): $(top_srcdir)/celt/arm/arm2gnu.pl + +# convert ARM asm to GNU as format +%-gnu.S: $(top_srcdir)/%.s + $(top_srcdir)/celt/arm/arm2gnu.pl @ARM2GNU_PARAMS@ < $< > $@ +# For autoconf-modified sources (e.g., armopts.s) +%-gnu.S: %.s + $(top_srcdir)/celt/arm/arm2gnu.pl @ARM2GNU_PARAMS@ < $< > $@ + +OPT_UNIT_TEST_OBJ = $(celt_tests_test_unit_mathops_SOURCES:.c=.o) \ + $(celt_tests_test_unit_rotation_SOURCES:.c=.o) \ + $(celt_tests_test_unit_mdct_SOURCES:.c=.o) \ + $(celt_tests_test_unit_dft_SOURCES:.c=.o) \ + $(silk_tests_test_unit_LPC_inv_pred_gain_SOURCES:.c=.o) + +if HAVE_SSE +SSE_OBJ = $(CELT_SOURCES_SSE:.c=.lo) +$(SSE_OBJ): CFLAGS += $(OPUS_X86_SSE_CFLAGS) +endif + +if HAVE_SSE2 +SSE2_OBJ = $(CELT_SOURCES_SSE2:.c=.lo) +$(SSE2_OBJ): CFLAGS += $(OPUS_X86_SSE2_CFLAGS) +endif + +if HAVE_SSE4_1 +SSE4_1_OBJ = $(CELT_SOURCES_SSE4_1:.c=.lo) \ + $(SILK_SOURCES_SSE4_1:.c=.lo) \ + $(SILK_SOURCES_FIXED_SSE4_1:.c=.lo) +$(SSE4_1_OBJ): CFLAGS += $(OPUS_X86_SSE4_1_CFLAGS) +endif + +if HAVE_ARM_NEON_INTR +ARM_NEON_INTR_OBJ = $(CELT_SOURCES_ARM_NEON_INTR:.c=.lo) \ + $(SILK_SOURCES_ARM_NEON_INTR:.c=.lo) \ + $(SILK_SOURCES_FIXED_ARM_NEON_INTR:.c=.lo) +$(ARM_NEON_INTR_OBJ): CFLAGS += \ + $(OPUS_ARM_NEON_INTR_CFLAGS) $(NE10_CFLAGS) +endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/Makefile.mips b/native/opennow-streamer/vendor/audiopus-sys/opus/Makefile.mips new file mode 100644 index 000000000..e9bfc22e8 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/Makefile.mips @@ -0,0 +1,161 @@ +#################### COMPILE OPTIONS ####################### + +# Uncomment this for fixed-point build +FIXED_POINT=1 + +# It is strongly recommended to uncomment one of these +# VAR_ARRAYS: Use C99 variable-length arrays for stack allocation +# USE_ALLOCA: Use alloca() for stack allocation +# If none is defined, then the fallback is a non-threadsafe global array +CFLAGS := -DUSE_ALLOCA $(CFLAGS) +#CFLAGS := -DVAR_ARRAYS $(CFLAGS) + +# These options affect performance +# HAVE_LRINTF: Use C99 intrinsics to speed up float-to-int conversion +CFLAGS := -DHAVE_LRINTF $(CFLAGS) + +###################### END OF OPTIONS ###################### + +-include package_version + +include silk_sources.mk +include celt_sources.mk +include opus_sources.mk + +ifdef FIXED_POINT +SILK_SOURCES += $(SILK_SOURCES_FIXED) +else +SILK_SOURCES += $(SILK_SOURCES_FLOAT) +OPUS_SOURCES += $(OPUS_SOURCES_FLOAT) +endif + +EXESUFFIX = +LIBPREFIX = lib +LIBSUFFIX = .a +OBJSUFFIX = .o + +CC = $(TOOLCHAIN_PREFIX)cc$(TOOLCHAIN_SUFFIX) +AR = $(TOOLCHAIN_PREFIX)ar +RANLIB = $(TOOLCHAIN_PREFIX)ranlib +CP = $(TOOLCHAIN_PREFIX)cp + +cppflags-from-defines = $(addprefix -D,$(1)) +cppflags-from-includes = $(addprefix -I,$(1)) +ldflags-from-ldlibdirs = $(addprefix -L,$(1)) +ldlibs-from-libs = $(addprefix -l,$(1)) + +WARNINGS = -Wall -W -Wstrict-prototypes -Wextra -Wcast-align -Wnested-externs -Wshadow + +CFLAGS += -mips32r2 -mno-mips16 -std=gnu99 -O2 -g $(WARNINGS) -DENABLE_ASSERTIONS -DMIPSr1_ASM -DOPUS_BUILD -mdspr2 -march=74kc -mtune=74kc -mmt -mgp32 + +CINCLUDES = include silk celt + +ifdef FIXED_POINT +CFLAGS += -DFIXED_POINT=1 -DDISABLE_FLOAT_API +CINCLUDES += silk/fixed +else +CINCLUDES += silk/float +endif + + +LIBS = m + +LDLIBDIRS = ./ + +CFLAGS += $(call cppflags-from-defines,$(CDEFINES)) +CFLAGS += $(call cppflags-from-includes,$(CINCLUDES)) +LDFLAGS += $(call ldflags-from-ldlibdirs,$(LDLIBDIRS)) +LDLIBS += $(call ldlibs-from-libs,$(LIBS)) + +COMPILE.c.cmdline = $(CC) -c $(CFLAGS) -o $@ $< +LINK.o = $(CC) $(LDPREFLAGS) $(LDFLAGS) +LINK.o.cmdline = $(LINK.o) $^ $(LDLIBS) -o $@$(EXESUFFIX) + +ARCHIVE.cmdline = $(AR) $(ARFLAGS) $@ $^ && $(RANLIB) $@ + +%$(OBJSUFFIX):%.c + $(COMPILE.c.cmdline) + +%$(OBJSUFFIX):%.cpp + $(COMPILE.cpp.cmdline) + +# Directives + + +# Variable definitions +LIB_NAME = opus +TARGET = $(LIBPREFIX)$(LIB_NAME)$(LIBSUFFIX) + +SRCS_C = $(SILK_SOURCES) $(CELT_SOURCES) $(OPUS_SOURCES) + +OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(SRCS_C)) + +OPUSDEMO_SRCS_C = src/opus_demo.c +OPUSDEMO_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(OPUSDEMO_SRCS_C)) + +TESTOPUSAPI_SRCS_C = tests/test_opus_api.c +TESTOPUSAPI_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSAPI_SRCS_C)) + +TESTOPUSDECODE_SRCS_C = tests/test_opus_decode.c +TESTOPUSDECODE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSDECODE_SRCS_C)) + +TESTOPUSENCODE_SRCS_C = tests/test_opus_encode.c tests/opus_encode_regressions.c +TESTOPUSENCODE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSENCODE_SRCS_C)) + +TESTOPUSPADDING_SRCS_C = tests/test_opus_padding.c +TESTOPUSPADDING_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSPADDING_SRCS_C)) + +OPUSCOMPARE_SRCS_C = src/opus_compare.c +OPUSCOMPARE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(OPUSCOMPARE_SRCS_C)) + +TESTS := test_opus_api test_opus_decode test_opus_encode test_opus_padding + +# Rules +all: lib opus_demo opus_compare $(TESTS) + +lib: $(TARGET) + +check: all + for test in $(TESTS); do ./$$test; done + +$(TARGET): $(OBJS) + $(ARCHIVE.cmdline) + +opus_demo$(EXESUFFIX): $(OPUSDEMO_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_api$(EXESUFFIX): $(TESTOPUSAPI_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_decode$(EXESUFFIX): $(TESTOPUSDECODE_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_encode$(EXESUFFIX): $(TESTOPUSENCODE_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_padding$(EXESUFFIX): $(TESTOPUSPADDING_OBJS) $(TARGET) + $(LINK.o.cmdline) + +opus_compare$(EXESUFFIX): $(OPUSCOMPARE_OBJS) + $(LINK.o.cmdline) + +celt/celt.o: CFLAGS += -DPACKAGE_VERSION='$(PACKAGE_VERSION)' +celt/celt.o: package_version + +package_version: force + @if [ -x ./update_version ]; then \ + ./update_version || true; \ + elif [ ! -e ./package_version ]; then \ + echo 'PACKAGE_VERSION="unknown"' > ./package_version; \ + fi + +force: + +clean: + rm -f opus_demo$(EXESUFFIX) opus_compare$(EXESUFFIX) $(TARGET) \ + test_opus_api$(EXESUFFIX) test_opus_decode$(EXESUFFIX) \ + test_opus_encode$(EXESUFFIX) test_opus_padding$(EXESUFFIX) \ + $(OBJS) $(OPUSDEMO_OBJS) $(OPUSCOMPARE_OBJS) $(TESTOPUSAPI_OBJS) \ + $(TESTOPUSDECODE_OBJS) $(TESTOPUSENCODE_OBJS) $(TESTOPUSPADDING_OBJS) + +.PHONY: all lib clean force check diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/Makefile.unix b/native/opennow-streamer/vendor/audiopus-sys/opus/Makefile.unix new file mode 100644 index 000000000..90a48f0cc --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/Makefile.unix @@ -0,0 +1,159 @@ +#################### COMPILE OPTIONS ####################### + +# Uncomment this for fixed-point build +#FIXED_POINT=1 + +# It is strongly recommended to uncomment one of these +# VAR_ARRAYS: Use C99 variable-length arrays for stack allocation +# USE_ALLOCA: Use alloca() for stack allocation +# If none is defined, then the fallback is a non-threadsafe global array +CFLAGS := -DUSE_ALLOCA $(CFLAGS) +#CFLAGS := -DVAR_ARRAYS $(CFLAGS) + +# These options affect performance +# HAVE_LRINTF: Use C99 intrinsics to speed up float-to-int conversion +#CFLAGS := -DHAVE_LRINTF $(CFLAGS) + +###################### END OF OPTIONS ###################### + +-include package_version + +include silk_sources.mk +include celt_sources.mk +include opus_sources.mk + +ifdef FIXED_POINT +SILK_SOURCES += $(SILK_SOURCES_FIXED) +else +SILK_SOURCES += $(SILK_SOURCES_FLOAT) +OPUS_SOURCES += $(OPUS_SOURCES_FLOAT) +endif + +EXESUFFIX = +LIBPREFIX = lib +LIBSUFFIX = .a +OBJSUFFIX = .o + +CC = $(TOOLCHAIN_PREFIX)cc$(TOOLCHAIN_SUFFIX) +AR = $(TOOLCHAIN_PREFIX)ar +RANLIB = $(TOOLCHAIN_PREFIX)ranlib +CP = $(TOOLCHAIN_PREFIX)cp + +cppflags-from-defines = $(addprefix -D,$(1)) +cppflags-from-includes = $(addprefix -I,$(1)) +ldflags-from-ldlibdirs = $(addprefix -L,$(1)) +ldlibs-from-libs = $(addprefix -l,$(1)) + +WARNINGS = -Wall -W -Wstrict-prototypes -Wextra -Wcast-align -Wnested-externs -Wshadow +CFLAGS += -O2 -g $(WARNINGS) -DOPUS_BUILD +CINCLUDES = include silk celt + +ifdef FIXED_POINT +CFLAGS += -DFIXED_POINT=1 -DDISABLE_FLOAT_API +CINCLUDES += silk/fixed +else +CINCLUDES += silk/float +endif + + +LIBS = m + +LDLIBDIRS = ./ + +CFLAGS += $(call cppflags-from-defines,$(CDEFINES)) +CFLAGS += $(call cppflags-from-includes,$(CINCLUDES)) +LDFLAGS += $(call ldflags-from-ldlibdirs,$(LDLIBDIRS)) +LDLIBS += $(call ldlibs-from-libs,$(LIBS)) + +COMPILE.c.cmdline = $(CC) -c $(CFLAGS) -o $@ $< +LINK.o = $(CC) $(LDPREFLAGS) $(LDFLAGS) +LINK.o.cmdline = $(LINK.o) $^ $(LDLIBS) -o $@$(EXESUFFIX) + +ARCHIVE.cmdline = $(AR) $(ARFLAGS) $@ $^ && $(RANLIB) $@ + +%$(OBJSUFFIX):%.c + $(COMPILE.c.cmdline) + +%$(OBJSUFFIX):%.cpp + $(COMPILE.cpp.cmdline) + +# Directives + + +# Variable definitions +LIB_NAME = opus +TARGET = $(LIBPREFIX)$(LIB_NAME)$(LIBSUFFIX) + +SRCS_C = $(SILK_SOURCES) $(CELT_SOURCES) $(OPUS_SOURCES) + +OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(SRCS_C)) + +OPUSDEMO_SRCS_C = src/opus_demo.c +OPUSDEMO_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(OPUSDEMO_SRCS_C)) + +TESTOPUSAPI_SRCS_C = tests/test_opus_api.c +TESTOPUSAPI_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSAPI_SRCS_C)) + +TESTOPUSDECODE_SRCS_C = tests/test_opus_decode.c +TESTOPUSDECODE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSDECODE_SRCS_C)) + +TESTOPUSENCODE_SRCS_C = tests/test_opus_encode.c tests/opus_encode_regressions.c +TESTOPUSENCODE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSENCODE_SRCS_C)) + +TESTOPUSPADDING_SRCS_C = tests/test_opus_padding.c +TESTOPUSPADDING_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSPADDING_SRCS_C)) + +OPUSCOMPARE_SRCS_C = src/opus_compare.c +OPUSCOMPARE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(OPUSCOMPARE_SRCS_C)) + +TESTS := test_opus_api test_opus_decode test_opus_encode test_opus_padding + +# Rules +all: lib opus_demo opus_compare $(TESTS) + +lib: $(TARGET) + +check: all + for test in $(TESTS); do ./$$test; done + +$(TARGET): $(OBJS) + $(ARCHIVE.cmdline) + +opus_demo$(EXESUFFIX): $(OPUSDEMO_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_api$(EXESUFFIX): $(TESTOPUSAPI_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_decode$(EXESUFFIX): $(TESTOPUSDECODE_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_encode$(EXESUFFIX): $(TESTOPUSENCODE_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_padding$(EXESUFFIX): $(TESTOPUSPADDING_OBJS) $(TARGET) + $(LINK.o.cmdline) + +opus_compare$(EXESUFFIX): $(OPUSCOMPARE_OBJS) + $(LINK.o.cmdline) + +celt/celt.o: CFLAGS += -DPACKAGE_VERSION='$(PACKAGE_VERSION)' +celt/celt.o: package_version + +package_version: force + @if [ -x ./update_version ]; then \ + ./update_version || true; \ + elif [ ! -e ./package_version ]; then \ + echo 'PACKAGE_VERSION="unknown"' > ./package_version; \ + fi + +force: + +clean: + rm -f opus_demo$(EXESUFFIX) opus_compare$(EXESUFFIX) $(TARGET) \ + test_opus_api$(EXESUFFIX) test_opus_decode$(EXESUFFIX) \ + test_opus_encode$(EXESUFFIX) test_opus_padding$(EXESUFFIX) \ + $(OBJS) $(OPUSDEMO_OBJS) $(OPUSCOMPARE_OBJS) $(TESTOPUSAPI_OBJS) \ + $(TESTOPUSDECODE_OBJS) $(TESTOPUSENCODE_OBJS) $(TESTOPUSPADDING_OBJS) + +.PHONY: all lib clean force check diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/NEWS b/native/opennow-streamer/vendor/audiopus-sys/opus/NEWS new file mode 100644 index 000000000..e69de29bb diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/README b/native/opennow-streamer/vendor/audiopus-sys/opus/README new file mode 100644 index 000000000..4b13076fa --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/README @@ -0,0 +1,161 @@ +== Opus audio codec == + +Opus is a codec for interactive speech and audio transmission over the Internet. + + Opus can handle a wide range of interactive audio applications, including +Voice over IP, videoconferencing, in-game chat, and even remote live music +performances. It can scale from low bit-rate narrowband speech to very high +quality stereo music. + + Opus, when coupled with an appropriate container format, is also suitable +for non-realtime stored-file applications such as music distribution, game +soundtracks, portable music players, jukeboxes, and other applications that +have historically used high latency formats such as MP3, AAC, or Vorbis. + + Opus is specified by IETF RFC 6716: + https://tools.ietf.org/html/rfc6716 + + The Opus format and this implementation of it are subject to the royalty- +free patent and copyright licenses specified in the file COPYING. + +This package implements a shared library for encoding and decoding raw Opus +bitstreams. Raw Opus bitstreams should be used over RTP according to + https://tools.ietf.org/html/rfc7587 + +The package also includes a number of test tools used for testing the +correct operation of the library. The bitstreams read/written by these +tools should not be used for Opus file distribution: They include +additional debugging data and cannot support seeking. + +Opus stored in files should use the Ogg encapsulation for Opus which is +described at: + https://tools.ietf.org/html/rfc7845 + +An opus-tools package is available which provides encoding and decoding of +Ogg encapsulated Opus files and includes a number of useful features. + +Opus-tools can be found at: + https://gitlab.xiph.org/xiph/opus-tools.git +or on the main Opus website: + https://opus-codec.org/ + +== Compiling libopus == + +To build from a distribution tarball, you only need to do the following: + + % ./configure + % make + +To build from the git repository, the following steps are necessary: + +0) Set up a development environment: + +On an Ubuntu or Debian family Linux distribution: + + % sudo apt-get install git autoconf automake libtool gcc make + +On a Fedora/Redhat based Linux: + + % sudo dnf install git autoconf automake libtool gcc make + +Or for older Redhat/Centos Linux releases: + + % sudo yum install git autoconf automake libtool gcc make + +On Apple macOS, install Xcode and brew.sh, then in the Terminal enter: + + % brew install autoconf automake libtool + +1) Clone the repository: + + % git clone https://gitlab.xiph.org/xiph/opus.git + % cd opus + +2) Compiling the source + + % ./autogen.sh + % ./configure + % make + +3) Install the codec libraries (optional) + + % sudo make install + +Once you have compiled the codec, there will be a opus_demo executable +in the top directory. + +Usage: opus_demo [-e] + [options] + opus_demo -d [options] + + +mode: voip | audio | restricted-lowdelay +options: + -e : only runs the encoder (output the bit-stream) + -d : only runs the decoder (reads the bit-stream as input) + -cbr : enable constant bitrate; default: variable bitrate + -cvbr : enable constrained variable bitrate; default: + unconstrained + -bandwidth + : audio bandwidth (from narrowband to fullband); + default: sampling rate + -framesize <2.5|5|10|20|40|60> + : frame size in ms; default: 20 + -max_payload + : maximum payload size in bytes, default: 1024 + -complexity + : complexity, 0 (lowest) ... 10 (highest); default: 10 + -inbandfec : enable SILK inband FEC + -forcemono : force mono encoding, even for stereo input + -dtx : enable SILK DTX + -loss : simulate packet loss, in percent (0-100); default: 0 + +input and output are little-endian signed 16-bit PCM files or opus +bitstreams with simple opus_demo proprietary framing. + +== Testing == + +This package includes a collection of automated unit and system tests +which SHOULD be run after compiling the package especially the first +time it is run on a new platform. + +To run the integrated tests: + + % make check + +There is also collection of standard test vectors which are not +included in this package for size reasons but can be obtained from: +https://opus-codec.org/docs/opus_testvectors-rfc8251.tar.gz + +To run compare the code to these test vectors: + + % curl -OL https://opus-codec.org/docs/opus_testvectors-rfc8251.tar.gz + % tar -zxf opus_testvectors-rfc8251.tar.gz + % ./tests/run_vectors.sh ./ opus_newvectors 48000 + +== Portability notes == + +This implementation uses floating-point by default but can be compiled to +use only fixed-point arithmetic by setting --enable-fixed-point (if using +autoconf) or by defining the FIXED_POINT macro (if building manually). +The fixed point implementation has somewhat lower audio quality and is +slower on platforms with fast FPUs, it is normally only used in embedded +environments. + +The implementation can be compiled with either a C89 or a C99 compiler. +While it does not rely on any _undefined behavior_ as defined by C89 or +C99, it relies on common _implementation-defined behavior_ for two's +complement architectures: + +o Right shifts of negative values are consistent with two's + complement arithmetic, so that a>>b is equivalent to + floor(a/(2^b)), + +o For conversion to a signed integer of N bits, the value is reduced + modulo 2^N to be within range of the type, + +o The result of integer division of a negative value is truncated + towards zero, and + +o The compiler provides a 64-bit integer type (a C99 requirement + which is supported by most C89 compilers). diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/README.draft b/native/opennow-streamer/vendor/audiopus-sys/opus/README.draft new file mode 100644 index 000000000..9c31bd023 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/README.draft @@ -0,0 +1,54 @@ +To build this source code, simply type: + +% make + +If this does not work, or if you want to change the default configuration +(e.g., to compile for a fixed-point architecture), simply edit the options +in the Makefile. + +An up-to-date implementation conforming to this standard is available in a +Git repository at https://gitlab.xiph.org/xiph/opus.git or on a website at: +https://opus-codec.org/ +However, although that implementation is expected to remain conformant +with the standard, it is the code in this RFC that shall remain normative. +To build from the git repository instead of using this RFC, follow these +steps: + +1) Clone the repository (latest implementation of this standard at the time +of publication) + +% git clone https://gitlab.xiph.org/xiph/opus.git +% cd opus + +2) Compile + +% ./autogen.sh +% ./configure +% make + +Once you have compiled the codec, there will be a opus_demo executable in +the top directory. + +Usage: opus_demo [-e] + [options] + opus_demo -d [options] + + +mode: voip | audio | restricted-lowdelay +options: +-e : only runs the encoder (output the bit-stream) +-d : only runs the decoder (reads the bit-stream as input) +-cbr : enable constant bitrate; default: variable bitrate +-cvbr : enable constrained variable bitrate; default: unconstrained +-bandwidth : audio bandwidth (from narrowband to fullband); + default: sampling rate +-framesize <2.5|5|10|20|40|60> : frame size in ms; default: 20 +-max_payload : maximum payload size in bytes, default: 1024 +-complexity : complexity, 0 (lowest) ... 10 (highest); default: 10 +-inbandfec : enable SILK inband FEC +-forcemono : force mono encoding, even for stereo input +-dtx : enable SILK DTX +-loss : simulate packet loss, in percent (0-100); default: 0 + +input and output are little endian signed 16-bit PCM files or opus bitstreams +with simple opus_demo proprietary framing. diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/autogen.sh b/native/opennow-streamer/vendor/audiopus-sys/opus/autogen.sh new file mode 100755 index 000000000..380d1f3ca --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/autogen.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# Copyright (c) 2010-2015 Xiph.Org Foundation and contributors. +# Use of this source code is governed by a BSD-style license that can be +# found in the COPYING file. + +# Run this to set up the build system: configure, makefiles, etc. +set -e + +srcdir=`dirname $0` +test -n "$srcdir" && cd "$srcdir" + +echo "Updating build configuration files, please wait...." + +autoreconf -isf diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/_kiss_fft_guts.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/_kiss_fft_guts.h new file mode 100644 index 000000000..17392b3e9 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/_kiss_fft_guts.h @@ -0,0 +1,182 @@ +/*Copyright (c) 2003-2004, Mark Borgerding + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * 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. + + 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 OWNER 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.*/ + +#ifndef KISS_FFT_GUTS_H +#define KISS_FFT_GUTS_H + +#define MIN(a,b) ((a)<(b) ? (a):(b)) +#define MAX(a,b) ((a)>(b) ? (a):(b)) + +/* kiss_fft.h + defines kiss_fft_scalar as either short or a float type + and defines + typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ +#include "kiss_fft.h" + +/* + Explanation of macros dealing with complex math: + + C_MUL(m,a,b) : m = a*b + C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise + C_SUB( res, a,b) : res = a - b + C_SUBFROM( res , a) : res -= a + C_ADDTO( res , a) : res += a + * */ +#ifdef FIXED_POINT +#include "arch.h" + + +#define SAMP_MAX 2147483647 +#define TWID_MAX 32767 +#define TRIG_UPSCALE 1 + +#define SAMP_MIN -SAMP_MAX + + +# define S_MUL(a,b) MULT16_32_Q15(b, a) + +# define C_MUL(m,a,b) \ + do{ (m).r = SUB32_ovflw(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \ + (m).i = ADD32_ovflw(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0) + +# define C_MULC(m,a,b) \ + do{ (m).r = ADD32_ovflw(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \ + (m).i = SUB32_ovflw(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0) + +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r = S_MUL( (c).r , s ) ;\ + (c).i = S_MUL( (c).i , s ) ; }while(0) + +# define DIVSCALAR(x,k) \ + (x) = S_MUL( x, (TWID_MAX-((k)>>1))/(k)+1 ) + +# define C_FIXDIV(c,div) \ + do { DIVSCALAR( (c).r , div); \ + DIVSCALAR( (c).i , div); }while (0) + +#define C_ADD( res, a,b)\ + do {(res).r=ADD32_ovflw((a).r,(b).r); (res).i=ADD32_ovflw((a).i,(b).i); \ + }while(0) +#define C_SUB( res, a,b)\ + do {(res).r=SUB32_ovflw((a).r,(b).r); (res).i=SUB32_ovflw((a).i,(b).i); \ + }while(0) +#define C_ADDTO( res , a)\ + do {(res).r = ADD32_ovflw((res).r, (a).r); (res).i = ADD32_ovflw((res).i,(a).i);\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {(res).r = ADD32_ovflw((res).r,(a).r); (res).i = SUB32_ovflw((res).i,(a).i); \ + }while(0) + +#if defined(OPUS_ARM_INLINE_ASM) +#include "arm/kiss_fft_armv4.h" +#endif + +#if defined(OPUS_ARM_INLINE_EDSP) +#include "arm/kiss_fft_armv5e.h" +#endif +#if defined(MIPSr1_ASM) +#include "mips/kiss_fft_mipsr1.h" +#endif + +#else /* not FIXED_POINT*/ + +# define S_MUL(a,b) ( (a)*(b) ) +#define C_MUL(m,a,b) \ + do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ + (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) +#define C_MULC(m,a,b) \ + do{ (m).r = (a).r*(b).r + (a).i*(b).i;\ + (m).i = (a).i*(b).r - (a).r*(b).i; }while(0) + +#define C_MUL4(m,a,b) C_MUL(m,a,b) + +# define C_FIXDIV(c,div) /* NOOP */ +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r *= (s);\ + (c).i *= (s); }while(0) +#endif + +#ifndef CHECK_OVERFLOW_OP +# define CHECK_OVERFLOW_OP(a,op,b) /* noop */ +#endif + +#ifndef C_ADD +#define C_ADD( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,+,(b).r)\ + CHECK_OVERFLOW_OP((a).i,+,(b).i)\ + (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ + }while(0) +#define C_SUB( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,-,(b).r)\ + CHECK_OVERFLOW_OP((a).i,-,(b).i)\ + (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ + }while(0) +#define C_ADDTO( res , a)\ + do { \ + CHECK_OVERFLOW_OP((res).r,+,(a).r)\ + CHECK_OVERFLOW_OP((res).i,+,(a).i)\ + (res).r += (a).r; (res).i += (a).i;\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {\ + CHECK_OVERFLOW_OP((res).r,-,(a).r)\ + CHECK_OVERFLOW_OP((res).i,-,(a).i)\ + (res).r -= (a).r; (res).i -= (a).i; \ + }while(0) +#endif /* C_ADD defined */ + +#ifdef FIXED_POINT +/*# define KISS_FFT_COS(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase)))) +# define KISS_FFT_SIN(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase))))*/ +# define KISS_FFT_COS(phase) floor(.5+TWID_MAX*cos (phase)) +# define KISS_FFT_SIN(phase) floor(.5+TWID_MAX*sin (phase)) +# define HALF_OF(x) ((x)>>1) +#elif defined(USE_SIMD) +# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) ) +# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) ) +# define HALF_OF(x) ((x)*_mm_set1_ps(.5f)) +#else +# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase) +# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) +# define HALF_OF(x) ((x)*.5f) +#endif + +#define kf_cexp(x,phase) \ + do{ \ + (x)->r = KISS_FFT_COS(phase);\ + (x)->i = KISS_FFT_SIN(phase);\ + }while(0) + +#define kf_cexp2(x,phase) \ + do{ \ + (x)->r = TRIG_UPSCALE*celt_cos_norm((phase));\ + (x)->i = TRIG_UPSCALE*celt_cos_norm((phase)-32768);\ +}while(0) + +#endif /* KISS_FFT_GUTS_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arch.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arch.h new file mode 100644 index 000000000..3845c3a08 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arch.h @@ -0,0 +1,291 @@ +/* Copyright (c) 2003-2008 Jean-Marc Valin + Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file arch.h + @brief Various architecture definitions for CELT +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef ARCH_H +#define ARCH_H + +#include "opus_types.h" +#include "opus_defines.h" + +# if !defined(__GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define __GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define __GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +#if OPUS_GNUC_PREREQ(3, 0) +#define opus_likely(x) (__builtin_expect(!!(x), 1)) +#define opus_unlikely(x) (__builtin_expect(!!(x), 0)) +#else +#define opus_likely(x) (!!(x)) +#define opus_unlikely(x) (!!(x)) +#endif + +#define CELT_SIG_SCALE 32768.f + +#define CELT_FATAL(str) celt_fatal(str, __FILE__, __LINE__); + +#if defined(ENABLE_ASSERTIONS) || defined(ENABLE_HARDENING) +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +void celt_fatal(const char *str, const char *file, int line); + +#if defined(CELT_C) && !defined(OVERRIDE_celt_fatal) +#include +#include +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +void celt_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); +#if defined(_MSC_VER) + _set_abort_behavior( 0, _WRITE_ABORT_MSG); +#endif + abort(); +} +#endif + +#define celt_assert(cond) {if (!(cond)) {CELT_FATAL("assertion failed: " #cond);}} +#define celt_assert2(cond, message) {if (!(cond)) {CELT_FATAL("assertion failed: " #cond "\n" message);}} +#define MUST_SUCCEED(call) celt_assert((call) == OPUS_OK) +#else +#define celt_assert(cond) +#define celt_assert2(cond, message) +#define MUST_SUCCEED(call) do {if((call) != OPUS_OK) {RESTORE_STACK; return OPUS_INTERNAL_ERROR;} } while (0) +#endif + +#if defined(ENABLE_ASSERTIONS) +#define celt_sig_assert(cond) {if (!(cond)) {CELT_FATAL("signal assertion failed: " #cond);}} +#else +#define celt_sig_assert(cond) +#endif + +#define IMUL32(a,b) ((a)*(b)) + +#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 16-bit value. */ +#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 32-bit value. */ +#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ +#define IMIN(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum int value. */ +#define IMAX(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum int value. */ +#define UADD32(a,b) ((a)+(b)) +#define USUB32(a,b) ((a)-(b)) + +/* Set this if opus_int64 is a native type of the CPU. */ +/* Assume that all LP64 architectures have fast 64-bit types; also x86_64 + (which can be ILP32 for x32) and Win64 (which is LLP64). */ +#if defined(__x86_64__) || defined(__LP64__) || defined(_WIN64) +#define OPUS_FAST_INT64 1 +#else +#define OPUS_FAST_INT64 0 +#endif + +#define PRINT_MIPS(file) + +#ifdef FIXED_POINT + +typedef opus_int16 opus_val16; +typedef opus_int32 opus_val32; +typedef opus_int64 opus_val64; + +typedef opus_val32 celt_sig; +typedef opus_val16 celt_norm; +typedef opus_val32 celt_ener; + +#define celt_isnan(x) 0 + +#define Q15ONE 32767 + +#define SIG_SHIFT 12 +/* Safe saturation value for 32-bit signals. Should be less than + 2^31*(1-0.85) to avoid blowing up on DC at deemphasis.*/ +#define SIG_SAT (300000000) + +#define NORM_SCALING 16384 + +#define DB_SHIFT 10 + +#define EPSILON 1 +#define VERY_SMALL 0 +#define VERY_LARGE16 ((opus_val16)32767) +#define Q15_ONE ((opus_val16)32767) + +#define SCALEIN(a) (a) +#define SCALEOUT(a) (a) + +#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) +#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) + +static OPUS_INLINE opus_int16 SAT16(opus_int32 x) { + return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x; +} + +#ifdef FIXED_DEBUG +#include "fixed_debug.h" +#else + +#include "fixed_generic.h" + +#ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR +#include "arm/fixed_arm64.h" +#elif defined (OPUS_ARM_INLINE_EDSP) +#include "arm/fixed_armv5e.h" +#elif defined (OPUS_ARM_INLINE_ASM) +#include "arm/fixed_armv4.h" +#elif defined (BFIN_ASM) +#include "fixed_bfin.h" +#elif defined (TI_C5X_ASM) +#include "fixed_c5x.h" +#elif defined (TI_C6X_ASM) +#include "fixed_c6x.h" +#endif + +#endif + +#else /* FIXED_POINT */ + +typedef float opus_val16; +typedef float opus_val32; +typedef float opus_val64; + +typedef float celt_sig; +typedef float celt_norm; +typedef float celt_ener; + +#ifdef FLOAT_APPROX +/* This code should reliably detect NaN/inf even when -ffast-math is used. + Assumes IEEE 754 format. */ +static OPUS_INLINE int celt_isnan(float x) +{ + union {float f; opus_uint32 i;} in; + in.f = x; + return ((in.i>>23)&0xFF)==0xFF && (in.i&0x007FFFFF)!=0; +} +#else +#ifdef __FAST_MATH__ +#error Cannot build libopus with -ffast-math unless FLOAT_APPROX is defined. This could result in crashes on extreme (e.g. NaN) input +#endif +#define celt_isnan(x) ((x)!=(x)) +#endif + +#define Q15ONE 1.0f + +#define NORM_SCALING 1.f + +#define EPSILON 1e-15f +#define VERY_SMALL 1e-30f +#define VERY_LARGE16 1e15f +#define Q15_ONE ((opus_val16)1.f) + +/* This appears to be the same speed as C99's fabsf() but it's more portable. */ +#define ABS16(x) ((float)fabs(x)) +#define ABS32(x) ((float)fabs(x)) + +#define QCONST16(x,bits) (x) +#define QCONST32(x,bits) (x) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define NEG32_ovflw(x) (-(x)) +#define EXTRACT16(x) (x) +#define EXTEND32(x) (x) +#define SHR16(a,shift) (a) +#define SHL16(a,shift) (a) +#define SHR32(a,shift) (a) +#define SHL32(a,shift) (a) +#define PSHR32(a,shift) (a) +#define VSHR32(a,shift) (a) + +#define PSHR(a,shift) (a) +#define SHR(a,shift) (a) +#define SHL(a,shift) (a) +#define SATURATE(x,a) (x) +#define SATURATE16(x) (x) + +#define ROUND16(a,shift) (a) +#define SROUND16(a,shift) (a) +#define HALF16(x) (.5f*(x)) +#define HALF32(x) (.5f*(x)) + +#define ADD16(a,b) ((a)+(b)) +#define SUB16(a,b) ((a)-(b)) +#define ADD32(a,b) ((a)+(b)) +#define SUB32(a,b) ((a)-(b)) +#define ADD32_ovflw(a,b) ((a)+(b)) +#define SUB32_ovflw(a,b) ((a)-(b)) +#define MULT16_16_16(a,b) ((a)*(b)) +#define MULT16_16(a,b) ((opus_val32)(a)*(opus_val32)(b)) +#define MAC16_16(c,a,b) ((c)+(opus_val32)(a)*(opus_val32)(b)) + +#define MULT16_32_Q15(a,b) ((a)*(b)) +#define MULT16_32_Q16(a,b) ((a)*(b)) + +#define MULT32_32_Q31(a,b) ((a)*(b)) + +#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) +#define MAC16_32_Q16(c,a,b) ((c)+(a)*(b)) + +#define MULT16_16_Q11_32(a,b) ((a)*(b)) +#define MULT16_16_Q11(a,b) ((a)*(b)) +#define MULT16_16_Q13(a,b) ((a)*(b)) +#define MULT16_16_Q14(a,b) ((a)*(b)) +#define MULT16_16_Q15(a,b) ((a)*(b)) +#define MULT16_16_P15(a,b) ((a)*(b)) +#define MULT16_16_P13(a,b) ((a)*(b)) +#define MULT16_16_P14(a,b) ((a)*(b)) +#define MULT16_32_P16(a,b) ((a)*(b)) + +#define DIV32_16(a,b) (((opus_val32)(a))/(opus_val16)(b)) +#define DIV32(a,b) (((opus_val32)(a))/(opus_val32)(b)) + +#define SCALEIN(a) ((a)*CELT_SIG_SCALE) +#define SCALEOUT(a) ((a)*(1/CELT_SIG_SCALE)) + +#define SIG2WORD16(x) (x) + +#endif /* !FIXED_POINT */ + +#ifndef GLOBAL_STACK_SIZE +#ifdef FIXED_POINT +#define GLOBAL_STACK_SIZE 120000 +#else +#define GLOBAL_STACK_SIZE 120000 +#endif +#endif + +#endif /* ARCH_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/arm2gnu.pl b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/arm2gnu.pl new file mode 100755 index 000000000..a2895f744 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/arm2gnu.pl @@ -0,0 +1,353 @@ +#!/usr/bin/perl +# Copyright (C) 2002-2013 Xiph.org Foundation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - 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. +# +# 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 OWNER +# 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. + +my $bigend; # little/big endian +my $nxstack; +my $apple = 0; +my $symprefix = ""; + +$nxstack = 0; + +eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}' + if $running_under_some_shell; + +while ($ARGV[0] =~ /^-/) { + $_ = shift; + last if /^--$/; + if (/^-n$/) { + $nflag++; + next; + } + if (/^--apple$/) { + $apple = 1; + $symprefix = "_"; + next; + } + die "I don't recognize this switch: $_\\n"; +} +$printit++ unless $nflag; + +$\ = "\n"; # automatically add newline on print +$n=0; + +$thumb = 0; # ARM mode by default, not Thumb. +@proc_stack = (); + +printf (" .syntax unified\n"); + +LINE: +while (<>) { + + # For ADRLs we need to add a new line after the substituted one. + $addPadding = 0; + + # First, we do not dare to touch *anything* inside double quotes, do we? + # Second, if you want a dollar character in the string, + # insert two of them -- that's how ARM C and assembler treat strings. + s/^([A-Za-z_]\w*)[ \t]+DCB[ \t]*\"/$1: .ascii \"/ && do { s/\$\$/\$/g; next }; + s/\bDCB\b[ \t]*\"/.ascii \"/ && do { s/\$\$/\$/g; next }; + s/^(\S+)\s+RN\s+(\S+)/$1 .req r$2/ && do { s/\$\$/\$/g; next }; + # If there's nothing on a line but a comment, don't try to apply any further + # substitutions (this is a cheap hack to avoid mucking up the license header) + s/^([ \t]*);/$1@/ && do { s/\$\$/\$/g; next }; + # If substituted -- leave immediately ! + + s/@/,:/; + s/;/@/; + while ( /@.*'/ ) { + s/(@.*)'/$1/g; + } + s/\{FALSE\}/0/g; + s/\{TRUE\}/1/g; + s/\{(\w\w\w\w+)\}/$1/g; + s/\bINCLUDE[ \t]*([^ \t\n]+)/.include \"$1\"/; + s/\bGET[ \t]*([^ \t\n]+)/.include \"${ my $x=$1; $x =~ s|\.s|-gnu.S|; \$x }\"/; + s/\bIMPORT\b/.extern/; + s/\bEXPORT\b\s*/.global $symprefix/; + s/^(\s+)\[/$1IF/; + s/^(\s+)\|/$1ELSE/; + s/^(\s+)\]/$1ENDIF/; + s/IF *:DEF:/ .ifdef/; + s/IF *:LNOT: *:DEF:/ .ifndef/; + s/ELSE/ .else/; + s/ENDIF/ .endif/; + + if( /\bIF\b/ ) { + s/\bIF\b/ .if/; + s/=/==/; + } + if ( $n == 2) { + s/\$/\\/g; + } + if ($n == 1) { + s/\$//g; + s/label//g; + $n = 2; + } + if ( /MACRO/ ) { + s/MACRO *\n/.macro/; + $n=1; + } + if ( /\bMEND\b/ ) { + s/\bMEND\b/.endm/; + $n=0; + } + + # ".rdata" doesn't work in 'as' version 2.13.2, as it is ".rodata" there. + # + if ( /\bAREA\b/ ) { + my $align; + $align = "2"; + if ( /ALIGN=(\d+)/ ) { + $align = $1; + } + if ( /CODE/ ) { + $nxstack = 1; + } + s/^(.+)CODE(.+)READONLY(.*)/ .text/; + s/^(.+)DATA(.+)READONLY(.*)/ .section .rdata/; + s/^(.+)\|\|\.data\|\|(.+)/ .data/; + s/^(.+)\|\|\.bss\|\|(.+)/ .bss/; + s/$/; .p2align $align/; + # Enable NEON instructions but don't produce a binary that requires + # ARMv7. RVCT does not have equivalent directives, so we just do this + # for all CODE areas. + if ( /.text/ ) { + # Separating .arch, .fpu, etc., by semicolons does not work (gas + # thinks the semicolon is part of the arch name, even when there's + # whitespace separating them). Sadly this means our line numbers + # won't match the original source file (we could use the .line + # directive, which is documented to be obsolete, but then gdb will + # show the wrong line in the translated source file). + s/$/; .arch armv7-a\n .fpu neon\n .object_arch armv4t/ unless ($apple); + } + } + + s/\|\|\.constdata\$(\d+)\|\|/.L_CONST$1/; # ||.constdata$3|| + s/\|\|\.bss\$(\d+)\|\|/.L_BSS$1/; # ||.bss$2|| + s/\|\|\.data\$(\d+)\|\|/.L_DATA$1/; # ||.data$2|| + s/\|\|([a-zA-Z0-9_]+)\@([a-zA-Z0-9_]+)\|\|/@ $&/; + s/^(\s+)\%(\s)/ .space $1/; + + s/\|(.+)\.(\d+)\|/\.$1_$2/; # |L80.123| -> .L80_123 + s/\bCODE32\b/.code 32/ && do {$thumb = 0}; + s/\bCODE16\b/.code 16/ && do {$thumb = 1}; + if (/\bPROC\b/) + { + my $prefix; + my $proc; + /^([A-Za-z_\.]\w+)\b/; + $proc = $1; + $prefix = ""; + if ($proc) + { + $prefix = $prefix.sprintf("\t.type\t%s, %%function", $proc) unless ($apple); + # Make sure we $prefix isn't empty here (for the $apple case). + # We handle mangling the label here, make sure it doesn't match + # the label handling below (if $prefix would be empty). + $prefix = $prefix."; "; + push(@proc_stack, $proc); + s/^[A-Za-z_\.]\w+/$symprefix$&:/; + } + $prefix = $prefix."\t.thumb_func; " if ($thumb); + s/\bPROC\b/@ $&/; + $_ = $prefix.$_; + } + s/^(\s*)(S|Q|SH|U|UQ|UH)ASX\b/$1$2ADDSUBX/; + s/^(\s*)(S|Q|SH|U|UQ|UH)SAX\b/$1$2SUBADDX/; + if (/\bENDP\b/) + { + my $proc; + s/\bENDP\b/@ $&/; + $proc = pop(@proc_stack); + $_ = "\t.size $proc, .-$proc".$_ if ($proc && !$apple); + } + s/\bSUBT\b/@ $&/; + s/\bDATA\b/@ $&/; # DATA directive is deprecated -- Asm guide, p.7-25 + s/\bKEEP\b/@ $&/; + s/\bEXPORTAS\b/@ $&/; + s/\|\|(.)+\bEQU\b/@ $&/; + s/\|\|([\w\$]+)\|\|/$1/; + s/\bENTRY\b/@ $&/; + s/\bASSERT\b/@ $&/; + s/\bGBLL\b/@ $&/; + s/\bGBLA\b/@ $&/; + s/^\W+OPT\b/@ $&/; + s/:OR:/|/g; + s/:SHL:/<>/g; + s/:AND:/&/g; + s/:LAND:/&&/g; + s/CPSR/cpsr/; + s/SPSR/spsr/; + s/ALIGN$/.balign 4/; + s/ALIGN\s+([0-9x]+)$/.balign $1/; + s/psr_cxsf/psr_all/; + s/LTORG/.ltorg/; + s/^([A-Za-z_]\w*)[ \t]+EQU/ .set $1,/; + s/^([A-Za-z_]\w*)[ \t]+SETL/ .set $1,/; + s/^([A-Za-z_]\w*)[ \t]+SETA/ .set $1,/; + s/^([A-Za-z_]\w*)[ \t]+\*/ .set $1,/; + + # {PC} + 0xdeadfeed --> . + 0xdeadfeed + s/\{PC\} \+/ \. +/; + + # Single hex constant on the line ! + # + # >>> NOTE <<< + # Double-precision floats in gcc are always mixed-endian, which means + # bytes in two words are little-endian, but words are big-endian. + # So, 0x0000deadfeed0000 would be stored as 0x0000dead at low address + # and 0xfeed0000 at high address. + # + s/\bDCFD\b[ \t]+0x([a-fA-F0-9]{8})([a-fA-F0-9]{8})/.long 0x$1, 0x$2/; + # Only decimal constants on the line, no hex ! + s/\bDCFD\b[ \t]+([0-9\.\-]+)/.double $1/; + + # Single hex constant on the line ! +# s/\bDCFS\b[ \t]+0x([a-f0-9]{8})([a-f0-9]{8})/.long 0x$1, 0x$2/; + # Only decimal constants on the line, no hex ! +# s/\bDCFS\b[ \t]+([0-9\.\-]+)/.double $1/; + s/\bDCFS[ \t]+0x/.word 0x/; + s/\bDCFS\b/.float/; + + s/^([A-Za-z_]\w*)[ \t]+DCD/$1 .word/; + s/\bDCD\b/.word/; + s/^([A-Za-z_]\w*)[ \t]+DCW/$1 .short/; + s/\bDCW\b/.short/; + s/^([A-Za-z_]\w*)[ \t]+DCB/$1 .byte/; + s/\bDCB\b/.byte/; + s/^([A-Za-z_]\w*)[ \t]+\%/.comm $1,/; + s/^[A-Za-z_\.]\w+/$&:/; + s/^(\d+)/$1:/; + s/\%(\d+)/$1b_or_f/; + s/\%[Bb](\d+)/$1b/; + s/\%[Ff](\d+)/$1f/; + s/\%[Ff][Tt](\d+)/$1f/; + s/&([\dA-Fa-f]+)/0x$1/; + if ( /\b2_[01]+\b/ ) { + s/\b2_([01]+)\b/conv$1&&&&/g; + while ( /[01][01][01][01]&&&&/ ) { + s/0000&&&&/&&&&0/g; + s/0001&&&&/&&&&1/g; + s/0010&&&&/&&&&2/g; + s/0011&&&&/&&&&3/g; + s/0100&&&&/&&&&4/g; + s/0101&&&&/&&&&5/g; + s/0110&&&&/&&&&6/g; + s/0111&&&&/&&&&7/g; + s/1000&&&&/&&&&8/g; + s/1001&&&&/&&&&9/g; + s/1010&&&&/&&&&A/g; + s/1011&&&&/&&&&B/g; + s/1100&&&&/&&&&C/g; + s/1101&&&&/&&&&D/g; + s/1110&&&&/&&&&E/g; + s/1111&&&&/&&&&F/g; + } + s/000&&&&/&&&&0/g; + s/001&&&&/&&&&1/g; + s/010&&&&/&&&&2/g; + s/011&&&&/&&&&3/g; + s/100&&&&/&&&&4/g; + s/101&&&&/&&&&5/g; + s/110&&&&/&&&&6/g; + s/111&&&&/&&&&7/g; + s/00&&&&/&&&&0/g; + s/01&&&&/&&&&1/g; + s/10&&&&/&&&&2/g; + s/11&&&&/&&&&3/g; + s/0&&&&/&&&&0/g; + s/1&&&&/&&&&1/g; + s/conv&&&&/0x/g; + } + + if ( /commandline/) + { + if( /-bigend/) + { + $bigend=1; + } + } + + if ( /\bDCDU\b/ ) + { + my $cmd=$_; + my $value; + my $prefix; + my $w1; + my $w2; + my $w3; + my $w4; + + s/\s+DCDU\b/@ $&/; + + $cmd =~ /\bDCDU\b\s+0x(\d+)/; + $value = $1; + $value =~ /(\w\w)(\w\w)(\w\w)(\w\w)/; + $w1 = $1; + $w2 = $2; + $w3 = $3; + $w4 = $4; + + if( $bigend ne "") + { + # big endian + $prefix = "\t.byte\t0x".$w1.";". + "\t.byte\t0x".$w2.";". + "\t.byte\t0x".$w3.";". + "\t.byte\t0x".$w4."; "; + } + else + { + # little endian + $prefix = "\t.byte\t0x".$w4.";". + "\t.byte\t0x".$w3.";". + "\t.byte\t0x".$w2.";". + "\t.byte\t0x".$w1."; "; + } + $_=$prefix.$_; + } + + if ( /\badrl\b/i ) + { + s/\badrl\s+(\w+)\s*,\s*(\w+)/ldr $1,=$2/i; + $addPadding = 1; + } + s/\bEND\b/@ END/; +} continue { + printf ("%s", $_) if $printit; + if ($addPadding != 0) + { + printf (" mov r0,r0\n"); + $addPadding = 0; + } +} +#If we had a code section, mark that this object doesn't need an executable +# stack. +if ($nxstack && !$apple) { + printf (" .section\t.note.GNU-stack,\"\",\%\%progbits\n"); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/arm_celt_map.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/arm_celt_map.c new file mode 100644 index 000000000..ca988b66f --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/arm_celt_map.c @@ -0,0 +1,160 @@ +/* Copyright (c) 2010 Xiph.Org Foundation + * Copyright (c) 2013 Parrot */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pitch.h" +#include "kiss_fft.h" +#include "mdct.h" + +#if defined(OPUS_HAVE_RTCD) + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR) +opus_val32 (*const CELT_INNER_PROD_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *x, const opus_val16 *y, int N) = { + celt_inner_prod_c, /* ARMv4 */ + celt_inner_prod_c, /* EDSP */ + celt_inner_prod_c, /* Media */ + celt_inner_prod_neon /* NEON */ +}; + +void (*const DUAL_INNER_PROD_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2) = { + dual_inner_prod_c, /* ARMv4 */ + dual_inner_prod_c, /* EDSP */ + dual_inner_prod_c, /* Media */ + dual_inner_prod_neon /* NEON */ +}; +# endif + +# if defined(FIXED_POINT) +# if ((defined(OPUS_ARM_MAY_HAVE_NEON) && !defined(OPUS_ARM_PRESUME_NEON)) || \ + (defined(OPUS_ARM_MAY_HAVE_MEDIA) && !defined(OPUS_ARM_PRESUME_MEDIA)) || \ + (defined(OPUS_ARM_MAY_HAVE_EDSP) && !defined(OPUS_ARM_PRESUME_EDSP))) +opus_val32 (*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *, + const opus_val16 *, opus_val32 *, int, int, int) = { + celt_pitch_xcorr_c, /* ARMv4 */ + MAY_HAVE_EDSP(celt_pitch_xcorr), /* EDSP */ + MAY_HAVE_MEDIA(celt_pitch_xcorr), /* Media */ + MAY_HAVE_NEON(celt_pitch_xcorr) /* NEON */ +}; + +# endif +# else /* !FIXED_POINT */ +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR) +void (*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *, + const opus_val16 *, opus_val32 *, int, int, int) = { + celt_pitch_xcorr_c, /* ARMv4 */ + celt_pitch_xcorr_c, /* EDSP */ + celt_pitch_xcorr_c, /* Media */ + celt_pitch_xcorr_float_neon /* Neon */ +}; +# endif +# endif /* FIXED_POINT */ + +#if defined(FIXED_POINT) && defined(OPUS_HAVE_RTCD) && \ + defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR) + +void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])( + const opus_val16 *x, + const opus_val16 *y, + opus_val32 sum[4], + int len +) = { + xcorr_kernel_c, /* ARMv4 */ + xcorr_kernel_c, /* EDSP */ + xcorr_kernel_c, /* Media */ + xcorr_kernel_neon_fixed, /* Neon */ +}; + +#endif + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +# if defined(HAVE_ARM_NE10) +# if defined(CUSTOM_MODES) +int (*const OPUS_FFT_ALLOC_ARCH_IMPL[OPUS_ARCHMASK+1])(kiss_fft_state *st) = { + opus_fft_alloc_arch_c, /* ARMv4 */ + opus_fft_alloc_arch_c, /* EDSP */ + opus_fft_alloc_arch_c, /* Media */ + opus_fft_alloc_arm_neon /* Neon with NE10 library support */ +}; + +void (*const OPUS_FFT_FREE_ARCH_IMPL[OPUS_ARCHMASK+1])(kiss_fft_state *st) = { + opus_fft_free_arch_c, /* ARMv4 */ + opus_fft_free_arch_c, /* EDSP */ + opus_fft_free_arch_c, /* Media */ + opus_fft_free_arm_neon /* Neon with NE10 */ +}; +# endif /* CUSTOM_MODES */ + +void (*const OPUS_FFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout) = { + opus_fft_c, /* ARMv4 */ + opus_fft_c, /* EDSP */ + opus_fft_c, /* Media */ + opus_fft_neon /* Neon with NE10 */ +}; + +void (*const OPUS_IFFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout) = { + opus_ifft_c, /* ARMv4 */ + opus_ifft_c, /* EDSP */ + opus_ifft_c, /* Media */ + opus_ifft_neon /* Neon with NE10 */ +}; + +void (*const CLT_MDCT_FORWARD_IMPL[OPUS_ARCHMASK+1])(const mdct_lookup *l, + kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, + int overlap, int shift, + int stride, int arch) = { + clt_mdct_forward_c, /* ARMv4 */ + clt_mdct_forward_c, /* EDSP */ + clt_mdct_forward_c, /* Media */ + clt_mdct_forward_neon /* Neon with NE10 */ +}; + +void (*const CLT_MDCT_BACKWARD_IMPL[OPUS_ARCHMASK+1])(const mdct_lookup *l, + kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, + int overlap, int shift, + int stride, int arch) = { + clt_mdct_backward_c, /* ARMv4 */ + clt_mdct_backward_c, /* EDSP */ + clt_mdct_backward_c, /* Media */ + clt_mdct_backward_neon /* Neon with NE10 */ +}; + +# endif /* HAVE_ARM_NE10 */ +# endif /* OPUS_ARM_MAY_HAVE_NEON_INTR */ + +#endif /* OPUS_HAVE_RTCD */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/armcpu.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/armcpu.c new file mode 100644 index 000000000..cce3ae3a9 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/armcpu.c @@ -0,0 +1,187 @@ +/* Copyright (c) 2010 Xiph.Org Foundation + * Copyright (c) 2013 Parrot */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +/* Original code from libtheora modified to suit to Opus */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef OPUS_HAVE_RTCD + +#include "armcpu.h" +#include "cpu_support.h" +#include "os_support.h" +#include "opus_types.h" +#include "arch.h" + +#define OPUS_CPU_ARM_V4_FLAG (1< + +static OPUS_INLINE opus_uint32 opus_cpu_capabilities(void){ + opus_uint32 flags; + flags=0; + /* MSVC has no OPUS_INLINE __asm support for ARM, but it does let you __emit + * instructions via their assembled hex code. + * All of these instructions should be essentially nops. */ +# if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \ + || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + __try{ + /*PLD [r13]*/ + __emit(0xF5DDF000); + flags|=OPUS_CPU_ARM_EDSP_FLAG; + } + __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ + /*Ignore exception.*/ + } +# if defined(OPUS_ARM_MAY_HAVE_MEDIA) \ + || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + __try{ + /*SHADD8 r3,r3,r3*/ + __emit(0xE6333F93); + flags|=OPUS_CPU_ARM_MEDIA_FLAG; + } + __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ + /*Ignore exception.*/ + } +# if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + __try{ + /*VORR q0,q0,q0*/ + __emit(0xF2200150); + flags|=OPUS_CPU_ARM_NEON_FLAG; + } + __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ + /*Ignore exception.*/ + } +# endif +# endif +# endif + return flags; +} + +#elif defined(__linux__) +/* Linux based */ +#include + +opus_uint32 opus_cpu_capabilities(void) +{ + opus_uint32 flags = 0; + FILE *cpuinfo; + + /* Reading /proc/self/auxv would be easier, but that doesn't work reliably on + * Android */ + cpuinfo = fopen("/proc/cpuinfo", "r"); + + if(cpuinfo != NULL) + { + /* 512 should be enough for anybody (it's even enough for all the flags that + * x86 has accumulated... so far). */ + char buf[512]; + + while(fgets(buf, 512, cpuinfo) != NULL) + { +# if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \ + || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + /* Search for edsp and neon flag */ + if(memcmp(buf, "Features", 8) == 0) + { + char *p; + p = strstr(buf, " edsp"); + if(p != NULL && (p[5] == ' ' || p[5] == '\n')) + flags |= OPUS_CPU_ARM_EDSP_FLAG; + +# if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + p = strstr(buf, " neon"); + if(p != NULL && (p[5] == ' ' || p[5] == '\n')) + flags |= OPUS_CPU_ARM_NEON_FLAG; +# endif + } +# endif + +# if defined(OPUS_ARM_MAY_HAVE_MEDIA) \ + || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + /* Search for media capabilities (>= ARMv6) */ + if(memcmp(buf, "CPU architecture:", 17) == 0) + { + int version; + version = atoi(buf+17); + + if(version >= 6) + flags |= OPUS_CPU_ARM_MEDIA_FLAG; + } +# endif + } + + fclose(cpuinfo); + } + return flags; +} +#else +/* The feature registers which can tell us what the processor supports are + * accessible in priveleged modes only, so we can't have a general user-space + * detection method like on x86.*/ +# error "Configured to use ARM asm but no CPU detection method available for " \ + "your platform. Reconfigure with --disable-rtcd (or send patches)." +#endif + +int opus_select_arch(void) +{ + opus_uint32 flags = opus_cpu_capabilities(); + int arch = 0; + + if(!(flags & OPUS_CPU_ARM_EDSP_FLAG)) { + /* Asserts ensure arch values are sequential */ + celt_assert(arch == OPUS_ARCH_ARM_V4); + return arch; + } + arch++; + + if(!(flags & OPUS_CPU_ARM_MEDIA_FLAG)) { + celt_assert(arch == OPUS_ARCH_ARM_EDSP); + return arch; + } + arch++; + + if(!(flags & OPUS_CPU_ARM_NEON_FLAG)) { + celt_assert(arch == OPUS_ARCH_ARM_MEDIA); + return arch; + } + arch++; + + celt_assert(arch == OPUS_ARCH_ARM_NEON); + return arch; +} + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/armcpu.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/armcpu.h new file mode 100644 index 000000000..820262ff5 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/armcpu.h @@ -0,0 +1,77 @@ +/* Copyright (c) 2010 Xiph.Org Foundation + * Copyright (c) 2013 Parrot */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#if !defined(ARMCPU_H) +# define ARMCPU_H + +# if defined(OPUS_ARM_MAY_HAVE_EDSP) +# define MAY_HAVE_EDSP(name) name ## _edsp +# else +# define MAY_HAVE_EDSP(name) name ## _c +# endif + +# if defined(OPUS_ARM_MAY_HAVE_MEDIA) +# define MAY_HAVE_MEDIA(name) name ## _media +# else +# define MAY_HAVE_MEDIA(name) MAY_HAVE_EDSP(name) +# endif + +# if defined(OPUS_ARM_MAY_HAVE_NEON) +# define MAY_HAVE_NEON(name) name ## _neon +# else +# define MAY_HAVE_NEON(name) MAY_HAVE_MEDIA(name) +# endif + +# if defined(OPUS_ARM_PRESUME_EDSP) +# define PRESUME_EDSP(name) name ## _edsp +# else +# define PRESUME_EDSP(name) name ## _c +# endif + +# if defined(OPUS_ARM_PRESUME_MEDIA) +# define PRESUME_MEDIA(name) name ## _media +# else +# define PRESUME_MEDIA(name) PRESUME_EDSP(name) +# endif + +# if defined(OPUS_ARM_PRESUME_NEON) +# define PRESUME_NEON(name) name ## _neon +# else +# define PRESUME_NEON(name) PRESUME_MEDIA(name) +# endif + +# if defined(OPUS_HAVE_RTCD) +int opus_select_arch(void); + +#define OPUS_ARCH_ARM_V4 (0) +#define OPUS_ARCH_ARM_EDSP (1) +#define OPUS_ARCH_ARM_MEDIA (2) +#define OPUS_ARCH_ARM_NEON (3) + +# endif + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/armopts.s.in b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/armopts.s.in new file mode 100644 index 000000000..3d8aaf275 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/armopts.s.in @@ -0,0 +1,37 @@ +/* Copyright (C) 2013 Mozilla Corporation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +; Set the following to 1 if we have EDSP instructions +; (LDRD/STRD, etc., ARMv5E and later). +OPUS_ARM_MAY_HAVE_EDSP * @OPUS_ARM_MAY_HAVE_EDSP@ + +; Set the following to 1 if we have ARMv6 media instructions. +OPUS_ARM_MAY_HAVE_MEDIA * @OPUS_ARM_MAY_HAVE_MEDIA@ + +; Set the following to 1 if we have NEON (some ARMv7) +OPUS_ARM_MAY_HAVE_NEON * @OPUS_ARM_MAY_HAVE_NEON@ + +END diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/celt_fft_ne10.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/celt_fft_ne10.c new file mode 100644 index 000000000..ea5fd7808 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/celt_fft_ne10.c @@ -0,0 +1,173 @@ +/* Copyright (c) 2015 Xiph.Org Foundation + Written by Viswanath Puttagunta */ +/** + @file celt_fft_ne10.c + @brief ARM Neon optimizations for fft using NE10 library + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef SKIP_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +#include +#include "os_support.h" +#include "kiss_fft.h" +#include "stack_alloc.h" + +#if !defined(FIXED_POINT) +# define NE10_FFT_ALLOC_C2C_TYPE_NEON ne10_fft_alloc_c2c_float32_neon +# define NE10_FFT_CFG_TYPE_T ne10_fft_cfg_float32_t +# define NE10_FFT_STATE_TYPE_T ne10_fft_state_float32_t +# define NE10_FFT_DESTROY_C2C_TYPE ne10_fft_destroy_c2c_float32 +# define NE10_FFT_CPX_TYPE_T ne10_fft_cpx_float32_t +# define NE10_FFT_C2C_1D_TYPE_NEON ne10_fft_c2c_1d_float32_neon +#else +# define NE10_FFT_ALLOC_C2C_TYPE_NEON(nfft) ne10_fft_alloc_c2c_int32_neon(nfft) +# define NE10_FFT_CFG_TYPE_T ne10_fft_cfg_int32_t +# define NE10_FFT_STATE_TYPE_T ne10_fft_state_int32_t +# define NE10_FFT_DESTROY_C2C_TYPE ne10_fft_destroy_c2c_int32 +# define NE10_FFT_DESTROY_C2C_TYPE ne10_fft_destroy_c2c_int32 +# define NE10_FFT_CPX_TYPE_T ne10_fft_cpx_int32_t +# define NE10_FFT_C2C_1D_TYPE_NEON ne10_fft_c2c_1d_int32_neon +#endif + +#if defined(CUSTOM_MODES) + +/* nfft lengths in NE10 that support scaled fft */ +# define NE10_FFTSCALED_SUPPORT_MAX 4 +static const int ne10_fft_scaled_support[NE10_FFTSCALED_SUPPORT_MAX] = { + 480, 240, 120, 60 +}; + +int opus_fft_alloc_arm_neon(kiss_fft_state *st) +{ + int i; + size_t memneeded = sizeof(struct arch_fft_state); + + st->arch_fft = (arch_fft_state *)opus_alloc(memneeded); + if (!st->arch_fft) + return -1; + + for (i = 0; i < NE10_FFTSCALED_SUPPORT_MAX; i++) { + if(st->nfft == ne10_fft_scaled_support[i]) + break; + } + if (i == NE10_FFTSCALED_SUPPORT_MAX) { + /* This nfft length (scaled fft) is not supported in NE10 */ + st->arch_fft->is_supported = 0; + st->arch_fft->priv = NULL; + } + else { + st->arch_fft->is_supported = 1; + st->arch_fft->priv = (void *)NE10_FFT_ALLOC_C2C_TYPE_NEON(st->nfft); + if (st->arch_fft->priv == NULL) { + return -1; + } + } + return 0; +} + +void opus_fft_free_arm_neon(kiss_fft_state *st) +{ + NE10_FFT_CFG_TYPE_T cfg; + + if (!st->arch_fft) + return; + + cfg = (NE10_FFT_CFG_TYPE_T)st->arch_fft->priv; + if (cfg) + NE10_FFT_DESTROY_C2C_TYPE(cfg); + opus_free(st->arch_fft); +} +#endif + +void opus_fft_neon(const kiss_fft_state *st, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout) +{ + NE10_FFT_STATE_TYPE_T state; + NE10_FFT_CFG_TYPE_T cfg = &state; + VARDECL(NE10_FFT_CPX_TYPE_T, buffer); + SAVE_STACK; + ALLOC(buffer, st->nfft, NE10_FFT_CPX_TYPE_T); + + if (!st->arch_fft->is_supported) { + /* This nfft length (scaled fft) not supported in NE10 */ + opus_fft_c(st, fin, fout); + } + else { + memcpy((void *)cfg, st->arch_fft->priv, sizeof(NE10_FFT_STATE_TYPE_T)); + state.buffer = (NE10_FFT_CPX_TYPE_T *)&buffer[0]; +#if !defined(FIXED_POINT) + state.is_forward_scaled = 1; + + NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout, + (NE10_FFT_CPX_TYPE_T *)fin, + cfg, 0); +#else + NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout, + (NE10_FFT_CPX_TYPE_T *)fin, + cfg, 0, 1); +#endif + } + RESTORE_STACK; +} + +void opus_ifft_neon(const kiss_fft_state *st, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout) +{ + NE10_FFT_STATE_TYPE_T state; + NE10_FFT_CFG_TYPE_T cfg = &state; + VARDECL(NE10_FFT_CPX_TYPE_T, buffer); + SAVE_STACK; + ALLOC(buffer, st->nfft, NE10_FFT_CPX_TYPE_T); + + if (!st->arch_fft->is_supported) { + /* This nfft length (scaled fft) not supported in NE10 */ + opus_ifft_c(st, fin, fout); + } + else { + memcpy((void *)cfg, st->arch_fft->priv, sizeof(NE10_FFT_STATE_TYPE_T)); + state.buffer = (NE10_FFT_CPX_TYPE_T *)&buffer[0]; +#if !defined(FIXED_POINT) + state.is_backward_scaled = 0; + + NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout, + (NE10_FFT_CPX_TYPE_T *)fin, + cfg, 1); +#else + NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout, + (NE10_FFT_CPX_TYPE_T *)fin, + cfg, 1, 0); +#endif + } + RESTORE_STACK; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/celt_mdct_ne10.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/celt_mdct_ne10.c new file mode 100644 index 000000000..3531d02d1 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/celt_mdct_ne10.c @@ -0,0 +1,258 @@ +/* Copyright (c) 2015 Xiph.Org Foundation + Written by Viswanath Puttagunta */ +/** + @file celt_mdct_ne10.c + @brief ARM Neon optimizations for mdct using NE10 library + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef SKIP_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +#include "kiss_fft.h" +#include "_kiss_fft_guts.h" +#include "mdct.h" +#include "stack_alloc.h" + +void clt_mdct_forward_neon(const mdct_lookup *l, + kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, + int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + VARDECL(kiss_fft_scalar, f); + VARDECL(kiss_fft_cpx, f2); + const kiss_fft_state *st = l->kfft[shift]; + const kiss_twiddle_scalar *trig; + + SAVE_STACK; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + ALLOC(f, N2, kiss_fft_scalar); + ALLOC(f2, N4, kiss_fft_cpx); + + /* Consider the input to be composed of four blocks: [a, b, c, d] */ + /* Window, shuffle, fold */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1); + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1); + kiss_fft_scalar * OPUS_RESTRICT yp = f; + const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1); + const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1; + for(i=0;i<((overlap+3)>>2);i++) + { + /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/ + *yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2); + *yp++ = MULT16_32_Q15(*wp1, *xp1) - MULT16_32_Q15(*wp2, xp2[-N2]); + xp1+=2; + xp2-=2; + wp1+=2; + wp2-=2; + } + wp1 = window; + wp2 = window+overlap-1; + for(;i>2);i++) + { + /* Real part arranged as a-bR, Imag part arranged as -c-dR */ + *yp++ = *xp2; + *yp++ = *xp1; + xp1+=2; + xp2-=2; + } + for(;ii,t[N4+i]) - S_MUL(fp->r,t[i]); + yi = S_MUL(fp->r,t[N4+i]) + S_MUL(fp->i,t[i]); + *yp1 = yr; + *yp2 = yi; + fp++; + yp1 += 2*stride; + yp2 -= 2*stride; + } + } + RESTORE_STACK; +} + +void clt_mdct_backward_neon(const mdct_lookup *l, + kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 * OPUS_RESTRICT window, + int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + VARDECL(kiss_fft_scalar, f); + const kiss_twiddle_scalar *trig; + const kiss_fft_state *st = l->kfft[shift]; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + ALLOC(f, N2, kiss_fft_scalar); + + /* Pre-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in; + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1); + kiss_fft_scalar * OPUS_RESTRICT yp = f; + const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0]; + for(i=0;i>1)), arch); + + /* Post-rotate and de-shuffle from both ends of the buffer at once to make + it in-place. */ + { + kiss_fft_scalar * yp0 = out+(overlap>>1); + kiss_fft_scalar * yp1 = out+(overlap>>1)+N2-2; + const kiss_twiddle_scalar *t = &trig[0]; + /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the + middle pair will be computed twice. */ + for(i=0;i<(N4+1)>>1;i++) + { + kiss_fft_scalar re, im, yr, yi; + kiss_twiddle_scalar t0, t1; + re = yp0[0]; + im = yp0[1]; + t0 = t[i]; + t1 = t[N4+i]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = S_MUL(re,t0) + S_MUL(im,t1); + yi = S_MUL(re,t1) - S_MUL(im,t0); + re = yp1[0]; + im = yp1[1]; + yp0[0] = yr; + yp1[1] = yi; + + t0 = t[(N4-i-1)]; + t1 = t[(N2-i-1)]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = S_MUL(re,t0) + S_MUL(im,t1); + yi = S_MUL(re,t1) - S_MUL(im,t0); + yp1[0] = yr; + yp0[1] = yi; + yp0 += 2; + yp1 -= 2; + } + } + + /* Mirror on both sides for TDAC */ + { + kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + const opus_val16 * OPUS_RESTRICT wp1 = window; + const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1; + + for(i = 0; i < overlap/2; i++) + { + kiss_fft_scalar x1, x2; + x1 = *xp1; + x2 = *yp1; + *yp1++ = MULT16_32_Q15(*wp2, x2) - MULT16_32_Q15(*wp1, x1); + *xp1-- = MULT16_32_Q15(*wp1, x2) + MULT16_32_Q15(*wp2, x1); + wp1++; + wp2--; + } + } + RESTORE_STACK; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/celt_neon_intr.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/celt_neon_intr.c new file mode 100644 index 000000000..effda769d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/celt_neon_intr.c @@ -0,0 +1,211 @@ +/* Copyright (c) 2014-2015 Xiph.Org Foundation + Written by Viswanath Puttagunta */ +/** + @file celt_neon_intr.c + @brief ARM Neon Intrinsic optimizations for celt + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "../pitch.h" + +#if defined(FIXED_POINT) +void xcorr_kernel_neon_fixed(const opus_val16 * x, const opus_val16 * y, opus_val32 sum[4], int len) +{ + int j; + int32x4_t a = vld1q_s32(sum); + /* Load y[0...3] */ + /* This requires len>0 to always be valid (which we assert in the C code). */ + int16x4_t y0 = vld1_s16(y); + y += 4; + + for (j = 0; j + 8 <= len; j += 8) + { + /* Load x[0...7] */ + int16x8_t xx = vld1q_s16(x); + int16x4_t x0 = vget_low_s16(xx); + int16x4_t x4 = vget_high_s16(xx); + /* Load y[4...11] */ + int16x8_t yy = vld1q_s16(y); + int16x4_t y4 = vget_low_s16(yy); + int16x4_t y8 = vget_high_s16(yy); + int32x4_t a0 = vmlal_lane_s16(a, y0, x0, 0); + int32x4_t a1 = vmlal_lane_s16(a0, y4, x4, 0); + + int16x4_t y1 = vext_s16(y0, y4, 1); + int16x4_t y5 = vext_s16(y4, y8, 1); + int32x4_t a2 = vmlal_lane_s16(a1, y1, x0, 1); + int32x4_t a3 = vmlal_lane_s16(a2, y5, x4, 1); + + int16x4_t y2 = vext_s16(y0, y4, 2); + int16x4_t y6 = vext_s16(y4, y8, 2); + int32x4_t a4 = vmlal_lane_s16(a3, y2, x0, 2); + int32x4_t a5 = vmlal_lane_s16(a4, y6, x4, 2); + + int16x4_t y3 = vext_s16(y0, y4, 3); + int16x4_t y7 = vext_s16(y4, y8, 3); + int32x4_t a6 = vmlal_lane_s16(a5, y3, x0, 3); + int32x4_t a7 = vmlal_lane_s16(a6, y7, x4, 3); + + y0 = y8; + a = a7; + x += 8; + y += 8; + } + + for (; j < len; j++) + { + int16x4_t x0 = vld1_dup_s16(x); /* load next x */ + int32x4_t a0 = vmlal_s16(a, y0, x0); + + int16x4_t y4 = vld1_dup_s16(y); /* load next y */ + y0 = vext_s16(y0, y4, 1); + a = a0; + x++; + y++; + } + + vst1q_s32(sum, a); +} + +#else +/* + * Function: xcorr_kernel_neon_float + * --------------------------------- + * Computes 4 correlation values and stores them in sum[4] + */ +static void xcorr_kernel_neon_float(const float32_t *x, const float32_t *y, + float32_t sum[4], int len) { + float32x4_t YY[3]; + float32x4_t YEXT[3]; + float32x4_t XX[2]; + float32x2_t XX_2; + float32x4_t SUMM; + const float32_t *xi = x; + const float32_t *yi = y; + + celt_assert(len>0); + + YY[0] = vld1q_f32(yi); + SUMM = vdupq_n_f32(0); + + /* Consume 8 elements in x vector and 12 elements in y + * vector. However, the 12'th element never really gets + * touched in this loop. So, if len == 8, then we only + * must access y[0] to y[10]. y[11] must not be accessed + * hence make sure len > 8 and not len >= 8 + */ + while (len > 8) { + yi += 4; + YY[1] = vld1q_f32(yi); + yi += 4; + YY[2] = vld1q_f32(yi); + + XX[0] = vld1q_f32(xi); + xi += 4; + XX[1] = vld1q_f32(xi); + xi += 4; + + SUMM = vmlaq_lane_f32(SUMM, YY[0], vget_low_f32(XX[0]), 0); + YEXT[0] = vextq_f32(YY[0], YY[1], 1); + SUMM = vmlaq_lane_f32(SUMM, YEXT[0], vget_low_f32(XX[0]), 1); + YEXT[1] = vextq_f32(YY[0], YY[1], 2); + SUMM = vmlaq_lane_f32(SUMM, YEXT[1], vget_high_f32(XX[0]), 0); + YEXT[2] = vextq_f32(YY[0], YY[1], 3); + SUMM = vmlaq_lane_f32(SUMM, YEXT[2], vget_high_f32(XX[0]), 1); + + SUMM = vmlaq_lane_f32(SUMM, YY[1], vget_low_f32(XX[1]), 0); + YEXT[0] = vextq_f32(YY[1], YY[2], 1); + SUMM = vmlaq_lane_f32(SUMM, YEXT[0], vget_low_f32(XX[1]), 1); + YEXT[1] = vextq_f32(YY[1], YY[2], 2); + SUMM = vmlaq_lane_f32(SUMM, YEXT[1], vget_high_f32(XX[1]), 0); + YEXT[2] = vextq_f32(YY[1], YY[2], 3); + SUMM = vmlaq_lane_f32(SUMM, YEXT[2], vget_high_f32(XX[1]), 1); + + YY[0] = YY[2]; + len -= 8; + } + + /* Consume 4 elements in x vector and 8 elements in y + * vector. However, the 8'th element in y never really gets + * touched in this loop. So, if len == 4, then we only + * must access y[0] to y[6]. y[7] must not be accessed + * hence make sure len>4 and not len>=4 + */ + if (len > 4) { + yi += 4; + YY[1] = vld1q_f32(yi); + + XX[0] = vld1q_f32(xi); + xi += 4; + + SUMM = vmlaq_lane_f32(SUMM, YY[0], vget_low_f32(XX[0]), 0); + YEXT[0] = vextq_f32(YY[0], YY[1], 1); + SUMM = vmlaq_lane_f32(SUMM, YEXT[0], vget_low_f32(XX[0]), 1); + YEXT[1] = vextq_f32(YY[0], YY[1], 2); + SUMM = vmlaq_lane_f32(SUMM, YEXT[1], vget_high_f32(XX[0]), 0); + YEXT[2] = vextq_f32(YY[0], YY[1], 3); + SUMM = vmlaq_lane_f32(SUMM, YEXT[2], vget_high_f32(XX[0]), 1); + + YY[0] = YY[1]; + len -= 4; + } + + while (--len > 0) { + XX_2 = vld1_dup_f32(xi++); + SUMM = vmlaq_lane_f32(SUMM, YY[0], XX_2, 0); + YY[0]= vld1q_f32(++yi); + } + + XX_2 = vld1_dup_f32(xi); + SUMM = vmlaq_lane_f32(SUMM, YY[0], XX_2, 0); + + vst1q_f32(sum, SUMM); +} + +void celt_pitch_xcorr_float_neon(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch, int arch) { + int i; + (void)arch; + celt_assert(max_pitch > 0); + celt_sig_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0); + + for (i = 0; i < (max_pitch-3); i += 4) { + xcorr_kernel_neon_float((const float32_t *)_x, (const float32_t *)_y+i, + (float32_t *)xcorr+i, len); + } + + /* In case max_pitch isn't a multiple of 4, do non-unrolled version. */ + for (; i < max_pitch; i++) { + xcorr[i] = celt_inner_prod_neon(_x, _y+i, len); + } +} +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/celt_pitch_xcorr_arm.s b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/celt_pitch_xcorr_arm.s new file mode 100644 index 000000000..6e873afc3 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/celt_pitch_xcorr_arm.s @@ -0,0 +1,551 @@ +; Copyright (c) 2007-2008 CSIRO +; Copyright (c) 2007-2009 Xiph.Org Foundation +; Copyright (c) 2013 Parrot +; Written by Aurélien Zanelli +; +; Redistribution and use in source and binary forms, with or without +; modification, are permitted provided that the following conditions +; are met: +; +; - Redistributions of source code must retain the above copyright +; notice, this list of conditions and the following disclaimer. +; +; - 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. +; +; 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 OWNER +; 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. + + AREA |.text|, CODE, READONLY + + GET celt/arm/armopts.s + +IF OPUS_ARM_MAY_HAVE_EDSP + EXPORT celt_pitch_xcorr_edsp +ENDIF + +IF OPUS_ARM_MAY_HAVE_NEON + EXPORT celt_pitch_xcorr_neon +ENDIF + +IF OPUS_ARM_MAY_HAVE_NEON + +; Compute sum[k]=sum(x[j]*y[j+k],j=0...len-1), k=0...3 +xcorr_kernel_neon PROC +xcorr_kernel_neon_start + ; input: + ; r3 = int len + ; r4 = opus_val16 *x + ; r5 = opus_val16 *y + ; q0 = opus_val32 sum[4] + ; output: + ; q0 = opus_val32 sum[4] + ; preserved: r0-r3, r6-r11, d2, q4-q7, q9-q15 + ; internal usage: + ; r12 = int j + ; d3 = y_3|y_2|y_1|y_0 + ; q2 = y_B|y_A|y_9|y_8|y_7|y_6|y_5|y_4 + ; q3 = x_7|x_6|x_5|x_4|x_3|x_2|x_1|x_0 + ; q8 = scratch + ; + ; Load y[0...3] + ; This requires len>0 to always be valid (which we assert in the C code). + VLD1.16 {d5}, [r5]! + SUBS r12, r3, #8 + BLE xcorr_kernel_neon_process4 +; Process 8 samples at a time. +; This loop loads one y value more than we actually need. Therefore we have to +; stop as soon as there are 8 or fewer samples left (instead of 7), to avoid +; reading past the end of the array. +xcorr_kernel_neon_process8 + ; This loop has 19 total instructions (10 cycles to issue, minimum), with + ; - 2 cycles of ARM insrtuctions, + ; - 10 cycles of load/store/byte permute instructions, and + ; - 9 cycles of data processing instructions. + ; On a Cortex A8, we dual-issue the maximum amount (9 cycles) between the + ; latter two categories, meaning the whole loop should run in 10 cycles per + ; iteration, barring cache misses. + ; + ; Load x[0...7] + VLD1.16 {d6, d7}, [r4]! + ; Unlike VMOV, VAND is a data processsing instruction (and doesn't get + ; assembled to VMOV, like VORR would), so it dual-issues with the prior VLD1. + VAND d3, d5, d5 + SUBS r12, r12, #8 + ; Load y[4...11] + VLD1.16 {d4, d5}, [r5]! + VMLAL.S16 q0, d3, d6[0] + VEXT.16 d16, d3, d4, #1 + VMLAL.S16 q0, d4, d7[0] + VEXT.16 d17, d4, d5, #1 + VMLAL.S16 q0, d16, d6[1] + VEXT.16 d16, d3, d4, #2 + VMLAL.S16 q0, d17, d7[1] + VEXT.16 d17, d4, d5, #2 + VMLAL.S16 q0, d16, d6[2] + VEXT.16 d16, d3, d4, #3 + VMLAL.S16 q0, d17, d7[2] + VEXT.16 d17, d4, d5, #3 + VMLAL.S16 q0, d16, d6[3] + VMLAL.S16 q0, d17, d7[3] + BGT xcorr_kernel_neon_process8 +; Process 4 samples here if we have > 4 left (still reading one extra y value). +xcorr_kernel_neon_process4 + ADDS r12, r12, #4 + BLE xcorr_kernel_neon_process2 + ; Load x[0...3] + VLD1.16 d6, [r4]! + ; Use VAND since it's a data processing instruction again. + VAND d4, d5, d5 + SUB r12, r12, #4 + ; Load y[4...7] + VLD1.16 d5, [r5]! + VMLAL.S16 q0, d4, d6[0] + VEXT.16 d16, d4, d5, #1 + VMLAL.S16 q0, d16, d6[1] + VEXT.16 d16, d4, d5, #2 + VMLAL.S16 q0, d16, d6[2] + VEXT.16 d16, d4, d5, #3 + VMLAL.S16 q0, d16, d6[3] +; Process 2 samples here if we have > 2 left (still reading one extra y value). +xcorr_kernel_neon_process2 + ADDS r12, r12, #2 + BLE xcorr_kernel_neon_process1 + ; Load x[0...1] + VLD2.16 {d6[],d7[]}, [r4]! + ; Use VAND since it's a data processing instruction again. + VAND d4, d5, d5 + SUB r12, r12, #2 + ; Load y[4...5] + VLD1.32 {d5[]}, [r5]! + VMLAL.S16 q0, d4, d6 + VEXT.16 d16, d4, d5, #1 + ; Replace bottom copy of {y5,y4} in d5 with {y3,y2} from d4, using VSRI + ; instead of VEXT, since it's a data-processing instruction. + VSRI.64 d5, d4, #32 + VMLAL.S16 q0, d16, d7 +; Process 1 sample using the extra y value we loaded above. +xcorr_kernel_neon_process1 + ; Load next *x + VLD1.16 {d6[]}, [r4]! + ADDS r12, r12, #1 + ; y[0...3] are left in d5 from prior iteration(s) (if any) + VMLAL.S16 q0, d5, d6 + MOVLE pc, lr +; Now process 1 last sample, not reading ahead. + ; Load last *y + VLD1.16 {d4[]}, [r5]! + VSRI.64 d4, d5, #16 + ; Load last *x + VLD1.16 {d6[]}, [r4]! + VMLAL.S16 q0, d4, d6 + MOV pc, lr + ENDP + +; opus_val32 celt_pitch_xcorr_neon(opus_val16 *_x, opus_val16 *_y, +; opus_val32 *xcorr, int len, int max_pitch, int arch) +celt_pitch_xcorr_neon PROC + ; input: + ; r0 = opus_val16 *_x + ; r1 = opus_val16 *_y + ; r2 = opus_val32 *xcorr + ; r3 = int len + ; output: + ; r0 = int maxcorr + ; internal usage: + ; r4 = opus_val16 *x (for xcorr_kernel_neon()) + ; r5 = opus_val16 *y (for xcorr_kernel_neon()) + ; r6 = int max_pitch + ; r12 = int j + ; q15 = int maxcorr[4] (q15 is not used by xcorr_kernel_neon()) + ; ignored: + ; int arch + STMFD sp!, {r4-r6, lr} + LDR r6, [sp, #16] + VMOV.S32 q15, #1 + ; if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done + SUBS r6, r6, #4 + BLT celt_pitch_xcorr_neon_process4_done +celt_pitch_xcorr_neon_process4 + ; xcorr_kernel_neon parameters: + ; r3 = len, r4 = _x, r5 = _y, q0 = {0, 0, 0, 0} + MOV r4, r0 + MOV r5, r1 + VEOR q0, q0, q0 + ; xcorr_kernel_neon only modifies r4, r5, r12, and q0...q3. + ; So we don't save/restore any other registers. + BL xcorr_kernel_neon_start + SUBS r6, r6, #4 + VST1.32 {q0}, [r2]! + ; _y += 4 + ADD r1, r1, #8 + VMAX.S32 q15, q15, q0 + ; if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done + BGE celt_pitch_xcorr_neon_process4 +; We have less than 4 sums left to compute. +celt_pitch_xcorr_neon_process4_done + ADDS r6, r6, #4 + ; Reduce maxcorr to a single value + VMAX.S32 d30, d30, d31 + VPMAX.S32 d30, d30, d30 + ; if (max_pitch <= 0) goto celt_pitch_xcorr_neon_done + BLE celt_pitch_xcorr_neon_done +; Now compute each remaining sum one at a time. +celt_pitch_xcorr_neon_process_remaining + MOV r4, r0 + MOV r5, r1 + VMOV.I32 q0, #0 + SUBS r12, r3, #8 + BLT celt_pitch_xcorr_neon_process_remaining4 +; Sum terms 8 at a time. +celt_pitch_xcorr_neon_process_remaining_loop8 + ; Load x[0...7] + VLD1.16 {q1}, [r4]! + ; Load y[0...7] + VLD1.16 {q2}, [r5]! + SUBS r12, r12, #8 + VMLAL.S16 q0, d4, d2 + VMLAL.S16 q0, d5, d3 + BGE celt_pitch_xcorr_neon_process_remaining_loop8 +; Sum terms 4 at a time. +celt_pitch_xcorr_neon_process_remaining4 + ADDS r12, r12, #4 + BLT celt_pitch_xcorr_neon_process_remaining4_done + ; Load x[0...3] + VLD1.16 {d2}, [r4]! + ; Load y[0...3] + VLD1.16 {d3}, [r5]! + SUB r12, r12, #4 + VMLAL.S16 q0, d3, d2 +celt_pitch_xcorr_neon_process_remaining4_done + ; Reduce the sum to a single value. + VADD.S32 d0, d0, d1 + VPADDL.S32 d0, d0 + ADDS r12, r12, #4 + BLE celt_pitch_xcorr_neon_process_remaining_loop_done +; Sum terms 1 at a time. +celt_pitch_xcorr_neon_process_remaining_loop1 + VLD1.16 {d2[]}, [r4]! + VLD1.16 {d3[]}, [r5]! + SUBS r12, r12, #1 + VMLAL.S16 q0, d2, d3 + BGT celt_pitch_xcorr_neon_process_remaining_loop1 +celt_pitch_xcorr_neon_process_remaining_loop_done + VST1.32 {d0[0]}, [r2]! + VMAX.S32 d30, d30, d0 + SUBS r6, r6, #1 + ; _y++ + ADD r1, r1, #2 + ; if (--max_pitch > 0) goto celt_pitch_xcorr_neon_process_remaining + BGT celt_pitch_xcorr_neon_process_remaining +celt_pitch_xcorr_neon_done + VMOV.32 r0, d30[0] + LDMFD sp!, {r4-r6, pc} + ENDP + +ENDIF + +IF OPUS_ARM_MAY_HAVE_EDSP + +; This will get used on ARMv7 devices without NEON, so it has been optimized +; to take advantage of dual-issuing where possible. +xcorr_kernel_edsp PROC +xcorr_kernel_edsp_start + ; input: + ; r3 = int len + ; r4 = opus_val16 *_x (must be 32-bit aligned) + ; r5 = opus_val16 *_y (must be 32-bit aligned) + ; r6...r9 = opus_val32 sum[4] + ; output: + ; r6...r9 = opus_val32 sum[4] + ; preserved: r0-r5 + ; internal usage + ; r2 = int j + ; r12,r14 = opus_val16 x[4] + ; r10,r11 = opus_val16 y[4] + STMFD sp!, {r2,r4,r5,lr} + LDR r10, [r5], #4 ; Load y[0...1] + SUBS r2, r3, #4 ; j = len-4 + LDR r11, [r5], #4 ; Load y[2...3] + BLE xcorr_kernel_edsp_process4_done + LDR r12, [r4], #4 ; Load x[0...1] + ; Stall +xcorr_kernel_edsp_process4 + ; The multiplies must issue from pipeline 0, and can't dual-issue with each + ; other. Every other instruction here dual-issues with a multiply, and is + ; thus "free". There should be no stalls in the body of the loop. + SMLABB r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x_0,y_0) + LDR r14, [r4], #4 ; Load x[2...3] + SMLABT r7, r12, r10, r7 ; sum[1] = MAC16_16(sum[1],x_0,y_1) + SUBS r2, r2, #4 ; j-=4 + SMLABB r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x_0,y_2) + SMLABT r9, r12, r11, r9 ; sum[3] = MAC16_16(sum[3],x_0,y_3) + SMLATT r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x_1,y_1) + LDR r10, [r5], #4 ; Load y[4...5] + SMLATB r7, r12, r11, r7 ; sum[1] = MAC16_16(sum[1],x_1,y_2) + SMLATT r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x_1,y_3) + SMLATB r9, r12, r10, r9 ; sum[3] = MAC16_16(sum[3],x_1,y_4) + LDRGT r12, [r4], #4 ; Load x[0...1] + SMLABB r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],x_2,y_2) + SMLABT r7, r14, r11, r7 ; sum[1] = MAC16_16(sum[1],x_2,y_3) + SMLABB r8, r14, r10, r8 ; sum[2] = MAC16_16(sum[2],x_2,y_4) + SMLABT r9, r14, r10, r9 ; sum[3] = MAC16_16(sum[3],x_2,y_5) + SMLATT r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],x_3,y_3) + LDR r11, [r5], #4 ; Load y[6...7] + SMLATB r7, r14, r10, r7 ; sum[1] = MAC16_16(sum[1],x_3,y_4) + SMLATT r8, r14, r10, r8 ; sum[2] = MAC16_16(sum[2],x_3,y_5) + SMLATB r9, r14, r11, r9 ; sum[3] = MAC16_16(sum[3],x_3,y_6) + BGT xcorr_kernel_edsp_process4 +xcorr_kernel_edsp_process4_done + ADDS r2, r2, #4 + BLE xcorr_kernel_edsp_done + LDRH r12, [r4], #2 ; r12 = *x++ + SUBS r2, r2, #1 ; j-- + ; Stall + SMLABB r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x,y_0) + LDRHGT r14, [r4], #2 ; r14 = *x++ + SMLABT r7, r12, r10, r7 ; sum[1] = MAC16_16(sum[1],x,y_1) + SMLABB r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x,y_2) + SMLABT r9, r12, r11, r9 ; sum[3] = MAC16_16(sum[3],x,y_3) + BLE xcorr_kernel_edsp_done + SMLABT r6, r14, r10, r6 ; sum[0] = MAC16_16(sum[0],x,y_1) + SUBS r2, r2, #1 ; j-- + SMLABB r7, r14, r11, r7 ; sum[1] = MAC16_16(sum[1],x,y_2) + LDRH r10, [r5], #2 ; r10 = y_4 = *y++ + SMLABT r8, r14, r11, r8 ; sum[2] = MAC16_16(sum[2],x,y_3) + LDRHGT r12, [r4], #2 ; r12 = *x++ + SMLABB r9, r14, r10, r9 ; sum[3] = MAC16_16(sum[3],x,y_4) + BLE xcorr_kernel_edsp_done + SMLABB r6, r12, r11, r6 ; sum[0] = MAC16_16(sum[0],tmp,y_2) + CMP r2, #1 ; j-- + SMLABT r7, r12, r11, r7 ; sum[1] = MAC16_16(sum[1],tmp,y_3) + LDRH r2, [r5], #2 ; r2 = y_5 = *y++ + SMLABB r8, r12, r10, r8 ; sum[2] = MAC16_16(sum[2],tmp,y_4) + LDRHGT r14, [r4] ; r14 = *x + SMLABB r9, r12, r2, r9 ; sum[3] = MAC16_16(sum[3],tmp,y_5) + BLE xcorr_kernel_edsp_done + SMLABT r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],tmp,y_3) + LDRH r11, [r5] ; r11 = y_6 = *y + SMLABB r7, r14, r10, r7 ; sum[1] = MAC16_16(sum[1],tmp,y_4) + SMLABB r8, r14, r2, r8 ; sum[2] = MAC16_16(sum[2],tmp,y_5) + SMLABB r9, r14, r11, r9 ; sum[3] = MAC16_16(sum[3],tmp,y_6) +xcorr_kernel_edsp_done + LDMFD sp!, {r2,r4,r5,pc} + ENDP + +celt_pitch_xcorr_edsp PROC + ; input: + ; r0 = opus_val16 *_x (must be 32-bit aligned) + ; r1 = opus_val16 *_y (only needs to be 16-bit aligned) + ; r2 = opus_val32 *xcorr + ; r3 = int len + ; output: + ; r0 = maxcorr + ; internal usage + ; r4 = opus_val16 *x + ; r5 = opus_val16 *y + ; r6 = opus_val32 sum0 + ; r7 = opus_val32 sum1 + ; r8 = opus_val32 sum2 + ; r9 = opus_val32 sum3 + ; r1 = int max_pitch + ; r12 = int j + ; ignored: + ; int arch + STMFD sp!, {r4-r11, lr} + MOV r5, r1 + LDR r1, [sp, #36] + MOV r4, r0 + TST r5, #3 + ; maxcorr = 1 + MOV r0, #1 + BEQ celt_pitch_xcorr_edsp_process1u_done +; Compute one sum at the start to make y 32-bit aligned. + SUBS r12, r3, #4 + ; r14 = sum = 0 + MOV r14, #0 + LDRH r8, [r5], #2 + BLE celt_pitch_xcorr_edsp_process1u_loop4_done + LDR r6, [r4], #4 + MOV r8, r8, LSL #16 +celt_pitch_xcorr_edsp_process1u_loop4 + LDR r9, [r5], #4 + SMLABT r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0) + LDR r7, [r4], #4 + SMLATB r14, r6, r9, r14 ; sum = MAC16_16(sum, x_1, y_1) + LDR r8, [r5], #4 + SMLABT r14, r7, r9, r14 ; sum = MAC16_16(sum, x_2, y_2) + SUBS r12, r12, #4 ; j-=4 + SMLATB r14, r7, r8, r14 ; sum = MAC16_16(sum, x_3, y_3) + LDRGT r6, [r4], #4 + BGT celt_pitch_xcorr_edsp_process1u_loop4 + MOV r8, r8, LSR #16 +celt_pitch_xcorr_edsp_process1u_loop4_done + ADDS r12, r12, #4 +celt_pitch_xcorr_edsp_process1u_loop1 + LDRHGE r6, [r4], #2 + ; Stall + SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, *x, *y) + SUBSGE r12, r12, #1 + LDRHGT r8, [r5], #2 + BGT celt_pitch_xcorr_edsp_process1u_loop1 + ; Restore _x + SUB r4, r4, r3, LSL #1 + ; Restore and advance _y + SUB r5, r5, r3, LSL #1 + ; maxcorr = max(maxcorr, sum) + CMP r0, r14 + ADD r5, r5, #2 + MOVLT r0, r14 + SUBS r1, r1, #1 + ; xcorr[i] = sum + STR r14, [r2], #4 + BLE celt_pitch_xcorr_edsp_done +celt_pitch_xcorr_edsp_process1u_done + ; if (max_pitch < 4) goto celt_pitch_xcorr_edsp_process2 + SUBS r1, r1, #4 + BLT celt_pitch_xcorr_edsp_process2 +celt_pitch_xcorr_edsp_process4 + ; xcorr_kernel_edsp parameters: + ; r3 = len, r4 = _x, r5 = _y, r6...r9 = sum[4] = {0, 0, 0, 0} + MOV r6, #0 + MOV r7, #0 + MOV r8, #0 + MOV r9, #0 + BL xcorr_kernel_edsp_start ; xcorr_kernel_edsp(_x, _y+i, xcorr+i, len) + ; maxcorr = max(maxcorr, sum0, sum1, sum2, sum3) + CMP r0, r6 + ; _y+=4 + ADD r5, r5, #8 + MOVLT r0, r6 + CMP r0, r7 + MOVLT r0, r7 + CMP r0, r8 + MOVLT r0, r8 + CMP r0, r9 + MOVLT r0, r9 + STMIA r2!, {r6-r9} + SUBS r1, r1, #4 + BGE celt_pitch_xcorr_edsp_process4 +celt_pitch_xcorr_edsp_process2 + ADDS r1, r1, #2 + BLT celt_pitch_xcorr_edsp_process1a + SUBS r12, r3, #4 + ; {r10, r11} = {sum0, sum1} = {0, 0} + MOV r10, #0 + MOV r11, #0 + LDR r8, [r5], #4 + BLE celt_pitch_xcorr_edsp_process2_loop_done + LDR r6, [r4], #4 + LDR r9, [r5], #4 +celt_pitch_xcorr_edsp_process2_loop4 + SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0) + LDR r7, [r4], #4 + SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1) + SUBS r12, r12, #4 ; j-=4 + SMLATT r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_1, y_1) + LDR r8, [r5], #4 + SMLATB r11, r6, r9, r11 ; sum1 = MAC16_16(sum1, x_1, y_2) + LDRGT r6, [r4], #4 + SMLABB r10, r7, r9, r10 ; sum0 = MAC16_16(sum0, x_2, y_2) + SMLABT r11, r7, r9, r11 ; sum1 = MAC16_16(sum1, x_2, y_3) + SMLATT r10, r7, r9, r10 ; sum0 = MAC16_16(sum0, x_3, y_3) + LDRGT r9, [r5], #4 + SMLATB r11, r7, r8, r11 ; sum1 = MAC16_16(sum1, x_3, y_4) + BGT celt_pitch_xcorr_edsp_process2_loop4 +celt_pitch_xcorr_edsp_process2_loop_done + ADDS r12, r12, #2 + BLE celt_pitch_xcorr_edsp_process2_1 + LDR r6, [r4], #4 + ; Stall + SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0) + LDR r9, [r5], #4 + SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1) + SUB r12, r12, #2 + SMLATT r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_1, y_1) + MOV r8, r9 + SMLATB r11, r6, r9, r11 ; sum1 = MAC16_16(sum1, x_1, y_2) +celt_pitch_xcorr_edsp_process2_1 + LDRH r6, [r4], #2 + ADDS r12, r12, #1 + ; Stall + SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0) + LDRHGT r7, [r4], #2 + SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1) + BLE celt_pitch_xcorr_edsp_process2_done + LDRH r9, [r5], #2 + SMLABT r10, r7, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_1) + SMLABB r11, r7, r9, r11 ; sum1 = MAC16_16(sum1, x_0, y_2) +celt_pitch_xcorr_edsp_process2_done + ; Restore _x + SUB r4, r4, r3, LSL #1 + ; Restore and advance _y + SUB r5, r5, r3, LSL #1 + ; maxcorr = max(maxcorr, sum0) + CMP r0, r10 + ADD r5, r5, #2 + MOVLT r0, r10 + SUB r1, r1, #2 + ; maxcorr = max(maxcorr, sum1) + CMP r0, r11 + ; xcorr[i] = sum + STR r10, [r2], #4 + MOVLT r0, r11 + STR r11, [r2], #4 +celt_pitch_xcorr_edsp_process1a + ADDS r1, r1, #1 + BLT celt_pitch_xcorr_edsp_done + SUBS r12, r3, #4 + ; r14 = sum = 0 + MOV r14, #0 + BLT celt_pitch_xcorr_edsp_process1a_loop_done + LDR r6, [r4], #4 + LDR r8, [r5], #4 + LDR r7, [r4], #4 + LDR r9, [r5], #4 +celt_pitch_xcorr_edsp_process1a_loop4 + SMLABB r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0) + SUBS r12, r12, #4 ; j-=4 + SMLATT r14, r6, r8, r14 ; sum = MAC16_16(sum, x_1, y_1) + LDRGE r6, [r4], #4 + SMLABB r14, r7, r9, r14 ; sum = MAC16_16(sum, x_2, y_2) + LDRGE r8, [r5], #4 + SMLATT r14, r7, r9, r14 ; sum = MAC16_16(sum, x_3, y_3) + LDRGE r7, [r4], #4 + LDRGE r9, [r5], #4 + BGE celt_pitch_xcorr_edsp_process1a_loop4 +celt_pitch_xcorr_edsp_process1a_loop_done + ADDS r12, r12, #2 + LDRGE r6, [r4], #4 + LDRGE r8, [r5], #4 + ; Stall + SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0) + SUBGE r12, r12, #2 + SMLATTGE r14, r6, r8, r14 ; sum = MAC16_16(sum, x_1, y_1) + ADDS r12, r12, #1 + LDRHGE r6, [r4], #2 + LDRHGE r8, [r5], #2 + ; Stall + SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, *x, *y) + ; maxcorr = max(maxcorr, sum) + CMP r0, r14 + ; xcorr[i] = sum + STR r14, [r2], #4 + MOVLT r0, r14 +celt_pitch_xcorr_edsp_done + LDMFD sp!, {r4-r11, pc} + ENDP + +ENDIF + +END diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/fft_arm.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/fft_arm.h new file mode 100644 index 000000000..0b78175f3 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/fft_arm.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2015 Xiph.Org Foundation + Written by Viswanath Puttagunta */ +/** + @file fft_arm.h + @brief ARM Neon Intrinsic optimizations for fft using NE10 library + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + + +#if !defined(FFT_ARM_H) +#define FFT_ARM_H + +#include "kiss_fft.h" + +#if defined(HAVE_ARM_NE10) + +int opus_fft_alloc_arm_neon(kiss_fft_state *st); +void opus_fft_free_arm_neon(kiss_fft_state *st); + +void opus_fft_neon(const kiss_fft_state *st, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout); + +void opus_ifft_neon(const kiss_fft_state *st, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout); + +#if !defined(OPUS_HAVE_RTCD) +#define OVERRIDE_OPUS_FFT (1) + +#define opus_fft_alloc_arch(_st, arch) \ + ((void)(arch), opus_fft_alloc_arm_neon(_st)) + +#define opus_fft_free_arch(_st, arch) \ + ((void)(arch), opus_fft_free_arm_neon(_st)) + +#define opus_fft(_st, _fin, _fout, arch) \ + ((void)(arch), opus_fft_neon(_st, _fin, _fout)) + +#define opus_ifft(_st, _fin, _fout, arch) \ + ((void)(arch), opus_ifft_neon(_st, _fin, _fout)) + +#endif /* OPUS_HAVE_RTCD */ + +#endif /* HAVE_ARM_NE10 */ + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/fixed_arm64.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/fixed_arm64.h new file mode 100644 index 000000000..c6fbd3db2 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/fixed_arm64.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2015 Vidyo */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef FIXED_ARM64_H +#define FIXED_ARM64_H + +#include + +#undef SIG2WORD16 +#define SIG2WORD16(x) (vqmovns_s32(PSHR32((x), SIG_SHIFT))) + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/fixed_armv4.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/fixed_armv4.h new file mode 100644 index 000000000..d84888a77 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/fixed_armv4.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2013 Xiph.Org Foundation and contributors */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef FIXED_ARMv4_H +#define FIXED_ARMv4_H + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#undef MULT16_32_Q16 +static OPUS_INLINE opus_val32 MULT16_32_Q16_armv4(opus_val16 a, opus_val32 b) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#MULT16_32_Q16\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(b),"r"(SHL32(a,16)) + ); + return rd_hi; +} +#define MULT16_32_Q16(a, b) (MULT16_32_Q16_armv4(a, b)) + + +/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */ +#undef MULT16_32_Q15 +static OPUS_INLINE opus_val32 MULT16_32_Q15_armv4(opus_val16 a, opus_val32 b) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#MULT16_32_Q15\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(b), "r"(SHL32(a,16)) + ); + /*We intentionally don't OR in the high bit of rd_lo for speed.*/ + return SHL32(rd_hi,1); +} +#define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv4(a, b)) + + +/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add. + b must fit in 31 bits. + Result fits in 32 bits. */ +#undef MAC16_32_Q15 +#define MAC16_32_Q15(c, a, b) ADD32(c, MULT16_32_Q15(a, b)) + +/** 16x32 multiply, followed by a 16-bit shift right and 32-bit add. + Result fits in 32 bits. */ +#undef MAC16_32_Q16 +#define MAC16_32_Q16(c, a, b) ADD32(c, MULT16_32_Q16(a, b)) + +/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */ +#undef MULT32_32_Q31 +#define MULT32_32_Q31(a,b) (opus_val32)((((opus_int64)(a)) * ((opus_int64)(b)))>>31) + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/fixed_armv5e.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/fixed_armv5e.h new file mode 100644 index 000000000..6bf73cbac --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/fixed_armv5e.h @@ -0,0 +1,151 @@ +/* Copyright (C) 2007-2009 Xiph.Org Foundation + Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2008 CSIRO + Copyright (C) 2013 Parrot */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef FIXED_ARMv5E_H +#define FIXED_ARMv5E_H + +#include "fixed_armv4.h" + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#undef MULT16_32_Q16 +static OPUS_INLINE opus_val32 MULT16_32_Q16_armv5e(opus_val16 a, opus_val32 b) +{ + int res; + __asm__( + "#MULT16_32_Q16\n\t" + "smulwb %0, %1, %2\n\t" + : "=r"(res) + : "r"(b),"r"(a) + ); + return res; +} +#define MULT16_32_Q16(a, b) (MULT16_32_Q16_armv5e(a, b)) + + +/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */ +#undef MULT16_32_Q15 +static OPUS_INLINE opus_val32 MULT16_32_Q15_armv5e(opus_val16 a, opus_val32 b) +{ + int res; + __asm__( + "#MULT16_32_Q15\n\t" + "smulwb %0, %1, %2\n\t" + : "=r"(res) + : "r"(b), "r"(a) + ); + return SHL32(res,1); +} +#define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv5e(a, b)) + + +/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add. + b must fit in 31 bits. + Result fits in 32 bits. */ +#undef MAC16_32_Q15 +static OPUS_INLINE opus_val32 MAC16_32_Q15_armv5e(opus_val32 c, opus_val16 a, + opus_val32 b) +{ + int res; + __asm__( + "#MAC16_32_Q15\n\t" + "smlawb %0, %1, %2, %3;\n" + : "=r"(res) + : "r"(SHL32(b,1)), "r"(a), "r"(c) + ); + return res; +} +#define MAC16_32_Q15(c, a, b) (MAC16_32_Q15_armv5e(c, a, b)) + +/** 16x32 multiply, followed by a 16-bit shift right and 32-bit add. + Result fits in 32 bits. */ +#undef MAC16_32_Q16 +static OPUS_INLINE opus_val32 MAC16_32_Q16_armv5e(opus_val32 c, opus_val16 a, + opus_val32 b) +{ + int res; + __asm__( + "#MAC16_32_Q16\n\t" + "smlawb %0, %1, %2, %3;\n" + : "=r"(res) + : "r"(b), "r"(a), "r"(c) + ); + return res; +} +#define MAC16_32_Q16(c, a, b) (MAC16_32_Q16_armv5e(c, a, b)) + +/** 16x16 multiply-add where the result fits in 32 bits */ +#undef MAC16_16 +static OPUS_INLINE opus_val32 MAC16_16_armv5e(opus_val32 c, opus_val16 a, + opus_val16 b) +{ + int res; + __asm__( + "#MAC16_16\n\t" + "smlabb %0, %1, %2, %3;\n" + : "=r"(res) + : "r"(a), "r"(b), "r"(c) + ); + return res; +} +#define MAC16_16(c, a, b) (MAC16_16_armv5e(c, a, b)) + +/** 16x16 multiplication where the result fits in 32 bits */ +#undef MULT16_16 +static OPUS_INLINE opus_val32 MULT16_16_armv5e(opus_val16 a, opus_val16 b) +{ + int res; + __asm__( + "#MULT16_16\n\t" + "smulbb %0, %1, %2;\n" + : "=r"(res) + : "r"(a), "r"(b) + ); + return res; +} +#define MULT16_16(a, b) (MULT16_16_armv5e(a, b)) + +#ifdef OPUS_ARM_INLINE_MEDIA + +#undef SIG2WORD16 +static OPUS_INLINE opus_val16 SIG2WORD16_armv6(opus_val32 x) +{ + celt_sig res; + __asm__( + "#SIG2WORD16\n\t" + "ssat %0, #16, %1, ASR #12\n\t" + : "=r"(res) + : "r"(x+2048) + ); + return EXTRACT16(res); +} +#define SIG2WORD16(x) (SIG2WORD16_armv6(x)) + +#endif /* OPUS_ARM_INLINE_MEDIA */ + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/kiss_fft_armv4.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/kiss_fft_armv4.h new file mode 100644 index 000000000..e4faad6f2 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/kiss_fft_armv4.h @@ -0,0 +1,121 @@ +/*Copyright (c) 2013, Xiph.Org Foundation and contributors. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * 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. + + 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 OWNER 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.*/ + +#ifndef KISS_FFT_ARMv4_H +#define KISS_FFT_ARMv4_H + +#if !defined(KISS_FFT_GUTS_H) +#error "This file should only be included from _kiss_fft_guts.h" +#endif + +#ifdef FIXED_POINT + +#undef C_MUL +#define C_MUL(m,a,b) \ + do{ \ + int br__; \ + int bi__; \ + int tt__; \ + __asm__ __volatile__( \ + "#C_MUL\n\t" \ + "ldrsh %[br], [%[bp], #0]\n\t" \ + "ldm %[ap], {r0,r1}\n\t" \ + "ldrsh %[bi], [%[bp], #2]\n\t" \ + "smull %[tt], %[mi], r1, %[br]\n\t" \ + "smlal %[tt], %[mi], r0, %[bi]\n\t" \ + "rsb %[bi], %[bi], #0\n\t" \ + "smull %[br], %[mr], r0, %[br]\n\t" \ + "mov %[tt], %[tt], lsr #15\n\t" \ + "smlal %[br], %[mr], r1, %[bi]\n\t" \ + "orr %[mi], %[tt], %[mi], lsl #17\n\t" \ + "mov %[br], %[br], lsr #15\n\t" \ + "orr %[mr], %[br], %[mr], lsl #17\n\t" \ + : [mr]"=r"((m).r), [mi]"=r"((m).i), \ + [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \ + : [ap]"r"(&(a)), [bp]"r"(&(b)) \ + : "r0", "r1" \ + ); \ + } \ + while(0) + +#undef C_MUL4 +#define C_MUL4(m,a,b) \ + do{ \ + int br__; \ + int bi__; \ + int tt__; \ + __asm__ __volatile__( \ + "#C_MUL4\n\t" \ + "ldrsh %[br], [%[bp], #0]\n\t" \ + "ldm %[ap], {r0,r1}\n\t" \ + "ldrsh %[bi], [%[bp], #2]\n\t" \ + "smull %[tt], %[mi], r1, %[br]\n\t" \ + "smlal %[tt], %[mi], r0, %[bi]\n\t" \ + "rsb %[bi], %[bi], #0\n\t" \ + "smull %[br], %[mr], r0, %[br]\n\t" \ + "mov %[tt], %[tt], lsr #17\n\t" \ + "smlal %[br], %[mr], r1, %[bi]\n\t" \ + "orr %[mi], %[tt], %[mi], lsl #15\n\t" \ + "mov %[br], %[br], lsr #17\n\t" \ + "orr %[mr], %[br], %[mr], lsl #15\n\t" \ + : [mr]"=r"((m).r), [mi]"=r"((m).i), \ + [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \ + : [ap]"r"(&(a)), [bp]"r"(&(b)) \ + : "r0", "r1" \ + ); \ + } \ + while(0) + +#undef C_MULC +#define C_MULC(m,a,b) \ + do{ \ + int br__; \ + int bi__; \ + int tt__; \ + __asm__ __volatile__( \ + "#C_MULC\n\t" \ + "ldrsh %[br], [%[bp], #0]\n\t" \ + "ldm %[ap], {r0,r1}\n\t" \ + "ldrsh %[bi], [%[bp], #2]\n\t" \ + "smull %[tt], %[mr], r0, %[br]\n\t" \ + "smlal %[tt], %[mr], r1, %[bi]\n\t" \ + "rsb %[bi], %[bi], #0\n\t" \ + "smull %[br], %[mi], r1, %[br]\n\t" \ + "mov %[tt], %[tt], lsr #15\n\t" \ + "smlal %[br], %[mi], r0, %[bi]\n\t" \ + "orr %[mr], %[tt], %[mr], lsl #17\n\t" \ + "mov %[br], %[br], lsr #15\n\t" \ + "orr %[mi], %[br], %[mi], lsl #17\n\t" \ + : [mr]"=r"((m).r), [mi]"=r"((m).i), \ + [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \ + : [ap]"r"(&(a)), [bp]"r"(&(b)) \ + : "r0", "r1" \ + ); \ + } \ + while(0) + +#endif /* FIXED_POINT */ + +#endif /* KISS_FFT_ARMv4_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/kiss_fft_armv5e.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/kiss_fft_armv5e.h new file mode 100644 index 000000000..9eca183d7 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/kiss_fft_armv5e.h @@ -0,0 +1,118 @@ +/*Copyright (c) 2013, Xiph.Org Foundation and contributors. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * 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. + + 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 OWNER 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.*/ + +#ifndef KISS_FFT_ARMv5E_H +#define KISS_FFT_ARMv5E_H + +#if !defined(KISS_FFT_GUTS_H) +#error "This file should only be included from _kiss_fft_guts.h" +#endif + +#ifdef FIXED_POINT + +#if defined(__thumb__)||defined(__thumb2__) +#define LDRD_CONS "Q" +#else +#define LDRD_CONS "Uq" +#endif + +#undef C_MUL +#define C_MUL(m,a,b) \ + do{ \ + int mr1__; \ + int mr2__; \ + int mi__; \ + long long aval__; \ + int bval__; \ + __asm__( \ + "#C_MUL\n\t" \ + "ldrd %[aval], %H[aval], %[ap]\n\t" \ + "ldr %[bval], %[bp]\n\t" \ + "smulwb %[mi], %H[aval], %[bval]\n\t" \ + "smulwb %[mr1], %[aval], %[bval]\n\t" \ + "smulwt %[mr2], %H[aval], %[bval]\n\t" \ + "smlawt %[mi], %[aval], %[bval], %[mi]\n\t" \ + : [mr1]"=r"(mr1__), [mr2]"=r"(mr2__), [mi]"=r"(mi__), \ + [aval]"=&r"(aval__), [bval]"=r"(bval__) \ + : [ap]LDRD_CONS(a), [bp]"m"(b) \ + ); \ + (m).r = SHL32(SUB32(mr1__, mr2__), 1); \ + (m).i = SHL32(mi__, 1); \ + } \ + while(0) + +#undef C_MUL4 +#define C_MUL4(m,a,b) \ + do{ \ + int mr1__; \ + int mr2__; \ + int mi__; \ + long long aval__; \ + int bval__; \ + __asm__( \ + "#C_MUL4\n\t" \ + "ldrd %[aval], %H[aval], %[ap]\n\t" \ + "ldr %[bval], %[bp]\n\t" \ + "smulwb %[mi], %H[aval], %[bval]\n\t" \ + "smulwb %[mr1], %[aval], %[bval]\n\t" \ + "smulwt %[mr2], %H[aval], %[bval]\n\t" \ + "smlawt %[mi], %[aval], %[bval], %[mi]\n\t" \ + : [mr1]"=r"(mr1__), [mr2]"=r"(mr2__), [mi]"=r"(mi__), \ + [aval]"=&r"(aval__), [bval]"=r"(bval__) \ + : [ap]LDRD_CONS(a), [bp]"m"(b) \ + ); \ + (m).r = SHR32(SUB32(mr1__, mr2__), 1); \ + (m).i = SHR32(mi__, 1); \ + } \ + while(0) + +#undef C_MULC +#define C_MULC(m,a,b) \ + do{ \ + int mr__; \ + int mi1__; \ + int mi2__; \ + long long aval__; \ + int bval__; \ + __asm__( \ + "#C_MULC\n\t" \ + "ldrd %[aval], %H[aval], %[ap]\n\t" \ + "ldr %[bval], %[bp]\n\t" \ + "smulwb %[mr], %[aval], %[bval]\n\t" \ + "smulwb %[mi1], %H[aval], %[bval]\n\t" \ + "smulwt %[mi2], %[aval], %[bval]\n\t" \ + "smlawt %[mr], %H[aval], %[bval], %[mr]\n\t" \ + : [mr]"=r"(mr__), [mi1]"=r"(mi1__), [mi2]"=r"(mi2__), \ + [aval]"=&r"(aval__), [bval]"=r"(bval__) \ + : [ap]LDRD_CONS(a), [bp]"m"(b) \ + ); \ + (m).r = SHL32(mr__, 1); \ + (m).i = SHL32(SUB32(mi1__, mi2__), 1); \ + } \ + while(0) + +#endif /* FIXED_POINT */ + +#endif /* KISS_FFT_GUTS_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/mdct_arm.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/mdct_arm.h new file mode 100644 index 000000000..14200bac4 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/mdct_arm.h @@ -0,0 +1,59 @@ +/* Copyright (c) 2015 Xiph.Org Foundation + Written by Viswanath Puttagunta */ +/** + @file arm_mdct.h + @brief ARM Neon Intrinsic optimizations for mdct using NE10 library + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#if !defined(MDCT_ARM_H) +#define MDCT_ARM_H + +#include "mdct.h" + +#if defined(HAVE_ARM_NE10) +/** Compute a forward MDCT and scale by 4/N, trashes the input array */ +void clt_mdct_forward_neon(const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, + int shift, int stride, int arch); + +void clt_mdct_backward_neon(const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, + int shift, int stride, int arch); + +#if !defined(OPUS_HAVE_RTCD) +#define OVERRIDE_OPUS_MDCT (1) +#define clt_mdct_forward(_l, _in, _out, _window, _int, _shift, _stride, _arch) \ + clt_mdct_forward_neon(_l, _in, _out, _window, _int, _shift, _stride, _arch) +#define clt_mdct_backward(_l, _in, _out, _window, _int, _shift, _stride, _arch) \ + clt_mdct_backward_neon(_l, _in, _out, _window, _int, _shift, _stride, _arch) +#endif /* OPUS_HAVE_RTCD */ +#endif /* HAVE_ARM_NE10 */ + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/pitch_arm.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/pitch_arm.h new file mode 100644 index 000000000..bed8b04ea --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/pitch_arm.h @@ -0,0 +1,160 @@ +/* Copyright (c) 2010 Xiph.Org Foundation + * Copyright (c) 2013 Parrot */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#if !defined(PITCH_ARM_H) +# define PITCH_ARM_H + +# include "armcpu.h" + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +opus_val32 celt_inner_prod_neon(const opus_val16 *x, const opus_val16 *y, int N); +void dual_inner_prod_neon(const opus_val16 *x, const opus_val16 *y01, + const opus_val16 *y02, int N, opus_val32 *xy1, opus_val32 *xy2); + +# if !defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_PRESUME_NEON) +# define OVERRIDE_CELT_INNER_PROD (1) +# define OVERRIDE_DUAL_INNER_PROD (1) +# define celt_inner_prod(x, y, N, arch) ((void)(arch), PRESUME_NEON(celt_inner_prod)(x, y, N)) +# define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) ((void)(arch), PRESUME_NEON(dual_inner_prod)(x, y01, y02, N, xy1, xy2)) +# endif +# endif + +# if !defined(OVERRIDE_CELT_INNER_PROD) +# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern opus_val32 (*const CELT_INNER_PROD_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *x, const opus_val16 *y, int N); +# define OVERRIDE_CELT_INNER_PROD (1) +# define celt_inner_prod(x, y, N, arch) ((*CELT_INNER_PROD_IMPL[(arch)&OPUS_ARCHMASK])(x, y, N)) +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_CELT_INNER_PROD (1) +# define celt_inner_prod(x, y, N, arch) ((void)(arch), celt_inner_prod_neon(x, y, N)) +# endif +# endif + +# if !defined(OVERRIDE_DUAL_INNER_PROD) +# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern void (*const DUAL_INNER_PROD_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *x, + const opus_val16 *y01, const opus_val16 *y02, int N, opus_val32 *xy1, opus_val32 *xy2); +# define OVERRIDE_DUAL_INNER_PROD (1) +# define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) ((*DUAL_INNER_PROD_IMPL[(arch)&OPUS_ARCHMASK])(x, y01, y02, N, xy1, xy2)) +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_DUAL_INNER_PROD (1) +# define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) ((void)(arch), dual_inner_prod_neon(x, y01, y02, N, xy1, xy2)) +# endif +# endif + +# if defined(FIXED_POINT) + +# if defined(OPUS_ARM_MAY_HAVE_NEON) +opus_val32 celt_pitch_xcorr_neon(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch, int arch); +# endif + +# if defined(OPUS_ARM_MAY_HAVE_MEDIA) +# define celt_pitch_xcorr_media MAY_HAVE_EDSP(celt_pitch_xcorr) +# endif + +# if defined(OPUS_ARM_MAY_HAVE_EDSP) +opus_val32 celt_pitch_xcorr_edsp(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch, int arch); +# endif + +# if defined(OPUS_HAVE_RTCD) && \ + ((defined(OPUS_ARM_MAY_HAVE_NEON) && !defined(OPUS_ARM_PRESUME_NEON)) || \ + (defined(OPUS_ARM_MAY_HAVE_MEDIA) && !defined(OPUS_ARM_PRESUME_MEDIA)) || \ + (defined(OPUS_ARM_MAY_HAVE_EDSP) && !defined(OPUS_ARM_PRESUME_EDSP))) +extern opus_val32 +(*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *, + const opus_val16 *, opus_val32 *, int, int, int); +# define OVERRIDE_PITCH_XCORR (1) +# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \ + ((*CELT_PITCH_XCORR_IMPL[(arch)&OPUS_ARCHMASK])(_x, _y, \ + xcorr, len, max_pitch, arch)) + +# elif defined(OPUS_ARM_PRESUME_EDSP) || \ + defined(OPUS_ARM_PRESUME_MEDIA) || \ + defined(OPUS_ARM_PRESUME_NEON) +# define OVERRIDE_PITCH_XCORR (1) +# define celt_pitch_xcorr (PRESUME_NEON(celt_pitch_xcorr)) + +# endif + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +void xcorr_kernel_neon_fixed( + const opus_val16 *x, + const opus_val16 *y, + opus_val32 sum[4], + int len); +# endif + +# if defined(OPUS_HAVE_RTCD) && \ + (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) + +extern void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])( + const opus_val16 *x, + const opus_val16 *y, + opus_val32 sum[4], + int len); + +# define OVERRIDE_XCORR_KERNEL (1) +# define xcorr_kernel(x, y, sum, len, arch) \ + ((*XCORR_KERNEL_IMPL[(arch) & OPUS_ARCHMASK])(x, y, sum, len)) + +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_XCORR_KERNEL (1) +# define xcorr_kernel(x, y, sum, len, arch) \ + ((void)arch, xcorr_kernel_neon_fixed(x, y, sum, len)) + +# endif + +#else /* Start !FIXED_POINT */ +/* Float case */ +#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +void celt_pitch_xcorr_float_neon(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch, int arch); +#endif + +# if defined(OPUS_HAVE_RTCD) && \ + (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern void +(*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *, + const opus_val16 *, opus_val32 *, int, int, int); + +# define OVERRIDE_PITCH_XCORR (1) +# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \ + ((*CELT_PITCH_XCORR_IMPL[(arch)&OPUS_ARCHMASK])(_x, _y, \ + xcorr, len, max_pitch, arch)) + +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) + +# define OVERRIDE_PITCH_XCORR (1) +# define celt_pitch_xcorr celt_pitch_xcorr_float_neon + +# endif + +#endif /* end !FIXED_POINT */ + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/pitch_neon_intr.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/pitch_neon_intr.c new file mode 100644 index 000000000..1ac38c433 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/arm/pitch_neon_intr.c @@ -0,0 +1,290 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "pitch.h" + +#ifdef FIXED_POINT + +opus_val32 celt_inner_prod_neon(const opus_val16 *x, const opus_val16 *y, int N) +{ + int i; + opus_val32 xy; + int16x8_t x_s16x8, y_s16x8; + int32x4_t xy_s32x4 = vdupq_n_s32(0); + int64x2_t xy_s64x2; + int64x1_t xy_s64x1; + + for (i = 0; i < N - 7; i += 8) { + x_s16x8 = vld1q_s16(&x[i]); + y_s16x8 = vld1q_s16(&y[i]); + xy_s32x4 = vmlal_s16(xy_s32x4, vget_low_s16 (x_s16x8), vget_low_s16 (y_s16x8)); + xy_s32x4 = vmlal_s16(xy_s32x4, vget_high_s16(x_s16x8), vget_high_s16(y_s16x8)); + } + + if (N - i >= 4) { + const int16x4_t x_s16x4 = vld1_s16(&x[i]); + const int16x4_t y_s16x4 = vld1_s16(&y[i]); + xy_s32x4 = vmlal_s16(xy_s32x4, x_s16x4, y_s16x4); + i += 4; + } + + xy_s64x2 = vpaddlq_s32(xy_s32x4); + xy_s64x1 = vadd_s64(vget_low_s64(xy_s64x2), vget_high_s64(xy_s64x2)); + xy = vget_lane_s32(vreinterpret_s32_s64(xy_s64x1), 0); + + for (; i < N; i++) { + xy = MAC16_16(xy, x[i], y[i]); + } + +#ifdef OPUS_CHECK_ASM + celt_assert(celt_inner_prod_c(x, y, N) == xy); +#endif + + return xy; +} + +void dual_inner_prod_neon(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2) +{ + int i; + opus_val32 xy01, xy02; + int16x8_t x_s16x8, y01_s16x8, y02_s16x8; + int32x4_t xy01_s32x4 = vdupq_n_s32(0); + int32x4_t xy02_s32x4 = vdupq_n_s32(0); + int64x2_t xy01_s64x2, xy02_s64x2; + int64x1_t xy01_s64x1, xy02_s64x1; + + for (i = 0; i < N - 7; i += 8) { + x_s16x8 = vld1q_s16(&x[i]); + y01_s16x8 = vld1q_s16(&y01[i]); + y02_s16x8 = vld1q_s16(&y02[i]); + xy01_s32x4 = vmlal_s16(xy01_s32x4, vget_low_s16 (x_s16x8), vget_low_s16 (y01_s16x8)); + xy02_s32x4 = vmlal_s16(xy02_s32x4, vget_low_s16 (x_s16x8), vget_low_s16 (y02_s16x8)); + xy01_s32x4 = vmlal_s16(xy01_s32x4, vget_high_s16(x_s16x8), vget_high_s16(y01_s16x8)); + xy02_s32x4 = vmlal_s16(xy02_s32x4, vget_high_s16(x_s16x8), vget_high_s16(y02_s16x8)); + } + + if (N - i >= 4) { + const int16x4_t x_s16x4 = vld1_s16(&x[i]); + const int16x4_t y01_s16x4 = vld1_s16(&y01[i]); + const int16x4_t y02_s16x4 = vld1_s16(&y02[i]); + xy01_s32x4 = vmlal_s16(xy01_s32x4, x_s16x4, y01_s16x4); + xy02_s32x4 = vmlal_s16(xy02_s32x4, x_s16x4, y02_s16x4); + i += 4; + } + + xy01_s64x2 = vpaddlq_s32(xy01_s32x4); + xy02_s64x2 = vpaddlq_s32(xy02_s32x4); + xy01_s64x1 = vadd_s64(vget_low_s64(xy01_s64x2), vget_high_s64(xy01_s64x2)); + xy02_s64x1 = vadd_s64(vget_low_s64(xy02_s64x2), vget_high_s64(xy02_s64x2)); + xy01 = vget_lane_s32(vreinterpret_s32_s64(xy01_s64x1), 0); + xy02 = vget_lane_s32(vreinterpret_s32_s64(xy02_s64x1), 0); + + for (; i < N; i++) { + xy01 = MAC16_16(xy01, x[i], y01[i]); + xy02 = MAC16_16(xy02, x[i], y02[i]); + } + *xy1 = xy01; + *xy2 = xy02; + +#ifdef OPUS_CHECK_ASM + { + opus_val32 xy1_c, xy2_c; + dual_inner_prod_c(x, y01, y02, N, &xy1_c, &xy2_c); + celt_assert(xy1_c == *xy1); + celt_assert(xy2_c == *xy2); + } +#endif +} + +#else /* !FIXED_POINT */ + +/* ========================================================================== */ + +#ifdef OPUS_CHECK_ASM + +/* This part of code simulates floating-point NEON operations. */ + +/* celt_inner_prod_neon_float_c_simulation() simulates the floating-point */ +/* operations of celt_inner_prod_neon(), and both functions should have bit */ +/* exact output. */ +static opus_val32 celt_inner_prod_neon_float_c_simulation(const opus_val16 *x, const opus_val16 *y, int N) +{ + int i; + opus_val32 xy, xy0 = 0, xy1 = 0, xy2 = 0, xy3 = 0; + for (i = 0; i < N - 3; i += 4) { + xy0 = MAC16_16(xy0, x[i + 0], y[i + 0]); + xy1 = MAC16_16(xy1, x[i + 1], y[i + 1]); + xy2 = MAC16_16(xy2, x[i + 2], y[i + 2]); + xy3 = MAC16_16(xy3, x[i + 3], y[i + 3]); + } + xy0 += xy2; + xy1 += xy3; + xy = xy0 + xy1; + for (; i < N; i++) { + xy = MAC16_16(xy, x[i], y[i]); + } + return xy; +} + +/* dual_inner_prod_neon_float_c_simulation() simulates the floating-point */ +/* operations of dual_inner_prod_neon(), and both functions should have bit */ +/* exact output. */ +static void dual_inner_prod_neon_float_c_simulation(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2) +{ + int i; + opus_val32 xy01, xy02, xy01_0 = 0, xy01_1 = 0, xy01_2 = 0, xy01_3 = 0, xy02_0 = 0, xy02_1 = 0, xy02_2 = 0, xy02_3 = 0; + for (i = 0; i < N - 3; i += 4) { + xy01_0 = MAC16_16(xy01_0, x[i + 0], y01[i + 0]); + xy01_1 = MAC16_16(xy01_1, x[i + 1], y01[i + 1]); + xy01_2 = MAC16_16(xy01_2, x[i + 2], y01[i + 2]); + xy01_3 = MAC16_16(xy01_3, x[i + 3], y01[i + 3]); + xy02_0 = MAC16_16(xy02_0, x[i + 0], y02[i + 0]); + xy02_1 = MAC16_16(xy02_1, x[i + 1], y02[i + 1]); + xy02_2 = MAC16_16(xy02_2, x[i + 2], y02[i + 2]); + xy02_3 = MAC16_16(xy02_3, x[i + 3], y02[i + 3]); + } + xy01_0 += xy01_2; + xy02_0 += xy02_2; + xy01_1 += xy01_3; + xy02_1 += xy02_3; + xy01 = xy01_0 + xy01_1; + xy02 = xy02_0 + xy02_1; + for (; i < N; i++) { + xy01 = MAC16_16(xy01, x[i], y01[i]); + xy02 = MAC16_16(xy02, x[i], y02[i]); + } + *xy1 = xy01; + *xy2 = xy02; +} + +#endif /* OPUS_CHECK_ASM */ + +/* ========================================================================== */ + +opus_val32 celt_inner_prod_neon(const opus_val16 *x, const opus_val16 *y, int N) +{ + int i; + opus_val32 xy; + float32x4_t xy_f32x4 = vdupq_n_f32(0); + float32x2_t xy_f32x2; + + for (i = 0; i < N - 7; i += 8) { + float32x4_t x_f32x4, y_f32x4; + x_f32x4 = vld1q_f32(&x[i]); + y_f32x4 = vld1q_f32(&y[i]); + xy_f32x4 = vmlaq_f32(xy_f32x4, x_f32x4, y_f32x4); + x_f32x4 = vld1q_f32(&x[i + 4]); + y_f32x4 = vld1q_f32(&y[i + 4]); + xy_f32x4 = vmlaq_f32(xy_f32x4, x_f32x4, y_f32x4); + } + + if (N - i >= 4) { + const float32x4_t x_f32x4 = vld1q_f32(&x[i]); + const float32x4_t y_f32x4 = vld1q_f32(&y[i]); + xy_f32x4 = vmlaq_f32(xy_f32x4, x_f32x4, y_f32x4); + i += 4; + } + + xy_f32x2 = vadd_f32(vget_low_f32(xy_f32x4), vget_high_f32(xy_f32x4)); + xy_f32x2 = vpadd_f32(xy_f32x2, xy_f32x2); + xy = vget_lane_f32(xy_f32x2, 0); + + for (; i < N; i++) { + xy = MAC16_16(xy, x[i], y[i]); + } + +#ifdef OPUS_CHECK_ASM + celt_assert(ABS32(celt_inner_prod_neon_float_c_simulation(x, y, N) - xy) <= VERY_SMALL); +#endif + + return xy; +} + +void dual_inner_prod_neon(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2) +{ + int i; + opus_val32 xy01, xy02; + float32x4_t xy01_f32x4 = vdupq_n_f32(0); + float32x4_t xy02_f32x4 = vdupq_n_f32(0); + float32x2_t xy01_f32x2, xy02_f32x2; + + for (i = 0; i < N - 7; i += 8) { + float32x4_t x_f32x4, y01_f32x4, y02_f32x4; + x_f32x4 = vld1q_f32(&x[i]); + y01_f32x4 = vld1q_f32(&y01[i]); + y02_f32x4 = vld1q_f32(&y02[i]); + xy01_f32x4 = vmlaq_f32(xy01_f32x4, x_f32x4, y01_f32x4); + xy02_f32x4 = vmlaq_f32(xy02_f32x4, x_f32x4, y02_f32x4); + x_f32x4 = vld1q_f32(&x[i + 4]); + y01_f32x4 = vld1q_f32(&y01[i + 4]); + y02_f32x4 = vld1q_f32(&y02[i + 4]); + xy01_f32x4 = vmlaq_f32(xy01_f32x4, x_f32x4, y01_f32x4); + xy02_f32x4 = vmlaq_f32(xy02_f32x4, x_f32x4, y02_f32x4); + } + + if (N - i >= 4) { + const float32x4_t x_f32x4 = vld1q_f32(&x[i]); + const float32x4_t y01_f32x4 = vld1q_f32(&y01[i]); + const float32x4_t y02_f32x4 = vld1q_f32(&y02[i]); + xy01_f32x4 = vmlaq_f32(xy01_f32x4, x_f32x4, y01_f32x4); + xy02_f32x4 = vmlaq_f32(xy02_f32x4, x_f32x4, y02_f32x4); + i += 4; + } + + xy01_f32x2 = vadd_f32(vget_low_f32(xy01_f32x4), vget_high_f32(xy01_f32x4)); + xy02_f32x2 = vadd_f32(vget_low_f32(xy02_f32x4), vget_high_f32(xy02_f32x4)); + xy01_f32x2 = vpadd_f32(xy01_f32x2, xy01_f32x2); + xy02_f32x2 = vpadd_f32(xy02_f32x2, xy02_f32x2); + xy01 = vget_lane_f32(xy01_f32x2, 0); + xy02 = vget_lane_f32(xy02_f32x2, 0); + + for (; i < N; i++) { + xy01 = MAC16_16(xy01, x[i], y01[i]); + xy02 = MAC16_16(xy02, x[i], y02[i]); + } + *xy1 = xy01; + *xy2 = xy02; + +#ifdef OPUS_CHECK_ASM + { + opus_val32 xy1_c, xy2_c; + dual_inner_prod_neon_float_c_simulation(x, y01, y02, N, &xy1_c, &xy2_c); + celt_assert(ABS32(xy1_c - *xy1) <= VERY_SMALL); + celt_assert(ABS32(xy2_c - *xy2) <= VERY_SMALL); + } +#endif +} + +#endif /* FIXED_POINT */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/bands.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/bands.c new file mode 100644 index 000000000..2702963c3 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/bands.c @@ -0,0 +1,1672 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008-2009 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "bands.h" +#include "modes.h" +#include "vq.h" +#include "cwrs.h" +#include "stack_alloc.h" +#include "os_support.h" +#include "mathops.h" +#include "rate.h" +#include "quant_bands.h" +#include "pitch.h" + +int hysteresis_decision(opus_val16 val, const opus_val16 *thresholds, const opus_val16 *hysteresis, int N, int prev) +{ + int i; + for (i=0;iprev && val < thresholds[prev]+hysteresis[prev]) + i=prev; + if (i thresholds[prev-1]-hysteresis[prev-1]) + i=prev; + return i; +} + +opus_uint32 celt_lcg_rand(opus_uint32 seed) +{ + return 1664525 * seed + 1013904223; +} + +/* This is a cos() approximation designed to be bit-exact on any platform. Bit exactness + with this approximation is important because it has an impact on the bit allocation */ +opus_int16 bitexact_cos(opus_int16 x) +{ + opus_int32 tmp; + opus_int16 x2; + tmp = (4096+((opus_int32)(x)*(x)))>>13; + celt_sig_assert(tmp<=32767); + x2 = tmp; + x2 = (32767-x2) + FRAC_MUL16(x2, (-7651 + FRAC_MUL16(x2, (8277 + FRAC_MUL16(-626, x2))))); + celt_sig_assert(x2<=32766); + return 1+x2; +} + +int bitexact_log2tan(int isin,int icos) +{ + int lc; + int ls; + lc=EC_ILOG(icos); + ls=EC_ILOG(isin); + icos<<=15-lc; + isin<<=15-ls; + return (ls-lc)*(1<<11) + +FRAC_MUL16(isin, FRAC_MUL16(isin, -2597) + 7932) + -FRAC_MUL16(icos, FRAC_MUL16(icos, -2597) + 7932); +} + +#ifdef FIXED_POINT +/* Compute the amplitude (sqrt energy) in each of the bands */ +void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM, int arch) +{ + int i, c, N; + const opus_int16 *eBands = m->eBands; + (void)arch; + N = m->shortMdctSize< 0) + { + int shift = celt_ilog2(maxval) - 14 + (((m->logN[i]>>BITRES)+LM+1)>>1); + j=eBands[i]<0) + { + do { + sum = MAC16_16(sum, EXTRACT16(SHR32(X[j+c*N],shift)), + EXTRACT16(SHR32(X[j+c*N],shift))); + } while (++jnbEBands] = EPSILON+VSHR32(EXTEND32(celt_sqrt(sum)),-shift); + } else { + bandE[i+c*m->nbEBands] = EPSILON; + } + /*printf ("%f ", bandE[i+c*m->nbEBands]);*/ + } + } while (++ceBands; + N = M*m->shortMdctSize; + c=0; do { + i=0; do { + opus_val16 g; + int j,shift; + opus_val16 E; + shift = celt_zlog2(bandE[i+c*m->nbEBands])-13; + E = VSHR32(bandE[i+c*m->nbEBands], shift); + g = EXTRACT16(celt_rcp(SHL32(E,3))); + j=M*eBands[i]; do { + X[j+c*N] = MULT16_16_Q15(VSHR32(freq[j+c*N],shift-1),g); + } while (++jeBands; + N = m->shortMdctSize<nbEBands] = celt_sqrt(sum); + /*printf ("%f ", bandE[i+c*m->nbEBands]);*/ + } + } while (++ceBands; + N = M*m->shortMdctSize; + c=0; do { + for (i=0;inbEBands]); + for (j=M*eBands[i];jeBands; + N = M*m->shortMdctSize; + bound = M*eBands[end]; + if (downsample!=1) + bound = IMIN(bound, N/downsample); + if (silence) + { + bound = 0; + start = end = 0; + } + f = freq; + x = X+M*eBands[start]; + for (i=0;i>DB_SHIFT); + if (shift>31) + { + shift=0; + g=0; + } else { + /* Handle the fractional part. */ + g = celt_exp2_frac(lg&((1< 16384 we'd be likely to overflow, so we're + capping the gain here, which is equivalent to a cap of 18 on lg. + This shouldn't trigger unless the bitstream is already corrupted. */ + if (shift <= -2) + { + g = 16384; + shift = -2; + } + do { + *f++ = SHL32(MULT16_16(*x++, g), -shift); + } while (++jeBands[i+1]-m->eBands[i]; + /* depth in 1/8 bits */ + celt_sig_assert(pulses[i]>=0); + depth = celt_udiv(1+pulses[i], (m->eBands[i+1]-m->eBands[i]))>>LM; + +#ifdef FIXED_POINT + thresh32 = SHR32(celt_exp2(-SHL16(depth, 10-BITRES)),1); + thresh = MULT16_32_Q15(QCONST16(0.5f, 15), MIN32(32767,thresh32)); + { + opus_val32 t; + t = N0<>1; + t = SHL32(t, (7-shift)<<1); + sqrt_1 = celt_rsqrt_norm(t); + } +#else + thresh = .5f*celt_exp2(-.125f*depth); + sqrt_1 = celt_rsqrt(N0<nbEBands+i]; + prev2 = prev2logE[c*m->nbEBands+i]; + if (C==1) + { + prev1 = MAX16(prev1,prev1logE[m->nbEBands+i]); + prev2 = MAX16(prev2,prev2logE[m->nbEBands+i]); + } + Ediff = EXTEND32(logE[c*m->nbEBands+i])-EXTEND32(MIN16(prev1,prev2)); + Ediff = MAX32(0, Ediff); + +#ifdef FIXED_POINT + if (Ediff < 16384) + { + opus_val32 r32 = SHR32(celt_exp2(-EXTRACT16(Ediff)),1); + r = 2*MIN16(16383,r32); + } else { + r = 0; + } + if (LM==3) + r = MULT16_16_Q14(23170, MIN32(23169, r)); + r = SHR16(MIN16(thresh, r),1); + r = SHR32(MULT16_16_Q15(sqrt_1, r),shift); +#else + /* r needs to be multiplied by 2 or 2*sqrt(2) depending on LM because + short blocks don't have the same energy as long */ + r = 2.f*celt_exp2(-Ediff); + if (LM==3) + r *= 1.41421356f; + r = MIN16(thresh, r); + r = r*sqrt_1; +#endif + X = X_+c*size+(m->eBands[i]<nbEBands]))-13; +#endif + left = VSHR32(bandE[i],shift); + right = VSHR32(bandE[i+m->nbEBands],shift); + norm = EPSILON + celt_sqrt(EPSILON+MULT16_16(left,left)+MULT16_16(right,right)); + a1 = DIV32_16(SHL32(EXTEND32(left),14),norm); + a2 = DIV32_16(SHL32(EXTEND32(right),14),norm); + for (j=0;j>1; + kr = celt_ilog2(Er)>>1; +#endif + t = VSHR32(El, (kl-7)<<1); + lgain = celt_rsqrt_norm(t); + t = VSHR32(Er, (kr-7)<<1); + rgain = celt_rsqrt_norm(t); + +#ifdef FIXED_POINT + if (kl < 7) + kl = 7; + if (kr < 7) + kr = 7; +#endif + + for (j=0;jeBands; + int decision; + int hf_sum=0; + + celt_assert(end>0); + + N0 = M*m->shortMdctSize; + + if (M*(eBands[end]-eBands[end-1]) <= 8) + return SPREAD_NONE; + c=0; do { + for (i=0;im->nbEBands-4) + hf_sum += celt_udiv(32*(tcount[1]+tcount[0]), N); + tmp = (2*tcount[2] >= N) + (2*tcount[1] >= N) + (2*tcount[0] >= N); + sum += tmp*spread_weight[i]; + nbBands+=spread_weight[i]; + } + } while (++cnbEBands+end)); + *hf_average = (*hf_average+hf_sum)>>1; + hf_sum = *hf_average; + if (*tapset_decision==2) + hf_sum += 4; + else if (*tapset_decision==0) + hf_sum -= 4; + if (hf_sum > 22) + *tapset_decision=2; + else if (hf_sum > 18) + *tapset_decision=1; + else + *tapset_decision=0; + } + /*printf("%d %d %d\n", hf_sum, *hf_average, *tapset_decision);*/ + celt_assert(nbBands>0); /* end has to be non-zero */ + celt_assert(sum>=0); + sum = celt_udiv((opus_int32)sum<<8, nbBands); + /* Recursive averaging */ + sum = (sum+*average)>>1; + *average = sum; + /* Hysteresis */ + sum = (3*sum + (((3-last_decision)<<7) + 64) + 2)>>2; + if (sum < 80) + { + decision = SPREAD_AGGRESSIVE; + } else if (sum < 256) + { + decision = SPREAD_NORMAL; + } else if (sum < 384) + { + decision = SPREAD_LIGHT; + } else { + decision = SPREAD_NONE; + } +#ifdef FUZZING + decision = rand()&0x3; + *tapset_decision=rand()%3; +#endif + return decision; +} + +/* Indexing table for converting from natural Hadamard to ordery Hadamard + This is essentially a bit-reversed Gray, on top of which we've added + an inversion of the order because we want the DC at the end rather than + the beginning. The lines are for N=2, 4, 8, 16 */ +static const int ordery_table[] = { + 1, 0, + 3, 0, 2, 1, + 7, 0, 4, 3, 6, 1, 5, 2, + 15, 0, 8, 7, 12, 3, 11, 4, 14, 1, 9, 6, 13, 2, 10, 5, +}; + +static void deinterleave_hadamard(celt_norm *X, int N0, int stride, int hadamard) +{ + int i,j; + VARDECL(celt_norm, tmp); + int N; + SAVE_STACK; + N = N0*stride; + ALLOC(tmp, N, celt_norm); + celt_assert(stride>0); + if (hadamard) + { + const int *ordery = ordery_table+stride-2; + for (i=0;i>= 1; + for (i=0;i>1)) { + qn = 1; + } else { + qn = exp2_table8[qb&0x7]>>(14-(qb>>BITRES)); + qn = (qn+1)>>1<<1; + } + celt_assert(qn <= 256); + return qn; +} + +struct band_ctx { + int encode; + int resynth; + const CELTMode *m; + int i; + int intensity; + int spread; + int tf_change; + ec_ctx *ec; + opus_int32 remaining_bits; + const celt_ener *bandE; + opus_uint32 seed; + int arch; + int theta_round; + int disable_inv; + int avoid_split_noise; +}; + +struct split_ctx { + int inv; + int imid; + int iside; + int delta; + int itheta; + int qalloc; +}; + +static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx, + celt_norm *X, celt_norm *Y, int N, int *b, int B, int B0, + int LM, + int stereo, int *fill) +{ + int qn; + int itheta=0; + int delta; + int imid, iside; + int qalloc; + int pulse_cap; + int offset; + opus_int32 tell; + int inv=0; + int encode; + const CELTMode *m; + int i; + int intensity; + ec_ctx *ec; + const celt_ener *bandE; + + encode = ctx->encode; + m = ctx->m; + i = ctx->i; + intensity = ctx->intensity; + ec = ctx->ec; + bandE = ctx->bandE; + + /* Decide on the resolution to give to the split parameter theta */ + pulse_cap = m->logN[i]+LM*(1<>1) - (stereo&&N==2 ? QTHETA_OFFSET_TWOPHASE : QTHETA_OFFSET); + qn = compute_qn(N, *b, offset, pulse_cap, stereo); + if (stereo && i>=intensity) + qn = 1; + if (encode) + { + /* theta is the atan() of the ratio between the (normalized) + side and mid. With just that parameter, we can re-scale both + mid and side because we know that 1) they have unit norm and + 2) they are orthogonal. */ + itheta = stereo_itheta(X, Y, stereo, N, ctx->arch); + } + tell = ec_tell_frac(ec); + if (qn!=1) + { + if (encode) + { + if (!stereo || ctx->theta_round == 0) + { + itheta = (itheta*(opus_int32)qn+8192)>>14; + if (!stereo && ctx->avoid_split_noise && itheta > 0 && itheta < qn) + { + /* Check if the selected value of theta will cause the bit allocation + to inject noise on one side. If so, make sure the energy of that side + is zero. */ + int unquantized = celt_udiv((opus_int32)itheta*16384, qn); + imid = bitexact_cos((opus_int16)unquantized); + iside = bitexact_cos((opus_int16)(16384-unquantized)); + delta = FRAC_MUL16((N-1)<<7,bitexact_log2tan(iside,imid)); + if (delta > *b) + itheta = qn; + else if (delta < -*b) + itheta = 0; + } + } else { + int down; + /* Bias quantization towards itheta=0 and itheta=16384. */ + int bias = itheta > 8192 ? 32767/qn : -32767/qn; + down = IMIN(qn-1, IMAX(0, (itheta*(opus_int32)qn + bias)>>14)); + if (ctx->theta_round < 0) + itheta = down; + else + itheta = down+1; + } + } + /* Entropy coding of the angle. We use a uniform pdf for the + time split, a step for stereo, and a triangular one for the rest. */ + if (stereo && N>2) + { + int p0 = 3; + int x = itheta; + int x0 = qn/2; + int ft = p0*(x0+1) + x0; + /* Use a probability of p0 up to itheta=8192 and then use 1 after */ + if (encode) + { + ec_encode(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft); + } else { + int fs; + fs=ec_decode(ec,ft); + if (fs<(x0+1)*p0) + x=fs/p0; + else + x=x0+1+(fs-(x0+1)*p0); + ec_dec_update(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft); + itheta = x; + } + } else if (B0>1 || stereo) { + /* Uniform pdf */ + if (encode) + ec_enc_uint(ec, itheta, qn+1); + else + itheta = ec_dec_uint(ec, qn+1); + } else { + int fs=1, ft; + ft = ((qn>>1)+1)*((qn>>1)+1); + if (encode) + { + int fl; + + fs = itheta <= (qn>>1) ? itheta + 1 : qn + 1 - itheta; + fl = itheta <= (qn>>1) ? itheta*(itheta + 1)>>1 : + ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1); + + ec_encode(ec, fl, fl+fs, ft); + } else { + /* Triangular pdf */ + int fl=0; + int fm; + fm = ec_decode(ec, ft); + + if (fm < ((qn>>1)*((qn>>1) + 1)>>1)) + { + itheta = (isqrt32(8*(opus_uint32)fm + 1) - 1)>>1; + fs = itheta + 1; + fl = itheta*(itheta + 1)>>1; + } + else + { + itheta = (2*(qn + 1) + - isqrt32(8*(opus_uint32)(ft - fm - 1) + 1))>>1; + fs = qn + 1 - itheta; + fl = ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1); + } + + ec_dec_update(ec, fl, fl+fs, ft); + } + } + celt_assert(itheta>=0); + itheta = celt_udiv((opus_int32)itheta*16384, qn); + if (encode && stereo) + { + if (itheta==0) + intensity_stereo(m, X, Y, bandE, i, N); + else + stereo_split(X, Y, N); + } + /* NOTE: Renormalising X and Y *may* help fixed-point a bit at very high rate. + Let's do that at higher complexity */ + } else if (stereo) { + if (encode) + { + inv = itheta > 8192 && !ctx->disable_inv; + if (inv) + { + int j; + for (j=0;j2<remaining_bits > 2<disable_inv) + inv = 0; + itheta = 0; + } + qalloc = ec_tell_frac(ec) - tell; + *b -= qalloc; + + if (itheta == 0) + { + imid = 32767; + iside = 0; + *fill &= (1<inv = inv; + sctx->imid = imid; + sctx->iside = iside; + sctx->delta = delta; + sctx->itheta = itheta; + sctx->qalloc = qalloc; +} +static unsigned quant_band_n1(struct band_ctx *ctx, celt_norm *X, celt_norm *Y, int b, + celt_norm *lowband_out) +{ + int c; + int stereo; + celt_norm *x = X; + int encode; + ec_ctx *ec; + + encode = ctx->encode; + ec = ctx->ec; + + stereo = Y != NULL; + c=0; do { + int sign=0; + if (ctx->remaining_bits>=1<remaining_bits -= 1<resynth) + x[0] = sign ? -NORM_SCALING : NORM_SCALING; + x = Y; + } while (++c<1+stereo); + if (lowband_out) + lowband_out[0] = SHR16(X[0],4); + return 1; +} + +/* This function is responsible for encoding and decoding a mono partition. + It can split the band in two and transmit the energy difference with + the two half-bands. It can be called recursively so bands can end up being + split in 8 parts. */ +static unsigned quant_partition(struct band_ctx *ctx, celt_norm *X, + int N, int b, int B, celt_norm *lowband, + int LM, + opus_val16 gain, int fill) +{ + const unsigned char *cache; + int q; + int curr_bits; + int imid=0, iside=0; + int B0=B; + opus_val16 mid=0, side=0; + unsigned cm=0; + celt_norm *Y=NULL; + int encode; + const CELTMode *m; + int i; + int spread; + ec_ctx *ec; + + encode = ctx->encode; + m = ctx->m; + i = ctx->i; + spread = ctx->spread; + ec = ctx->ec; + + /* If we need 1.5 more bit than we can produce, split the band in two. */ + cache = m->cache.bits + m->cache.index[(LM+1)*m->nbEBands+i]; + if (LM != -1 && b > cache[cache[0]]+12 && N>2) + { + int mbits, sbits, delta; + int itheta; + int qalloc; + struct split_ctx sctx; + celt_norm *next_lowband2=NULL; + opus_int32 rebalance; + + N >>= 1; + Y = X+N; + LM -= 1; + if (B==1) + fill = (fill&1)|(fill<<1); + B = (B+1)>>1; + + compute_theta(ctx, &sctx, X, Y, N, &b, B, B0, LM, 0, &fill); + imid = sctx.imid; + iside = sctx.iside; + delta = sctx.delta; + itheta = sctx.itheta; + qalloc = sctx.qalloc; +#ifdef FIXED_POINT + mid = imid; + side = iside; +#else + mid = (1.f/32768)*imid; + side = (1.f/32768)*iside; +#endif + + /* Give more bits to low-energy MDCTs than they would otherwise deserve */ + if (B0>1 && (itheta&0x3fff)) + { + if (itheta > 8192) + /* Rough approximation for pre-echo masking */ + delta -= delta>>(4-LM); + else + /* Corresponds to a forward-masking slope of 1.5 dB per 10 ms */ + delta = IMIN(0, delta + (N<>(5-LM))); + } + mbits = IMAX(0, IMIN(b, (b-delta)/2)); + sbits = b-mbits; + ctx->remaining_bits -= qalloc; + + if (lowband) + next_lowband2 = lowband+N; /* >32-bit split case */ + + rebalance = ctx->remaining_bits; + if (mbits >= sbits) + { + cm = quant_partition(ctx, X, N, mbits, B, lowband, LM, + MULT16_16_P15(gain,mid), fill); + rebalance = mbits - (rebalance-ctx->remaining_bits); + if (rebalance > 3<>B)<<(B0>>1); + } else { + cm = quant_partition(ctx, Y, N, sbits, B, next_lowband2, LM, + MULT16_16_P15(gain,side), fill>>B)<<(B0>>1); + rebalance = sbits - (rebalance-ctx->remaining_bits); + if (rebalance > 3<remaining_bits -= curr_bits; + + /* Ensures we can never bust the budget */ + while (ctx->remaining_bits < 0 && q > 0) + { + ctx->remaining_bits += curr_bits; + q--; + curr_bits = pulses2bits(m, i, LM, q); + ctx->remaining_bits -= curr_bits; + } + + if (q!=0) + { + int K = get_pulses(q); + + /* Finally do the actual quantization */ + if (encode) + { + cm = alg_quant(X, N, K, spread, B, ec, gain, ctx->resynth, ctx->arch); + } else { + cm = alg_unquant(X, N, K, spread, B, ec, gain); + } + } else { + /* If there's no pulse, fill the band anyway */ + int j; + if (ctx->resynth) + { + unsigned cm_mask; + /* B can be as large as 16, so this shift might overflow an int on a + 16-bit platform; use a long to get defined behavior.*/ + cm_mask = (unsigned)(1UL<seed = celt_lcg_rand(ctx->seed); + X[j] = (celt_norm)((opus_int32)ctx->seed>>20); + } + cm = cm_mask; + } else { + /* Folded spectrum */ + for (j=0;jseed = celt_lcg_rand(ctx->seed); + /* About 48 dB below the "normal" folding level */ + tmp = QCONST16(1.0f/256, 10); + tmp = (ctx->seed)&0x8000 ? tmp : -tmp; + X[j] = lowband[j]+tmp; + } + cm = fill; + } + renormalise_vector(X, N, gain, ctx->arch); + } + } + } + } + + return cm; +} + + +/* This function is responsible for encoding and decoding a band for the mono case. */ +static unsigned quant_band(struct band_ctx *ctx, celt_norm *X, + int N, int b, int B, celt_norm *lowband, + int LM, celt_norm *lowband_out, + opus_val16 gain, celt_norm *lowband_scratch, int fill) +{ + int N0=N; + int N_B=N; + int N_B0; + int B0=B; + int time_divide=0; + int recombine=0; + int longBlocks; + unsigned cm=0; + int k; + int encode; + int tf_change; + + encode = ctx->encode; + tf_change = ctx->tf_change; + + longBlocks = B0==1; + + N_B = celt_udiv(N_B, B); + + /* Special case for one sample */ + if (N==1) + { + return quant_band_n1(ctx, X, NULL, b, lowband_out); + } + + if (tf_change>0) + recombine = tf_change; + /* Band recombining to increase frequency resolution */ + + if (lowband_scratch && lowband && (recombine || ((N_B&1) == 0 && tf_change<0) || B0>1)) + { + OPUS_COPY(lowband_scratch, lowband, N); + lowband = lowband_scratch; + } + + for (k=0;k>k, 1<>k, 1<>4]<<2; + } + B>>=recombine; + N_B<<=recombine; + + /* Increasing the time resolution */ + while ((N_B&1) == 0 && tf_change<0) + { + if (encode) + haar1(X, N_B, B); + if (lowband) + haar1(lowband, N_B, B); + fill |= fill<>= 1; + time_divide++; + tf_change++; + } + B0=B; + N_B0 = N_B; + + /* Reorganize the samples in time order instead of frequency order */ + if (B0>1) + { + if (encode) + deinterleave_hadamard(X, N_B>>recombine, B0<>recombine, B0<resynth) + { + /* Undo the sample reorganization going from time order to frequency order */ + if (B0>1) + interleave_hadamard(X, N_B>>recombine, B0<>= 1; + N_B <<= 1; + cm |= cm>>B; + haar1(X, N_B, B); + } + + for (k=0;k>k, 1<encode; + ec = ctx->ec; + + /* Special case for one sample */ + if (N==1) + { + return quant_band_n1(ctx, X, Y, b, lowband_out); + } + + orig_fill = fill; + + compute_theta(ctx, &sctx, X, Y, N, &b, B, B, LM, 1, &fill); + inv = sctx.inv; + imid = sctx.imid; + iside = sctx.iside; + delta = sctx.delta; + itheta = sctx.itheta; + qalloc = sctx.qalloc; +#ifdef FIXED_POINT + mid = imid; + side = iside; +#else + mid = (1.f/32768)*imid; + side = (1.f/32768)*iside; +#endif + + /* This is a special case for N=2 that only works for stereo and takes + advantage of the fact that mid and side are orthogonal to encode + the side with just one bit. */ + if (N==2) + { + int c; + int sign=0; + celt_norm *x2, *y2; + mbits = b; + sbits = 0; + /* Only need one bit for the side. */ + if (itheta != 0 && itheta != 16384) + sbits = 1< 8192; + ctx->remaining_bits -= qalloc+sbits; + + x2 = c ? Y : X; + y2 = c ? X : Y; + if (sbits) + { + if (encode) + { + /* Here we only need to encode a sign for the side. */ + sign = x2[0]*y2[1] - x2[1]*y2[0] < 0; + ec_enc_bits(ec, sign, 1); + } else { + sign = ec_dec_bits(ec, 1); + } + } + sign = 1-2*sign; + /* We use orig_fill here because we want to fold the side, but if + itheta==16384, we'll have cleared the low bits of fill. */ + cm = quant_band(ctx, x2, N, mbits, B, lowband, LM, lowband_out, Q15ONE, + lowband_scratch, orig_fill); + /* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse), + and there's no need to worry about mixing with the other channel. */ + y2[0] = -sign*x2[1]; + y2[1] = sign*x2[0]; + if (ctx->resynth) + { + celt_norm tmp; + X[0] = MULT16_16_Q15(mid, X[0]); + X[1] = MULT16_16_Q15(mid, X[1]); + Y[0] = MULT16_16_Q15(side, Y[0]); + Y[1] = MULT16_16_Q15(side, Y[1]); + tmp = X[0]; + X[0] = SUB16(tmp,Y[0]); + Y[0] = ADD16(tmp,Y[0]); + tmp = X[1]; + X[1] = SUB16(tmp,Y[1]); + Y[1] = ADD16(tmp,Y[1]); + } + } else { + /* "Normal" split code */ + opus_int32 rebalance; + + mbits = IMAX(0, IMIN(b, (b-delta)/2)); + sbits = b-mbits; + ctx->remaining_bits -= qalloc; + + rebalance = ctx->remaining_bits; + if (mbits >= sbits) + { + /* In stereo mode, we do not apply a scaling to the mid because we need the normalized + mid for folding later. */ + cm = quant_band(ctx, X, N, mbits, B, lowband, LM, lowband_out, Q15ONE, + lowband_scratch, fill); + rebalance = mbits - (rebalance-ctx->remaining_bits); + if (rebalance > 3<>B); + } else { + /* For a stereo split, the high bits of fill are always zero, so no + folding will be done to the side. */ + cm = quant_band(ctx, Y, N, sbits, B, NULL, LM, NULL, side, NULL, fill>>B); + rebalance = sbits - (rebalance-ctx->remaining_bits); + if (rebalance > 3<resynth) + { + if (N!=2) + stereo_merge(X, Y, mid, N, ctx->arch); + if (inv) + { + int j; + for (j=0;jeBands; + n1 = M*(eBands[start+1]-eBands[start]); + n2 = M*(eBands[start+2]-eBands[start+1]); + /* Duplicate enough of the first band folding data to be able to fold the second band. + Copies no data for CELT-only mode. */ + OPUS_COPY(&norm[n1], &norm[2*n1 - n2], n2-n1); + if (dual_stereo) + OPUS_COPY(&norm2[n1], &norm2[2*n1 - n2], n2-n1); +} + +void quant_all_bands(int encode, const CELTMode *m, int start, int end, + celt_norm *X_, celt_norm *Y_, unsigned char *collapse_masks, + const celt_ener *bandE, int *pulses, int shortBlocks, int spread, + int dual_stereo, int intensity, int *tf_res, opus_int32 total_bits, + opus_int32 balance, ec_ctx *ec, int LM, int codedBands, + opus_uint32 *seed, int complexity, int arch, int disable_inv) +{ + int i; + opus_int32 remaining_bits; + const opus_int16 * OPUS_RESTRICT eBands = m->eBands; + celt_norm * OPUS_RESTRICT norm, * OPUS_RESTRICT norm2; + VARDECL(celt_norm, _norm); + VARDECL(celt_norm, _lowband_scratch); + VARDECL(celt_norm, X_save); + VARDECL(celt_norm, Y_save); + VARDECL(celt_norm, X_save2); + VARDECL(celt_norm, Y_save2); + VARDECL(celt_norm, norm_save2); + int resynth_alloc; + celt_norm *lowband_scratch; + int B; + int M; + int lowband_offset; + int update_lowband = 1; + int C = Y_ != NULL ? 2 : 1; + int norm_offset; + int theta_rdo = encode && Y_!=NULL && !dual_stereo && complexity>=8; +#ifdef RESYNTH + int resynth = 1; +#else + int resynth = !encode || theta_rdo; +#endif + struct band_ctx ctx; + SAVE_STACK; + + M = 1<nbEBands-1]-norm_offset), celt_norm); + norm = _norm; + norm2 = norm + M*eBands[m->nbEBands-1]-norm_offset; + + /* For decoding, we can use the last band as scratch space because we don't need that + scratch space for the last band and we don't care about the data there until we're + decoding the last band. */ + if (encode && resynth) + resynth_alloc = M*(eBands[m->nbEBands]-eBands[m->nbEBands-1]); + else + resynth_alloc = ALLOC_NONE; + ALLOC(_lowband_scratch, resynth_alloc, celt_norm); + if (encode && resynth) + lowband_scratch = _lowband_scratch; + else + lowband_scratch = X_+M*eBands[m->nbEBands-1]; + ALLOC(X_save, resynth_alloc, celt_norm); + ALLOC(Y_save, resynth_alloc, celt_norm); + ALLOC(X_save2, resynth_alloc, celt_norm); + ALLOC(Y_save2, resynth_alloc, celt_norm); + ALLOC(norm_save2, resynth_alloc, celt_norm); + + lowband_offset = 0; + ctx.bandE = bandE; + ctx.ec = ec; + ctx.encode = encode; + ctx.intensity = intensity; + ctx.m = m; + ctx.seed = *seed; + ctx.spread = spread; + ctx.arch = arch; + ctx.disable_inv = disable_inv; + ctx.resynth = resynth; + ctx.theta_round = 0; + /* Avoid injecting noise in the first band on transients. */ + ctx.avoid_split_noise = B > 1; + for (i=start;i 0); + tell = ec_tell_frac(ec); + + /* Compute how many bits we want to allocate to this band */ + if (i != start) + balance -= tell; + remaining_bits = total_bits-tell-1; + ctx.remaining_bits = remaining_bits; + if (i <= codedBands-1) + { + curr_balance = celt_sudiv(balance, IMIN(3, codedBands-i)); + b = IMAX(0, IMIN(16383, IMIN(remaining_bits+1,pulses[i]+curr_balance))); + } else { + b = 0; + } + +#ifndef DISABLE_UPDATE_DRAFT + if (resynth && (M*eBands[i]-N >= M*eBands[start] || i==start+1) && (update_lowband || lowband_offset==0)) + lowband_offset = i; + if (i == start+1) + special_hybrid_folding(m, norm, norm2, start, M, dual_stereo); +#else + if (resynth && M*eBands[i]-N >= M*eBands[start] && (update_lowband || lowband_offset==0)) + lowband_offset = i; +#endif + + tf_change = tf_res[i]; + ctx.tf_change = tf_change; + if (i>=m->effEBands) + { + X=norm; + if (Y_!=NULL) + Y = norm; + lowband_scratch = NULL; + } + if (last && !theta_rdo) + lowband_scratch = NULL; + + /* Get a conservative estimate of the collapse_mask's for the bands we're + going to be folding from. */ + if (lowband_offset != 0 && (spread!=SPREAD_AGGRESSIVE || B>1 || tf_change<0)) + { + int fold_start; + int fold_end; + int fold_i; + /* This ensures we never repeat spectral content within one band */ + effective_lowband = IMAX(0, M*eBands[lowband_offset]-norm_offset-N); + fold_start = lowband_offset; + while(M*eBands[--fold_start] > effective_lowband+norm_offset); + fold_end = lowband_offset-1; +#ifndef DISABLE_UPDATE_DRAFT + while(++fold_end < i && M*eBands[fold_end] < effective_lowband+norm_offset+N); +#else + while(M*eBands[++fold_end] < effective_lowband+norm_offset+N); +#endif + x_cm = y_cm = 0; + fold_i = fold_start; do { + x_cm |= collapse_masks[fold_i*C+0]; + y_cm |= collapse_masks[fold_i*C+C-1]; + } while (++fold_inbEBands], w); + /* Make a copy. */ + cm = x_cm|y_cm; + ec_save = *ec; + ctx_save = ctx; + OPUS_COPY(X_save, X, N); + OPUS_COPY(Y_save, Y, N); + /* Encode and round down. */ + ctx.theta_round = -1; + x_cm = quant_band_stereo(&ctx, X, Y, N, b, B, + effective_lowband != -1 ? norm+effective_lowband : NULL, LM, + last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, cm); + dist0 = MULT16_32_Q15(w[0], celt_inner_prod(X_save, X, N, arch)) + MULT16_32_Q15(w[1], celt_inner_prod(Y_save, Y, N, arch)); + + /* Save first result. */ + cm2 = x_cm; + ec_save2 = *ec; + ctx_save2 = ctx; + OPUS_COPY(X_save2, X, N); + OPUS_COPY(Y_save2, Y, N); + if (!last) + OPUS_COPY(norm_save2, norm+M*eBands[i]-norm_offset, N); + nstart_bytes = ec_save.offs; + nend_bytes = ec_save.storage; + bytes_buf = ec_save.buf+nstart_bytes; + save_bytes = nend_bytes-nstart_bytes; + OPUS_COPY(bytes_save, bytes_buf, save_bytes); + + /* Restore */ + *ec = ec_save; + ctx = ctx_save; + OPUS_COPY(X, X_save, N); + OPUS_COPY(Y, Y_save, N); +#ifndef DISABLE_UPDATE_DRAFT + if (i == start+1) + special_hybrid_folding(m, norm, norm2, start, M, dual_stereo); +#endif + /* Encode and round up. */ + ctx.theta_round = 1; + x_cm = quant_band_stereo(&ctx, X, Y, N, b, B, + effective_lowband != -1 ? norm+effective_lowband : NULL, LM, + last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, cm); + dist1 = MULT16_32_Q15(w[0], celt_inner_prod(X_save, X, N, arch)) + MULT16_32_Q15(w[1], celt_inner_prod(Y_save, Y, N, arch)); + if (dist0 >= dist1) { + x_cm = cm2; + *ec = ec_save2; + ctx = ctx_save2; + OPUS_COPY(X, X_save2, N); + OPUS_COPY(Y, Y_save2, N); + if (!last) + OPUS_COPY(norm+M*eBands[i]-norm_offset, norm_save2, N); + OPUS_COPY(bytes_buf, bytes_save, save_bytes); + } + } else { + ctx.theta_round = 0; + x_cm = quant_band_stereo(&ctx, X, Y, N, b, B, + effective_lowband != -1 ? norm+effective_lowband : NULL, LM, + last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, x_cm|y_cm); + } + } else { + x_cm = quant_band(&ctx, X, N, b, B, + effective_lowband != -1 ? norm+effective_lowband : NULL, LM, + last?NULL:norm+M*eBands[i]-norm_offset, Q15ONE, lowband_scratch, x_cm|y_cm); + } + y_cm = x_cm; + } + collapse_masks[i*C+0] = (unsigned char)x_cm; + collapse_masks[i*C+C-1] = (unsigned char)y_cm; + balance += pulses[i] + tell; + + /* Update the folding position only as long as we have 1 bit/sample depth. */ + update_lowband = b>(N< +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +#if defined(MIPSr1_ASM) +#include "mips/celt_mipsr1.h" +#endif + + +int resampling_factor(opus_int32 rate) +{ + int ret; + switch (rate) + { + case 48000: + ret = 1; + break; + case 24000: + ret = 2; + break; + case 16000: + ret = 3; + break; + case 12000: + ret = 4; + break; + case 8000: + ret = 6; + break; + default: +#ifndef CUSTOM_MODES + celt_assert(0); +#endif + ret = 0; + break; + } + return ret; +} + +#if !defined(OVERRIDE_COMB_FILTER_CONST) || defined(NON_STATIC_COMB_FILTER_CONST_C) +/* This version should be faster on ARM */ +#ifdef OPUS_ARM_ASM +#ifndef NON_STATIC_COMB_FILTER_CONST_C +static +#endif +void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N, + opus_val16 g10, opus_val16 g11, opus_val16 g12) +{ + opus_val32 x0, x1, x2, x3, x4; + int i; + x4 = SHL32(x[-T-2], 1); + x3 = SHL32(x[-T-1], 1); + x2 = SHL32(x[-T], 1); + x1 = SHL32(x[-T+1], 1); + for (i=0;inbEBands;i++) + { + int N; + N=(m->eBands[i+1]-m->eBands[i])<cache.caps[m->nbEBands*(2*LM+C-1)+i]+64)*C*N>>2; + } +} + + + +const char *opus_strerror(int error) +{ + static const char * const error_strings[8] = { + "success", + "invalid argument", + "buffer too small", + "internal error", + "corrupted stream", + "request not implemented", + "invalid state", + "memory allocation failed" + }; + if (error > 0 || error < -7) + return "unknown error"; + else + return error_strings[-error]; +} + +const char *opus_get_version_string(void) +{ + return "libopus " PACKAGE_VERSION + /* Applications may rely on the presence of this substring in the version + string to determine if they have a fixed-point or floating-point build + at runtime. */ +#ifdef FIXED_POINT + "-fixed" +#endif +#ifdef FUZZING + "-fuzzing" +#endif + ; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/celt.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/celt.h new file mode 100644 index 000000000..24b6b2b52 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/celt.h @@ -0,0 +1,251 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/** + @file celt.h + @brief Contains all the functions for encoding and decoding audio + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef CELT_H +#define CELT_H + +#include "opus_types.h" +#include "opus_defines.h" +#include "opus_custom.h" +#include "entenc.h" +#include "entdec.h" +#include "arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CELTEncoder OpusCustomEncoder +#define CELTDecoder OpusCustomDecoder +#define CELTMode OpusCustomMode + +#define LEAK_BANDS 19 + +typedef struct { + int valid; + float tonality; + float tonality_slope; + float noisiness; + float activity; + float music_prob; + float music_prob_min; + float music_prob_max; + int bandwidth; + float activity_probability; + float max_pitch_ratio; + /* Store as Q6 char to save space. */ + unsigned char leak_boost[LEAK_BANDS]; +} AnalysisInfo; + +typedef struct { + int signalType; + int offset; +} SILKInfo; + +#define __celt_check_mode_ptr_ptr(ptr) ((ptr) + ((ptr) - (const CELTMode**)(ptr))) + +#define __celt_check_analysis_ptr(ptr) ((ptr) + ((ptr) - (const AnalysisInfo*)(ptr))) + +#define __celt_check_silkinfo_ptr(ptr) ((ptr) + ((ptr) - (const SILKInfo*)(ptr))) + +/* Encoder/decoder Requests */ + + +#define CELT_SET_PREDICTION_REQUEST 10002 +/** Controls the use of interframe prediction. + 0=Independent frames + 1=Short term interframe prediction allowed + 2=Long term prediction allowed + */ +#define CELT_SET_PREDICTION(x) CELT_SET_PREDICTION_REQUEST, __opus_check_int(x) + +#define CELT_SET_INPUT_CLIPPING_REQUEST 10004 +#define CELT_SET_INPUT_CLIPPING(x) CELT_SET_INPUT_CLIPPING_REQUEST, __opus_check_int(x) + +#define CELT_GET_AND_CLEAR_ERROR_REQUEST 10007 +#define CELT_GET_AND_CLEAR_ERROR(x) CELT_GET_AND_CLEAR_ERROR_REQUEST, __opus_check_int_ptr(x) + +#define CELT_SET_CHANNELS_REQUEST 10008 +#define CELT_SET_CHANNELS(x) CELT_SET_CHANNELS_REQUEST, __opus_check_int(x) + + +/* Internal */ +#define CELT_SET_START_BAND_REQUEST 10010 +#define CELT_SET_START_BAND(x) CELT_SET_START_BAND_REQUEST, __opus_check_int(x) + +#define CELT_SET_END_BAND_REQUEST 10012 +#define CELT_SET_END_BAND(x) CELT_SET_END_BAND_REQUEST, __opus_check_int(x) + +#define CELT_GET_MODE_REQUEST 10015 +/** Get the CELTMode used by an encoder or decoder */ +#define CELT_GET_MODE(x) CELT_GET_MODE_REQUEST, __celt_check_mode_ptr_ptr(x) + +#define CELT_SET_SIGNALLING_REQUEST 10016 +#define CELT_SET_SIGNALLING(x) CELT_SET_SIGNALLING_REQUEST, __opus_check_int(x) + +#define CELT_SET_TONALITY_REQUEST 10018 +#define CELT_SET_TONALITY(x) CELT_SET_TONALITY_REQUEST, __opus_check_int(x) +#define CELT_SET_TONALITY_SLOPE_REQUEST 10020 +#define CELT_SET_TONALITY_SLOPE(x) CELT_SET_TONALITY_SLOPE_REQUEST, __opus_check_int(x) + +#define CELT_SET_ANALYSIS_REQUEST 10022 +#define CELT_SET_ANALYSIS(x) CELT_SET_ANALYSIS_REQUEST, __celt_check_analysis_ptr(x) + +#define OPUS_SET_LFE_REQUEST 10024 +#define OPUS_SET_LFE(x) OPUS_SET_LFE_REQUEST, __opus_check_int(x) + +#define OPUS_SET_ENERGY_MASK_REQUEST 10026 +#define OPUS_SET_ENERGY_MASK(x) OPUS_SET_ENERGY_MASK_REQUEST, __opus_check_val16_ptr(x) + +#define CELT_SET_SILK_INFO_REQUEST 10028 +#define CELT_SET_SILK_INFO(x) CELT_SET_SILK_INFO_REQUEST, __celt_check_silkinfo_ptr(x) + +/* Encoder stuff */ + +int celt_encoder_get_size(int channels); + +int celt_encode_with_ec(OpusCustomEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc); + +int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels, + int arch); + + + +/* Decoder stuff */ + +int celt_decoder_get_size(int channels); + + +int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels); + +int celt_decode_with_ec(OpusCustomDecoder * OPUS_RESTRICT st, const unsigned char *data, + int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec, int accum); + +#define celt_encoder_ctl opus_custom_encoder_ctl +#define celt_decoder_ctl opus_custom_decoder_ctl + + +#ifdef CUSTOM_MODES +#define OPUS_CUSTOM_NOSTATIC +#else +#define OPUS_CUSTOM_NOSTATIC static OPUS_INLINE +#endif + +static const unsigned char trim_icdf[11] = {126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0}; +/* Probs: NONE: 21.875%, LIGHT: 6.25%, NORMAL: 65.625%, AGGRESSIVE: 6.25% */ +static const unsigned char spread_icdf[4] = {25, 23, 2, 0}; + +static const unsigned char tapset_icdf[3]={2,1,0}; + +#ifdef CUSTOM_MODES +static const unsigned char toOpusTable[20] = { + 0xE0, 0xE8, 0xF0, 0xF8, + 0xC0, 0xC8, 0xD0, 0xD8, + 0xA0, 0xA8, 0xB0, 0xB8, + 0x00, 0x00, 0x00, 0x00, + 0x80, 0x88, 0x90, 0x98, +}; + +static const unsigned char fromOpusTable[16] = { + 0x80, 0x88, 0x90, 0x98, + 0x40, 0x48, 0x50, 0x58, + 0x20, 0x28, 0x30, 0x38, + 0x00, 0x08, 0x10, 0x18 +}; + +static OPUS_INLINE int toOpus(unsigned char c) +{ + int ret=0; + if (c<0xA0) + ret = toOpusTable[c>>3]; + if (ret == 0) + return -1; + else + return ret|(c&0x7); +} + +static OPUS_INLINE int fromOpus(unsigned char c) +{ + if (c<0x80) + return -1; + else + return fromOpusTable[(c>>3)-16] | (c&0x7); +} +#endif /* CUSTOM_MODES */ + +#define COMBFILTER_MAXPERIOD 1024 +#define COMBFILTER_MINPERIOD 15 + +extern const signed char tf_select_table[4][8]; + +#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) +void validate_celt_decoder(CELTDecoder *st); +#define VALIDATE_CELT_DECODER(st) validate_celt_decoder(st) +#else +#define VALIDATE_CELT_DECODER(st) +#endif + +int resampling_factor(opus_int32 rate); + +void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp, + int N, int CC, int upsample, const opus_val16 *coef, celt_sig *mem, int clip); + +void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N, + opus_val16 g0, opus_val16 g1, int tapset0, int tapset1, + const opus_val16 *window, int overlap, int arch); + +#ifdef NON_STATIC_COMB_FILTER_CONST_C +void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N, + opus_val16 g10, opus_val16 g11, opus_val16 g12); +#endif + +#ifndef OVERRIDE_COMB_FILTER_CONST +# define comb_filter_const(y, x, T, N, g10, g11, g12, arch) \ + ((void)(arch),comb_filter_const_c(y, x, T, N, g10, g11, g12)) +#endif + +void init_caps(const CELTMode *m,int *cap,int LM,int C); + +#ifdef RESYNTH +void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, const opus_val16 *coef, celt_sig *mem); +void celt_synthesis(const CELTMode *mode, celt_norm *X, celt_sig * out_syn[], + opus_val16 *oldBandE, int start, int effEnd, int C, int CC, int isTransient, + int LM, int downsample, int silence); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* CELT_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/celt_decoder.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/celt_decoder.c new file mode 100644 index 000000000..74ca3b740 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/celt_decoder.c @@ -0,0 +1,1378 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2010 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define CELT_DECODER_C + +#include "cpu_support.h" +#include "os_support.h" +#include "mdct.h" +#include +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + +/* The maximum pitch lag to allow in the pitch-based PLC. It's possible to save + CPU time in the PLC pitch search by making this smaller than MAX_PERIOD. The + current value corresponds to a pitch of 66.67 Hz. */ +#define PLC_PITCH_LAG_MAX (720) +/* The minimum pitch lag to allow in the pitch-based PLC. This corresponds to a + pitch of 480 Hz. */ +#define PLC_PITCH_LAG_MIN (100) + +#if defined(SMALL_FOOTPRINT) && defined(FIXED_POINT) +#define NORM_ALIASING_HACK +#endif +/**********************************************************************/ +/* */ +/* DECODER */ +/* */ +/**********************************************************************/ +#define DECODE_BUFFER_SIZE 2048 + +/** Decoder state + @brief Decoder state + */ +struct OpusCustomDecoder { + const OpusCustomMode *mode; + int overlap; + int channels; + int stream_channels; + + int downsample; + int start, end; + int signalling; + int disable_inv; + int arch; + + /* Everything beyond this point gets cleared on a reset */ +#define DECODER_RESET_START rng + + opus_uint32 rng; + int error; + int last_pitch_index; + int loss_count; + int skip_plc; + int postfilter_period; + int postfilter_period_old; + opus_val16 postfilter_gain; + opus_val16 postfilter_gain_old; + int postfilter_tapset; + int postfilter_tapset_old; + + celt_sig preemph_memD[2]; + + celt_sig _decode_mem[1]; /* Size = channels*(DECODE_BUFFER_SIZE+mode->overlap) */ + /* opus_val16 lpc[], Size = channels*LPC_ORDER */ + /* opus_val16 oldEBands[], Size = 2*mode->nbEBands */ + /* opus_val16 oldLogE[], Size = 2*mode->nbEBands */ + /* opus_val16 oldLogE2[], Size = 2*mode->nbEBands */ + /* opus_val16 backgroundLogE[], Size = 2*mode->nbEBands */ +}; + +#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) +/* Make basic checks on the CELT state to ensure we don't end + up writing all over memory. */ +void validate_celt_decoder(CELTDecoder *st) +{ +#ifndef CUSTOM_MODES + celt_assert(st->mode == opus_custom_mode_create(48000, 960, NULL)); + celt_assert(st->overlap == 120); + celt_assert(st->end <= 21); +#else +/* From Section 4.3 in the spec: "The normal CELT layer uses 21 of those bands, + though Opus Custom (see Section 6.2) may use a different number of bands" + + Check if it's within the maximum number of Bark frequency bands instead */ + celt_assert(st->end <= 25); +#endif + celt_assert(st->channels == 1 || st->channels == 2); + celt_assert(st->stream_channels == 1 || st->stream_channels == 2); + celt_assert(st->downsample > 0); + celt_assert(st->start == 0 || st->start == 17); + celt_assert(st->start < st->end); +#ifdef OPUS_ARCHMASK + celt_assert(st->arch >= 0); + celt_assert(st->arch <= OPUS_ARCHMASK); +#endif + celt_assert(st->last_pitch_index <= PLC_PITCH_LAG_MAX); + celt_assert(st->last_pitch_index >= PLC_PITCH_LAG_MIN || st->last_pitch_index == 0); + celt_assert(st->postfilter_period < MAX_PERIOD); + celt_assert(st->postfilter_period >= COMBFILTER_MINPERIOD || st->postfilter_period == 0); + celt_assert(st->postfilter_period_old < MAX_PERIOD); + celt_assert(st->postfilter_period_old >= COMBFILTER_MINPERIOD || st->postfilter_period_old == 0); + celt_assert(st->postfilter_tapset <= 2); + celt_assert(st->postfilter_tapset >= 0); + celt_assert(st->postfilter_tapset_old <= 2); + celt_assert(st->postfilter_tapset_old >= 0); +} +#endif + +int celt_decoder_get_size(int channels) +{ + const CELTMode *mode = opus_custom_mode_create(48000, 960, NULL); + return opus_custom_decoder_get_size(mode, channels); +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_get_size(const CELTMode *mode, int channels) +{ + int size = sizeof(struct CELTDecoder) + + (channels*(DECODE_BUFFER_SIZE+mode->overlap)-1)*sizeof(celt_sig) + + channels*LPC_ORDER*sizeof(opus_val16) + + 4*2*mode->nbEBands*sizeof(opus_val16); + return size; +} + +#ifdef CUSTOM_MODES +CELTDecoder *opus_custom_decoder_create(const CELTMode *mode, int channels, int *error) +{ + int ret; + CELTDecoder *st = (CELTDecoder *)opus_alloc(opus_custom_decoder_get_size(mode, channels)); + ret = opus_custom_decoder_init(st, mode, channels); + if (ret != OPUS_OK) + { + opus_custom_decoder_destroy(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} +#endif /* CUSTOM_MODES */ + +int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels) +{ + int ret; + ret = opus_custom_decoder_init(st, opus_custom_mode_create(48000, 960, NULL), channels); + if (ret != OPUS_OK) + return ret; + st->downsample = resampling_factor(sampling_rate); + if (st->downsample==0) + return OPUS_BAD_ARG; + else + return OPUS_OK; +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_init(CELTDecoder *st, const CELTMode *mode, int channels) +{ + if (channels < 0 || channels > 2) + return OPUS_BAD_ARG; + + if (st==NULL) + return OPUS_ALLOC_FAIL; + + OPUS_CLEAR((char*)st, opus_custom_decoder_get_size(mode, channels)); + + st->mode = mode; + st->overlap = mode->overlap; + st->stream_channels = st->channels = channels; + + st->downsample = 1; + st->start = 0; + st->end = st->mode->effEBands; + st->signalling = 1; +#ifndef DISABLE_UPDATE_DRAFT + st->disable_inv = channels == 1; +#else + st->disable_inv = 0; +#endif + st->arch = opus_select_arch(); + + opus_custom_decoder_ctl(st, OPUS_RESET_STATE); + + return OPUS_OK; +} + +#ifdef CUSTOM_MODES +void opus_custom_decoder_destroy(CELTDecoder *st) +{ + opus_free(st); +} +#endif /* CUSTOM_MODES */ + +#ifndef CUSTOM_MODES +/* Special case for stereo with no downsampling and no accumulation. This is + quite common and we can make it faster by processing both channels in the + same loop, reducing overhead due to the dependency loop in the IIR filter. */ +static void deemphasis_stereo_simple(celt_sig *in[], opus_val16 *pcm, int N, const opus_val16 coef0, + celt_sig *mem) +{ + celt_sig * OPUS_RESTRICT x0; + celt_sig * OPUS_RESTRICT x1; + celt_sig m0, m1; + int j; + x0=in[0]; + x1=in[1]; + m0 = mem[0]; + m1 = mem[1]; + for (j=0;j1) + { + /* Shortcut for the standard (non-custom modes) case */ + for (j=0;joverlap; + nbEBands = mode->nbEBands; + N = mode->shortMdctSize<shortMdctSize; + shift = mode->maxLM; + } else { + B = 1; + NB = mode->shortMdctSize<maxLM-LM; + } + + if (CC==2&&C==1) + { + /* Copying a mono streams to two channels */ + celt_sig *freq2; + denormalise_bands(mode, X, freq, oldBandE, start, effEnd, M, + downsample, silence); + /* Store a temporary copy in the output buffer because the IMDCT destroys its input. */ + freq2 = out_syn[1]+overlap/2; + OPUS_COPY(freq2, freq, N); + for (b=0;bmdct, &freq2[b], out_syn[0]+NB*b, mode->window, overlap, shift, B, arch); + for (b=0;bmdct, &freq[b], out_syn[1]+NB*b, mode->window, overlap, shift, B, arch); + } else if (CC==1&&C==2) + { + /* Downmixing a stereo stream to mono */ + celt_sig *freq2; + freq2 = out_syn[0]+overlap/2; + denormalise_bands(mode, X, freq, oldBandE, start, effEnd, M, + downsample, silence); + /* Use the output buffer as temp array before downmixing. */ + denormalise_bands(mode, X+N, freq2, oldBandE+nbEBands, start, effEnd, M, + downsample, silence); + for (i=0;imdct, &freq[b], out_syn[0]+NB*b, mode->window, overlap, shift, B, arch); + } else { + /* Normal case (mono or stereo) */ + c=0; do { + denormalise_bands(mode, X+c*N, freq, oldBandE+c*nbEBands, start, effEnd, M, + downsample, silence); + for (b=0;bmdct, &freq[b], out_syn[c]+NB*b, mode->window, overlap, shift, B, arch); + } while (++cstorage*8; + tell = ec_tell(dec); + logp = isTransient ? 2 : 4; + tf_select_rsv = LM>0 && tell+logp+1<=budget; + budget -= tf_select_rsv; + tf_changed = curr = 0; + for (i=start;i>1, opus_val16 ); + pitch_downsample(decode_mem, lp_pitch_buf, + DECODE_BUFFER_SIZE, C, arch); + pitch_search(lp_pitch_buf+(PLC_PITCH_LAG_MAX>>1), lp_pitch_buf, + DECODE_BUFFER_SIZE-PLC_PITCH_LAG_MAX, + PLC_PITCH_LAG_MAX-PLC_PITCH_LAG_MIN, &pitch_index, arch); + pitch_index = PLC_PITCH_LAG_MAX-pitch_index; + RESTORE_STACK; + return pitch_index; +} + +static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM) +{ + int c; + int i; + const int C = st->channels; + celt_sig *decode_mem[2]; + celt_sig *out_syn[2]; + opus_val16 *lpc; + opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE; + const OpusCustomMode *mode; + int nbEBands; + int overlap; + int start; + int loss_count; + int noise_based; + const opus_int16 *eBands; + SAVE_STACK; + + mode = st->mode; + nbEBands = mode->nbEBands; + overlap = mode->overlap; + eBands = mode->eBands; + + c=0; do { + decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+overlap); + out_syn[c] = decode_mem[c]+DECODE_BUFFER_SIZE-N; + } while (++c_decode_mem+(DECODE_BUFFER_SIZE+overlap)*C); + oldBandE = lpc+C*LPC_ORDER; + oldLogE = oldBandE + 2*nbEBands; + oldLogE2 = oldLogE + 2*nbEBands; + backgroundLogE = oldLogE2 + 2*nbEBands; + + loss_count = st->loss_count; + start = st->start; + noise_based = loss_count >= 5 || start != 0 || st->skip_plc; + if (noise_based) + { + /* Noise-based PLC/CNG */ +#ifdef NORM_ALIASING_HACK + celt_norm *X; +#else + VARDECL(celt_norm, X); +#endif + opus_uint32 seed; + int end; + int effEnd; + opus_val16 decay; + end = st->end; + effEnd = IMAX(start, IMIN(end, mode->effEBands)); + +#ifdef NORM_ALIASING_HACK + /* This is an ugly hack that breaks aliasing rules and would be easily broken, + but it saves almost 4kB of stack. */ + X = (celt_norm*)(out_syn[C-1]+overlap/2); +#else + ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */ +#endif + + /* Energy decay */ + decay = loss_count==0 ? QCONST16(1.5f, DB_SHIFT) : QCONST16(.5f, DB_SHIFT); + c=0; do + { + for (i=start;irng; + for (c=0;c>20); + } + renormalise_vector(X+boffs, blen, Q15ONE, st->arch); + } + } + st->rng = seed; + + c=0; do { + OPUS_MOVE(decode_mem[c], decode_mem[c]+N, + DECODE_BUFFER_SIZE-N+(overlap>>1)); + } while (++cdownsample, 0, st->arch); + } else { + int exc_length; + /* Pitch-based PLC */ + const opus_val16 *window; + opus_val16 *exc; + opus_val16 fade = Q15ONE; + int pitch_index; + VARDECL(opus_val32, etmp); + VARDECL(opus_val16, _exc); + VARDECL(opus_val16, fir_tmp); + + if (loss_count == 0) + { + st->last_pitch_index = pitch_index = celt_plc_pitch_search(decode_mem, C, st->arch); + } else { + pitch_index = st->last_pitch_index; + fade = QCONST16(.8f,15); + } + + /* We want the excitation for 2 pitch periods in order to look for a + decaying signal, but we can't get more than MAX_PERIOD. */ + exc_length = IMIN(2*pitch_index, MAX_PERIOD); + + ALLOC(etmp, overlap, opus_val32); + ALLOC(_exc, MAX_PERIOD+LPC_ORDER, opus_val16); + ALLOC(fir_tmp, exc_length, opus_val16); + exc = _exc+LPC_ORDER; + window = mode->window; + c=0; do { + opus_val16 decay; + opus_val16 attenuation; + opus_val32 S1=0; + celt_sig *buf; + int extrapolation_offset; + int extrapolation_len; + int j; + + buf = decode_mem[c]; + for (i=0;iarch); + /* Add a noise floor of -40 dB. */ +#ifdef FIXED_POINT + ac[0] += SHR32(ac[0],13); +#else + ac[0] *= 1.0001f; +#endif + /* Use lag windowing to stabilize the Levinson-Durbin recursion. */ + for (i=1;i<=LPC_ORDER;i++) + { + /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ +#ifdef FIXED_POINT + ac[i] -= MULT16_32_Q15(2*i*i, ac[i]); +#else + ac[i] -= ac[i]*(0.008f*0.008f)*i*i; +#endif + } + _celt_lpc(lpc+c*LPC_ORDER, ac, LPC_ORDER); +#ifdef FIXED_POINT + /* For fixed-point, apply bandwidth expansion until we can guarantee that + no overflow can happen in the IIR filter. This means: + 32768*sum(abs(filter)) < 2^31 */ + while (1) { + opus_val16 tmp=Q15ONE; + opus_val32 sum=QCONST16(1., SIG_SHIFT); + for (i=0;iarch); + OPUS_COPY(exc+MAX_PERIOD-exc_length, fir_tmp, exc_length); + } + + /* Check if the waveform is decaying, and if so how fast. + We do this to avoid adding energy when concealing in a segment + with decaying energy. */ + { + opus_val32 E1=1, E2=1; + int decay_length; +#ifdef FIXED_POINT + int shift = IMAX(0,2*celt_zlog2(celt_maxabs16(&exc[MAX_PERIOD-exc_length], exc_length))-20); +#endif + decay_length = exc_length>>1; + for (i=0;i= pitch_index) { + j -= pitch_index; + attenuation = MULT16_16_Q15(attenuation, decay); + } + buf[DECODE_BUFFER_SIZE-N+i] = + SHL32(EXTEND32(MULT16_16_Q15(attenuation, + exc[extrapolation_offset+j])), SIG_SHIFT); + /* Compute the energy of the previously decoded signal whose + excitation we're copying. */ + tmp = ROUND16( + buf[DECODE_BUFFER_SIZE-MAX_PERIOD-N+extrapolation_offset+j], + SIG_SHIFT); + S1 += SHR32(MULT16_16(tmp, tmp), 10); + } + { + opus_val16 lpc_mem[LPC_ORDER]; + /* Copy the last decoded samples (prior to the overlap region) to + synthesis filter memory so we can have a continuous signal. */ + for (i=0;iarch); +#ifdef FIXED_POINT + for (i=0; i < extrapolation_len; i++) + buf[DECODE_BUFFER_SIZE-N+i] = SATURATE(buf[DECODE_BUFFER_SIZE-N+i], SIG_SAT); +#endif + } + + /* Check if the synthesis energy is higher than expected, which can + happen with the signal changes during our window. If so, + attenuate. */ + { + opus_val32 S2=0; + for (i=0;i SHR32(S2,2))) +#else + /* The float test is written this way to catch NaNs in the output + of the IIR filter at the same time. */ + if (!(S1 > 0.2f*S2)) +#endif + { + for (i=0;ipostfilter_period, st->postfilter_period, overlap, + -st->postfilter_gain, -st->postfilter_gain, + st->postfilter_tapset, st->postfilter_tapset, NULL, 0, st->arch); + + /* Simulate TDAC on the concealed audio so that it blends with the + MDCT of the next frame. */ + for (i=0;iloss_count = loss_count+1; + + RESTORE_STACK; +} + +int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, + int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec, int accum) +{ + int c, i, N; + int spread_decision; + opus_int32 bits; + ec_dec _dec; +#ifdef NORM_ALIASING_HACK + celt_norm *X; +#else + VARDECL(celt_norm, X); +#endif + VARDECL(int, fine_quant); + VARDECL(int, pulses); + VARDECL(int, cap); + VARDECL(int, offsets); + VARDECL(int, fine_priority); + VARDECL(int, tf_res); + VARDECL(unsigned char, collapse_masks); + celt_sig *decode_mem[2]; + celt_sig *out_syn[2]; + opus_val16 *lpc; + opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE; + + int shortBlocks; + int isTransient; + int intra_ener; + const int CC = st->channels; + int LM, M; + int start; + int end; + int effEnd; + int codedBands; + int alloc_trim; + int postfilter_pitch; + opus_val16 postfilter_gain; + int intensity=0; + int dual_stereo=0; + opus_int32 total_bits; + opus_int32 balance; + opus_int32 tell; + int dynalloc_logp; + int postfilter_tapset; + int anti_collapse_rsv; + int anti_collapse_on=0; + int silence; + int C = st->stream_channels; + const OpusCustomMode *mode; + int nbEBands; + int overlap; + const opus_int16 *eBands; + ALLOC_STACK; + + VALIDATE_CELT_DECODER(st); + mode = st->mode; + nbEBands = mode->nbEBands; + overlap = mode->overlap; + eBands = mode->eBands; + start = st->start; + end = st->end; + frame_size *= st->downsample; + + lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+overlap)*CC); + oldBandE = lpc+CC*LPC_ORDER; + oldLogE = oldBandE + 2*nbEBands; + oldLogE2 = oldLogE + 2*nbEBands; + backgroundLogE = oldLogE2 + 2*nbEBands; + +#ifdef CUSTOM_MODES + if (st->signalling && data!=NULL) + { + int data0=data[0]; + /* Convert "standard mode" to Opus header */ + if (mode->Fs==48000 && mode->shortMdctSize==120) + { + data0 = fromOpus(data0); + if (data0<0) + return OPUS_INVALID_PACKET; + } + st->end = end = IMAX(1, mode->effEBands-2*(data0>>5)); + LM = (data0>>3)&0x3; + C = 1 + ((data0>>2)&0x1); + data++; + len--; + if (LM>mode->maxLM) + return OPUS_INVALID_PACKET; + if (frame_size < mode->shortMdctSize<shortMdctSize<maxLM;LM++) + if (mode->shortMdctSize<mode->maxLM) + return OPUS_BAD_ARG; + } + M=1<1275 || pcm==NULL) + return OPUS_BAD_ARG; + + N = M*mode->shortMdctSize; + c=0; do { + decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+overlap); + out_syn[c] = decode_mem[c]+DECODE_BUFFER_SIZE-N; + } while (++c mode->effEBands) + effEnd = mode->effEBands; + + if (data == NULL || len<=1) + { + celt_decode_lost(st, N, LM); + deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD, accum); + RESTORE_STACK; + return frame_size/st->downsample; + } + + /* Check if there are at least two packets received consecutively before + * turning on the pitch-based PLC */ + st->skip_plc = st->loss_count != 0; + + if (dec == NULL) + { + ec_dec_init(&_dec,(unsigned char*)data,len); + dec = &_dec; + } + + if (C==1) + { + for (i=0;i= total_bits) + silence = 1; + else if (tell==1) + silence = ec_dec_bit_logp(dec, 15); + else + silence = 0; + if (silence) + { + /* Pretend we've read all the remaining bits */ + tell = len*8; + dec->nbits_total+=tell-ec_tell(dec); + } + + postfilter_gain = 0; + postfilter_pitch = 0; + postfilter_tapset = 0; + if (start==0 && tell+16 <= total_bits) + { + if(ec_dec_bit_logp(dec, 1)) + { + int qg, octave; + octave = ec_dec_uint(dec, 6); + postfilter_pitch = (16< 0 && tell+3 <= total_bits) + { + isTransient = ec_dec_bit_logp(dec, 3); + tell = ec_tell(dec); + } + else + isTransient = 0; + + if (isTransient) + shortBlocks = M; + else + shortBlocks = 0; + + /* Decode the global flags (first symbols in the stream) */ + intra_ener = tell+3<=total_bits ? ec_dec_bit_logp(dec, 3) : 0; + /* Get band energies */ + unquant_coarse_energy(mode, start, end, oldBandE, + intra_ener, dec, C, LM); + + ALLOC(tf_res, nbEBands, int); + tf_decode(start, end, isTransient, tf_res, LM, dec); + + tell = ec_tell(dec); + spread_decision = SPREAD_NORMAL; + if (tell+4 <= total_bits) + spread_decision = ec_dec_icdf(dec, spread_icdf, 5); + + ALLOC(cap, nbEBands, int); + + init_caps(mode,cap,LM,C); + + ALLOC(offsets, nbEBands, int); + + dynalloc_logp = 6; + total_bits<<=BITRES; + tell = ec_tell_frac(dec); + for (i=start;i0) + dynalloc_logp = IMAX(2, dynalloc_logp-1); + } + + ALLOC(fine_quant, nbEBands, int); + alloc_trim = tell+(6<=2&&bits>=((LM+2)<rng, 0, + st->arch, st->disable_inv); + + if (anti_collapse_rsv > 0) + { + anti_collapse_on = ec_dec_bits(dec, 1); + } + + unquant_energy_finalise(mode, start, end, oldBandE, + fine_quant, fine_priority, len*8-ec_tell(dec), dec, C); + + if (anti_collapse_on) + anti_collapse(mode, X, collapse_masks, LM, C, N, + start, end, oldBandE, oldLogE, oldLogE2, pulses, st->rng, st->arch); + + if (silence) + { + for (i=0;idownsample, silence, st->arch); + + c=0; do { + st->postfilter_period=IMAX(st->postfilter_period, COMBFILTER_MINPERIOD); + st->postfilter_period_old=IMAX(st->postfilter_period_old, COMBFILTER_MINPERIOD); + comb_filter(out_syn[c], out_syn[c], st->postfilter_period_old, st->postfilter_period, mode->shortMdctSize, + st->postfilter_gain_old, st->postfilter_gain, st->postfilter_tapset_old, st->postfilter_tapset, + mode->window, overlap, st->arch); + if (LM!=0) + comb_filter(out_syn[c]+mode->shortMdctSize, out_syn[c]+mode->shortMdctSize, st->postfilter_period, postfilter_pitch, N-mode->shortMdctSize, + st->postfilter_gain, postfilter_gain, st->postfilter_tapset, postfilter_tapset, + mode->window, overlap, st->arch); + + } while (++cpostfilter_period_old = st->postfilter_period; + st->postfilter_gain_old = st->postfilter_gain; + st->postfilter_tapset_old = st->postfilter_tapset; + st->postfilter_period = postfilter_pitch; + st->postfilter_gain = postfilter_gain; + st->postfilter_tapset = postfilter_tapset; + if (LM!=0) + { + st->postfilter_period_old = st->postfilter_period; + st->postfilter_gain_old = st->postfilter_gain; + st->postfilter_tapset_old = st->postfilter_tapset; + } + + if (C==1) + OPUS_COPY(&oldBandE[nbEBands], oldBandE, nbEBands); + + /* In case start or end were to change */ + if (!isTransient) + { + opus_val16 max_background_increase; + OPUS_COPY(oldLogE2, oldLogE, 2*nbEBands); + OPUS_COPY(oldLogE, oldBandE, 2*nbEBands); + /* In normal circumstances, we only allow the noise floor to increase by + up to 2.4 dB/second, but when we're in DTX, we allow up to 6 dB + increase for each update.*/ + if (st->loss_count < 10) + max_background_increase = M*QCONST16(0.001f,DB_SHIFT); + else + max_background_increase = QCONST16(1.f,DB_SHIFT); + for (i=0;i<2*nbEBands;i++) + backgroundLogE[i] = MIN16(backgroundLogE[i] + max_background_increase, oldBandE[i]); + } else { + for (i=0;i<2*nbEBands;i++) + oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]); + } + c=0; do + { + for (i=0;irng = dec->rng; + + deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD, accum); + st->loss_count = 0; + RESTORE_STACK; + if (ec_tell(dec) > 8*len) + return OPUS_INTERNAL_ERROR; + if(ec_get_error(dec)) + st->error = 1; + return frame_size/st->downsample; +} + + +#ifdef CUSTOM_MODES + +#ifdef FIXED_POINT +int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_int16 * OPUS_RESTRICT pcm, int frame_size) +{ + return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL, 0); +} + +#ifndef DISABLE_FLOAT_API +int opus_custom_decode_float(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, float * OPUS_RESTRICT pcm, int frame_size) +{ + int j, ret, C, N; + VARDECL(opus_int16, out); + ALLOC_STACK; + + if (pcm==NULL) + return OPUS_BAD_ARG; + + C = st->channels; + N = frame_size; + + ALLOC(out, C*N, opus_int16); + ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL, 0); + if (ret>0) + for (j=0;jchannels; + N = frame_size; + ALLOC(out, C*N, celt_sig); + + ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL, 0); + + if (ret>0) + for (j=0;j=st->mode->nbEBands) + goto bad_arg; + st->start = value; + } + break; + case CELT_SET_END_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>st->mode->nbEBands) + goto bad_arg; + st->end = value; + } + break; + case CELT_SET_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>2) + goto bad_arg; + st->stream_channels = value; + } + break; + case CELT_GET_AND_CLEAR_ERROR_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value=st->error; + st->error = 0; + } + break; + case OPUS_GET_LOOKAHEAD_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value = st->overlap/st->downsample; + } + break; + case OPUS_RESET_STATE: + { + int i; + opus_val16 *lpc, *oldBandE, *oldLogE, *oldLogE2; + lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*st->channels); + oldBandE = lpc+st->channels*LPC_ORDER; + oldLogE = oldBandE + 2*st->mode->nbEBands; + oldLogE2 = oldLogE + 2*st->mode->nbEBands; + OPUS_CLEAR((char*)&st->DECODER_RESET_START, + opus_custom_decoder_get_size(st->mode, st->channels)- + ((char*)&st->DECODER_RESET_START - (char*)st)); + for (i=0;i<2*st->mode->nbEBands;i++) + oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT); + st->skip_plc = 1; + } + break; + case OPUS_GET_PITCH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value = st->postfilter_period; + } + break; + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (value==0) + goto bad_arg; + *value=st->mode; + } + break; + case CELT_SET_SIGNALLING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->signalling = value; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 * value = va_arg(ap, opus_uint32 *); + if (value==0) + goto bad_arg; + *value=st->rng; + } + break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->disable_inv = value; + } + break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->disable_inv; + } + break; + default: + goto bad_request; + } + va_end(ap); + return OPUS_OK; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +bad_request: + va_end(ap); + return OPUS_UNIMPLEMENTED; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/celt_encoder.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/celt_encoder.c new file mode 100644 index 000000000..d6f8afc20 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/celt_encoder.c @@ -0,0 +1,2607 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2010 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define CELT_ENCODER_C + +#include "cpu_support.h" +#include "os_support.h" +#include "mdct.h" +#include +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + + +/** Encoder state + @brief Encoder state + */ +struct OpusCustomEncoder { + const OpusCustomMode *mode; /**< Mode used by the encoder */ + int channels; + int stream_channels; + + int force_intra; + int clip; + int disable_pf; + int complexity; + int upsample; + int start, end; + + opus_int32 bitrate; + int vbr; + int signalling; + int constrained_vbr; /* If zero, VBR can do whatever it likes with the rate */ + int loss_rate; + int lsb_depth; + int lfe; + int disable_inv; + int arch; + + /* Everything beyond this point gets cleared on a reset */ +#define ENCODER_RESET_START rng + + opus_uint32 rng; + int spread_decision; + opus_val32 delayedIntra; + int tonal_average; + int lastCodedBands; + int hf_average; + int tapset_decision; + + int prefilter_period; + opus_val16 prefilter_gain; + int prefilter_tapset; +#ifdef RESYNTH + int prefilter_period_old; + opus_val16 prefilter_gain_old; + int prefilter_tapset_old; +#endif + int consec_transient; + AnalysisInfo analysis; + SILKInfo silk_info; + + opus_val32 preemph_memE[2]; + opus_val32 preemph_memD[2]; + + /* VBR-related parameters */ + opus_int32 vbr_reservoir; + opus_int32 vbr_drift; + opus_int32 vbr_offset; + opus_int32 vbr_count; + opus_val32 overlap_max; + opus_val16 stereo_saving; + int intensity; + opus_val16 *energy_mask; + opus_val16 spec_avg; + +#ifdef RESYNTH + /* +MAX_PERIOD/2 to make space for overlap */ + celt_sig syn_mem[2][2*MAX_PERIOD+MAX_PERIOD/2]; +#endif + + celt_sig in_mem[1]; /* Size = channels*mode->overlap */ + /* celt_sig prefilter_mem[], Size = channels*COMBFILTER_MAXPERIOD */ + /* opus_val16 oldBandE[], Size = channels*mode->nbEBands */ + /* opus_val16 oldLogE[], Size = channels*mode->nbEBands */ + /* opus_val16 oldLogE2[], Size = channels*mode->nbEBands */ + /* opus_val16 energyError[], Size = channels*mode->nbEBands */ +}; + +int celt_encoder_get_size(int channels) +{ + CELTMode *mode = opus_custom_mode_create(48000, 960, NULL); + return opus_custom_encoder_get_size(mode, channels); +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_encoder_get_size(const CELTMode *mode, int channels) +{ + int size = sizeof(struct CELTEncoder) + + (channels*mode->overlap-1)*sizeof(celt_sig) /* celt_sig in_mem[channels*mode->overlap]; */ + + channels*COMBFILTER_MAXPERIOD*sizeof(celt_sig) /* celt_sig prefilter_mem[channels*COMBFILTER_MAXPERIOD]; */ + + 4*channels*mode->nbEBands*sizeof(opus_val16); /* opus_val16 oldBandE[channels*mode->nbEBands]; */ + /* opus_val16 oldLogE[channels*mode->nbEBands]; */ + /* opus_val16 oldLogE2[channels*mode->nbEBands]; */ + /* opus_val16 energyError[channels*mode->nbEBands]; */ + return size; +} + +#ifdef CUSTOM_MODES +CELTEncoder *opus_custom_encoder_create(const CELTMode *mode, int channels, int *error) +{ + int ret; + CELTEncoder *st = (CELTEncoder *)opus_alloc(opus_custom_encoder_get_size(mode, channels)); + /* init will handle the NULL case */ + ret = opus_custom_encoder_init(st, mode, channels); + if (ret != OPUS_OK) + { + opus_custom_encoder_destroy(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} +#endif /* CUSTOM_MODES */ + +static int opus_custom_encoder_init_arch(CELTEncoder *st, const CELTMode *mode, + int channels, int arch) +{ + if (channels < 0 || channels > 2) + return OPUS_BAD_ARG; + + if (st==NULL || mode==NULL) + return OPUS_ALLOC_FAIL; + + OPUS_CLEAR((char*)st, opus_custom_encoder_get_size(mode, channels)); + + st->mode = mode; + st->stream_channels = st->channels = channels; + + st->upsample = 1; + st->start = 0; + st->end = st->mode->effEBands; + st->signalling = 1; + st->arch = arch; + + st->constrained_vbr = 1; + st->clip = 1; + + st->bitrate = OPUS_BITRATE_MAX; + st->vbr = 0; + st->force_intra = 0; + st->complexity = 5; + st->lsb_depth=24; + + opus_custom_encoder_ctl(st, OPUS_RESET_STATE); + + return OPUS_OK; +} + +#ifdef CUSTOM_MODES +int opus_custom_encoder_init(CELTEncoder *st, const CELTMode *mode, int channels) +{ + return opus_custom_encoder_init_arch(st, mode, channels, opus_select_arch()); +} +#endif + +int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels, + int arch) +{ + int ret; + ret = opus_custom_encoder_init_arch(st, + opus_custom_mode_create(48000, 960, NULL), channels, arch); + if (ret != OPUS_OK) + return ret; + st->upsample = resampling_factor(sampling_rate); + return OPUS_OK; +} + +#ifdef CUSTOM_MODES +void opus_custom_encoder_destroy(CELTEncoder *st) +{ + opus_free(st); +} +#endif /* CUSTOM_MODES */ + + +static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int C, + opus_val16 *tf_estimate, int *tf_chan, int allow_weak_transients, + int *weak_transient) +{ + int i; + VARDECL(opus_val16, tmp); + opus_val32 mem0,mem1; + int is_transient = 0; + opus_int32 mask_metric = 0; + int c; + opus_val16 tf_max; + int len2; + /* Forward masking: 6.7 dB/ms. */ +#ifdef FIXED_POINT + int forward_shift = 4; +#else + opus_val16 forward_decay = QCONST16(.0625f,15); +#endif + /* Table of 6*64/x, trained on real data to minimize the average error */ + static const unsigned char inv_table[128] = { + 255,255,156,110, 86, 70, 59, 51, 45, 40, 37, 33, 31, 28, 26, 25, + 23, 22, 21, 20, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12, + 12, 12, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8, + 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, + }; + SAVE_STACK; + ALLOC(tmp, len, opus_val16); + + *weak_transient = 0; + /* For lower bitrates, let's be more conservative and have a forward masking + decay of 3.3 dB/ms. This avoids having to code transients at very low + bitrate (mostly for hybrid), which can result in unstable energy and/or + partial collapse. */ + if (allow_weak_transients) + { +#ifdef FIXED_POINT + forward_shift = 5; +#else + forward_decay = QCONST16(.03125f,15); +#endif + } + len2=len/2; + for (c=0;c=0;i--) + { + /* Backward masking: 13.9 dB/ms. */ +#ifdef FIXED_POINT + /* FIXME: Use PSHR16() instead */ + tmp[i] = mem0 + PSHR32(tmp[i]-mem0,3); +#else + tmp[i] = mem0 + MULT16_16_P15(QCONST16(0.125f,15),tmp[i]-mem0); +#endif + mem0 = tmp[i]; + maxE = MAX16(maxE, mem0); + } + /*for (i=0;i>1))); +#else + mean = celt_sqrt(mean * maxE*.5*len2); +#endif + /* Inverse of the mean energy in Q15+6 */ + norm = SHL32(EXTEND32(len2),6+14)/ADD32(EPSILON,SHR32(mean,1)); + /* Compute harmonic mean discarding the unreliable boundaries + The data is smooth, so we only take 1/4th of the samples */ + unmask=0; + /* We should never see NaNs here. If we find any, then something really bad happened and we better abort + before it does any damage later on. If these asserts are disabled (no hardening), then the table + lookup a few lines below (id = ...) is likely to crash dur to an out-of-bounds read. DO NOT FIX + that crash on NaN since it could result in a worse issue later on. */ + celt_assert(!celt_isnan(tmp[0])); + celt_assert(!celt_isnan(norm)); + for (i=12;imask_metric) + { + *tf_chan = c; + mask_metric = unmask; + } + } + is_transient = mask_metric>200; + /* For low bitrates, define "weak transients" that need to be + handled differently to avoid partial collapse. */ + if (allow_weak_transients && is_transient && mask_metric<600) { + is_transient = 0; + *weak_transient = 1; + } + /* Arbitrary metric for VBR boost */ + tf_max = MAX16(0,celt_sqrt(27*mask_metric)-42); + /* *tf_estimate = 1 + MIN16(1, sqrt(MAX16(0, tf_max-30))/20); */ + *tf_estimate = celt_sqrt(MAX32(0, SHL32(MULT16_16(QCONST16(0.0069,14),MIN16(163,tf_max)),14)-QCONST32(0.139,28))); + /*printf("%d %f\n", tf_max, mask_metric);*/ + RESTORE_STACK; +#ifdef FUZZING + is_transient = rand()&0x1; +#endif + /*printf("%d %f %d\n", is_transient, (float)*tf_estimate, tf_max);*/ + return is_transient; +} + +/* Looks for sudden increases of energy to decide whether we need to patch + the transient decision */ +static int patch_transient_decision(opus_val16 *newE, opus_val16 *oldE, int nbEBands, + int start, int end, int C) +{ + int i, c; + opus_val32 mean_diff=0; + opus_val16 spread_old[26]; + /* Apply an aggressive (-6 dB/Bark) spreading function to the old frame to + avoid false detection caused by irrelevant bands */ + if (C==1) + { + spread_old[start] = oldE[start]; + for (i=start+1;i=start;i--) + spread_old[i] = MAX16(spread_old[i], spread_old[i+1]-QCONST16(1.0f, DB_SHIFT)); + /* Compute mean increase */ + c=0; do { + for (i=IMAX(2,start);i QCONST16(1.f, DB_SHIFT); +} + +/** Apply window and compute the MDCT for all sub-frames and + all channels in a frame */ +static void compute_mdcts(const CELTMode *mode, int shortBlocks, celt_sig * OPUS_RESTRICT in, + celt_sig * OPUS_RESTRICT out, int C, int CC, int LM, int upsample, + int arch) +{ + const int overlap = mode->overlap; + int N; + int B; + int shift; + int i, b, c; + if (shortBlocks) + { + B = shortBlocks; + N = mode->shortMdctSize; + shift = mode->maxLM; + } else { + B = 1; + N = mode->shortMdctSize<maxLM-LM; + } + c=0; do { + for (b=0;bmdct, in+c*(B*N+overlap)+b*N, + &out[b+c*N*B], mode->window, overlap, shift, B, + arch); + } + } while (++ceBands[len]-m->eBands[len-1])<eBands[len]-m->eBands[len-1])<eBands[i+1]-m->eBands[i])<eBands[i+1]-m->eBands[i])==1; + OPUS_COPY(tmp, &X[tf_chan*N0 + (m->eBands[i]<eBands[i]<>LM, 1<>k, 1<=0;i--) + { + if (tf_res[i+1] == 1) + tf_res[i] = path1[i+1]; + else + tf_res[i] = path0[i+1]; + } + /*printf("%d %f\n", *tf_sum, tf_estimate);*/ + RESTORE_STACK; +#ifdef FUZZING + tf_select = rand()&0x1; + tf_res[0] = rand()&0x1; + for (i=1;istorage*8; + tell = ec_tell(enc); + logp = isTransient ? 2 : 4; + /* Reserve space to code the tf_select decision. */ + tf_select_rsv = LM>0 && tell+logp+1 <= budget; + budget -= tf_select_rsv; + curr = tf_changed = 0; + for (i=start;i> 10; + trim = QCONST16(4.f, 8) + QCONST16(1.f/16.f, 8)*frac; + } + if (C==2) + { + opus_val16 sum = 0; /* Q10 */ + opus_val16 minXC; /* Q10 */ + /* Compute inter-channel correlation for low frequencies */ + for (i=0;i<8;i++) + { + opus_val32 partial; + partial = celt_inner_prod(&X[m->eBands[i]<eBands[i]<eBands[i+1]-m->eBands[i])<eBands[i]<eBands[i]<eBands[i+1]-m->eBands[i])<nbEBands]*(opus_int32)(2+2*i-end); + } + } while (++cvalid) + { + trim -= MAX16(-QCONST16(2.f, 8), MIN16(QCONST16(2.f, 8), + (opus_val16)(QCONST16(2.f, 8)*(analysis->tonality_slope+.05f)))); + } +#else + (void)analysis; +#endif + +#ifdef FIXED_POINT + trim_index = PSHR32(trim, 8); +#else + trim_index = (int)floor(.5f+trim); +#endif + trim_index = IMAX(0, IMIN(10, trim_index)); + /*printf("%d\n", trim_index);*/ +#ifdef FUZZING + trim_index = rand()%11; +#endif + return trim_index; +} + +static int stereo_analysis(const CELTMode *m, const celt_norm *X, + int LM, int N0) +{ + int i; + int thetas; + opus_val32 sumLR = EPSILON, sumMS = EPSILON; + + /* Use the L1 norm to model the entropy of the L/R signal vs the M/S signal */ + for (i=0;i<13;i++) + { + int j; + for (j=m->eBands[i]<eBands[i+1]<eBands[13]<<(LM+1))+thetas, sumMS) + > MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR); +} + +#define MSWAP(a,b) do {opus_val16 tmp = a;a=b;b=tmp;} while(0) +static opus_val16 median_of_5(const opus_val16 *x) +{ + opus_val16 t0, t1, t2, t3, t4; + t2 = x[2]; + if (x[0] > x[1]) + { + t0 = x[1]; + t1 = x[0]; + } else { + t0 = x[0]; + t1 = x[1]; + } + if (x[3] > x[4]) + { + t3 = x[4]; + t4 = x[3]; + } else { + t3 = x[3]; + t4 = x[4]; + } + if (t0 > t3) + { + MSWAP(t0, t3); + MSWAP(t1, t4); + } + if (t2 > t1) + { + if (t1 < t3) + return MIN16(t2, t3); + else + return MIN16(t4, t1); + } else { + if (t2 < t3) + return MIN16(t1, t3); + else + return MIN16(t2, t4); + } +} + +static opus_val16 median_of_3(const opus_val16 *x) +{ + opus_val16 t0, t1, t2; + if (x[0] > x[1]) + { + t0 = x[1]; + t1 = x[0]; + } else { + t0 = x[0]; + t1 = x[1]; + } + t2 = x[2]; + if (t1 < t2) + return t1; + else if (t0 < t2) + return t2; + else + return t0; +} + +static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16 *bandLogE2, + int nbEBands, int start, int end, int C, int *offsets, int lsb_depth, const opus_int16 *logN, + int isTransient, int vbr, int constrained_vbr, const opus_int16 *eBands, int LM, + int effectiveBytes, opus_int32 *tot_boost_, int lfe, opus_val16 *surround_dynalloc, + AnalysisInfo *analysis, int *importance, int *spread_weight) +{ + int i, c; + opus_int32 tot_boost=0; + opus_val16 maxDepth; + VARDECL(opus_val16, follower); + VARDECL(opus_val16, noise_floor); + SAVE_STACK; + ALLOC(follower, C*nbEBands, opus_val16); + ALLOC(noise_floor, C*nbEBands, opus_val16); + OPUS_CLEAR(offsets, nbEBands); + /* Dynamic allocation code */ + maxDepth=-QCONST16(31.9f, DB_SHIFT); + for (i=0;i=0;i--) + mask[i] = MAX16(mask[i], mask[i+1] - QCONST16(3.f, DB_SHIFT)); + for (i=0;i> shift; + } + /*for (i=0;i 50 && LM>=1 && !lfe) + { + int last=0; + c=0;do + { + opus_val16 offset; + opus_val16 tmp; + opus_val16 *f; + f = &follower[c*nbEBands]; + f[0] = bandLogE2[c*nbEBands]; + for (i=1;i bandLogE2[c*nbEBands+i-1]+QCONST16(.5f,DB_SHIFT)) + last=i; + f[i] = MIN16(f[i-1]+QCONST16(1.5f,DB_SHIFT), bandLogE2[c*nbEBands+i]); + } + for (i=last-1;i>=0;i--) + f[i] = MIN16(f[i], MIN16(f[i+1]+QCONST16(2.f,DB_SHIFT), bandLogE2[c*nbEBands+i])); + + /* Combine with a median filter to avoid dynalloc triggering unnecessarily. + The "offset" value controls how conservative we are -- a higher offset + reduces the impact of the median filter and makes dynalloc use more bits. */ + offset = QCONST16(1.f, DB_SHIFT); + for (i=2;i=12) + follower[i] = HALF16(follower[i]); + } +#ifdef DISABLE_FLOAT_API + (void)analysis; +#else + if (analysis->valid) + { + for (i=start;ileak_boost[i]; + } +#endif + for (i=start;i 48) { + boost = (int)SHR32(EXTEND32(follower[i])*8,DB_SHIFT); + boost_bits = (boost*width<>BITRES>>3 > 2*effectiveBytes/3) + { + opus_int32 cap = ((2*effectiveBytes/3)<mode; + overlap = mode->overlap; + ALLOC(_pre, CC*(N+COMBFILTER_MAXPERIOD), celt_sig); + + pre[0] = _pre; + pre[1] = _pre + (N+COMBFILTER_MAXPERIOD); + + + c=0; do { + OPUS_COPY(pre[c], prefilter_mem+c*COMBFILTER_MAXPERIOD, COMBFILTER_MAXPERIOD); + OPUS_COPY(pre[c]+COMBFILTER_MAXPERIOD, in+c*(N+overlap)+overlap, N); + } while (++c>1, opus_val16); + + pitch_downsample(pre, pitch_buf, COMBFILTER_MAXPERIOD+N, CC, st->arch); + /* Don't search for the fir last 1.5 octave of the range because + there's too many false-positives due to short-term correlation */ + pitch_search(pitch_buf+(COMBFILTER_MAXPERIOD>>1), pitch_buf, N, + COMBFILTER_MAXPERIOD-3*COMBFILTER_MINPERIOD, &pitch_index, + st->arch); + pitch_index = COMBFILTER_MAXPERIOD-pitch_index; + + gain1 = remove_doubling(pitch_buf, COMBFILTER_MAXPERIOD, COMBFILTER_MINPERIOD, + N, &pitch_index, st->prefilter_period, st->prefilter_gain, st->arch); + if (pitch_index > COMBFILTER_MAXPERIOD-2) + pitch_index = COMBFILTER_MAXPERIOD-2; + gain1 = MULT16_16_Q15(QCONST16(.7f,15),gain1); + /*printf("%d %d %f %f\n", pitch_change, pitch_index, gain1, st->analysis.tonality);*/ + if (st->loss_rate>2) + gain1 = HALF32(gain1); + if (st->loss_rate>4) + gain1 = HALF32(gain1); + if (st->loss_rate>8) + gain1 = 0; + } else { + gain1 = 0; + pitch_index = COMBFILTER_MINPERIOD; + } +#ifndef DISABLE_FLOAT_API + if (analysis->valid) + gain1 = (opus_val16)(gain1 * analysis->max_pitch_ratio); +#else + (void)analysis; +#endif + /* Gain threshold for enabling the prefilter/postfilter */ + pf_threshold = QCONST16(.2f,15); + + /* Adjusting the threshold based on rate and continuity */ + if (abs(pitch_index-st->prefilter_period)*10>pitch_index) + pf_threshold += QCONST16(.2f,15); + if (nbAvailableBytes<25) + pf_threshold += QCONST16(.1f,15); + if (nbAvailableBytes<35) + pf_threshold += QCONST16(.1f,15); + if (st->prefilter_gain > QCONST16(.4f,15)) + pf_threshold -= QCONST16(.1f,15); + if (st->prefilter_gain > QCONST16(.55f,15)) + pf_threshold -= QCONST16(.1f,15); + + /* Hard threshold at 0.2 */ + pf_threshold = MAX16(pf_threshold, QCONST16(.2f,15)); + if (gain1prefilter_gain)prefilter_gain; + +#ifdef FIXED_POINT + qg = ((gain1+1536)>>10)/3-1; +#else + qg = (int)floor(.5f+gain1*32/3)-1; +#endif + qg = IMAX(0, IMIN(7, qg)); + gain1 = QCONST16(0.09375f,15)*(qg+1); + pf_on = 1; + } + /*printf("%d %f\n", pitch_index, gain1);*/ + + c=0; do { + int offset = mode->shortMdctSize-overlap; + st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD); + OPUS_COPY(in+c*(N+overlap), st->in_mem+c*(overlap), overlap); + if (offset) + comb_filter(in+c*(N+overlap)+overlap, pre[c]+COMBFILTER_MAXPERIOD, + st->prefilter_period, st->prefilter_period, offset, -st->prefilter_gain, -st->prefilter_gain, + st->prefilter_tapset, st->prefilter_tapset, NULL, 0, st->arch); + + comb_filter(in+c*(N+overlap)+overlap+offset, pre[c]+COMBFILTER_MAXPERIOD+offset, + st->prefilter_period, pitch_index, N-offset, -st->prefilter_gain, -gain1, + st->prefilter_tapset, prefilter_tapset, mode->window, overlap, st->arch); + OPUS_COPY(st->in_mem+c*(overlap), in+c*(N+overlap)+N, overlap); + + if (N>COMBFILTER_MAXPERIOD) + { + OPUS_COPY(prefilter_mem+c*COMBFILTER_MAXPERIOD, pre[c]+N, COMBFILTER_MAXPERIOD); + } else { + OPUS_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD, prefilter_mem+c*COMBFILTER_MAXPERIOD+N, COMBFILTER_MAXPERIOD-N); + OPUS_COPY(prefilter_mem+c*COMBFILTER_MAXPERIOD+COMBFILTER_MAXPERIOD-N, pre[c]+COMBFILTER_MAXPERIOD, N); + } + } while (++cnbEBands; + eBands = mode->eBands; + + coded_bands = lastCodedBands ? lastCodedBands : nbEBands; + coded_bins = eBands[coded_bands]<analysis.activity, st->analysis.tonality, tf_estimate, st->stereo_saving, tot_boost, coded_bands);*/ +#ifndef DISABLE_FLOAT_API + if (analysis->valid && analysis->activity<.4) + target -= (opus_int32)((coded_bins<activity)); +#endif + /* Stereo savings */ + if (C==2) + { + int coded_stereo_bands; + int coded_stereo_dof; + opus_val16 max_frac; + coded_stereo_bands = IMIN(intensity, coded_bands); + coded_stereo_dof = (eBands[coded_stereo_bands]<valid && !lfe) + { + opus_int32 tonal_target; + float tonal; + + /* Tonality boost (compensating for the average). */ + tonal = MAX16(0.f,analysis->tonality-.15f)-0.12f; + tonal_target = target + (opus_int32)((coded_bins<tonality, tonal);*/ + target = tonal_target; + } +#else + (void)analysis; + (void)pitch_change; +#endif + + if (has_surround_mask&&!lfe) + { + opus_int32 surround_target = target + (opus_int32)SHR32(MULT16_16(surround_masking,coded_bins<end, st->intensity, surround_target, target, st->bitrate);*/ + target = IMAX(target/4, surround_target); + } + + { + opus_int32 floor_depth; + int bins; + bins = eBands[nbEBands-2]<>2); + target = IMIN(target, floor_depth); + /*printf("%f %d\n", maxDepth, floor_depth);*/ + } + + /* Make VBR less aggressive for constrained VBR because we can't keep a higher bitrate + for long. Needs tuning. */ + if ((!has_surround_mask||lfe) && constrained_vbr) + { + target = base_target + (opus_int32)MULT16_32_Q15(QCONST16(0.67f, 15), target-base_target); + } + + if (!has_surround_mask && tf_estimate < QCONST16(.2f, 14)) + { + opus_val16 amount; + opus_val16 tvbr_factor; + amount = MULT16_16_Q15(QCONST16(.0000031f, 30), IMAX(0, IMIN(32000, 96000-bitrate))); + tvbr_factor = SHR32(MULT16_16(temporal_vbr, amount), DB_SHIFT); + target += (opus_int32)MULT16_32_Q15(tvbr_factor, target); + } + + /* Don't allow more than doubling the rate */ + target = IMIN(2*base_target, target); + + return target; +} + +int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc) +{ + int i, c, N; + opus_int32 bits; + ec_enc _enc; + VARDECL(celt_sig, in); + VARDECL(celt_sig, freq); + VARDECL(celt_norm, X); + VARDECL(celt_ener, bandE); + VARDECL(opus_val16, bandLogE); + VARDECL(opus_val16, bandLogE2); + VARDECL(int, fine_quant); + VARDECL(opus_val16, error); + VARDECL(int, pulses); + VARDECL(int, cap); + VARDECL(int, offsets); + VARDECL(int, importance); + VARDECL(int, spread_weight); + VARDECL(int, fine_priority); + VARDECL(int, tf_res); + VARDECL(unsigned char, collapse_masks); + celt_sig *prefilter_mem; + opus_val16 *oldBandE, *oldLogE, *oldLogE2, *energyError; + int shortBlocks=0; + int isTransient=0; + const int CC = st->channels; + const int C = st->stream_channels; + int LM, M; + int tf_select; + int nbFilledBytes, nbAvailableBytes; + int start; + int end; + int effEnd; + int codedBands; + int alloc_trim; + int pitch_index=COMBFILTER_MINPERIOD; + opus_val16 gain1 = 0; + int dual_stereo=0; + int effectiveBytes; + int dynalloc_logp; + opus_int32 vbr_rate; + opus_int32 total_bits; + opus_int32 total_boost; + opus_int32 balance; + opus_int32 tell; + opus_int32 tell0_frac; + int prefilter_tapset=0; + int pf_on; + int anti_collapse_rsv; + int anti_collapse_on=0; + int silence=0; + int tf_chan = 0; + opus_val16 tf_estimate; + int pitch_change=0; + opus_int32 tot_boost; + opus_val32 sample_max; + opus_val16 maxDepth; + const OpusCustomMode *mode; + int nbEBands; + int overlap; + const opus_int16 *eBands; + int secondMdct; + int signalBandwidth; + int transient_got_disabled=0; + opus_val16 surround_masking=0; + opus_val16 temporal_vbr=0; + opus_val16 surround_trim = 0; + opus_int32 equiv_rate; + int hybrid; + int weak_transient = 0; + int enable_tf_analysis; + VARDECL(opus_val16, surround_dynalloc); + ALLOC_STACK; + + mode = st->mode; + nbEBands = mode->nbEBands; + overlap = mode->overlap; + eBands = mode->eBands; + start = st->start; + end = st->end; + hybrid = start != 0; + tf_estimate = 0; + if (nbCompressedBytes<2 || pcm==NULL) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + frame_size *= st->upsample; + for (LM=0;LM<=mode->maxLM;LM++) + if (mode->shortMdctSize<mode->maxLM) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + M=1<shortMdctSize; + + prefilter_mem = st->in_mem+CC*(overlap); + oldBandE = (opus_val16*)(st->in_mem+CC*(overlap+COMBFILTER_MAXPERIOD)); + oldLogE = oldBandE + CC*nbEBands; + oldLogE2 = oldLogE + CC*nbEBands; + energyError = oldLogE2 + CC*nbEBands; + + if (enc==NULL) + { + tell0_frac=tell=1; + nbFilledBytes=0; + } else { + tell0_frac=ec_tell_frac(enc); + tell=ec_tell(enc); + nbFilledBytes=(tell+4)>>3; + } + +#ifdef CUSTOM_MODES + if (st->signalling && enc==NULL) + { + int tmp = (mode->effEBands-end)>>1; + end = st->end = IMAX(1, mode->effEBands-tmp); + compressed[0] = tmp<<5; + compressed[0] |= LM<<3; + compressed[0] |= (C==2)<<2; + /* Convert "standard mode" to Opus header */ + if (mode->Fs==48000 && mode->shortMdctSize==120) + { + int c0 = toOpus(compressed[0]); + if (c0<0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + compressed[0] = c0; + } + compressed++; + nbCompressedBytes--; + } +#else + celt_assert(st->signalling==0); +#endif + + /* Can't produce more than 1275 output bytes */ + nbCompressedBytes = IMIN(nbCompressedBytes,1275); + nbAvailableBytes = nbCompressedBytes - nbFilledBytes; + + if (st->vbr && st->bitrate!=OPUS_BITRATE_MAX) + { + opus_int32 den=mode->Fs>>BITRES; + vbr_rate=(st->bitrate*frame_size+(den>>1))/den; +#ifdef CUSTOM_MODES + if (st->signalling) + vbr_rate -= 8<>(3+BITRES); + } else { + opus_int32 tmp; + vbr_rate = 0; + tmp = st->bitrate*frame_size; + if (tell>1) + tmp += tell; + if (st->bitrate!=OPUS_BITRATE_MAX) + nbCompressedBytes = IMAX(2, IMIN(nbCompressedBytes, + (tmp+4*mode->Fs)/(8*mode->Fs)-!!st->signalling)); + effectiveBytes = nbCompressedBytes - nbFilledBytes; + } + equiv_rate = ((opus_int32)nbCompressedBytes*8*50 << (3-LM)) - (40*C+20)*((400>>LM) - 50); + if (st->bitrate != OPUS_BITRATE_MAX) + equiv_rate = IMIN(equiv_rate, st->bitrate - (40*C+20)*((400>>LM) - 50)); + + if (enc==NULL) + { + ec_enc_init(&_enc, compressed, nbCompressedBytes); + enc = &_enc; + } + + if (vbr_rate>0) + { + /* Computes the max bit-rate allowed in VBR mode to avoid violating the + target rate and buffering. + We must do this up front so that bust-prevention logic triggers + correctly if we don't have enough bits. */ + if (st->constrained_vbr) + { + opus_int32 vbr_bound; + opus_int32 max_allowed; + /* We could use any multiple of vbr_rate as bound (depending on the + delay). + This is clamped to ensure we use at least two bytes if the encoder + was entirely empty, but to allow 0 in hybrid mode. */ + vbr_bound = vbr_rate; + max_allowed = IMIN(IMAX(tell==1?2:0, + (vbr_rate+vbr_bound-st->vbr_reservoir)>>(BITRES+3)), + nbAvailableBytes); + if(max_allowed < nbAvailableBytes) + { + nbCompressedBytes = nbFilledBytes+max_allowed; + nbAvailableBytes = max_allowed; + ec_enc_shrink(enc, nbCompressedBytes); + } + } + } + total_bits = nbCompressedBytes*8; + + effEnd = end; + if (effEnd > mode->effEBands) + effEnd = mode->effEBands; + + ALLOC(in, CC*(N+overlap), celt_sig); + + sample_max=MAX32(st->overlap_max, celt_maxabs16(pcm, C*(N-overlap)/st->upsample)); + st->overlap_max=celt_maxabs16(pcm+C*(N-overlap)/st->upsample, C*overlap/st->upsample); + sample_max=MAX32(sample_max, st->overlap_max); +#ifdef FIXED_POINT + silence = (sample_max==0); +#else + silence = (sample_max <= (opus_val16)1/(1<lsb_depth)); +#endif +#ifdef FUZZING + if ((rand()&0x3F)==0) + silence = 1; +#endif + if (tell==1) + ec_enc_bit_logp(enc, silence, 15); + else + silence=0; + if (silence) + { + /*In VBR mode there is no need to send more than the minimum. */ + if (vbr_rate>0) + { + effectiveBytes=nbCompressedBytes=IMIN(nbCompressedBytes, nbFilledBytes+2); + total_bits=nbCompressedBytes*8; + nbAvailableBytes=2; + ec_enc_shrink(enc, nbCompressedBytes); + } + /* Pretend we've filled all the remaining bits with zeros + (that's what the initialiser did anyway) */ + tell = nbCompressedBytes*8; + enc->nbits_total+=tell-ec_tell(enc); + } + c=0; do { + int need_clip=0; +#ifndef FIXED_POINT + need_clip = st->clip && sample_max>65536.f; +#endif + celt_preemphasis(pcm+c, in+c*(N+overlap)+overlap, N, CC, st->upsample, + mode->preemph, st->preemph_memE+c, need_clip); + } while (++clfe&&nbAvailableBytes>3) || nbAvailableBytes>12*C) && !hybrid && !silence && !st->disable_pf + && st->complexity >= 5; + + prefilter_tapset = st->tapset_decision; + pf_on = run_prefilter(st, in, prefilter_mem, CC, N, prefilter_tapset, &pitch_index, &gain1, &qg, enabled, nbAvailableBytes, &st->analysis); + if ((gain1 > QCONST16(.4f,15) || st->prefilter_gain > QCONST16(.4f,15)) && (!st->analysis.valid || st->analysis.tonality > .3) + && (pitch_index > 1.26*st->prefilter_period || pitch_index < .79*st->prefilter_period)) + pitch_change = 1; + if (pf_on==0) + { + if(!hybrid && tell+16<=total_bits) + ec_enc_bit_logp(enc, 0, 1); + } else { + /*This block is not gated by a total bits check only because + of the nbAvailableBytes check above.*/ + int octave; + ec_enc_bit_logp(enc, 1, 1); + pitch_index += 1; + octave = EC_ILOG(pitch_index)-5; + ec_enc_uint(enc, octave, 6); + ec_enc_bits(enc, pitch_index-(16<complexity >= 1 && !st->lfe) + { + /* Reduces the likelihood of energy instability on fricatives at low bitrate + in hybrid mode. It seems like we still want to have real transients on vowels + though (small SILK quantization offset value). */ + int allow_weak_transients = hybrid && effectiveBytes<15 && st->silk_info.signalType != 2; + isTransient = transient_analysis(in, N+overlap, CC, + &tf_estimate, &tf_chan, allow_weak_transients, &weak_transient); + } + if (LM>0 && ec_tell(enc)+3<=total_bits) + { + if (isTransient) + shortBlocks = M; + } else { + isTransient = 0; + transient_got_disabled=1; + } + + ALLOC(freq, CC*N, celt_sig); /**< Interleaved signal MDCTs */ + ALLOC(bandE,nbEBands*CC, celt_ener); + ALLOC(bandLogE,nbEBands*CC, opus_val16); + + secondMdct = shortBlocks && st->complexity>=8; + ALLOC(bandLogE2, C*nbEBands, opus_val16); + if (secondMdct) + { + compute_mdcts(mode, 0, in, freq, C, CC, LM, st->upsample, st->arch); + compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch); + amp2Log2(mode, effEnd, end, bandE, bandLogE2, C); + for (i=0;iupsample, st->arch); + /* This should catch any NaN in the CELT input. Since we're not supposed to see any (they're filtered + at the Opus layer), just abort. */ + celt_assert(!celt_isnan(freq[0]) && (C==1 || !celt_isnan(freq[N]))); + if (CC==2&&C==1) + tf_chan = 0; + compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch); + + if (st->lfe) + { + for (i=2;ienergy_mask&&!st->lfe) + { + int mask_end; + int midband; + int count_dynalloc; + opus_val32 mask_avg=0; + opus_val32 diff=0; + int count=0; + mask_end = IMAX(2,st->lastCodedBands); + for (c=0;cenergy_mask[nbEBands*c+i], + QCONST16(.25f, DB_SHIFT)), -QCONST16(2.0f, DB_SHIFT)); + if (mask > 0) + mask = HALF16(mask); + mask_avg += MULT16_16(mask, eBands[i+1]-eBands[i]); + count += eBands[i+1]-eBands[i]; + diff += MULT16_16(mask, 1+2*i-mask_end); + } + } + celt_assert(count>0); + mask_avg = DIV32_16(mask_avg,count); + mask_avg += QCONST16(.2f, DB_SHIFT); + diff = diff*6/(C*(mask_end-1)*(mask_end+1)*mask_end); + /* Again, being conservative */ + diff = HALF32(diff); + diff = MAX32(MIN32(diff, QCONST32(.031f, DB_SHIFT)), -QCONST32(.031f, DB_SHIFT)); + /* Find the band that's in the middle of the coded spectrum */ + for (midband=0;eBands[midband+1] < eBands[mask_end]/2;midband++); + count_dynalloc=0; + for(i=0;ienergy_mask[i], st->energy_mask[nbEBands+i]); + else + unmask = st->energy_mask[i]; + unmask = MIN16(unmask, QCONST16(.0f, DB_SHIFT)); + unmask -= lin; + if (unmask > QCONST16(.25f, DB_SHIFT)) + { + surround_dynalloc[i] = unmask - QCONST16(.25f, DB_SHIFT); + count_dynalloc++; + } + } + if (count_dynalloc>=3) + { + /* If we need dynalloc in many bands, it's probably because our + initial masking rate was too low. */ + mask_avg += QCONST16(.25f, DB_SHIFT); + if (mask_avg>0) + { + /* Something went really wrong in the original calculations, + disabling masking. */ + mask_avg = 0; + diff = 0; + OPUS_CLEAR(surround_dynalloc, mask_end); + } else { + for(i=0;ilfe) + { + opus_val16 follow=-QCONST16(10.0f,DB_SHIFT); + opus_val32 frame_avg=0; + opus_val16 offset = shortBlocks?HALF16(SHL16(LM, DB_SHIFT)):0; + for(i=start;ispec_avg); + temporal_vbr = MIN16(QCONST16(3.f, DB_SHIFT), MAX16(-QCONST16(1.5f, DB_SHIFT), temporal_vbr)); + st->spec_avg += MULT16_16_Q15(QCONST16(.02f, 15), temporal_vbr); + } + /*for (i=0;i<21;i++) + printf("%f ", bandLogE[i]); + printf("\n");*/ + + if (!secondMdct) + { + OPUS_COPY(bandLogE2, bandLogE, C*nbEBands); + } + + /* Last chance to catch any transient we might have missed in the + time-domain analysis */ + if (LM>0 && ec_tell(enc)+3<=total_bits && !isTransient && st->complexity>=5 && !st->lfe && !hybrid) + { + if (patch_transient_decision(bandLogE, oldBandE, nbEBands, start, end, C)) + { + isTransient = 1; + shortBlocks = M; + compute_mdcts(mode, shortBlocks, in, freq, C, CC, LM, st->upsample, st->arch); + compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch); + amp2Log2(mode, effEnd, end, bandE, bandLogE, C); + /* Compensate for the scaling of short vs long mdcts */ + for (i=0;i0 && ec_tell(enc)+3<=total_bits) + ec_enc_bit_logp(enc, isTransient, 3); + + ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */ + + /* Band normalisation */ + normalise_bands(mode, freq, X, bandE, effEnd, C, M); + + enable_tf_analysis = effectiveBytes>=15*C && !hybrid && st->complexity>=2 && !st->lfe; + + ALLOC(offsets, nbEBands, int); + ALLOC(importance, nbEBands, int); + ALLOC(spread_weight, nbEBands, int); + + maxDepth = dynalloc_analysis(bandLogE, bandLogE2, nbEBands, start, end, C, offsets, + st->lsb_depth, mode->logN, isTransient, st->vbr, st->constrained_vbr, + eBands, LM, effectiveBytes, &tot_boost, st->lfe, surround_dynalloc, &st->analysis, importance, spread_weight); + + ALLOC(tf_res, nbEBands, int); + /* Disable variable tf resolution for hybrid and at very low bitrate */ + if (enable_tf_analysis) + { + int lambda; + lambda = IMAX(80, 20480/effectiveBytes + 2); + tf_select = tf_analysis(mode, effEnd, isTransient, tf_res, lambda, X, N, LM, tf_estimate, tf_chan, importance); + for (i=effEnd;isilk_info.signalType != 2) + { + /* For low bitrate hybrid, we force temporal resolution to 5 ms rather than 2.5 ms. */ + for (i=0;iforce_intra, + &st->delayedIntra, st->complexity >= 4, st->loss_rate, st->lfe); + + tf_encode(start, end, isTransient, tf_res, LM, tf_select, enc); + + if (ec_tell(enc)+4<=total_bits) + { + if (st->lfe) + { + st->tapset_decision = 0; + st->spread_decision = SPREAD_NORMAL; + } else if (hybrid) + { + if (st->complexity == 0) + st->spread_decision = SPREAD_NONE; + else if (isTransient) + st->spread_decision = SPREAD_NORMAL; + else + st->spread_decision = SPREAD_AGGRESSIVE; + } else if (shortBlocks || st->complexity < 3 || nbAvailableBytes < 10*C) + { + if (st->complexity == 0) + st->spread_decision = SPREAD_NONE; + else + st->spread_decision = SPREAD_NORMAL; + } else { + /* Disable new spreading+tapset estimator until we can show it works + better than the old one. So far it seems like spreading_decision() + works best. */ +#if 0 + if (st->analysis.valid) + { + static const opus_val16 spread_thresholds[3] = {-QCONST16(.6f, 15), -QCONST16(.2f, 15), -QCONST16(.07f, 15)}; + static const opus_val16 spread_histeresis[3] = {QCONST16(.15f, 15), QCONST16(.07f, 15), QCONST16(.02f, 15)}; + static const opus_val16 tapset_thresholds[2] = {QCONST16(.0f, 15), QCONST16(.15f, 15)}; + static const opus_val16 tapset_histeresis[2] = {QCONST16(.1f, 15), QCONST16(.05f, 15)}; + st->spread_decision = hysteresis_decision(-st->analysis.tonality, spread_thresholds, spread_histeresis, 3, st->spread_decision); + st->tapset_decision = hysteresis_decision(st->analysis.tonality_slope, tapset_thresholds, tapset_histeresis, 2, st->tapset_decision); + } else +#endif + { + st->spread_decision = spreading_decision(mode, X, + &st->tonal_average, st->spread_decision, &st->hf_average, + &st->tapset_decision, pf_on&&!shortBlocks, effEnd, C, M, spread_weight); + } + /*printf("%d %d\n", st->tapset_decision, st->spread_decision);*/ + /*printf("%f %d %f %d\n\n", st->analysis.tonality, st->spread_decision, st->analysis.tonality_slope, st->tapset_decision);*/ + } + ec_enc_icdf(enc, st->spread_decision, spread_icdf, 5); + } + + /* For LFE, everything interesting is in the first band */ + if (st->lfe) + offsets[0] = IMIN(8, effectiveBytes/3); + ALLOC(cap, nbEBands, int); + init_caps(mode,cap,LM,C); + + dynalloc_logp = 6; + total_bits<<=BITRES; + total_boost = 0; + tell = ec_tell_frac(enc); + for (i=start;iintensity = hysteresis_decision((opus_val16)(equiv_rate/1000), + intensity_thresholds, intensity_histeresis, 21, st->intensity); + st->intensity = IMIN(end,IMAX(start, st->intensity)); + } + + alloc_trim = 5; + if (tell+(6< 0 || st->lfe) + { + st->stereo_saving = 0; + alloc_trim = 5; + } else { + alloc_trim = alloc_trim_analysis(mode, X, bandLogE, + end, LM, C, N, &st->analysis, &st->stereo_saving, tf_estimate, + st->intensity, surround_trim, equiv_rate, st->arch); + } + ec_enc_icdf(enc, alloc_trim, trim_icdf, 7); + tell = ec_tell_frac(enc); + } + + /* Variable bitrate */ + if (vbr_rate>0) + { + opus_val16 alpha; + opus_int32 delta; + /* The target rate in 8th bits per frame */ + opus_int32 target, base_target; + opus_int32 min_allowed; + int lm_diff = mode->maxLM - LM; + + /* Don't attempt to use more than 510 kb/s, even for frames smaller than 20 ms. + The CELT allocator will just not be able to use more than that anyway. */ + nbCompressedBytes = IMIN(nbCompressedBytes,1275>>(3-LM)); + if (!hybrid) + { + base_target = vbr_rate - ((40*C+20)<constrained_vbr) + base_target += (st->vbr_offset>>lm_diff); + + if (!hybrid) + { + target = compute_vbr(mode, &st->analysis, base_target, LM, equiv_rate, + st->lastCodedBands, C, st->intensity, st->constrained_vbr, + st->stereo_saving, tot_boost, tf_estimate, pitch_change, maxDepth, + st->lfe, st->energy_mask!=NULL, surround_masking, + temporal_vbr); + } else { + target = base_target; + /* Tonal frames (offset<100) need more bits than noisy (offset>100) ones. */ + if (st->silk_info.offset < 100) target += 12 << BITRES >> (3-LM); + if (st->silk_info.offset > 100) target -= 18 << BITRES >> (3-LM); + /* Boosting bitrate on transients and vowels with significant temporal + spikes. */ + target += (opus_int32)MULT16_16_Q14(tf_estimate-QCONST16(.25f,14), (50< QCONST16(.7f,14)) + target = IMAX(target, 50<>(BITRES+3)) + 2; + /* Take into account the 37 bits we need to have left in the packet to + signal a redundant frame in hybrid mode. Creating a shorter packet would + create an entropy coder desync. */ + if (hybrid) + min_allowed = IMAX(min_allowed, (tell0_frac+(37<>(BITRES+3)); + + nbAvailableBytes = (target+(1<<(BITRES+2)))>>(BITRES+3); + nbAvailableBytes = IMAX(min_allowed,nbAvailableBytes); + nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes); + + /* By how much did we "miss" the target on that frame */ + delta = target - vbr_rate; + + target=nbAvailableBytes<<(BITRES+3); + + /*If the frame is silent we don't adjust our drift, otherwise + the encoder will shoot to very high rates after hitting a + span of silence, but we do allow the bitres to refill. + This means that we'll undershoot our target in CVBR/VBR modes + on files with lots of silence. */ + if(silence) + { + nbAvailableBytes = 2; + target = 2*8<vbr_count < 970) + { + st->vbr_count++; + alpha = celt_rcp(SHL32(EXTEND32(st->vbr_count+20),16)); + } else + alpha = QCONST16(.001f,15); + /* How many bits have we used in excess of what we're allowed */ + if (st->constrained_vbr) + st->vbr_reservoir += target - vbr_rate; + /*printf ("%d\n", st->vbr_reservoir);*/ + + /* Compute the offset we need to apply in order to reach the target */ + if (st->constrained_vbr) + { + st->vbr_drift += (opus_int32)MULT16_32_Q15(alpha,(delta*(1<vbr_offset-st->vbr_drift); + st->vbr_offset = -st->vbr_drift; + } + /*printf ("%d\n", st->vbr_drift);*/ + + if (st->constrained_vbr && st->vbr_reservoir < 0) + { + /* We're under the min value -- increase rate */ + int adjust = (-st->vbr_reservoir)/(8<vbr_reservoir = 0; + /*printf ("+%d\n", adjust);*/ + } + nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes); + /*printf("%d\n", nbCompressedBytes*50*8);*/ + /* This moves the raw bits to take into account the new compressed size */ + ec_enc_shrink(enc, nbCompressedBytes); + } + + /* Bit allocation */ + ALLOC(fine_quant, nbEBands, int); + ALLOC(pulses, nbEBands, int); + ALLOC(fine_priority, nbEBands, int); + + /* bits = packet size - where we are - safety*/ + bits = (((opus_int32)nbCompressedBytes*8)<=2&&bits>=((LM+2)<analysis.valid) + { + int min_bandwidth; + if (equiv_rate < (opus_int32)32000*C) + min_bandwidth = 13; + else if (equiv_rate < (opus_int32)48000*C) + min_bandwidth = 16; + else if (equiv_rate < (opus_int32)60000*C) + min_bandwidth = 18; + else if (equiv_rate < (opus_int32)80000*C) + min_bandwidth = 19; + else + min_bandwidth = 20; + signalBandwidth = IMAX(st->analysis.bandwidth, min_bandwidth); + } +#endif + if (st->lfe) + signalBandwidth = 1; + codedBands = clt_compute_allocation(mode, start, end, offsets, cap, + alloc_trim, &st->intensity, &dual_stereo, bits, &balance, pulses, + fine_quant, fine_priority, C, LM, enc, 1, st->lastCodedBands, signalBandwidth); + if (st->lastCodedBands) + st->lastCodedBands = IMIN(st->lastCodedBands+1,IMAX(st->lastCodedBands-1,codedBands)); + else + st->lastCodedBands = codedBands; + + quant_fine_energy(mode, start, end, oldBandE, error, fine_quant, enc, C); + + /* Residual quantisation */ + ALLOC(collapse_masks, C*nbEBands, unsigned char); + quant_all_bands(1, mode, start, end, X, C==2 ? X+N : NULL, collapse_masks, + bandE, pulses, shortBlocks, st->spread_decision, + dual_stereo, st->intensity, tf_res, nbCompressedBytes*(8<rng, st->complexity, st->arch, st->disable_inv); + + if (anti_collapse_rsv > 0) + { + anti_collapse_on = st->consec_transient<2; +#ifdef FUZZING + anti_collapse_on = rand()&0x1; +#endif + ec_enc_bits(enc, anti_collapse_on, 1); + } + quant_energy_finalise(mode, start, end, oldBandE, error, fine_quant, fine_priority, nbCompressedBytes*8-ec_tell(enc), enc, C); + OPUS_CLEAR(energyError, nbEBands*CC); + c=0; + do { + for (i=start;irng); + } + + c=0; do { + OPUS_MOVE(st->syn_mem[c], st->syn_mem[c]+N, 2*MAX_PERIOD-N+overlap/2); + } while (++csyn_mem[c]+2*MAX_PERIOD-N; + } while (++cupsample, silence, st->arch); + + c=0; do { + st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD); + st->prefilter_period_old=IMAX(st->prefilter_period_old, COMBFILTER_MINPERIOD); + comb_filter(out_mem[c], out_mem[c], st->prefilter_period_old, st->prefilter_period, mode->shortMdctSize, + st->prefilter_gain_old, st->prefilter_gain, st->prefilter_tapset_old, st->prefilter_tapset, + mode->window, overlap); + if (LM!=0) + comb_filter(out_mem[c]+mode->shortMdctSize, out_mem[c]+mode->shortMdctSize, st->prefilter_period, pitch_index, N-mode->shortMdctSize, + st->prefilter_gain, gain1, st->prefilter_tapset, prefilter_tapset, + mode->window, overlap); + } while (++cupsample, mode->preemph, st->preemph_memD); + st->prefilter_period_old = st->prefilter_period; + st->prefilter_gain_old = st->prefilter_gain; + st->prefilter_tapset_old = st->prefilter_tapset; + } +#endif + + st->prefilter_period = pitch_index; + st->prefilter_gain = gain1; + st->prefilter_tapset = prefilter_tapset; +#ifdef RESYNTH + if (LM!=0) + { + st->prefilter_period_old = st->prefilter_period; + st->prefilter_gain_old = st->prefilter_gain; + st->prefilter_tapset_old = st->prefilter_tapset; + } +#endif + + if (CC==2&&C==1) { + OPUS_COPY(&oldBandE[nbEBands], oldBandE, nbEBands); + } + + if (!isTransient) + { + OPUS_COPY(oldLogE2, oldLogE, CC*nbEBands); + OPUS_COPY(oldLogE, oldBandE, CC*nbEBands); + } else { + for (i=0;iconsec_transient++; + else + st->consec_transient=0; + st->rng = enc->rng; + + /* If there's any room left (can only happen for very high rates), + it's already filled with zeros */ + ec_enc_done(enc); + +#ifdef CUSTOM_MODES + if (st->signalling) + nbCompressedBytes++; +#endif + + RESTORE_STACK; + if (ec_get_error(enc)) + return OPUS_INTERNAL_ERROR; + else + return nbCompressedBytes; +} + + +#ifdef CUSTOM_MODES + +#ifdef FIXED_POINT +int opus_custom_encode(CELTEncoder * OPUS_RESTRICT st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes) +{ + return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL); +} + +#ifndef DISABLE_FLOAT_API +int opus_custom_encode_float(CELTEncoder * OPUS_RESTRICT st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes) +{ + int j, ret, C, N; + VARDECL(opus_int16, in); + ALLOC_STACK; + + if (pcm==NULL) + return OPUS_BAD_ARG; + + C = st->channels; + N = frame_size; + ALLOC(in, C*N, opus_int16); + + for (j=0;jchannels; + N=frame_size; + ALLOC(in, C*N, celt_sig); + for (j=0;j10) + goto bad_arg; + st->complexity = value; + } + break; + case CELT_SET_START_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<0 || value>=st->mode->nbEBands) + goto bad_arg; + st->start = value; + } + break; + case CELT_SET_END_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>st->mode->nbEBands) + goto bad_arg; + st->end = value; + } + break; + case CELT_SET_PREDICTION_REQUEST: + { + int value = va_arg(ap, opus_int32); + if (value<0 || value>2) + goto bad_arg; + st->disable_pf = value<=1; + st->force_intra = value==0; + } + break; + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + { + int value = va_arg(ap, opus_int32); + if (value<0 || value>100) + goto bad_arg; + st->loss_rate = value; + } + break; + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->constrained_vbr = value; + } + break; + case OPUS_SET_VBR_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->vbr = value; + } + break; + case OPUS_SET_BITRATE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<=500 && value!=OPUS_BITRATE_MAX) + goto bad_arg; + value = IMIN(value, 260000*st->channels); + st->bitrate = value; + } + break; + case CELT_SET_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>2) + goto bad_arg; + st->stream_channels = value; + } + break; + case OPUS_SET_LSB_DEPTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<8 || value>24) + goto bad_arg; + st->lsb_depth=value; + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value=st->lsb_depth; + } + break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->disable_inv = value; + } + break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->disable_inv; + } + break; + case OPUS_RESET_STATE: + { + int i; + opus_val16 *oldBandE, *oldLogE, *oldLogE2; + oldBandE = (opus_val16*)(st->in_mem+st->channels*(st->mode->overlap+COMBFILTER_MAXPERIOD)); + oldLogE = oldBandE + st->channels*st->mode->nbEBands; + oldLogE2 = oldLogE + st->channels*st->mode->nbEBands; + OPUS_CLEAR((char*)&st->ENCODER_RESET_START, + opus_custom_encoder_get_size(st->mode, st->channels)- + ((char*)&st->ENCODER_RESET_START - (char*)st)); + for (i=0;ichannels*st->mode->nbEBands;i++) + oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT); + st->vbr_offset = 0; + st->delayedIntra = 1; + st->spread_decision = SPREAD_NORMAL; + st->tonal_average = 256; + st->hf_average = 0; + st->tapset_decision = 0; + } + break; +#ifdef CUSTOM_MODES + case CELT_SET_INPUT_CLIPPING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->clip = value; + } + break; +#endif + case CELT_SET_SIGNALLING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->signalling = value; + } + break; + case CELT_SET_ANALYSIS_REQUEST: + { + AnalysisInfo *info = va_arg(ap, AnalysisInfo *); + if (info) + OPUS_COPY(&st->analysis, info, 1); + } + break; + case CELT_SET_SILK_INFO_REQUEST: + { + SILKInfo *info = va_arg(ap, SILKInfo *); + if (info) + OPUS_COPY(&st->silk_info, info, 1); + } + break; + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (value==0) + goto bad_arg; + *value=st->mode; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 * value = va_arg(ap, opus_uint32 *); + if (value==0) + goto bad_arg; + *value=st->rng; + } + break; + case OPUS_SET_LFE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->lfe = value; + } + break; + case OPUS_SET_ENERGY_MASK_REQUEST: + { + opus_val16 *value = va_arg(ap, opus_val16*); + st->energy_mask = value; + } + break; + default: + goto bad_request; + } + va_end(ap); + return OPUS_OK; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +bad_request: + va_end(ap); + return OPUS_UNIMPLEMENTED; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/celt_lpc.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/celt_lpc.c new file mode 100644 index 000000000..457e7ed0d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/celt_lpc.c @@ -0,0 +1,340 @@ +/* Copyright (c) 2009-2010 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "pitch.h" + +void _celt_lpc( + opus_val16 *_lpc, /* out: [0...p-1] LPC coefficients */ +const opus_val32 *ac, /* in: [0...p] autocorrelation values */ +int p +) +{ + int i, j; + opus_val32 r; + opus_val32 error = ac[0]; +#ifdef FIXED_POINT + opus_val32 lpc[LPC_ORDER]; +#else + float *lpc = _lpc; +#endif + + OPUS_CLEAR(lpc, p); + if (ac[0] != 0) + { + for (i = 0; i < p; i++) { + /* Sum up this iteration's reflection coefficient */ + opus_val32 rr = 0; + for (j = 0; j < i; j++) + rr += MULT32_32_Q31(lpc[j],ac[i - j]); + rr += SHR32(ac[i + 1],6); + r = -frac_div32(SHL32(rr,6), error); + /* Update LPC coefficients and total error */ + lpc[i] = SHR32(r,6); + for (j = 0; j < (i+1)>>1; j++) + { + opus_val32 tmp1, tmp2; + tmp1 = lpc[j]; + tmp2 = lpc[i-1-j]; + lpc[j] = tmp1 + MULT32_32_Q31(r,tmp2); + lpc[i-1-j] = tmp2 + MULT32_32_Q31(r,tmp1); + } + + error = error - MULT32_32_Q31(MULT32_32_Q31(r,r),error); + /* Bail out once we get 30 dB gain */ +#ifdef FIXED_POINT + if (error maxabs) { + maxabs = absval; + idx = i; + } + } + maxabs = PSHR32(maxabs, 13); /* Q25->Q12 */ + + if (maxabs > 32767) { + maxabs = MIN32(maxabs, 163838); + chirp_Q16 = QCONST32(0.999, 16) - DIV32(SHL32(maxabs - 32767, 14), + SHR32(MULT32_32_32(maxabs, idx + 1), 2)); + chirp_minus_one_Q16 = chirp_Q16 - 65536; + + /* Apply bandwidth expansion. */ + for (i = 0; i < p - 1; i++) { + lpc[i] = MULT32_32_Q16(chirp_Q16, lpc[i]); + chirp_Q16 += PSHR32(MULT32_32_32(chirp_Q16, chirp_minus_one_Q16), 16); + } + lpc[p - 1] = MULT32_32_Q16(chirp_Q16, lpc[p - 1]); + } else { + break; + } + } + + if (iter == 10) { + /* If the coeffs still do not fit into the 16 bit range after 10 iterations, + fall back to the A(z)=1 filter. */ + OPUS_CLEAR(lpc, p); + _lpc[0] = 4096; /* Q12 */ + } else { + for (i = 0; i < p; i++) { + _lpc[i] = EXTRACT16(PSHR32(lpc[i], 13)); /* Q25->Q12 */ + } + } + } +#endif +} + + +void celt_fir_c( + const opus_val16 *x, + const opus_val16 *num, + opus_val16 *y, + int N, + int ord, + int arch) +{ + int i,j; + VARDECL(opus_val16, rnum); + SAVE_STACK; + celt_assert(x != y); + ALLOC(rnum, ord, opus_val16); + for(i=0;i=1;j--) + { + mem[j]=mem[j-1]; + } + mem[0] = SROUND16(sum, SIG_SHIFT); + _y[i] = sum; + } +#else + int i,j; + VARDECL(opus_val16, rden); + VARDECL(opus_val16, y); + SAVE_STACK; + + celt_assert((ord&3)==0); + ALLOC(rden, ord, opus_val16); + ALLOC(y, N+ord, opus_val16); + for(i=0;i0); + celt_assert(overlap>=0); + if (overlap == 0) + { + xptr = x; + } else { + for (i=0;i0) + { + for(i=0;i= 536870912) + { + int shift2=1; + if (ac[0] >= 1073741824) + shift2++; + for (i=0;i<=lag;i++) + ac[i] = SHR32(ac[i], shift2); + shift += shift2; + } +#endif + + RESTORE_STACK; + return shift; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/celt_lpc.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/celt_lpc.h new file mode 100644 index 000000000..a4c5fd6ea --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/celt_lpc.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2009-2010 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef PLC_H +#define PLC_H + +#include "arch.h" +#include "cpu_support.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) +#include "x86/celt_lpc_sse.h" +#endif + +#define LPC_ORDER 24 + +void _celt_lpc(opus_val16 *_lpc, const opus_val32 *ac, int p); + +void celt_fir_c( + const opus_val16 *x, + const opus_val16 *num, + opus_val16 *y, + int N, + int ord, + int arch); + +#if !defined(OVERRIDE_CELT_FIR) +#define celt_fir(x, num, y, N, ord, arch) \ + (celt_fir_c(x, num, y, N, ord, arch)) +#endif + +void celt_iir(const opus_val32 *x, + const opus_val16 *den, + opus_val32 *y, + int N, + int ord, + opus_val16 *mem, + int arch); + +int _celt_autocorr(const opus_val16 *x, opus_val32 *ac, + const opus_val16 *window, int overlap, int lag, int n, int arch); + +#endif /* PLC_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/cpu_support.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/cpu_support.h new file mode 100644 index 000000000..68fc60678 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/cpu_support.h @@ -0,0 +1,70 @@ +/* Copyright (c) 2010 Xiph.Org Foundation + * Copyright (c) 2013 Parrot */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef CPU_SUPPORT_H +#define CPU_SUPPORT_H + +#include "opus_types.h" +#include "opus_defines.h" + +#if defined(OPUS_HAVE_RTCD) && \ + (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#include "arm/armcpu.h" + +/* We currently support 4 ARM variants: + * arch[0] -> ARMv4 + * arch[1] -> ARMv5E + * arch[2] -> ARMv6 + * arch[3] -> NEON + */ +#define OPUS_ARCHMASK 3 + +#elif (defined(OPUS_X86_MAY_HAVE_SSE) && !defined(OPUS_X86_PRESUME_SSE)) || \ + (defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(OPUS_X86_PRESUME_SSE2)) || \ + (defined(OPUS_X86_MAY_HAVE_SSE4_1) && !defined(OPUS_X86_PRESUME_SSE4_1)) || \ + (defined(OPUS_X86_MAY_HAVE_AVX) && !defined(OPUS_X86_PRESUME_AVX)) + +#include "x86/x86cpu.h" +/* We currently support 5 x86 variants: + * arch[0] -> non-sse + * arch[1] -> sse + * arch[2] -> sse2 + * arch[3] -> sse4.1 + * arch[4] -> avx + */ +#define OPUS_ARCHMASK 7 +int opus_select_arch(void); + +#else +#define OPUS_ARCHMASK 0 + +static OPUS_INLINE int opus_select_arch(void) +{ + return 0; +} +#endif +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/cwrs.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/cwrs.c new file mode 100644 index 000000000..a552e4f0f --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/cwrs.c @@ -0,0 +1,715 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2007-2009 Timothy B. Terriberry + Written by Timothy B. Terriberry and Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "os_support.h" +#include "cwrs.h" +#include "mathops.h" +#include "arch.h" + +#ifdef CUSTOM_MODES + +/*Guaranteed to return a conservatively large estimate of the binary logarithm + with frac bits of fractional precision. + Tested for all possible 32-bit inputs with frac=4, where the maximum + overestimation is 0.06254243 bits.*/ +int log2_frac(opus_uint32 val, int frac) +{ + int l; + l=EC_ILOG(val); + if(val&(val-1)){ + /*This is (val>>l-16), but guaranteed to round up, even if adding a bias + before the shift would cause overflow (e.g., for 0xFFFFxxxx). + Doesn't work for val=0, but that case fails the test above.*/ + if(l>16)val=((val-1)>>(l-16))+1; + else val<<=16-l; + l=(l-1)<>16); + l+=b<>b; + val=(val*val+0x7FFF)>>15; + } + while(frac-->0); + /*If val is not exactly 0x8000, then we have to round up the remainder.*/ + return l+(val>0x8000); + } + /*Exact powers of two require no rounding.*/ + else return (l-1)<0 ? sum(k=1...K,2**k*choose(N,k)*choose(K-1,k-1)) : 1, + where choose() is the binomial function. + A table of values for N<10 and K<10 looks like: + V[10][10] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 2, 2, 2, 2, 2, 2, 2, 2, 2}, + {1, 4, 8, 12, 16, 20, 24, 28, 32, 36}, + {1, 6, 18, 38, 66, 102, 146, 198, 258, 326}, + {1, 8, 32, 88, 192, 360, 608, 952, 1408, 1992}, + {1, 10, 50, 170, 450, 1002, 1970, 3530, 5890, 9290}, + {1, 12, 72, 292, 912, 2364, 5336, 10836, 20256, 35436}, + {1, 14, 98, 462, 1666, 4942, 12642, 28814, 59906, 115598}, + {1, 16, 128, 688, 2816, 9424, 27008, 68464, 157184, 332688}, + {1, 18, 162, 978, 4482, 16722, 53154, 148626, 374274, 864146} + }; + + U(N,K) = the number of such combinations wherein N-1 objects are taken at + most K-1 at a time. + This is given by + U(N,K) = sum(k=0...K-1,V(N-1,k)) + = K>0 ? (V(N-1,K-1) + V(N,K-1))/2 : 0. + The latter expression also makes clear that U(N,K) is half the number of such + combinations wherein the first object is taken at least once. + Although it may not be clear from either of these definitions, U(N,K) is the + natural function to work with when enumerating the pulse vector codebooks, + not V(N,K). + U(N,K) is not well-defined for N=0, but with the extension + U(0,K) = K>0 ? 0 : 1, + the function becomes symmetric: U(N,K) = U(K,N), with a similar table: + U[10][10] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {0, 1, 3, 5, 7, 9, 11, 13, 15, 17}, + {0, 1, 5, 13, 25, 41, 61, 85, 113, 145}, + {0, 1, 7, 25, 63, 129, 231, 377, 575, 833}, + {0, 1, 9, 41, 129, 321, 681, 1289, 2241, 3649}, + {0, 1, 11, 61, 231, 681, 1683, 3653, 7183, 13073}, + {0, 1, 13, 85, 377, 1289, 3653, 8989, 19825, 40081}, + {0, 1, 15, 113, 575, 2241, 7183, 19825, 48639, 108545}, + {0, 1, 17, 145, 833, 3649, 13073, 40081, 108545, 265729} + }; + + With this extension, V(N,K) may be written in terms of U(N,K): + V(N,K) = U(N,K) + U(N,K+1) + for all N>=0, K>=0. + Thus U(N,K+1) represents the number of combinations where the first element + is positive or zero, and U(N,K) represents the number of combinations where + it is negative. + With a large enough table of U(N,K) values, we could write O(N) encoding + and O(min(N*log(K),N+K)) decoding routines, but such a table would be + prohibitively large for small embedded devices (K may be as large as 32767 + for small N, and N may be as large as 200). + + Both functions obey the same recurrence relation: + V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1), + U(N,K) = U(N-1,K) + U(N,K-1) + U(N-1,K-1), + for all N>0, K>0, with different initial conditions at N=0 or K=0. + This allows us to construct a row of one of the tables above given the + previous row or the next row. + Thus we can derive O(NK) encoding and decoding routines with O(K) memory + using only addition and subtraction. + + When encoding, we build up from the U(2,K) row and work our way forwards. + When decoding, we need to start at the U(N,K) row and work our way backwards, + which requires a means of computing U(N,K). + U(N,K) may be computed from two previous values with the same N: + U(N,K) = ((2*N-1)*U(N,K-1) - U(N,K-2))/(K-1) + U(N,K-2) + for all N>1, and since U(N,K) is symmetric, a similar relation holds for two + previous values with the same K: + U(N,K>1) = ((2*K-1)*U(N-1,K) - U(N-2,K))/(N-1) + U(N-2,K) + for all K>1. + This allows us to construct an arbitrary row of the U(N,K) table by starting + with the first two values, which are constants. + This saves roughly 2/3 the work in our O(NK) decoding routine, but costs O(K) + multiplications. + Similar relations can be derived for V(N,K), but are not used here. + + For N>0 and K>0, U(N,K) and V(N,K) take on the form of an (N-1)-degree + polynomial for fixed N. + The first few are + U(1,K) = 1, + U(2,K) = 2*K-1, + U(3,K) = (2*K-2)*K+1, + U(4,K) = (((4*K-6)*K+8)*K-3)/3, + U(5,K) = ((((2*K-4)*K+10)*K-8)*K+3)/3, + and + V(1,K) = 2, + V(2,K) = 4*K, + V(3,K) = 4*K*K+2, + V(4,K) = 8*(K*K+2)*K/3, + V(5,K) = ((4*K*K+20)*K*K+6)/3, + for all K>0. + This allows us to derive O(N) encoding and O(N*log(K)) decoding routines for + small N (and indeed decoding is also O(N) for N<3). + + @ARTICLE{Fis86, + author="Thomas R. Fischer", + title="A Pyramid Vector Quantizer", + journal="IEEE Transactions on Information Theory", + volume="IT-32", + number=4, + pages="568--583", + month=Jul, + year=1986 + }*/ + +#if !defined(SMALL_FOOTPRINT) + +/*U(N,K) = U(K,N) := N>0?K>0?U(N-1,K)+U(N,K-1)+U(N-1,K-1):0:K>0?1:0*/ +# define CELT_PVQ_U(_n,_k) (CELT_PVQ_U_ROW[IMIN(_n,_k)][IMAX(_n,_k)]) +/*V(N,K) := U(N,K)+U(N,K+1) = the number of PVQ codewords for a band of size N + with K pulses allocated to it.*/ +# define CELT_PVQ_V(_n,_k) (CELT_PVQ_U(_n,_k)+CELT_PVQ_U(_n,(_k)+1)) + +/*For each V(N,K) supported, we will access element U(min(N,K+1),max(N,K+1)). + Thus, the number of entries in row I is the larger of the maximum number of + pulses we will ever allocate for a given N=I (K=128, or however many fit in + 32 bits, whichever is smaller), plus one, and the maximum N for which + K=I-1 pulses fit in 32 bits. + The largest band size in an Opus Custom mode is 208. + Otherwise, we can limit things to the set of N which can be achieved by + splitting a band from a standard Opus mode: 176, 144, 96, 88, 72, 64, 48, + 44, 36, 32, 24, 22, 18, 16, 8, 4, 2).*/ +#if defined(CUSTOM_MODES) +static const opus_uint32 CELT_PVQ_U_DATA[1488]={ +#else +static const opus_uint32 CELT_PVQ_U_DATA[1272]={ +#endif + /*N=0, K=0...176:*/ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#if defined(CUSTOM_MODES) + /*...208:*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, +#endif + /*N=1, K=1...176:*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +#if defined(CUSTOM_MODES) + /*...208:*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, +#endif + /*N=2, K=2...176:*/ + 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, + 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, + 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, + 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, + 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, + 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, + 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, + 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263, + 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293, + 295, 297, 299, 301, 303, 305, 307, 309, 311, 313, 315, 317, 319, 321, 323, + 325, 327, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351, +#if defined(CUSTOM_MODES) + /*...208:*/ + 353, 355, 357, 359, 361, 363, 365, 367, 369, 371, 373, 375, 377, 379, 381, + 383, 385, 387, 389, 391, 393, 395, 397, 399, 401, 403, 405, 407, 409, 411, + 413, 415, +#endif + /*N=3, K=3...176:*/ + 13, 25, 41, 61, 85, 113, 145, 181, 221, 265, 313, 365, 421, 481, 545, 613, + 685, 761, 841, 925, 1013, 1105, 1201, 1301, 1405, 1513, 1625, 1741, 1861, + 1985, 2113, 2245, 2381, 2521, 2665, 2813, 2965, 3121, 3281, 3445, 3613, 3785, + 3961, 4141, 4325, 4513, 4705, 4901, 5101, 5305, 5513, 5725, 5941, 6161, 6385, + 6613, 6845, 7081, 7321, 7565, 7813, 8065, 8321, 8581, 8845, 9113, 9385, 9661, + 9941, 10225, 10513, 10805, 11101, 11401, 11705, 12013, 12325, 12641, 12961, + 13285, 13613, 13945, 14281, 14621, 14965, 15313, 15665, 16021, 16381, 16745, + 17113, 17485, 17861, 18241, 18625, 19013, 19405, 19801, 20201, 20605, 21013, + 21425, 21841, 22261, 22685, 23113, 23545, 23981, 24421, 24865, 25313, 25765, + 26221, 26681, 27145, 27613, 28085, 28561, 29041, 29525, 30013, 30505, 31001, + 31501, 32005, 32513, 33025, 33541, 34061, 34585, 35113, 35645, 36181, 36721, + 37265, 37813, 38365, 38921, 39481, 40045, 40613, 41185, 41761, 42341, 42925, + 43513, 44105, 44701, 45301, 45905, 46513, 47125, 47741, 48361, 48985, 49613, + 50245, 50881, 51521, 52165, 52813, 53465, 54121, 54781, 55445, 56113, 56785, + 57461, 58141, 58825, 59513, 60205, 60901, 61601, +#if defined(CUSTOM_MODES) + /*...208:*/ + 62305, 63013, 63725, 64441, 65161, 65885, 66613, 67345, 68081, 68821, 69565, + 70313, 71065, 71821, 72581, 73345, 74113, 74885, 75661, 76441, 77225, 78013, + 78805, 79601, 80401, 81205, 82013, 82825, 83641, 84461, 85285, 86113, +#endif + /*N=4, K=4...176:*/ + 63, 129, 231, 377, 575, 833, 1159, 1561, 2047, 2625, 3303, 4089, 4991, 6017, + 7175, 8473, 9919, 11521, 13287, 15225, 17343, 19649, 22151, 24857, 27775, + 30913, 34279, 37881, 41727, 45825, 50183, 54809, 59711, 64897, 70375, 76153, + 82239, 88641, 95367, 102425, 109823, 117569, 125671, 134137, 142975, 152193, + 161799, 171801, 182207, 193025, 204263, 215929, 228031, 240577, 253575, + 267033, 280959, 295361, 310247, 325625, 341503, 357889, 374791, 392217, + 410175, 428673, 447719, 467321, 487487, 508225, 529543, 551449, 573951, + 597057, 620775, 645113, 670079, 695681, 721927, 748825, 776383, 804609, + 833511, 863097, 893375, 924353, 956039, 988441, 1021567, 1055425, 1090023, + 1125369, 1161471, 1198337, 1235975, 1274393, 1313599, 1353601, 1394407, + 1436025, 1478463, 1521729, 1565831, 1610777, 1656575, 1703233, 1750759, + 1799161, 1848447, 1898625, 1949703, 2001689, 2054591, 2108417, 2163175, + 2218873, 2275519, 2333121, 2391687, 2451225, 2511743, 2573249, 2635751, + 2699257, 2763775, 2829313, 2895879, 2963481, 3032127, 3101825, 3172583, + 3244409, 3317311, 3391297, 3466375, 3542553, 3619839, 3698241, 3777767, + 3858425, 3940223, 4023169, 4107271, 4192537, 4278975, 4366593, 4455399, + 4545401, 4636607, 4729025, 4822663, 4917529, 5013631, 5110977, 5209575, + 5309433, 5410559, 5512961, 5616647, 5721625, 5827903, 5935489, 6044391, + 6154617, 6266175, 6379073, 6493319, 6608921, 6725887, 6844225, 6963943, + 7085049, 7207551, +#if defined(CUSTOM_MODES) + /*...208:*/ + 7331457, 7456775, 7583513, 7711679, 7841281, 7972327, 8104825, 8238783, + 8374209, 8511111, 8649497, 8789375, 8930753, 9073639, 9218041, 9363967, + 9511425, 9660423, 9810969, 9963071, 10116737, 10271975, 10428793, 10587199, + 10747201, 10908807, 11072025, 11236863, 11403329, 11571431, 11741177, + 11912575, +#endif + /*N=5, K=5...176:*/ + 321, 681, 1289, 2241, 3649, 5641, 8361, 11969, 16641, 22569, 29961, 39041, + 50049, 63241, 78889, 97281, 118721, 143529, 172041, 204609, 241601, 283401, + 330409, 383041, 441729, 506921, 579081, 658689, 746241, 842249, 947241, + 1061761, 1186369, 1321641, 1468169, 1626561, 1797441, 1981449, 2179241, + 2391489, 2618881, 2862121, 3121929, 3399041, 3694209, 4008201, 4341801, + 4695809, 5071041, 5468329, 5888521, 6332481, 6801089, 7295241, 7815849, + 8363841, 8940161, 9545769, 10181641, 10848769, 11548161, 12280841, 13047849, + 13850241, 14689089, 15565481, 16480521, 17435329, 18431041, 19468809, + 20549801, 21675201, 22846209, 24064041, 25329929, 26645121, 28010881, + 29428489, 30899241, 32424449, 34005441, 35643561, 37340169, 39096641, + 40914369, 42794761, 44739241, 46749249, 48826241, 50971689, 53187081, + 55473921, 57833729, 60268041, 62778409, 65366401, 68033601, 70781609, + 73612041, 76526529, 79526721, 82614281, 85790889, 89058241, 92418049, + 95872041, 99421961, 103069569, 106816641, 110664969, 114616361, 118672641, + 122835649, 127107241, 131489289, 135983681, 140592321, 145317129, 150160041, + 155123009, 160208001, 165417001, 170752009, 176215041, 181808129, 187533321, + 193392681, 199388289, 205522241, 211796649, 218213641, 224775361, 231483969, + 238341641, 245350569, 252512961, 259831041, 267307049, 274943241, 282741889, + 290705281, 298835721, 307135529, 315607041, 324252609, 333074601, 342075401, + 351257409, 360623041, 370174729, 379914921, 389846081, 399970689, 410291241, + 420810249, 431530241, 442453761, 453583369, 464921641, 476471169, 488234561, + 500214441, 512413449, 524834241, 537479489, 550351881, 563454121, 576788929, + 590359041, 604167209, 618216201, 632508801, +#if defined(CUSTOM_MODES) + /*...208:*/ + 647047809, 661836041, 676876329, 692171521, 707724481, 723538089, 739615241, + 755958849, 772571841, 789457161, 806617769, 824056641, 841776769, 859781161, + 878072841, 896654849, 915530241, 934702089, 954173481, 973947521, 994027329, + 1014416041, 1035116809, 1056132801, 1077467201, 1099123209, 1121104041, + 1143412929, 1166053121, 1189027881, 1212340489, 1235994241, +#endif + /*N=6, K=6...96:*/ + 1683, 3653, 7183, 13073, 22363, 36365, 56695, 85305, 124515, 177045, 246047, + 335137, 448427, 590557, 766727, 982729, 1244979, 1560549, 1937199, 2383409, + 2908411, 3522221, 4235671, 5060441, 6009091, 7095093, 8332863, 9737793, + 11326283, 13115773, 15124775, 17372905, 19880915, 22670725, 25765455, + 29189457, 32968347, 37129037, 41699767, 46710137, 52191139, 58175189, + 64696159, 71789409, 79491819, 87841821, 96879431, 106646281, 117185651, + 128542501, 140763503, 153897073, 167993403, 183104493, 199284183, 216588185, + 235074115, 254801525, 275831935, 298228865, 322057867, 347386557, 374284647, + 402823977, 433078547, 465124549, 499040399, 534906769, 572806619, 612825229, + 655050231, 699571641, 746481891, 795875861, 847850911, 902506913, 959946283, + 1020274013, 1083597703, 1150027593, 1219676595, 1292660325, 1369097135, + 1449108145, 1532817275, 1620351277, 1711839767, 1807415257, 1907213187, + 2011371957, 2120032959, +#if defined(CUSTOM_MODES) + /*...109:*/ + 2233340609U, 2351442379U, 2474488829U, 2602633639U, 2736033641U, 2874848851U, + 3019242501U, 3169381071U, 3325434321U, 3487575323U, 3655980493U, 3830829623U, + 4012305913U, +#endif + /*N=7, K=7...54*/ + 8989, 19825, 40081, 75517, 134245, 227305, 369305, 579125, 880685, 1303777, + 1884961, 2668525, 3707509, 5064793, 6814249, 9041957, 11847485, 15345233, + 19665841, 24957661, 31388293, 39146185, 48442297, 59511829, 72616013, + 88043969, 106114625, 127178701, 151620757, 179861305, 212358985, 249612805, + 292164445, 340600625, 395555537, 457713341, 527810725, 606639529, 695049433, + 793950709, 904317037, 1027188385, 1163673953, 1314955181, 1482288821, + 1667010073, 1870535785, 2094367717, +#if defined(CUSTOM_MODES) + /*...60:*/ + 2340095869U, 2609401873U, 2904062449U, 3225952925U, 3577050821U, 3959439497U, +#endif + /*N=8, K=8...37*/ + 48639, 108545, 224143, 433905, 795455, 1392065, 2340495, 3800305, 5984767, + 9173505, 13726991, 20103025, 28875327, 40754369, 56610575, 77500017, + 104692735, 139703809, 184327311, 240673265, 311207743, 398796225, 506750351, + 638878193, 799538175, 993696769, 1226990095, 1505789553, 1837271615, + 2229491905U, +#if defined(CUSTOM_MODES) + /*...40:*/ + 2691463695U, 3233240945U, 3866006015U, +#endif + /*N=9, K=9...28:*/ + 265729, 598417, 1256465, 2485825, 4673345, 8405905, 14546705, 24331777, + 39490049, 62390545, 96220561, 145198913, 214828609, 312193553, 446304145, + 628496897, 872893441, 1196924561, 1621925137, 2173806145U, +#if defined(CUSTOM_MODES) + /*...29:*/ + 2883810113U, +#endif + /*N=10, K=10...24:*/ + 1462563, 3317445, 7059735, 14218905, 27298155, 50250765, 89129247, 152951073, + 254831667, 413442773, 654862247, 1014889769, 1541911931, 2300409629U, + 3375210671U, + /*N=11, K=11...19:*/ + 8097453, 18474633, 39753273, 81270333, 158819253, 298199265, 540279585, + 948062325, 1616336765, +#if defined(CUSTOM_MODES) + /*...20:*/ + 2684641785U, +#endif + /*N=12, K=12...18:*/ + 45046719, 103274625, 224298231, 464387817, 921406335, 1759885185, + 3248227095U, + /*N=13, K=13...16:*/ + 251595969, 579168825, 1267854873, 2653649025U, + /*N=14, K=14:*/ + 1409933619 +}; + +#if defined(CUSTOM_MODES) +static const opus_uint32 *const CELT_PVQ_U_ROW[15]={ + CELT_PVQ_U_DATA+ 0,CELT_PVQ_U_DATA+ 208,CELT_PVQ_U_DATA+ 415, + CELT_PVQ_U_DATA+ 621,CELT_PVQ_U_DATA+ 826,CELT_PVQ_U_DATA+1030, + CELT_PVQ_U_DATA+1233,CELT_PVQ_U_DATA+1336,CELT_PVQ_U_DATA+1389, + CELT_PVQ_U_DATA+1421,CELT_PVQ_U_DATA+1441,CELT_PVQ_U_DATA+1455, + CELT_PVQ_U_DATA+1464,CELT_PVQ_U_DATA+1470,CELT_PVQ_U_DATA+1473 +}; +#else +static const opus_uint32 *const CELT_PVQ_U_ROW[15]={ + CELT_PVQ_U_DATA+ 0,CELT_PVQ_U_DATA+ 176,CELT_PVQ_U_DATA+ 351, + CELT_PVQ_U_DATA+ 525,CELT_PVQ_U_DATA+ 698,CELT_PVQ_U_DATA+ 870, + CELT_PVQ_U_DATA+1041,CELT_PVQ_U_DATA+1131,CELT_PVQ_U_DATA+1178, + CELT_PVQ_U_DATA+1207,CELT_PVQ_U_DATA+1226,CELT_PVQ_U_DATA+1240, + CELT_PVQ_U_DATA+1248,CELT_PVQ_U_DATA+1254,CELT_PVQ_U_DATA+1257 +}; +#endif + +#if defined(CUSTOM_MODES) +void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){ + int k; + /*_maxk==0 => there's nothing to do.*/ + celt_assert(_maxk>0); + _bits[0]=0; + for(k=1;k<=_maxk;k++)_bits[k]=log2_frac(CELT_PVQ_V(_n,k),_frac); +} +#endif + +static opus_uint32 icwrs(int _n,const int *_y){ + opus_uint32 i; + int j; + int k; + celt_assert(_n>=2); + j=_n-1; + i=_y[j]<0; + k=abs(_y[j]); + do{ + j--; + i+=CELT_PVQ_U(_n-j,k); + k+=abs(_y[j]); + if(_y[j]<0)i+=CELT_PVQ_U(_n-j,k+1); + } + while(j>0); + return i; +} + +void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){ + celt_assert(_k>0); + ec_enc_uint(_enc,icwrs(_n,_y),CELT_PVQ_V(_n,_k)); +} + +static opus_val32 cwrsi(int _n,int _k,opus_uint32 _i,int *_y){ + opus_uint32 p; + int s; + int k0; + opus_int16 val; + opus_val32 yy=0; + celt_assert(_k>0); + celt_assert(_n>1); + while(_n>2){ + opus_uint32 q; + /*Lots of pulses case:*/ + if(_k>=_n){ + const opus_uint32 *row; + row=CELT_PVQ_U_ROW[_n]; + /*Are the pulses in this dimension negative?*/ + p=row[_k+1]; + s=-(_i>=p); + _i-=p&s; + /*Count how many pulses were placed in this dimension.*/ + k0=_k; + q=row[_n]; + if(q>_i){ + celt_sig_assert(p>q); + _k=_n; + do p=CELT_PVQ_U_ROW[--_k][_n]; + while(p>_i); + } + else for(p=row[_k];p>_i;p=row[_k])_k--; + _i-=p; + val=(k0-_k+s)^s; + *_y++=val; + yy=MAC16_16(yy,val,val); + } + /*Lots of dimensions case:*/ + else{ + /*Are there any pulses in this dimension at all?*/ + p=CELT_PVQ_U_ROW[_k][_n]; + q=CELT_PVQ_U_ROW[_k+1][_n]; + if(p<=_i&&_i=q); + _i-=q&s; + /*Count how many pulses were placed in this dimension.*/ + k0=_k; + do p=CELT_PVQ_U_ROW[--_k][_n]; + while(p>_i); + _i-=p; + val=(k0-_k+s)^s; + *_y++=val; + yy=MAC16_16(yy,val,val); + } + } + _n--; + } + /*_n==2*/ + p=2*_k+1; + s=-(_i>=p); + _i-=p&s; + k0=_k; + _k=(_i+1)>>1; + if(_k)_i-=2*_k-1; + val=(k0-_k+s)^s; + *_y++=val; + yy=MAC16_16(yy,val,val); + /*_n==1*/ + s=-(int)_i; + val=(_k+s)^s; + *_y=val; + yy=MAC16_16(yy,val,val); + return yy; +} + +opus_val32 decode_pulses(int *_y,int _n,int _k,ec_dec *_dec){ + return cwrsi(_n,_k,ec_dec_uint(_dec,CELT_PVQ_V(_n,_k)),_y); +} + +#else /* SMALL_FOOTPRINT */ + +/*Computes the next row/column of any recurrence that obeys the relation + u[i][j]=u[i-1][j]+u[i][j-1]+u[i-1][j-1]. + _ui0 is the base case for the new row/column.*/ +static OPUS_INLINE void unext(opus_uint32 *_ui,unsigned _len,opus_uint32 _ui0){ + opus_uint32 ui1; + unsigned j; + /*This do-while will overrun the array if we don't have storage for at least + 2 values.*/ + j=1; do { + ui1=UADD32(UADD32(_ui[j],_ui[j-1]),_ui0); + _ui[j-1]=_ui0; + _ui0=ui1; + } while (++j<_len); + _ui[j-1]=_ui0; +} + +/*Computes the previous row/column of any recurrence that obeys the relation + u[i-1][j]=u[i][j]-u[i][j-1]-u[i-1][j-1]. + _ui0 is the base case for the new row/column.*/ +static OPUS_INLINE void uprev(opus_uint32 *_ui,unsigned _n,opus_uint32 _ui0){ + opus_uint32 ui1; + unsigned j; + /*This do-while will overrun the array if we don't have storage for at least + 2 values.*/ + j=1; do { + ui1=USUB32(USUB32(_ui[j],_ui[j-1]),_ui0); + _ui[j-1]=_ui0; + _ui0=ui1; + } while (++j<_n); + _ui[j-1]=_ui0; +} + +/*Compute V(_n,_k), as well as U(_n,0..._k+1). + _u: On exit, _u[i] contains U(_n,i) for i in [0..._k+1].*/ +static opus_uint32 ncwrs_urow(unsigned _n,unsigned _k,opus_uint32 *_u){ + opus_uint32 um2; + unsigned len; + unsigned k; + len=_k+2; + /*We require storage at least 3 values (e.g., _k>0).*/ + celt_assert(len>=3); + _u[0]=0; + _u[1]=um2=1; + /*If _n==0, _u[0] should be 1 and the rest should be 0.*/ + /*If _n==1, _u[i] should be 1 for i>1.*/ + celt_assert(_n>=2); + /*If _k==0, the following do-while loop will overflow the buffer.*/ + celt_assert(_k>0); + k=2; + do _u[k]=(k<<1)-1; + while(++k0); + j=0; + do{ + opus_uint32 p; + int s; + int yj; + p=_u[_k+1]; + s=-(_i>=p); + _i-=p&s; + yj=_k; + p=_u[_k]; + while(p>_i)p=_u[--_k]; + _i-=p; + yj-=_k; + val=(yj+s)^s; + _y[j]=val; + yy=MAC16_16(yy,val,val); + uprev(_u,_k+2,0); + } + while(++j<_n); + return yy; +} + +/*Returns the index of the given combination of K elements chosen from a set + of size 1 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static OPUS_INLINE opus_uint32 icwrs1(const int *_y,int *_k){ + *_k=abs(_y[0]); + return _y[0]<0; +} + +/*Returns the index of the given combination of K elements chosen from a set + of size _n with associated sign bits. + _y: The vector of pulses, whose sum of absolute values must be _k. + _nc: Returns V(_n,_k).*/ +static OPUS_INLINE opus_uint32 icwrs(int _n,int _k,opus_uint32 *_nc,const int *_y, + opus_uint32 *_u){ + opus_uint32 i; + int j; + int k; + /*We can't unroll the first two iterations of the loop unless _n>=2.*/ + celt_assert(_n>=2); + _u[0]=0; + for(k=1;k<=_k+1;k++)_u[k]=(k<<1)-1; + i=icwrs1(_y+_n-1,&k); + j=_n-2; + i+=_u[k]; + k+=abs(_y[j]); + if(_y[j]<0)i+=_u[k+1]; + while(j-->0){ + unext(_u,_k+2,0); + i+=_u[k]; + k+=abs(_y[j]); + if(_y[j]<0)i+=_u[k+1]; + } + *_nc=_u[k]+_u[k+1]; + return i; +} + +#ifdef CUSTOM_MODES +void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){ + int k; + /*_maxk==0 => there's nothing to do.*/ + celt_assert(_maxk>0); + _bits[0]=0; + if (_n==1) + { + for (k=1;k<=_maxk;k++) + _bits[k] = 1<<_frac; + } + else { + VARDECL(opus_uint32,u); + SAVE_STACK; + ALLOC(u,_maxk+2U,opus_uint32); + ncwrs_urow(_n,_maxk,u); + for(k=1;k<=_maxk;k++) + _bits[k]=log2_frac(u[k]+u[k+1],_frac); + RESTORE_STACK; + } +} +#endif /* CUSTOM_MODES */ + +void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){ + opus_uint32 i; + VARDECL(opus_uint32,u); + opus_uint32 nc; + SAVE_STACK; + celt_assert(_k>0); + ALLOC(u,_k+2U,opus_uint32); + i=icwrs(_n,_k,&nc,_y,u); + ec_enc_uint(_enc,i,nc); + RESTORE_STACK; +} + +opus_val32 decode_pulses(int *_y,int _n,int _k,ec_dec *_dec){ + VARDECL(opus_uint32,u); + int ret; + SAVE_STACK; + celt_assert(_k>0); + ALLOC(u,_k+2U,opus_uint32); + ret = cwrsi(_n,_k,ec_dec_uint(_dec,ncwrs_urow(_n,_k,u)),_y,u); + RESTORE_STACK; + return ret; +} + +#endif /* SMALL_FOOTPRINT */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/cwrs.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/cwrs.h new file mode 100644 index 000000000..7cd471745 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/cwrs.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2007-2009 Timothy B. Terriberry + Written by Timothy B. Terriberry and Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef CWRS_H +#define CWRS_H + +#include "arch.h" +#include "stack_alloc.h" +#include "entenc.h" +#include "entdec.h" + +#ifdef CUSTOM_MODES +int log2_frac(opus_uint32 val, int frac); +#endif + +void get_required_bits(opus_int16 *bits, int N, int K, int frac); + +void encode_pulses(const int *_y, int N, int K, ec_enc *enc); + +opus_val32 decode_pulses(int *_y, int N, int K, ec_dec *dec); + +#endif /* CWRS_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/dump_modes/dump_modes.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/dump_modes/dump_modes.c new file mode 100644 index 000000000..9105a5344 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/dump_modes/dump_modes.c @@ -0,0 +1,353 @@ +/* Copyright (c) 2008 CSIRO + Copyright (c) 2008-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "modes.h" +#include "celt.h" +#include "rate.h" +#include "dump_modes_arch.h" + +#define INT16 "%d" +#define INT32 "%d" +#define FLOAT "%#0.8gf" + +#ifdef FIXED_POINT +#define WORD16 INT16 +#define WORD32 INT32 +#else +#define WORD16 FLOAT +#define WORD32 FLOAT +#endif + +void dump_modes(FILE *file, CELTMode **modes, int nb_modes) +{ + int i, j, k; + int mdct_twiddles_size; + fprintf(file, "/* The contents of this file was automatically generated by dump_modes.c\n"); + fprintf(file, " with arguments:"); + for (i=0;iFs,mode->shortMdctSize*mode->nbShortMdcts); + } + fprintf(file, "\n It contains static definitions for some pre-defined modes. */\n"); + fprintf(file, "#include \"modes.h\"\n"); + fprintf(file, "#include \"rate.h\"\n"); + fprintf(file, "\n#ifdef HAVE_ARM_NE10\n"); + fprintf(file, "#define OVERRIDE_FFT 1\n"); + fprintf(file, "#include \"%s\"\n", ARM_NE10_ARCH_FILE_NAME); + fprintf(file, "#endif\n"); + + fprintf(file, "\n"); + + for (i=0;ishortMdctSize*mode->nbShortMdcts; + standard = (mode->Fs == 400*(opus_int32)mode->shortMdctSize); + framerate = mode->Fs/mode->shortMdctSize; + + if (!standard) + { + fprintf(file, "#ifndef DEF_EBANDS%d_%d\n", mode->Fs, mdctSize); + fprintf(file, "#define DEF_EBANDS%d_%d\n", mode->Fs, mdctSize); + fprintf (file, "static const opus_int16 eBands%d_%d[%d] = {\n", mode->Fs, mdctSize, mode->nbEBands+2); + for (j=0;jnbEBands+2;j++) + fprintf (file, "%d, ", mode->eBands[j]); + fprintf (file, "};\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + } + + fprintf(file, "#ifndef DEF_WINDOW%d\n", mode->overlap); + fprintf(file, "#define DEF_WINDOW%d\n", mode->overlap); + fprintf (file, "static const opus_val16 window%d[%d] = {\n", mode->overlap, mode->overlap); + for (j=0;joverlap;j++) + fprintf (file, WORD16 ",%c", mode->window[j],(j+6)%5==0?'\n':' '); + fprintf (file, "};\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + if (!standard) + { + fprintf(file, "#ifndef DEF_ALLOC_VECTORS%d_%d\n", mode->Fs, mdctSize); + fprintf(file, "#define DEF_ALLOC_VECTORS%d_%d\n", mode->Fs, mdctSize); + fprintf (file, "static const unsigned char allocVectors%d_%d[%d] = {\n", mode->Fs, mdctSize, mode->nbEBands*mode->nbAllocVectors); + for (j=0;jnbAllocVectors;j++) + { + for (k=0;knbEBands;k++) + fprintf (file, "%2d, ", mode->allocVectors[j*mode->nbEBands+k]); + fprintf (file, "\n"); + } + fprintf (file, "};\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + } + + fprintf(file, "#ifndef DEF_LOGN%d\n", framerate); + fprintf(file, "#define DEF_LOGN%d\n", framerate); + fprintf (file, "static const opus_int16 logN%d[%d] = {\n", framerate, mode->nbEBands); + for (j=0;jnbEBands;j++) + fprintf (file, "%d, ", mode->logN[j]); + fprintf (file, "};\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + /* Pulse cache */ + fprintf(file, "#ifndef DEF_PULSE_CACHE%d\n", mode->Fs/mdctSize); + fprintf(file, "#define DEF_PULSE_CACHE%d\n", mode->Fs/mdctSize); + fprintf (file, "static const opus_int16 cache_index%d[%d] = {\n", mode->Fs/mdctSize, (mode->maxLM+2)*mode->nbEBands); + for (j=0;jnbEBands*(mode->maxLM+2);j++) + fprintf (file, "%d,%c", mode->cache.index[j],(j+16)%15==0?'\n':' '); + fprintf (file, "};\n"); + fprintf (file, "static const unsigned char cache_bits%d[%d] = {\n", mode->Fs/mdctSize, mode->cache.size); + for (j=0;jcache.size;j++) + fprintf (file, "%d,%c", mode->cache.bits[j],(j+16)%15==0?'\n':' '); + fprintf (file, "};\n"); + fprintf (file, "static const unsigned char cache_caps%d[%d] = {\n", mode->Fs/mdctSize, (mode->maxLM+1)*2*mode->nbEBands); + for (j=0;j<(mode->maxLM+1)*2*mode->nbEBands;j++) + fprintf (file, "%d,%c", mode->cache.caps[j],(j+16)%15==0?'\n':' '); + fprintf (file, "};\n"); + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + /* FFT twiddles */ + fprintf(file, "#ifndef FFT_TWIDDLES%d_%d\n", mode->Fs, mdctSize); + fprintf(file, "#define FFT_TWIDDLES%d_%d\n", mode->Fs, mdctSize); + fprintf (file, "static const kiss_twiddle_cpx fft_twiddles%d_%d[%d] = {\n", + mode->Fs, mdctSize, mode->mdct.kfft[0]->nfft); + for (j=0;jmdct.kfft[0]->nfft;j++) + fprintf (file, "{" WORD16 ", " WORD16 "},%c", mode->mdct.kfft[0]->twiddles[j].r, mode->mdct.kfft[0]->twiddles[j].i,(j+3)%2==0?'\n':' '); + fprintf (file, "};\n"); + +#ifdef OVERRIDE_FFT + dump_mode_arch(mode); +#endif + /* FFT Bitrev tables */ + for (k=0;k<=mode->mdct.maxshift;k++) + { + fprintf(file, "#ifndef FFT_BITREV%d\n", mode->mdct.kfft[k]->nfft); + fprintf(file, "#define FFT_BITREV%d\n", mode->mdct.kfft[k]->nfft); + fprintf (file, "static const opus_int16 fft_bitrev%d[%d] = {\n", + mode->mdct.kfft[k]->nfft, mode->mdct.kfft[k]->nfft); + for (j=0;jmdct.kfft[k]->nfft;j++) + fprintf (file, "%d,%c", mode->mdct.kfft[k]->bitrev[j],(j+16)%15==0?'\n':' '); + fprintf (file, "};\n"); + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + } + + /* FFT States */ + for (k=0;k<=mode->mdct.maxshift;k++) + { + fprintf(file, "#ifndef FFT_STATE%d_%d_%d\n", mode->Fs, mdctSize, k); + fprintf(file, "#define FFT_STATE%d_%d_%d\n", mode->Fs, mdctSize, k); + fprintf (file, "static const kiss_fft_state fft_state%d_%d_%d = {\n", + mode->Fs, mdctSize, k); + fprintf (file, "%d, /* nfft */\n", mode->mdct.kfft[k]->nfft); + fprintf (file, WORD16 ", /* scale */\n", mode->mdct.kfft[k]->scale); +#ifdef FIXED_POINT + fprintf (file, "%d, /* scale_shift */\n", mode->mdct.kfft[k]->scale_shift); +#endif + fprintf (file, "%d, /* shift */\n", mode->mdct.kfft[k]->shift); + fprintf (file, "{"); + for (j=0;j<2*MAXFACTORS;j++) + fprintf (file, "%d, ", mode->mdct.kfft[k]->factors[j]); + fprintf (file, "}, /* factors */\n"); + fprintf (file, "fft_bitrev%d, /* bitrev */\n", mode->mdct.kfft[k]->nfft); + fprintf (file, "fft_twiddles%d_%d, /* bitrev */\n", mode->Fs, mdctSize); + + fprintf (file, "#ifdef OVERRIDE_FFT\n"); + fprintf (file, "(arch_fft_state *)&cfg_arch_%d,\n", mode->mdct.kfft[k]->nfft); + fprintf (file, "#else\n"); + fprintf (file, "NULL,\n"); + fprintf(file, "#endif\n"); + + fprintf (file, "};\n"); + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + } + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + /* MDCT twiddles */ + mdct_twiddles_size = mode->mdct.n-(mode->mdct.n/2>>mode->mdct.maxshift); + fprintf(file, "#ifndef MDCT_TWIDDLES%d\n", mdctSize); + fprintf(file, "#define MDCT_TWIDDLES%d\n", mdctSize); + fprintf (file, "static const opus_val16 mdct_twiddles%d[%d] = {\n", + mdctSize, mdct_twiddles_size); + for (j=0;jmdct.trig[j],(j+6)%5==0?'\n':' '); + fprintf (file, "};\n"); + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + + /* Print the actual mode data */ + fprintf(file, "static const CELTMode mode%d_%d_%d = {\n", mode->Fs, mdctSize, mode->overlap); + fprintf(file, INT32 ", /* Fs */\n", mode->Fs); + fprintf(file, "%d, /* overlap */\n", mode->overlap); + fprintf(file, "%d, /* nbEBands */\n", mode->nbEBands); + fprintf(file, "%d, /* effEBands */\n", mode->effEBands); + fprintf(file, "{"); + for (j=0;j<4;j++) + fprintf(file, WORD16 ", ", mode->preemph[j]); + fprintf(file, "}, /* preemph */\n"); + if (standard) + fprintf(file, "eband5ms, /* eBands */\n"); + else + fprintf(file, "eBands%d_%d, /* eBands */\n", mode->Fs, mdctSize); + + fprintf(file, "%d, /* maxLM */\n", mode->maxLM); + fprintf(file, "%d, /* nbShortMdcts */\n", mode->nbShortMdcts); + fprintf(file, "%d, /* shortMdctSize */\n", mode->shortMdctSize); + + fprintf(file, "%d, /* nbAllocVectors */\n", mode->nbAllocVectors); + if (standard) + fprintf(file, "band_allocation, /* allocVectors */\n"); + else + fprintf(file, "allocVectors%d_%d, /* allocVectors */\n", mode->Fs, mdctSize); + + fprintf(file, "logN%d, /* logN */\n", framerate); + fprintf(file, "window%d, /* window */\n", mode->overlap); + fprintf(file, "{%d, %d, {", mode->mdct.n, mode->mdct.maxshift); + for (k=0;k<=mode->mdct.maxshift;k++) + fprintf(file, "&fft_state%d_%d_%d, ", mode->Fs, mdctSize, k); + fprintf (file, "}, mdct_twiddles%d}, /* mdct */\n", mdctSize); + + fprintf(file, "{%d, cache_index%d, cache_bits%d, cache_caps%d}, /* cache */\n", + mode->cache.size, mode->Fs/mdctSize, mode->Fs/mdctSize, mode->Fs/mdctSize); + fprintf(file, "};\n"); + } + fprintf(file, "\n"); + fprintf(file, "/* List of all the available modes */\n"); + fprintf(file, "#define TOTAL_MODES %d\n", nb_modes); + fprintf(file, "static const CELTMode * const static_mode_list[TOTAL_MODES] = {\n"); + for (i=0;ishortMdctSize*mode->nbShortMdcts; + fprintf(file, "&mode%d_%d_%d,\n", mode->Fs, mdctSize, mode->overlap); + } + fprintf(file, "};\n"); +} + +void dump_header(FILE *file, CELTMode **modes, int nb_modes) +{ + int i; + int channels = 0; + int frame_size = 0; + int overlap = 0; + fprintf (file, "/* This header file is generated automatically*/\n"); + for (i=0;ishortMdctSize*mode->nbShortMdcts; + else if (frame_size != mode->shortMdctSize*mode->nbShortMdcts) + frame_size = -1; + if (overlap==0) + overlap = mode->overlap; + else if (overlap != mode->overlap) + overlap = -1; + } + if (channels>0) + { + fprintf (file, "#define CHANNELS(mode) %d\n", channels); + if (channels==1) + fprintf (file, "#define DISABLE_STEREO\n"); + } + if (frame_size>0) + { + fprintf (file, "#define FRAMESIZE(mode) %d\n", frame_size); + } + if (overlap>0) + { + fprintf (file, "#define OVERLAP(mode) %d\n", overlap); + } +} + +#ifdef FIXED_POINT +#define BASENAME "static_modes_fixed" +#else +#define BASENAME "static_modes_float" +#endif + +int main(int argc, char **argv) +{ + int i, nb; + FILE *file; + CELTMode **m; + if (argc%2 != 1 || argc<3) + { + fprintf (stderr, "Usage: %s rate frame_size [rate frame_size] [rate frame_size]...\n",argv[0]); + return 1; + } + nb = (argc-1)/2; + m = malloc(nb*sizeof(CELTMode*)); + for (i=0;i +#include +#include "modes.h" +#include "dump_modes_arch.h" +#include + +#if !defined(FIXED_POINT) +# define NE10_FFT_CFG_TYPE_T ne10_fft_cfg_float32_t +# define NE10_FFT_CPX_TYPE_T_STR "ne10_fft_cpx_float32_t" +# define NE10_FFT_STATE_TYPE_T_STR "ne10_fft_state_float32_t" +#else +# define NE10_FFT_CFG_TYPE_T ne10_fft_cfg_int32_t +# define NE10_FFT_CPX_TYPE_T_STR "ne10_fft_cpx_int32_t" +# define NE10_FFT_STATE_TYPE_T_STR "ne10_fft_state_int32_t" +#endif + +static FILE *file; + +void dump_modes_arch_init(CELTMode **modes, int nb_modes) +{ + int i; + + file = fopen(ARM_NE10_ARCH_FILE_NAME, "w"); + fprintf(file, "/* The contents of this file was automatically generated by\n"); + fprintf(file, " * dump_mode_arm_ne10.c with arguments:"); + for (i=0;iFs,mode->shortMdctSize*mode->nbShortMdcts); + } + fprintf(file, "\n * It contains static definitions for some pre-defined modes. */\n"); + fprintf(file, "#include \n\n"); +} + +void dump_modes_arch_finalize() +{ + fclose(file); +} + +void dump_mode_arch(CELTMode *mode) +{ + int k, j; + int mdctSize; + + mdctSize = mode->shortMdctSize*mode->nbShortMdcts; + + fprintf(file, "#ifndef NE10_FFT_PARAMS%d_%d\n", mode->Fs, mdctSize); + fprintf(file, "#define NE10_FFT_PARAMS%d_%d\n", mode->Fs, mdctSize); + /* cfg->factors */ + for(k=0;k<=mode->mdct.maxshift;k++) { + NE10_FFT_CFG_TYPE_T cfg; + cfg = (NE10_FFT_CFG_TYPE_T)mode->mdct.kfft[k]->arch_fft->priv; + if (!cfg) + continue; + fprintf(file, "static const ne10_int32_t ne10_factors_%d[%d] = {\n", + mode->mdct.kfft[k]->nfft, (NE10_MAXFACTORS * 2)); + for(j=0;j<(NE10_MAXFACTORS * 2);j++) { + fprintf(file, "%d,%c", cfg->factors[j],(j+16)%15==0?'\n':' '); + } + fprintf (file, "};\n"); + } + + /* cfg->twiddles */ + for(k=0;k<=mode->mdct.maxshift;k++) { + NE10_FFT_CFG_TYPE_T cfg; + cfg = (NE10_FFT_CFG_TYPE_T)mode->mdct.kfft[k]->arch_fft->priv; + if (!cfg) + continue; + fprintf(file, "static const %s ne10_twiddles_%d[%d] = {\n", + NE10_FFT_CPX_TYPE_T_STR, mode->mdct.kfft[k]->nfft, + mode->mdct.kfft[k]->nfft); + for(j=0;jmdct.kfft[k]->nfft;j++) { +#if !defined(FIXED_POINT) + fprintf(file, "{%#0.8gf,%#0.8gf},%c", + cfg->twiddles[j].r, cfg->twiddles[j].i,(j+4)%3==0?'\n':' '); +#else + fprintf(file, "{%d,%d},%c", + cfg->twiddles[j].r, cfg->twiddles[j].i,(j+4)%3==0?'\n':' '); +#endif + } + fprintf (file, "};\n"); + } + + for(k=0;k<=mode->mdct.maxshift;k++) { + NE10_FFT_CFG_TYPE_T cfg; + cfg = (NE10_FFT_CFG_TYPE_T)mode->mdct.kfft[k]->arch_fft->priv; + if (!cfg) { + fprintf(file, "/* Ne10 does not support scaled FFT for length = %d */\n", + mode->mdct.kfft[k]->nfft); + fprintf(file, "static const arch_fft_state cfg_arch_%d = {\n", mode->mdct.kfft[k]->nfft); + fprintf(file, "0,\n"); + fprintf(file, "NULL\n"); + fprintf(file, "};\n"); + continue; + } + fprintf(file, "static const %s %s_%d = {\n", NE10_FFT_STATE_TYPE_T_STR, + NE10_FFT_STATE_TYPE_T_STR, mode->mdct.kfft[k]->nfft); + fprintf(file, "%d,\n", cfg->nfft); + fprintf(file, "(ne10_int32_t *)ne10_factors_%d,\n", mode->mdct.kfft[k]->nfft); + fprintf(file, "(%s *)ne10_twiddles_%d,\n", + NE10_FFT_CPX_TYPE_T_STR, mode->mdct.kfft[k]->nfft); + fprintf(file, "NULL,\n"); /* buffer */ + fprintf(file, "(%s *)&ne10_twiddles_%d[%d],\n", + NE10_FFT_CPX_TYPE_T_STR, mode->mdct.kfft[k]->nfft, cfg->nfft); +#if !defined(FIXED_POINT) + fprintf(file, "/* is_forward_scaled = true */\n"); + fprintf(file, "(ne10_int32_t) 1,\n"); + fprintf(file, "/* is_backward_scaled = false */\n"); + fprintf(file, "(ne10_int32_t) 0,\n"); +#endif + fprintf(file, "};\n"); + + fprintf(file, "static const arch_fft_state cfg_arch_%d = {\n", + mode->mdct.kfft[k]->nfft); + fprintf(file, "1,\n"); + fprintf(file, "(void *)&%s_%d,\n", + NE10_FFT_STATE_TYPE_T_STR, mode->mdct.kfft[k]->nfft); + fprintf(file, "};\n\n"); + } + fprintf(file, "#endif /* end NE10_FFT_PARAMS%d_%d */\n", mode->Fs, mdctSize); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/ecintrin.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/ecintrin.h new file mode 100644 index 000000000..66a4c36ea --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/ecintrin.h @@ -0,0 +1,91 @@ +/* Copyright (c) 2003-2008 Timothy B. Terriberry + Copyright (c) 2008 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +/*Some common macros for potential platform-specific optimization.*/ +#include "opus_types.h" +#include +#include +#include "arch.h" +#if !defined(_ecintrin_H) +# define _ecintrin_H (1) + +/*Some specific platforms may have optimized intrinsic or OPUS_INLINE assembly + versions of these functions which can substantially improve performance. + We define macros for them to allow easy incorporation of these non-ANSI + features.*/ + +/*Modern gcc (4.x) can compile the naive versions of min and max with cmov if + given an appropriate architecture, but the branchless bit-twiddling versions + are just as fast, and do not require any special target architecture. + Earlier gcc versions (3.x) compiled both code to the same assembly + instructions, because of the way they represented ((_b)>(_a)) internally.*/ +# define EC_MINI(_a,_b) ((_a)+(((_b)-(_a))&-((_b)<(_a)))) + +/*Count leading zeros. + This macro should only be used for implementing ec_ilog(), if it is defined. + All other code should use EC_ILOG() instead.*/ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#if defined(_MSC_VER) && (_MSC_VER >= 1910) +# include /* Improve compiler throughput. */ +#else +# include +#endif +/*In _DEBUG mode this is not an intrinsic by default.*/ +# pragma intrinsic(_BitScanReverse) + +static __inline int ec_bsr(unsigned long _x){ + unsigned long ret; + _BitScanReverse(&ret,_x); + return (int)ret; +} +# define EC_CLZ0 (1) +# define EC_CLZ(_x) (-ec_bsr(_x)) +#elif defined(ENABLE_TI_DSPLIB) +# include "dsplib.h" +# define EC_CLZ0 (31) +# define EC_CLZ(_x) (_lnorm(_x)) +#elif __GNUC_PREREQ(3,4) +# if INT_MAX>=2147483647 +# define EC_CLZ0 ((int)sizeof(unsigned)*CHAR_BIT) +# define EC_CLZ(_x) (__builtin_clz(_x)) +# elif LONG_MAX>=2147483647L +# define EC_CLZ0 ((int)sizeof(unsigned long)*CHAR_BIT) +# define EC_CLZ(_x) (__builtin_clzl(_x)) +# endif +#endif + +#if defined(EC_CLZ) +/*Note that __builtin_clz is not defined when _x==0, according to the gcc + documentation (and that of the BSR instruction that implements it on x86). + The majority of the time we can never pass it zero. + When we need to, it can be special cased.*/ +# define EC_ILOG(_x) (EC_CLZ0-EC_CLZ(_x)) +#else +int ec_ilog(opus_uint32 _v); +# define EC_ILOG(_x) (ec_ilog(_x)) +#endif +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entcode.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entcode.c new file mode 100644 index 000000000..70f32016e --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entcode.c @@ -0,0 +1,153 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "entcode.h" +#include "arch.h" + +#if !defined(EC_CLZ) +/*This is a fallback for systems where we don't know how to access + a BSR or CLZ instruction (see ecintrin.h). + If you are optimizing Opus on a new platform and it has a native CLZ or + BZR (e.g. cell, MIPS, x86, etc) then making it available to Opus will be + an easy performance win.*/ +int ec_ilog(opus_uint32 _v){ + /*On a Pentium M, this branchless version tested as the fastest on + 1,000,000,000 random 32-bit integers, edging out a similar version with + branches, and a 256-entry LUT version.*/ + int ret; + int m; + ret=!!_v; + m=!!(_v&0xFFFF0000)<<4; + _v>>=m; + ret|=m; + m=!!(_v&0xFF00)<<3; + _v>>=m; + ret|=m; + m=!!(_v&0xF0)<<2; + _v>>=m; + ret|=m; + m=!!(_v&0xC)<<1; + _v>>=m; + ret|=m; + ret+=!!(_v&0x2); + return ret; +} +#endif + +#if 1 +/* This is a faster version of ec_tell_frac() that takes advantage + of the low (1/8 bit) resolution to use just a linear function + followed by a lookup to determine the exact transition thresholds. */ +opus_uint32 ec_tell_frac(ec_ctx *_this){ + static const unsigned correction[8] = + {35733, 38967, 42495, 46340, + 50535, 55109, 60097, 65535}; + opus_uint32 nbits; + opus_uint32 r; + int l; + unsigned b; + nbits=_this->nbits_total<rng); + r=_this->rng>>(l-16); + b = (r>>12)-8; + b += r>correction[b]; + l = (l<<3)+b; + return nbits-l; +} +#else +opus_uint32 ec_tell_frac(ec_ctx *_this){ + opus_uint32 nbits; + opus_uint32 r; + int l; + int i; + /*To handle the non-integral number of bits still left in the encoder/decoder + state, we compute the worst-case number of bits of val that must be + encoded to ensure that the value is inside the range for any possible + subsequent bits. + The computation here is independent of val itself (the decoder does not + even track that value), even though the real number of bits used after + ec_enc_done() may be 1 smaller if rng is a power of two and the + corresponding trailing bits of val are all zeros. + If we did try to track that special case, then coding a value with a + probability of 1/(1<nbits_total<rng); + r=_this->rng>>(l-16); + for(i=BITRES;i-->0;){ + int b; + r=r*r>>15; + b=(int)(r>>16); + l=l<<1|b; + r>>=b; + } + return nbits-l; +} +#endif + +#ifdef USE_SMALL_DIV_TABLE +/* Result of 2^32/(2*i+1), except for i=0. */ +const opus_uint32 SMALL_DIV_TABLE[129] = { + 0xFFFFFFFF, 0x55555555, 0x33333333, 0x24924924, + 0x1C71C71C, 0x1745D174, 0x13B13B13, 0x11111111, + 0x0F0F0F0F, 0x0D79435E, 0x0C30C30C, 0x0B21642C, + 0x0A3D70A3, 0x097B425E, 0x08D3DCB0, 0x08421084, + 0x07C1F07C, 0x07507507, 0x06EB3E45, 0x06906906, + 0x063E7063, 0x05F417D0, 0x05B05B05, 0x0572620A, + 0x05397829, 0x05050505, 0x04D4873E, 0x04A7904A, + 0x047DC11F, 0x0456C797, 0x04325C53, 0x04104104, + 0x03F03F03, 0x03D22635, 0x03B5CC0E, 0x039B0AD1, + 0x0381C0E0, 0x0369D036, 0x03531DEC, 0x033D91D2, + 0x0329161F, 0x03159721, 0x03030303, 0x02F14990, + 0x02E05C0B, 0x02D02D02, 0x02C0B02C, 0x02B1DA46, + 0x02A3A0FD, 0x0295FAD4, 0x0288DF0C, 0x027C4597, + 0x02702702, 0x02647C69, 0x02593F69, 0x024E6A17, + 0x0243F6F0, 0x0239E0D5, 0x02302302, 0x0226B902, + 0x021D9EAD, 0x0214D021, 0x020C49BA, 0x02040810, + 0x01FC07F0, 0x01F44659, 0x01ECC07B, 0x01E573AC, + 0x01DE5D6E, 0x01D77B65, 0x01D0CB58, 0x01CA4B30, + 0x01C3F8F0, 0x01BDD2B8, 0x01B7D6C3, 0x01B20364, + 0x01AC5701, 0x01A6D01A, 0x01A16D3F, 0x019C2D14, + 0x01970E4F, 0x01920FB4, 0x018D3018, 0x01886E5F, + 0x0183C977, 0x017F405F, 0x017AD220, 0x01767DCE, + 0x01724287, 0x016E1F76, 0x016A13CD, 0x01661EC6, + 0x01623FA7, 0x015E75BB, 0x015AC056, 0x01571ED3, + 0x01539094, 0x01501501, 0x014CAB88, 0x0149539E, + 0x01460CBC, 0x0142D662, 0x013FB013, 0x013C995A, + 0x013991C2, 0x013698DF, 0x0133AE45, 0x0130D190, + 0x012E025C, 0x012B404A, 0x01288B01, 0x0125E227, + 0x01234567, 0x0120B470, 0x011E2EF3, 0x011BB4A4, + 0x01194538, 0x0116E068, 0x011485F0, 0x0112358E, + 0x010FEF01, 0x010DB20A, 0x010B7E6E, 0x010953F3, + 0x01073260, 0x0105197F, 0x0103091B, 0x01010101 +}; +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entcode.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entcode.h new file mode 100644 index 000000000..3763e3f28 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entcode.h @@ -0,0 +1,152 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#include "opus_types.h" +#include "opus_defines.h" + +#if !defined(_entcode_H) +# define _entcode_H (1) +# include +# include +# include "ecintrin.h" + +extern const opus_uint32 SMALL_DIV_TABLE[129]; + +#ifdef OPUS_ARM_ASM +#define USE_SMALL_DIV_TABLE +#endif + +/*OPT: ec_window must be at least 32 bits, but if you have fast arithmetic on a + larger type, you can speed up the decoder by using it here.*/ +typedef opus_uint32 ec_window; +typedef struct ec_ctx ec_ctx; +typedef struct ec_ctx ec_enc; +typedef struct ec_ctx ec_dec; + +# define EC_WINDOW_SIZE ((int)sizeof(ec_window)*CHAR_BIT) + +/*The number of bits to use for the range-coded part of unsigned integers.*/ +# define EC_UINT_BITS (8) + +/*The resolution of fractional-precision bit usage measurements, i.e., + 3 => 1/8th bits.*/ +# define BITRES 3 + +/*The entropy encoder/decoder context. + We use the same structure for both, so that common functions like ec_tell() + can be used on either one.*/ +struct ec_ctx{ + /*Buffered input/output.*/ + unsigned char *buf; + /*The size of the buffer.*/ + opus_uint32 storage; + /*The offset at which the last byte containing raw bits was read/written.*/ + opus_uint32 end_offs; + /*Bits that will be read from/written at the end.*/ + ec_window end_window; + /*Number of valid bits in end_window.*/ + int nend_bits; + /*The total number of whole bits read/written. + This does not include partial bits currently in the range coder.*/ + int nbits_total; + /*The offset at which the next range coder byte will be read/written.*/ + opus_uint32 offs; + /*The number of values in the current range.*/ + opus_uint32 rng; + /*In the decoder: the difference between the top of the current range and + the input value, minus one. + In the encoder: the low end of the current range.*/ + opus_uint32 val; + /*In the decoder: the saved normalization factor from ec_decode(). + In the encoder: the number of oustanding carry propagating symbols.*/ + opus_uint32 ext; + /*A buffered input/output symbol, awaiting carry propagation.*/ + int rem; + /*Nonzero if an error occurred.*/ + int error; +}; + +static OPUS_INLINE opus_uint32 ec_range_bytes(ec_ctx *_this){ + return _this->offs; +} + +static OPUS_INLINE unsigned char *ec_get_buffer(ec_ctx *_this){ + return _this->buf; +} + +static OPUS_INLINE int ec_get_error(ec_ctx *_this){ + return _this->error; +} + +/*Returns the number of bits "used" by the encoded or decoded symbols so far. + This same number can be computed in either the encoder or the decoder, and is + suitable for making coding decisions. + Return: The number of bits. + This will always be slightly larger than the exact value (e.g., all + rounding error is in the positive direction).*/ +static OPUS_INLINE int ec_tell(ec_ctx *_this){ + return _this->nbits_total-EC_ILOG(_this->rng); +} + +/*Returns the number of bits "used" by the encoded or decoded symbols so far. + This same number can be computed in either the encoder or the decoder, and is + suitable for making coding decisions. + Return: The number of bits scaled by 2**BITRES. + This will always be slightly larger than the exact value (e.g., all + rounding error is in the positive direction).*/ +opus_uint32 ec_tell_frac(ec_ctx *_this); + +/* Tested exhaustively for all n and for 1<=d<=256 */ +static OPUS_INLINE opus_uint32 celt_udiv(opus_uint32 n, opus_uint32 d) { + celt_sig_assert(d>0); +#ifdef USE_SMALL_DIV_TABLE + if (d>256) + return n/d; + else { + opus_uint32 t, q; + t = EC_ILOG(d&-d); + q = (opus_uint64)SMALL_DIV_TABLE[d>>t]*(n>>(t-1))>>32; + return q+(n-q*d >= d); + } +#else + return n/d; +#endif +} + +static OPUS_INLINE opus_int32 celt_sudiv(opus_int32 n, opus_int32 d) { + celt_sig_assert(d>0); +#ifdef USE_SMALL_DIV_TABLE + if (n<0) + return -(opus_int32)celt_udiv(-n, d); + else + return celt_udiv(n, d); +#else + return n/d; +#endif +} + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entdec.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entdec.c new file mode 100644 index 000000000..0b3433ed8 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entdec.c @@ -0,0 +1,245 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "os_support.h" +#include "arch.h" +#include "entdec.h" +#include "mfrngcod.h" + +/*A range decoder. + This is an entropy decoder based upon \cite{Mar79}, which is itself a + rediscovery of the FIFO arithmetic code introduced by \cite{Pas76}. + It is very similar to arithmetic encoding, except that encoding is done with + digits in any base, instead of with bits, and so it is faster when using + larger bases (i.e.: a byte). + The author claims an average waste of $\frac{1}{2}\log_b(2b)$ bits, where $b$ + is the base, longer than the theoretical optimum, but to my knowledge there + is no published justification for this claim. + This only seems true when using near-infinite precision arithmetic so that + the process is carried out with no rounding errors. + + An excellent description of implementation details is available at + http://www.arturocampos.com/ac_range.html + A recent work \cite{MNW98} which proposes several changes to arithmetic + encoding for efficiency actually re-discovers many of the principles + behind range encoding, and presents a good theoretical analysis of them. + + End of stream is handled by writing out the smallest number of bits that + ensures that the stream will be correctly decoded regardless of the value of + any subsequent bits. + ec_tell() can be used to determine how many bits were needed to decode + all the symbols thus far; other data can be packed in the remaining bits of + the input buffer. + @PHDTHESIS{Pas76, + author="Richard Clark Pasco", + title="Source coding algorithms for fast data compression", + school="Dept. of Electrical Engineering, Stanford University", + address="Stanford, CA", + month=May, + year=1976 + } + @INPROCEEDINGS{Mar79, + author="Martin, G.N.N.", + title="Range encoding: an algorithm for removing redundancy from a digitised + message", + booktitle="Video & Data Recording Conference", + year=1979, + address="Southampton", + month=Jul + } + @ARTICLE{MNW98, + author="Alistair Moffat and Radford Neal and Ian H. Witten", + title="Arithmetic Coding Revisited", + journal="{ACM} Transactions on Information Systems", + year=1998, + volume=16, + number=3, + pages="256--294", + month=Jul, + URL="http://www.stanford.edu/class/ee398a/handouts/papers/Moffat98ArithmCoding.pdf" + }*/ + +static int ec_read_byte(ec_dec *_this){ + return _this->offs<_this->storage?_this->buf[_this->offs++]:0; +} + +static int ec_read_byte_from_end(ec_dec *_this){ + return _this->end_offs<_this->storage? + _this->buf[_this->storage-++(_this->end_offs)]:0; +} + +/*Normalizes the contents of val and rng so that rng lies entirely in the + high-order symbol.*/ +static void ec_dec_normalize(ec_dec *_this){ + /*If the range is too small, rescale it and input some bits.*/ + while(_this->rng<=EC_CODE_BOT){ + int sym; + _this->nbits_total+=EC_SYM_BITS; + _this->rng<<=EC_SYM_BITS; + /*Use up the remaining bits from our last symbol.*/ + sym=_this->rem; + /*Read the next value from the input.*/ + _this->rem=ec_read_byte(_this); + /*Take the rest of the bits we need from this new symbol.*/ + sym=(sym<rem)>>(EC_SYM_BITS-EC_CODE_EXTRA); + /*And subtract them from val, capped to be less than EC_CODE_TOP.*/ + _this->val=((_this->val<buf=_buf; + _this->storage=_storage; + _this->end_offs=0; + _this->end_window=0; + _this->nend_bits=0; + /*This is the offset from which ec_tell() will subtract partial bits. + The final value after the ec_dec_normalize() call will be the same as in + the encoder, but we have to compensate for the bits that are added there.*/ + _this->nbits_total=EC_CODE_BITS+1 + -((EC_CODE_BITS-EC_CODE_EXTRA)/EC_SYM_BITS)*EC_SYM_BITS; + _this->offs=0; + _this->rng=1U<rem=ec_read_byte(_this); + _this->val=_this->rng-1-(_this->rem>>(EC_SYM_BITS-EC_CODE_EXTRA)); + _this->error=0; + /*Normalize the interval.*/ + ec_dec_normalize(_this); +} + +unsigned ec_decode(ec_dec *_this,unsigned _ft){ + unsigned s; + _this->ext=celt_udiv(_this->rng,_ft); + s=(unsigned)(_this->val/_this->ext); + return _ft-EC_MINI(s+1,_ft); +} + +unsigned ec_decode_bin(ec_dec *_this,unsigned _bits){ + unsigned s; + _this->ext=_this->rng>>_bits; + s=(unsigned)(_this->val/_this->ext); + return (1U<<_bits)-EC_MINI(s+1U,1U<<_bits); +} + +void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft){ + opus_uint32 s; + s=IMUL32(_this->ext,_ft-_fh); + _this->val-=s; + _this->rng=_fl>0?IMUL32(_this->ext,_fh-_fl):_this->rng-s; + ec_dec_normalize(_this); +} + +/*The probability of having a "one" is 1/(1<<_logp).*/ +int ec_dec_bit_logp(ec_dec *_this,unsigned _logp){ + opus_uint32 r; + opus_uint32 d; + opus_uint32 s; + int ret; + r=_this->rng; + d=_this->val; + s=r>>_logp; + ret=dval=d-s; + _this->rng=ret?s:r-s; + ec_dec_normalize(_this); + return ret; +} + +int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb){ + opus_uint32 r; + opus_uint32 d; + opus_uint32 s; + opus_uint32 t; + int ret; + s=_this->rng; + d=_this->val; + r=s>>_ftb; + ret=-1; + do{ + t=s; + s=IMUL32(r,_icdf[++ret]); + } + while(dval=d-s; + _this->rng=t-s; + ec_dec_normalize(_this); + return ret; +} + +opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft){ + unsigned ft; + unsigned s; + int ftb; + /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ + celt_assert(_ft>1); + _ft--; + ftb=EC_ILOG(_ft); + if(ftb>EC_UINT_BITS){ + opus_uint32 t; + ftb-=EC_UINT_BITS; + ft=(unsigned)(_ft>>ftb)+1; + s=ec_decode(_this,ft); + ec_dec_update(_this,s,s+1,ft); + t=(opus_uint32)s<error=1; + return _ft; + } + else{ + _ft++; + s=ec_decode(_this,(unsigned)_ft); + ec_dec_update(_this,s,s+1,(unsigned)_ft); + return s; + } +} + +opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _bits){ + ec_window window; + int available; + opus_uint32 ret; + window=_this->end_window; + available=_this->nend_bits; + if((unsigned)available<_bits){ + do{ + window|=(ec_window)ec_read_byte_from_end(_this)<>=_bits; + available-=_bits; + _this->end_window=window; + _this->nend_bits=available; + _this->nbits_total+=_bits; + return ret; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entdec.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entdec.h new file mode 100644 index 000000000..025fc1870 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entdec.h @@ -0,0 +1,100 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#if !defined(_entdec_H) +# define _entdec_H (1) +# include +# include "entcode.h" + +/*Initializes the decoder. + _buf: The input buffer to use. + Return: 0 on success, or a negative value on error.*/ +void ec_dec_init(ec_dec *_this,unsigned char *_buf,opus_uint32 _storage); + +/*Calculates the cumulative frequency for the next symbol. + This can then be fed into the probability model to determine what that + symbol is, and the additional frequency information required to advance to + the next symbol. + This function cannot be called more than once without a corresponding call to + ec_dec_update(), or decoding will not proceed correctly. + _ft: The total frequency of the symbols in the alphabet the next symbol was + encoded with. + Return: A cumulative frequency representing the encoded symbol. + If the cumulative frequency of all the symbols before the one that + was encoded was fl, and the cumulative frequency of all the symbols + up to and including the one encoded is fh, then the returned value + will fall in the range [fl,fh).*/ +unsigned ec_decode(ec_dec *_this,unsigned _ft); + +/*Equivalent to ec_decode() with _ft==1<<_bits.*/ +unsigned ec_decode_bin(ec_dec *_this,unsigned _bits); + +/*Advance the decoder past the next symbol using the frequency information the + symbol was encoded with. + Exactly one call to ec_decode() must have been made so that all necessary + intermediate calculations are performed. + _fl: The cumulative frequency of all symbols that come before the symbol + decoded. + _fh: The cumulative frequency of all symbols up to and including the symbol + decoded. + Together with _fl, this defines the range [_fl,_fh) in which the value + returned above must fall. + _ft: The total frequency of the symbols in the alphabet the symbol decoded + was encoded in. + This must be the same as passed to the preceding call to ec_decode().*/ +void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft); + +/* Decode a bit that has a 1/(1<<_logp) probability of being a one */ +int ec_dec_bit_logp(ec_dec *_this,unsigned _logp); + +/*Decodes a symbol given an "inverse" CDF table. + No call to ec_dec_update() is necessary after this call. + _icdf: The "inverse" CDF, such that symbol s falls in the range + [s>0?ft-_icdf[s-1]:0,ft-_icdf[s]), where ft=1<<_ftb. + The values must be monotonically non-increasing, and the last value + must be 0. + _ftb: The number of bits of precision in the cumulative distribution. + Return: The decoded symbol s.*/ +int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb); + +/*Extracts a raw unsigned integer with a non-power-of-2 range from the stream. + The bits must have been encoded with ec_enc_uint(). + No call to ec_dec_update() is necessary after this call. + _ft: The number of integers that can be decoded (one more than the max). + This must be at least 2, and no more than 2**32-1. + Return: The decoded bits.*/ +opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft); + +/*Extracts a sequence of raw bits from the stream. + The bits must have been encoded with ec_enc_bits(). + No call to ec_dec_update() is necessary after this call. + _ftb: The number of bits to extract. + This must be between 0 and 25, inclusive. + Return: The decoded bits.*/ +opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _ftb); + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entenc.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entenc.c new file mode 100644 index 000000000..f1750d25b --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entenc.c @@ -0,0 +1,294 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#if defined(HAVE_CONFIG_H) +# include "config.h" +#endif +#include "os_support.h" +#include "arch.h" +#include "entenc.h" +#include "mfrngcod.h" + +/*A range encoder. + See entdec.c and the references for implementation details \cite{Mar79,MNW98}. + + @INPROCEEDINGS{Mar79, + author="Martin, G.N.N.", + title="Range encoding: an algorithm for removing redundancy from a digitised + message", + booktitle="Video \& Data Recording Conference", + year=1979, + address="Southampton", + month=Jul + } + @ARTICLE{MNW98, + author="Alistair Moffat and Radford Neal and Ian H. Witten", + title="Arithmetic Coding Revisited", + journal="{ACM} Transactions on Information Systems", + year=1998, + volume=16, + number=3, + pages="256--294", + month=Jul, + URL="http://www.stanford.edu/class/ee398/handouts/papers/Moffat98ArithmCoding.pdf" + }*/ + +static int ec_write_byte(ec_enc *_this,unsigned _value){ + if(_this->offs+_this->end_offs>=_this->storage)return -1; + _this->buf[_this->offs++]=(unsigned char)_value; + return 0; +} + +static int ec_write_byte_at_end(ec_enc *_this,unsigned _value){ + if(_this->offs+_this->end_offs>=_this->storage)return -1; + _this->buf[_this->storage-++(_this->end_offs)]=(unsigned char)_value; + return 0; +} + +/*Outputs a symbol, with a carry bit. + If there is a potential to propagate a carry over several symbols, they are + buffered until it can be determined whether or not an actual carry will + occur. + If the counter for the buffered symbols overflows, then the stream becomes + undecodable. + This gives a theoretical limit of a few billion symbols in a single packet on + 32-bit systems. + The alternative is to truncate the range in order to force a carry, but + requires similar carry tracking in the decoder, needlessly slowing it down.*/ +static void ec_enc_carry_out(ec_enc *_this,int _c){ + if(_c!=EC_SYM_MAX){ + /*No further carry propagation possible, flush buffer.*/ + int carry; + carry=_c>>EC_SYM_BITS; + /*Don't output a byte on the first write. + This compare should be taken care of by branch-prediction thereafter.*/ + if(_this->rem>=0)_this->error|=ec_write_byte(_this,_this->rem+carry); + if(_this->ext>0){ + unsigned sym; + sym=(EC_SYM_MAX+carry)&EC_SYM_MAX; + do _this->error|=ec_write_byte(_this,sym); + while(--(_this->ext)>0); + } + _this->rem=_c&EC_SYM_MAX; + } + else _this->ext++; +} + +static OPUS_INLINE void ec_enc_normalize(ec_enc *_this){ + /*If the range is too small, output some bits and rescale it.*/ + while(_this->rng<=EC_CODE_BOT){ + ec_enc_carry_out(_this,(int)(_this->val>>EC_CODE_SHIFT)); + /*Move the next-to-high-order symbol into the high-order position.*/ + _this->val=(_this->val<rng<<=EC_SYM_BITS; + _this->nbits_total+=EC_SYM_BITS; + } +} + +void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size){ + _this->buf=_buf; + _this->end_offs=0; + _this->end_window=0; + _this->nend_bits=0; + /*This is the offset from which ec_tell() will subtract partial bits.*/ + _this->nbits_total=EC_CODE_BITS+1; + _this->offs=0; + _this->rng=EC_CODE_TOP; + _this->rem=-1; + _this->val=0; + _this->ext=0; + _this->storage=_size; + _this->error=0; +} + +void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft){ + opus_uint32 r; + r=celt_udiv(_this->rng,_ft); + if(_fl>0){ + _this->val+=_this->rng-IMUL32(r,(_ft-_fl)); + _this->rng=IMUL32(r,(_fh-_fl)); + } + else _this->rng-=IMUL32(r,(_ft-_fh)); + ec_enc_normalize(_this); +} + +void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits){ + opus_uint32 r; + r=_this->rng>>_bits; + if(_fl>0){ + _this->val+=_this->rng-IMUL32(r,((1U<<_bits)-_fl)); + _this->rng=IMUL32(r,(_fh-_fl)); + } + else _this->rng-=IMUL32(r,((1U<<_bits)-_fh)); + ec_enc_normalize(_this); +} + +/*The probability of having a "one" is 1/(1<<_logp).*/ +void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp){ + opus_uint32 r; + opus_uint32 s; + opus_uint32 l; + r=_this->rng; + l=_this->val; + s=r>>_logp; + r-=s; + if(_val)_this->val=l+r; + _this->rng=_val?s:r; + ec_enc_normalize(_this); +} + +void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb){ + opus_uint32 r; + r=_this->rng>>_ftb; + if(_s>0){ + _this->val+=_this->rng-IMUL32(r,_icdf[_s-1]); + _this->rng=IMUL32(r,_icdf[_s-1]-_icdf[_s]); + } + else _this->rng-=IMUL32(r,_icdf[_s]); + ec_enc_normalize(_this); +} + +void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft){ + unsigned ft; + unsigned fl; + int ftb; + /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ + celt_assert(_ft>1); + _ft--; + ftb=EC_ILOG(_ft); + if(ftb>EC_UINT_BITS){ + ftb-=EC_UINT_BITS; + ft=(_ft>>ftb)+1; + fl=(unsigned)(_fl>>ftb); + ec_encode(_this,fl,fl+1,ft); + ec_enc_bits(_this,_fl&(((opus_uint32)1<end_window; + used=_this->nend_bits; + celt_assert(_bits>0); + if(used+_bits>EC_WINDOW_SIZE){ + do{ + _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX); + window>>=EC_SYM_BITS; + used-=EC_SYM_BITS; + } + while(used>=EC_SYM_BITS); + } + window|=(ec_window)_fl<end_window=window; + _this->nend_bits=used; + _this->nbits_total+=_bits; +} + +void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits){ + int shift; + unsigned mask; + celt_assert(_nbits<=EC_SYM_BITS); + shift=EC_SYM_BITS-_nbits; + mask=((1<<_nbits)-1)<offs>0){ + /*The first byte has been finalized.*/ + _this->buf[0]=(unsigned char)((_this->buf[0]&~mask)|_val<rem>=0){ + /*The first byte is still awaiting carry propagation.*/ + _this->rem=(_this->rem&~mask)|_val<rng<=(EC_CODE_TOP>>_nbits)){ + /*The renormalization loop has never been run.*/ + _this->val=(_this->val&~((opus_uint32)mask<error=-1; +} + +void ec_enc_shrink(ec_enc *_this,opus_uint32 _size){ + celt_assert(_this->offs+_this->end_offs<=_size); + OPUS_MOVE(_this->buf+_size-_this->end_offs, + _this->buf+_this->storage-_this->end_offs,_this->end_offs); + _this->storage=_size; +} + +void ec_enc_done(ec_enc *_this){ + ec_window window; + int used; + opus_uint32 msk; + opus_uint32 end; + int l; + /*We output the minimum number of bits that ensures that the symbols encoded + thus far will be decoded correctly regardless of the bits that follow.*/ + l=EC_CODE_BITS-EC_ILOG(_this->rng); + msk=(EC_CODE_TOP-1)>>l; + end=(_this->val+msk)&~msk; + if((end|msk)>=_this->val+_this->rng){ + l++; + msk>>=1; + end=(_this->val+msk)&~msk; + } + while(l>0){ + ec_enc_carry_out(_this,(int)(end>>EC_CODE_SHIFT)); + end=(end<rem>=0||_this->ext>0)ec_enc_carry_out(_this,0); + /*If we have buffered extra bits, flush them as well.*/ + window=_this->end_window; + used=_this->nend_bits; + while(used>=EC_SYM_BITS){ + _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX); + window>>=EC_SYM_BITS; + used-=EC_SYM_BITS; + } + /*Clear any excess space and add any remaining extra bits to the last byte.*/ + if(!_this->error){ + OPUS_CLEAR(_this->buf+_this->offs, + _this->storage-_this->offs-_this->end_offs); + if(used>0){ + /*If there's no range coder data at all, give up.*/ + if(_this->end_offs>=_this->storage)_this->error=-1; + else{ + l=-l; + /*If we've busted, don't add too many extra bits to the last byte; it + would corrupt the range coder data, and that's more important.*/ + if(_this->offs+_this->end_offs>=_this->storage&&lerror=-1; + } + _this->buf[_this->storage-_this->end_offs-1]|=(unsigned char)window; + } + } + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entenc.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entenc.h new file mode 100644 index 000000000..f502eaf66 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/entenc.h @@ -0,0 +1,110 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#if !defined(_entenc_H) +# define _entenc_H (1) +# include +# include "entcode.h" + +/*Initializes the encoder. + _buf: The buffer to store output bytes in. + _size: The size of the buffer, in chars.*/ +void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size); +/*Encodes a symbol given its frequency information. + The frequency information must be discernable by the decoder, assuming it + has read only the previous symbols from the stream. + It is allowable to change the frequency information, or even the entire + source alphabet, so long as the decoder can tell from the context of the + previously encoded information that it is supposed to do so as well. + _fl: The cumulative frequency of all symbols that come before the one to be + encoded. + _fh: The cumulative frequency of all symbols up to and including the one to + be encoded. + Together with _fl, this defines the range [_fl,_fh) in which the + decoded value will fall. + _ft: The sum of the frequencies of all the symbols*/ +void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft); + +/*Equivalent to ec_encode() with _ft==1<<_bits.*/ +void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits); + +/* Encode a bit that has a 1/(1<<_logp) probability of being a one */ +void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp); + +/*Encodes a symbol given an "inverse" CDF table. + _s: The index of the symbol to encode. + _icdf: The "inverse" CDF, such that symbol _s falls in the range + [_s>0?ft-_icdf[_s-1]:0,ft-_icdf[_s]), where ft=1<<_ftb. + The values must be monotonically non-increasing, and the last value + must be 0. + _ftb: The number of bits of precision in the cumulative distribution.*/ +void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb); + +/*Encodes a raw unsigned integer in the stream. + _fl: The integer to encode. + _ft: The number of integers that can be encoded (one more than the max). + This must be at least 2, and no more than 2**32-1.*/ +void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft); + +/*Encodes a sequence of raw bits in the stream. + _fl: The bits to encode. + _ftb: The number of bits to encode. + This must be between 1 and 25, inclusive.*/ +void ec_enc_bits(ec_enc *_this,opus_uint32 _fl,unsigned _ftb); + +/*Overwrites a few bits at the very start of an existing stream, after they + have already been encoded. + This makes it possible to have a few flags up front, where it is easy for + decoders to access them without parsing the whole stream, even if their + values are not determined until late in the encoding process, without having + to buffer all the intermediate symbols in the encoder. + In order for this to work, at least _nbits bits must have already been + encoded using probabilities that are an exact power of two. + The encoder can verify the number of encoded bits is sufficient, but cannot + check this latter condition. + _val: The bits to encode (in the least _nbits significant bits). + They will be decoded in order from most-significant to least. + _nbits: The number of bits to overwrite. + This must be no more than 8.*/ +void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits); + +/*Compacts the data to fit in the target size. + This moves up the raw bits at the end of the current buffer so they are at + the end of the new buffer size. + The caller must ensure that the amount of data that's already been written + will fit in the new size. + _size: The number of bytes in the new buffer. + This must be large enough to contain the bits already written, and + must be no larger than the existing size.*/ +void ec_enc_shrink(ec_enc *_this,opus_uint32 _size); + +/*Indicates that there are no more symbols to encode. + All reamining output bytes are flushed to the output buffer. + ec_enc_init() must be called before the encoder can be used again.*/ +void ec_enc_done(ec_enc *_this); + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/fixed_c5x.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/fixed_c5x.h new file mode 100644 index 000000000..ea95a998c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/fixed_c5x.h @@ -0,0 +1,79 @@ +/* Copyright (C) 2003 Jean-Marc Valin */ +/** + @file fixed_c5x.h + @brief Fixed-point operations for the TI C5x DSP family +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef FIXED_C5X_H +#define FIXED_C5X_H + +#include "dsplib.h" + +#undef IMUL32 +static OPUS_INLINE long IMUL32(long i, long j) +{ + long ac0, ac1; + ac0 = _lmpy(i>>16,j); + ac1 = ac0 + _lmpy(i,j>>16); + return _lmpyu(i,j) + (ac1<<16); +} + +#undef MAX16 +#define MAX16(a,b) _max(a,b) + +#undef MIN16 +#define MIN16(a,b) _min(a,b) + +#undef MAX32 +#define MAX32(a,b) _lmax(a,b) + +#undef MIN32 +#define MIN32(a,b) _lmin(a,b) + +#undef VSHR32 +#define VSHR32(a, shift) _lshl(a,-(shift)) + +#undef MULT16_16_Q15 +#define MULT16_16_Q15(a,b) (_smpy(a,b)) + +#undef MULT16_16SU +#define MULT16_16SU(a,b) _lmpysu(a,b) + +#undef MULT_16_16 +#define MULT_16_16(a,b) _lmpy(a,b) + +/* FIXME: This is technically incorrect and is bound to cause problems. Is there any cleaner solution? */ +#undef MULT16_32_Q15 +#define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),(b)),15)) + +#define celt_ilog2(x) (30 - _lnorm(x)) +#define OVERRIDE_CELT_ILOG2 + +#define celt_maxabs16(x, len) MAX32(EXTEND32(maxval((DATA *)x, len)),-EXTEND32(minval((DATA *)x, len))) +#define OVERRIDE_CELT_MAXABS16 + +#endif /* FIXED_C5X_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/fixed_c6x.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/fixed_c6x.h new file mode 100644 index 000000000..bb6ad9278 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/fixed_c6x.h @@ -0,0 +1,70 @@ +/* Copyright (C) 2008 CSIRO */ +/** + @file fixed_c6x.h + @brief Fixed-point operations for the TI C6x DSP family +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef FIXED_C6X_H +#define FIXED_C6X_H + +#undef MULT16_16SU +#define MULT16_16SU(a,b) _mpysu(a,b) + +#undef MULT_16_16 +#define MULT_16_16(a,b) _mpy(a,b) + +#define celt_ilog2(x) (30 - _norm(x)) +#define OVERRIDE_CELT_ILOG2 + +#undef MULT16_32_Q15 +#define MULT16_32_Q15(a,b) (_mpylill(a, b) >> 15) + +#if 0 +#include "dsplib.h" + +#undef MAX16 +#define MAX16(a,b) _max(a,b) + +#undef MIN16 +#define MIN16(a,b) _min(a,b) + +#undef MAX32 +#define MAX32(a,b) _lmax(a,b) + +#undef MIN32 +#define MIN32(a,b) _lmin(a,b) + +#undef VSHR32 +#define VSHR32(a, shift) _lshl(a,-(shift)) + +#undef MULT16_16_Q15 +#define MULT16_16_Q15(a,b) (_smpy(a,b)) + +#define celt_maxabs16(x, len) MAX32(EXTEND32(maxval((DATA *)x, len)),-EXTEND32(minval((DATA *)x, len))) +#define OVERRIDE_CELT_MAXABS16 + +#endif /* FIXED_C6X_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/fixed_debug.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/fixed_debug.h new file mode 100644 index 000000000..3765baa60 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/fixed_debug.h @@ -0,0 +1,836 @@ +/* Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2012 Xiph.Org Foundation */ +/** + @file fixed_debug.h + @brief Fixed-point operations with debugging +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef FIXED_DEBUG_H +#define FIXED_DEBUG_H + +#include +#include "opus_defines.h" + +#ifdef CELT_C +OPUS_EXPORT opus_int64 celt_mips=0; +#else +extern opus_int64 celt_mips; +#endif + +#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b)) +#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL32(MULT16_16(SHR32((a),16),SHR((b),16)),1), SHR32(MULT16_16SU(SHR32((a),16),((b)&0x0000ffff)),15)), SHR32(MULT16_16SU(SHR32((b),16),((a)&0x0000ffff)),15)) + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR32((b),16)), SHR32(MULT16_16SU((a),((b)&0x0000ffff)),16)) + +#define MULT16_32_P16(a,b) MULT16_32_PX(a,b,16) + +#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits)))) +#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits)))) + +#define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768) +#define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL) +#define VERIFY_UINT(x) ((x)<=(2147483647LLU<<1)) + +#define SHR(a,b) SHR32(a,b) +#define PSHR(a,b) PSHR32(a,b) + +/** Add two 32-bit values, ignore any overflows */ +#define ADD32_ovflw(a,b) (celt_mips+=2,(opus_val32)((opus_uint32)(a)+(opus_uint32)(b))) +/** Subtract two 32-bit values, ignore any overflows */ +#define SUB32_ovflw(a,b) (celt_mips+=2,(opus_val32)((opus_uint32)(a)-(opus_uint32)(b))) +/* Avoid MSVC warning C4146: unary minus operator applied to unsigned type */ +/** Negate 32-bit value, ignore any overflows */ +#define NEG32_ovflw(a) (celt_mips+=2,(opus_val32)(0-(opus_uint32)(a))) + +static OPUS_INLINE short NEG16(int x) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "NEG16: input is not short: %d\n", (int)x); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = -x; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "NEG16: output is not short: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} +static OPUS_INLINE int NEG32(opus_int64 x) +{ + opus_int64 res; + if (!VERIFY_INT(x)) + { + fprintf (stderr, "NEG16: input is not int: %d\n", (int)x); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = -x; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "NEG16: output is not int: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#define EXTRACT16(x) EXTRACT16_(x, __FILE__, __LINE__) +static OPUS_INLINE short EXTRACT16_(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = x; + celt_mips++; + return res; +} + +#define EXTEND32(x) EXTEND32_(x, __FILE__, __LINE__) +static OPUS_INLINE int EXTEND32_(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = x; + celt_mips++; + return res; +} + +#define SHR16(a, shift) SHR16_(a, shift, __FILE__, __LINE__) +static OPUS_INLINE short SHR16_(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a>>shift; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} +#define SHL16(a, shift) SHL16_(a, shift, __FILE__, __LINE__) +static OPUS_INLINE short SHL16_(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a<>shift; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "SHR32: output is not int: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} +#define SHL32(a, shift) SHL32_(a, shift, __FILE__, __LINE__) +static OPUS_INLINE int SHL32_(opus_int64 a, int shift, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL32: inputs are not int: %lld %d in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a<>1))),shift)) +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +#define ROUND16(x,a) (celt_mips--,EXTRACT16(PSHR32((x),(a)))) +#define SROUND16(x,a) (celt_mips--,EXTRACT16(SATURATE(PSHR32(x,a), 32767))); + +#define HALF16(x) (SHR16(x,1)) +#define HALF32(x) (SHR32(x,1)) + +#define ADD16(a, b) ADD16_(a, b, __FILE__, __LINE__) +static OPUS_INLINE short ADD16_(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a+b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} + +#define SUB16(a, b) SUB16_(a, b, __FILE__, __LINE__) +static OPUS_INLINE short SUB16_(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a-b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} + +#define ADD32(a, b) ADD32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE int ADD32_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a+b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#define SUB32(a, b) SUB32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE int SUB32_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "SUB32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a-b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "SUB32: output is not int: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#undef UADD32 +#define UADD32(a, b) UADD32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE unsigned int UADD32_(opus_uint64 a, opus_uint64 b, char *file, int line) +{ + opus_uint64 res; + if (!VERIFY_UINT(a) || !VERIFY_UINT(b)) + { + fprintf (stderr, "UADD32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a+b; + if (!VERIFY_UINT(res)) + { + fprintf (stderr, "UADD32: output is not uint32: %llu in %s: line %d\n", res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#undef USUB32 +#define USUB32(a, b) USUB32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE unsigned int USUB32_(opus_uint64 a, opus_uint64 b, char *file, int line) +{ + opus_uint64 res; + if (!VERIFY_UINT(a) || !VERIFY_UINT(b)) + { + fprintf (stderr, "USUB32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (a> 16; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT32_32_Q16: output is not int: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=5; + return res; +} + +#define MULT16_16(a, b) MULT16_16_(a, b, __FILE__, __LINE__) +static OPUS_INLINE int MULT16_16_(int a, int b, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16: output is not int: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} + +#define MAC16_16(c,a,b) (celt_mips-=2,ADD32((c),MULT16_16((a),(b)))) + +#define MULT16_32_QX(a, b, Q) MULT16_32_QX_(a, b, Q, __FILE__, __LINE__) +static OPUS_INLINE int MULT16_32_QX_(int a, opus_int64 b, int Q, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (ABS32(b)>=((opus_val32)(1)<<(15+Q))) + { + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = (((opus_int64)a)*(opus_int64)b) >> Q; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (Q==15) + celt_mips+=3; + else + celt_mips+=4; + return res; +} + +#define MULT16_32_PX(a, b, Q) MULT16_32_PX_(a, b, Q, __FILE__, __LINE__) +static OPUS_INLINE int MULT16_32_PX_(int a, opus_int64 b, int Q, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d in %s: line %d\n\n", Q, (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (ABS32(b)>=((opus_int64)(1)<<(15+Q))) + { + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n\n", Q, (int)a, (int)b,file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((((opus_int64)a)*(opus_int64)b) + (((opus_val32)(1)<>1))>> Q; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d in %s: line %d\n\n", Q, (int)a, (int)b,(int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (Q==15) + celt_mips+=4; + else + celt_mips+=5; + return res; +} + +#define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15) +#define MAC16_32_Q15(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q15((a),(b)))) +#define MAC16_32_Q16(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q16((a),(b)))) + +static OPUS_INLINE int SATURATE(int a, int b) +{ + if (a>b) + a=b; + if (a<-b) + a = -b; + celt_mips+=3; + return a; +} + +static OPUS_INLINE opus_int16 SATURATE16(opus_int32 a) +{ + celt_mips+=3; + if (a>32767) + return 32767; + else if (a<-32768) + return -32768; + else return a; +} + +static OPUS_INLINE int MULT16_16_Q11_32(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 11; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=3; + return res; +} +static OPUS_INLINE short MULT16_16_Q13(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 13; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=3; + return res; +} +static OPUS_INLINE short MULT16_16_Q14(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 14; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=3; + return res; +} + +#define MULT16_16_Q15(a, b) MULT16_16_Q15_(a, b, __FILE__, __LINE__) +static OPUS_INLINE short MULT16_16_Q15_(int a, int b, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 15; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q15: output is not short: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=1; + return res; +} + +static OPUS_INLINE short MULT16_16_P13(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res += 4096; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res >>= 13; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=4; + return res; +} +static OPUS_INLINE short MULT16_16_P14(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res += 8192; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res >>= 14; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=4; + return res; +} +static OPUS_INLINE short MULT16_16_P15(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res += 16384; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res >>= 15; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#define DIV32_16(a, b) DIV32_16_(a, b, __FILE__, __LINE__) + +static OPUS_INLINE int DIV32_16_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (b==0) + { + fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + return 0; + } + if (!VERIFY_INT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a/b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line); + if (res>32767) + res = 32767; + if (res<-32768) + res = -32768; +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=35; + return res; +} + +#define DIV32(a, b) DIV32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE int DIV32_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (b==0) + { + fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + return 0; + } + + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a/b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=70; + return res; +} + +static OPUS_INLINE opus_val16 SIG2WORD16_generic(celt_sig x) +{ + x = PSHR32(x, SIG_SHIFT); + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return EXTRACT16(x); +} +#define SIG2WORD16(x) (SIG2WORD16_generic(x)) + + +#undef PRINT_MIPS +#define PRINT_MIPS(file) do {fprintf (file, "total complexity = %llu MIPS\n", celt_mips);} while (0); + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/fixed_generic.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/fixed_generic.h new file mode 100644 index 000000000..8f29d46bb --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/fixed_generic.h @@ -0,0 +1,188 @@ +/* Copyright (C) 2007-2009 Xiph.Org Foundation + Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2008 CSIRO */ +/** + @file fixed_generic.h + @brief Generic fixed-point operations +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef FIXED_GENERIC_H +#define FIXED_GENERIC_H + +/** Multiply a 16-bit signed value by a 16-bit unsigned value. The result is a 32-bit signed value */ +#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b)) + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT16_32_Q16(a,b) ((opus_val32)SHR((opus_int64)((opus_val16)(a))*(b),16)) +#else +#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16)) +#endif + +/** 16x32 multiplication, followed by a 16-bit shift right (round-to-nearest). Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT16_32_P16(a,b) ((opus_val32)PSHR((opus_int64)((opus_val16)(a))*(b),16)) +#else +#define MULT16_32_P16(a,b) ADD32(MULT16_16((a),SHR((b),16)), PSHR(MULT16_16SU((a),((b)&0x0000ffff)),16)) +#endif + +/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT16_32_Q15(a,b) ((opus_val32)SHR((opus_int64)((opus_val16)(a))*(b),15)) +#else +#define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),((b)&0x0000ffff)),15)) +#endif + +/** 32x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT32_32_Q16(a,b) ((opus_val32)SHR((opus_int64)(a)*(opus_int64)(b),16)) +#else +#define MULT32_32_Q16(a,b) (ADD32(ADD32(ADD32((opus_val32)(SHR32(((opus_uint32)((a)&0x0000ffff)*(opus_uint32)((b)&0x0000ffff)),16)), MULT16_16SU(SHR32(a,16),((b)&0x0000ffff))), MULT16_16SU(SHR32(b,16),((a)&0x0000ffff))), SHL32(MULT16_16(SHR32(a,16),SHR32(b,16)),16))) +#endif + +/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT32_32_Q31(a,b) ((opus_val32)SHR((opus_int64)(a)*(opus_int64)(b),31)) +#else +#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL(MULT16_16(SHR((a),16),SHR((b),16)),1), SHR(MULT16_16SU(SHR((a),16),((b)&0x0000ffff)),15)), SHR(MULT16_16SU(SHR((b),16),((a)&0x0000ffff)),15)) +#endif + +/** Compile-time conversion of float constant to 16-bit value */ +#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits)))) + +/** Compile-time conversion of float constant to 32-bit value */ +#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits)))) + +/** Negate a 16-bit value */ +#define NEG16(x) (-(x)) +/** Negate a 32-bit value */ +#define NEG32(x) (-(x)) + +/** Change a 32-bit value into a 16-bit value. The value is assumed to fit in 16-bit, otherwise the result is undefined */ +#define EXTRACT16(x) ((opus_val16)(x)) +/** Change a 16-bit value into a 32-bit value */ +#define EXTEND32(x) ((opus_val32)(x)) + +/** Arithmetic shift-right of a 16-bit value */ +#define SHR16(a,shift) ((a) >> (shift)) +/** Arithmetic shift-left of a 16-bit value */ +#define SHL16(a,shift) ((opus_int16)((opus_uint16)(a)<<(shift))) +/** Arithmetic shift-right of a 32-bit value */ +#define SHR32(a,shift) ((a) >> (shift)) +/** Arithmetic shift-left of a 32-bit value */ +#define SHL32(a,shift) ((opus_int32)((opus_uint32)(a)<<(shift))) + +/** 32-bit arithmetic shift right with rounding-to-nearest instead of rounding down */ +#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +/** 32-bit arithmetic shift right where the argument can be negative */ +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +/** "RAW" macros, should not be used outside of this header file */ +#define SHR(a,shift) ((a) >> (shift)) +#define SHL(a,shift) SHL32(a,shift) +#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + +#define SATURATE16(x) (EXTRACT16((x)>32767 ? 32767 : (x)<-32768 ? -32768 : (x))) + +/** Shift by a and round-to-nearest 32-bit value. Result is a 16-bit value */ +#define ROUND16(x,a) (EXTRACT16(PSHR32((x),(a)))) +/** Shift by a and round-to-nearest 32-bit value. Result is a saturated 16-bit value */ +#define SROUND16(x,a) EXTRACT16(SATURATE(PSHR32(x,a), 32767)); + +/** Divide by two */ +#define HALF16(x) (SHR16(x,1)) +#define HALF32(x) (SHR32(x,1)) + +/** Add two 16-bit values */ +#define ADD16(a,b) ((opus_val16)((opus_val16)(a)+(opus_val16)(b))) +/** Subtract two 16-bit values */ +#define SUB16(a,b) ((opus_val16)(a)-(opus_val16)(b)) +/** Add two 32-bit values */ +#define ADD32(a,b) ((opus_val32)(a)+(opus_val32)(b)) +/** Subtract two 32-bit values */ +#define SUB32(a,b) ((opus_val32)(a)-(opus_val32)(b)) + +/** Add two 32-bit values, ignore any overflows */ +#define ADD32_ovflw(a,b) ((opus_val32)((opus_uint32)(a)+(opus_uint32)(b))) +/** Subtract two 32-bit values, ignore any overflows */ +#define SUB32_ovflw(a,b) ((opus_val32)((opus_uint32)(a)-(opus_uint32)(b))) +/* Avoid MSVC warning C4146: unary minus operator applied to unsigned type */ +/** Negate 32-bit value, ignore any overflows */ +#define NEG32_ovflw(a) ((opus_val32)(0-(opus_uint32)(a))) + +/** 16x16 multiplication where the result fits in 16 bits */ +#define MULT16_16_16(a,b) ((((opus_val16)(a))*((opus_val16)(b)))) + +/** 32x32 multiplication where the result fits in 32 bits */ +#define MULT32_32_32(a,b) ((((opus_val32)(a))*((opus_val32)(b)))) + +/* (opus_val32)(opus_val16) gives TI compiler a hint that it's 16x16->32 multiply */ +/** 16x16 multiplication where the result fits in 32 bits */ +#define MULT16_16(a,b) (((opus_val32)(opus_val16)(a))*((opus_val32)(opus_val16)(b))) + +/** 16x16 multiply-add where the result fits in 32 bits */ +#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b)))) +/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add. + b must fit in 31 bits. + Result fits in 32 bits. */ +#define MAC16_32_Q15(c,a,b) ADD32((c),ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))) + +/** 16x32 multiplication, followed by a 16-bit shift right and 32-bit add. + Results fits in 32 bits */ +#define MAC16_32_Q16(c,a,b) ADD32((c),ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16))) + +#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11)) +#define MULT16_16_Q11(a,b) (SHR(MULT16_16((a),(b)),11)) +#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13)) +#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14)) +#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15)) + +#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13)) +#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14)) +#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15)) + +/** Divide a 32-bit value by a 16-bit value. Result fits in 16 bits */ +#define DIV32_16(a,b) ((opus_val16)(((opus_val32)(a))/((opus_val16)(b)))) + +/** Divide a 32-bit value by a 32-bit value. Result fits in 32 bits */ +#define DIV32(a,b) (((opus_val32)(a))/((opus_val32)(b))) + +#if defined(MIPSr1_ASM) +#include "mips/fixed_generic_mipsr1.h" +#endif + +static OPUS_INLINE opus_val16 SIG2WORD16_generic(celt_sig x) +{ + x = PSHR32(x, SIG_SHIFT); + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return EXTRACT16(x); +} +#define SIG2WORD16(x) (SIG2WORD16_generic(x)) + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/float_cast.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/float_cast.h new file mode 100644 index 000000000..9d34976ee --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/float_cast.h @@ -0,0 +1,152 @@ +/* Copyright (C) 2001 Erik de Castro Lopo */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +/* Version 1.1 */ + +#ifndef FLOAT_CAST_H +#define FLOAT_CAST_H + + +#include "arch.h" + +/*============================================================================ +** On Intel Pentium processors (especially PIII and probably P4), converting +** from float to int is very slow. To meet the C specs, the code produced by +** most C compilers targeting Pentium needs to change the FPU rounding mode +** before the float to int conversion is performed. +** +** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It +** is this flushing of the pipeline which is so slow. +** +** Fortunately the ISO C99 specifications define the functions lrint, lrintf, +** llrint and llrintf which fix this problem as a side effect. +** +** On Unix-like systems, the configure process should have detected the +** presence of these functions. If they weren't found we have to replace them +** here with a standard C cast. +*/ + +/* +** The C99 prototypes for lrint and lrintf are as follows: +** +** long int lrintf (float x) ; +** long int lrint (double x) ; +*/ + +/* The presence of the required functions are detected during the configure +** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in +** the config.h file. +*/ + +/* With GCC, when SSE is available, the fastest conversion is cvtss2si. */ +#if defined(__GNUC__) && defined(__SSE__) + +#include +static OPUS_INLINE opus_int32 float2int(float x) {return _mm_cvt_ss2si(_mm_set_ss(x));} + +#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)) + + #include + static OPUS_INLINE opus_int32 float2int(float value) + { + /* _mm_load_ss will generate same code as _mm_set_ss + ** in _MSC_VER >= 1914 /02 so keep __mm_load__ss + ** for backward compatibility. + */ + return _mm_cvtss_si32(_mm_load_ss(&value)); + } + +#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && defined (_M_IX86) + + #include + + /* Win32 doesn't seem to have these functions. + ** Therefore implement OPUS_INLINE versions of these functions here. + */ + + static OPUS_INLINE opus_int32 + float2int (float flt) + { int intgr; + + _asm + { fld flt + fistp intgr + } ; + + return intgr ; + } + +#elif defined(HAVE_LRINTF) + +/* These defines enable functionality introduced with the 1999 ISO C +** standard. They must be defined before the inclusion of math.h to +** engage them. If optimisation is enabled, these functions will be +** inlined. With optimisation switched off, you have to link in the +** maths library using -lm. +*/ + +#define _ISOC9X_SOURCE 1 +#define _ISOC99_SOURCE 1 + +#define __USE_ISOC9X 1 +#define __USE_ISOC99 1 + +#include +#define float2int(x) lrintf(x) + +#elif (defined(HAVE_LRINT)) + +#define _ISOC9X_SOURCE 1 +#define _ISOC99_SOURCE 1 + +#define __USE_ISOC9X 1 +#define __USE_ISOC99 1 + +#include +#define float2int(x) lrint(x) + +#else + +#if (defined(__GNUC__) && defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) + /* supported by gcc in C99 mode, but not by all other compilers */ + #warning "Don't have the functions lrint() and lrintf ()." + #warning "Replacing these functions with a standard C cast." +#endif /* __STDC_VERSION__ >= 199901L */ + #include + #define float2int(flt) ((int)(floor(.5+flt))) +#endif + +#ifndef DISABLE_FLOAT_API +static OPUS_INLINE opus_int16 FLOAT2INT16(float x) +{ + x = x*CELT_SIG_SCALE; + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return (opus_int16)float2int(x); +} +#endif /* DISABLE_FLOAT_API */ + +#endif /* FLOAT_CAST_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/kiss_fft.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/kiss_fft.c new file mode 100644 index 000000000..83775165d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/kiss_fft.c @@ -0,0 +1,604 @@ +/*Copyright (c) 2003-2004, Mark Borgerding + Lots of modifications by Jean-Marc Valin + Copyright (c) 2005-2007, Xiph.Org Foundation + Copyright (c) 2008, Xiph.Org Foundation, CSIRO + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * 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. + + 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 OWNER 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.*/ + +/* This code is originally from Mark Borgerding's KISS-FFT but has been + heavily modified to better suit Opus */ + +#ifndef SKIP_CONFIG_H +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif +#endif + +#include "_kiss_fft_guts.h" +#include "arch.h" +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" + +/* The guts header contains all the multiplication and addition macros that are defined for + complex numbers. It also delares the kf_ internal functions. +*/ + +static void kf_bfly2( + kiss_fft_cpx * Fout, + int m, + int N + ) +{ + kiss_fft_cpx * Fout2; + int i; + (void)m; +#ifdef CUSTOM_MODES + if (m==1) + { + celt_assert(m==1); + for (i=0;itwiddles; + /* m is guaranteed to be a multiple of 4. */ + for (j=0;jtwiddles[fstride*m]; +#endif + for (i=0;itwiddles; + /* For non-custom modes, m is guaranteed to be a multiple of 4. */ + k=m; + do { + + C_MUL(scratch[1],Fout[m] , *tw1); + C_MUL(scratch[2],Fout[m2] , *tw2); + + C_ADD(scratch[3],scratch[1],scratch[2]); + C_SUB(scratch[0],scratch[1],scratch[2]); + tw1 += fstride; + tw2 += fstride*2; + + Fout[m].r = SUB32_ovflw(Fout->r, HALF_OF(scratch[3].r)); + Fout[m].i = SUB32_ovflw(Fout->i, HALF_OF(scratch[3].i)); + + C_MULBYSCALAR( scratch[0] , epi3.i ); + + C_ADDTO(*Fout,scratch[3]); + + Fout[m2].r = ADD32_ovflw(Fout[m].r, scratch[0].i); + Fout[m2].i = SUB32_ovflw(Fout[m].i, scratch[0].r); + + Fout[m].r = SUB32_ovflw(Fout[m].r, scratch[0].i); + Fout[m].i = ADD32_ovflw(Fout[m].i, scratch[0].r); + + ++Fout; + } while(--k); + } +} + + +#ifndef OVERRIDE_kf_bfly5 +static void kf_bfly5( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; + int i, u; + kiss_fft_cpx scratch[13]; + const kiss_twiddle_cpx *tw; + kiss_twiddle_cpx ya,yb; + kiss_fft_cpx * Fout_beg = Fout; + +#ifdef FIXED_POINT + ya.r = 10126; + ya.i = -31164; + yb.r = -26510; + yb.i = -19261; +#else + ya = st->twiddles[fstride*m]; + yb = st->twiddles[fstride*2*m]; +#endif + tw=st->twiddles; + + for (i=0;ir = ADD32_ovflw(Fout0->r, ADD32_ovflw(scratch[7].r, scratch[8].r)); + Fout0->i = ADD32_ovflw(Fout0->i, ADD32_ovflw(scratch[7].i, scratch[8].i)); + + scratch[5].r = ADD32_ovflw(scratch[0].r, ADD32_ovflw(S_MUL(scratch[7].r,ya.r), S_MUL(scratch[8].r,yb.r))); + scratch[5].i = ADD32_ovflw(scratch[0].i, ADD32_ovflw(S_MUL(scratch[7].i,ya.r), S_MUL(scratch[8].i,yb.r))); + + scratch[6].r = ADD32_ovflw(S_MUL(scratch[10].i,ya.i), S_MUL(scratch[9].i,yb.i)); + scratch[6].i = NEG32_ovflw(ADD32_ovflw(S_MUL(scratch[10].r,ya.i), S_MUL(scratch[9].r,yb.i))); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = ADD32_ovflw(scratch[0].r, ADD32_ovflw(S_MUL(scratch[7].r,yb.r), S_MUL(scratch[8].r,ya.r))); + scratch[11].i = ADD32_ovflw(scratch[0].i, ADD32_ovflw(S_MUL(scratch[7].i,yb.r), S_MUL(scratch[8].i,ya.r))); + scratch[12].r = SUB32_ovflw(S_MUL(scratch[9].i,ya.i), S_MUL(scratch[10].i,yb.i)); + scratch[12].i = SUB32_ovflw(S_MUL(scratch[10].r,yb.i), S_MUL(scratch[9].r,ya.i)); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } + } +} +#endif /* OVERRIDE_kf_bfly5 */ + + +#endif + + +#ifdef CUSTOM_MODES + +static +void compute_bitrev_table( + int Fout, + opus_int16 *f, + const size_t fstride, + int in_stride, + opus_int16 * factors, + const kiss_fft_state *st + ) +{ + const int p=*factors++; /* the radix */ + const int m=*factors++; /* stage's fft length/p */ + + /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/ + if (m==1) + { + int j; + for (j=0;j32000 || (opus_int32)p*(opus_int32)p > n) + p = n; /* no more factors, skip to end */ + } + n /= p; +#ifdef RADIX_TWO_ONLY + if (p!=2 && p != 4) +#else + if (p>5) +#endif + { + return 0; + } + facbuf[2*stages] = p; + if (p==2 && stages > 1) + { + facbuf[2*stages] = 4; + facbuf[2] = 2; + } + stages++; + } while (n > 1); + n = nbak; + /* Reverse the order to get the radix 4 at the end, so we can use the + fast degenerate case. It turns out that reversing the order also + improves the noise behaviour. */ + for (i=0;i= memneeded) + st = (kiss_fft_state*)mem; + *lenmem = memneeded; + } + if (st) { + opus_int16 *bitrev; + kiss_twiddle_cpx *twiddles; + + st->nfft=nfft; +#ifdef FIXED_POINT + st->scale_shift = celt_ilog2(st->nfft); + if (st->nfft == 1<scale_shift) + st->scale = Q15ONE; + else + st->scale = (1073741824+st->nfft/2)/st->nfft>>(15-st->scale_shift); +#else + st->scale = 1.f/nfft; +#endif + if (base != NULL) + { + st->twiddles = base->twiddles; + st->shift = 0; + while (st->shift < 32 && nfft<shift != base->nfft) + st->shift++; + if (st->shift>=32) + goto fail; + } else { + st->twiddles = twiddles = (kiss_twiddle_cpx*)KISS_FFT_MALLOC(sizeof(kiss_twiddle_cpx)*nfft); + compute_twiddles(twiddles, nfft); + st->shift = -1; + } + if (!kf_factor(nfft,st->factors)) + { + goto fail; + } + + /* bitrev */ + st->bitrev = bitrev = (opus_int16*)KISS_FFT_MALLOC(sizeof(opus_int16)*nfft); + if (st->bitrev==NULL) + goto fail; + compute_bitrev_table(0, bitrev, 1,1, st->factors,st); + + /* Initialize architecture specific fft parameters */ + if (opus_fft_alloc_arch(st, arch)) + goto fail; + } + return st; +fail: + opus_fft_free(st, arch); + return NULL; +} + +kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem, int arch) +{ + return opus_fft_alloc_twiddles(nfft, mem, lenmem, NULL, arch); +} + +void opus_fft_free_arch_c(kiss_fft_state *st) { + (void)st; +} + +void opus_fft_free(const kiss_fft_state *cfg, int arch) +{ + if (cfg) + { + opus_fft_free_arch((kiss_fft_state *)cfg, arch); + opus_free((opus_int16*)cfg->bitrev); + if (cfg->shift < 0) + opus_free((kiss_twiddle_cpx*)cfg->twiddles); + opus_free((kiss_fft_state*)cfg); + } +} + +#endif /* CUSTOM_MODES */ + +void opus_fft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout) +{ + int m2, m; + int p; + int L; + int fstride[MAXFACTORS]; + int i; + int shift; + + /* st->shift can be -1 */ + shift = st->shift>0 ? st->shift : 0; + + fstride[0] = 1; + L=0; + do { + p = st->factors[2*L]; + m = st->factors[2*L+1]; + fstride[L+1] = fstride[L]*p; + L++; + } while(m!=1); + m = st->factors[2*L-1]; + for (i=L-1;i>=0;i--) + { + if (i!=0) + m2 = st->factors[2*i-1]; + else + m2 = 1; + switch (st->factors[2*i]) + { + case 2: + kf_bfly2(fout, m, fstride[i]); + break; + case 4: + kf_bfly4(fout,fstride[i]<scale_shift-1; +#endif + scale = st->scale; + + celt_assert2 (fin != fout, "In-place FFT not supported"); + /* Bit-reverse the input */ + for (i=0;infft;i++) + { + kiss_fft_cpx x = fin[i]; + fout[st->bitrev[i]].r = SHR32(MULT16_32_Q16(scale, x.r), scale_shift); + fout[st->bitrev[i]].i = SHR32(MULT16_32_Q16(scale, x.i), scale_shift); + } + opus_fft_impl(st, fout); +} + + +void opus_ifft_c(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) +{ + int i; + celt_assert2 (fin != fout, "In-place FFT not supported"); + /* Bit-reverse the input */ + for (i=0;infft;i++) + fout[st->bitrev[i]] = fin[i]; + for (i=0;infft;i++) + fout[i].i = -fout[i].i; + opus_fft_impl(st, fout); + for (i=0;infft;i++) + fout[i].i = -fout[i].i; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/kiss_fft.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/kiss_fft.h new file mode 100644 index 000000000..bffa2bfad --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/kiss_fft.h @@ -0,0 +1,200 @@ +/*Copyright (c) 2003-2004, Mark Borgerding + Lots of modifications by Jean-Marc Valin + Copyright (c) 2005-2007, Xiph.Org Foundation + Copyright (c) 2008, Xiph.Org Foundation, CSIRO + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * 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. + + 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 OWNER 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.*/ + +#ifndef KISS_FFT_H +#define KISS_FFT_H + +#include +#include +#include "arch.h" +#include "cpu_support.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef USE_SIMD +# include +# define kiss_fft_scalar __m128 +#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes) +#else +#define KISS_FFT_MALLOC opus_alloc +#endif + +#ifdef FIXED_POINT +#include "arch.h" + +# define kiss_fft_scalar opus_int32 +# define kiss_twiddle_scalar opus_int16 + + +#else +# ifndef kiss_fft_scalar +/* default is float */ +# define kiss_fft_scalar float +# define kiss_twiddle_scalar float +# define KF_SUFFIX _celt_single +# endif +#endif + +typedef struct { + kiss_fft_scalar r; + kiss_fft_scalar i; +}kiss_fft_cpx; + +typedef struct { + kiss_twiddle_scalar r; + kiss_twiddle_scalar i; +}kiss_twiddle_cpx; + +#define MAXFACTORS 8 +/* e.g. an fft of length 128 has 4 factors + as far as kissfft is concerned + 4*4*4*2 + */ + +typedef struct arch_fft_state{ + int is_supported; + void *priv; +} arch_fft_state; + +typedef struct kiss_fft_state{ + int nfft; + opus_val16 scale; +#ifdef FIXED_POINT + int scale_shift; +#endif + int shift; + opus_int16 factors[2*MAXFACTORS]; + const opus_int16 *bitrev; + const kiss_twiddle_cpx *twiddles; + arch_fft_state *arch_fft; +} kiss_fft_state; + +#if defined(HAVE_ARM_NE10) +#include "arm/fft_arm.h" +#endif + +/*typedef struct kiss_fft_state* kiss_fft_cfg;*/ + +/** + * opus_fft_alloc + * + * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. + * + * typical usage: kiss_fft_cfg mycfg=opus_fft_alloc(1024,0,NULL,NULL); + * + * The return value from fft_alloc is a cfg buffer used internally + * by the fft routine or NULL. + * + * If lenmem is NULL, then opus_fft_alloc will allocate a cfg buffer using malloc. + * The returned value should be free()d when done to avoid memory leaks. + * + * The state can be placed in a user supplied buffer 'mem': + * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, + * then the function places the cfg in mem and the size used in *lenmem + * and returns mem. + * + * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), + * then the function returns NULL and places the minimum cfg + * buffer size in *lenmem. + * */ + +kiss_fft_state *opus_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem, const kiss_fft_state *base, int arch); + +kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem, int arch); + +/** + * opus_fft(cfg,in_out_buf) + * + * Perform an FFT on a complex input buffer. + * for a forward FFT, + * fin should be f[0] , f[1] , ... ,f[nfft-1] + * fout will be F[0] , F[1] , ... ,F[nfft-1] + * Note that each element is complex and can be accessed like + f[k].r and f[k].i + * */ +void opus_fft_c(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); +void opus_ifft_c(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); + +void opus_fft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout); +void opus_ifft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout); + +void opus_fft_free(const kiss_fft_state *cfg, int arch); + + +void opus_fft_free_arch_c(kiss_fft_state *st); +int opus_fft_alloc_arch_c(kiss_fft_state *st); + +#if !defined(OVERRIDE_OPUS_FFT) +/* Is run-time CPU detection enabled on this platform? */ +#if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) + +extern int (*const OPUS_FFT_ALLOC_ARCH_IMPL[OPUS_ARCHMASK+1])( + kiss_fft_state *st); + +#define opus_fft_alloc_arch(_st, arch) \ + ((*OPUS_FFT_ALLOC_ARCH_IMPL[(arch)&OPUS_ARCHMASK])(_st)) + +extern void (*const OPUS_FFT_FREE_ARCH_IMPL[OPUS_ARCHMASK+1])( + kiss_fft_state *st); +#define opus_fft_free_arch(_st, arch) \ + ((*OPUS_FFT_FREE_ARCH_IMPL[(arch)&OPUS_ARCHMASK])(_st)) + +extern void (*const OPUS_FFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg, + const kiss_fft_cpx *fin, kiss_fft_cpx *fout); +#define opus_fft(_cfg, _fin, _fout, arch) \ + ((*OPUS_FFT[(arch)&OPUS_ARCHMASK])(_cfg, _fin, _fout)) + +extern void (*const OPUS_IFFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg, + const kiss_fft_cpx *fin, kiss_fft_cpx *fout); +#define opus_ifft(_cfg, _fin, _fout, arch) \ + ((*OPUS_IFFT[(arch)&OPUS_ARCHMASK])(_cfg, _fin, _fout)) + +#else /* else for if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) */ + +#define opus_fft_alloc_arch(_st, arch) \ + ((void)(arch), opus_fft_alloc_arch_c(_st)) + +#define opus_fft_free_arch(_st, arch) \ + ((void)(arch), opus_fft_free_arch_c(_st)) + +#define opus_fft(_cfg, _fin, _fout, arch) \ + ((void)(arch), opus_fft_c(_cfg, _fin, _fout)) + +#define opus_ifft(_cfg, _fin, _fout, arch) \ + ((void)(arch), opus_ifft_c(_cfg, _fin, _fout)) + +#endif /* end if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) */ +#endif /* end if !defined(OVERRIDE_OPUS_FFT) */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/laplace.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/laplace.c new file mode 100644 index 000000000..a7bca874b --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/laplace.c @@ -0,0 +1,134 @@ +/* Copyright (c) 2007 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "laplace.h" +#include "mathops.h" + +/* The minimum probability of an energy delta (out of 32768). */ +#define LAPLACE_LOG_MINP (0) +#define LAPLACE_MINP (1<>15; +} + +void ec_laplace_encode(ec_enc *enc, int *value, unsigned fs, int decay) +{ + unsigned fl; + int val = *value; + fl = 0; + if (val) + { + int s; + int i; + s = -(val<0); + val = (val+s)^s; + fl = fs; + fs = ec_laplace_get_freq1(fs, decay); + /* Search the decaying part of the PDF.*/ + for (i=1; fs > 0 && i < val; i++) + { + fs *= 2; + fl += fs+2*LAPLACE_MINP; + fs = (fs*(opus_int32)decay)>>15; + } + /* Everything beyond that has probability LAPLACE_MINP. */ + if (!fs) + { + int di; + int ndi_max; + ndi_max = (32768-fl+LAPLACE_MINP-1)>>LAPLACE_LOG_MINP; + ndi_max = (ndi_max-s)>>1; + di = IMIN(val - i, ndi_max - 1); + fl += (2*di+1+s)*LAPLACE_MINP; + fs = IMIN(LAPLACE_MINP, 32768-fl); + *value = (i+di+s)^s; + } + else + { + fs += LAPLACE_MINP; + fl += fs&~s; + } + celt_assert(fl+fs<=32768); + celt_assert(fs>0); + } + ec_encode_bin(enc, fl, fl+fs, 15); +} + +int ec_laplace_decode(ec_dec *dec, unsigned fs, int decay) +{ + int val=0; + unsigned fl; + unsigned fm; + fm = ec_decode_bin(dec, 15); + fl = 0; + if (fm >= fs) + { + val++; + fl = fs; + fs = ec_laplace_get_freq1(fs, decay)+LAPLACE_MINP; + /* Search the decaying part of the PDF.*/ + while(fs > LAPLACE_MINP && fm >= fl+2*fs) + { + fs *= 2; + fl += fs; + fs = ((fs-2*LAPLACE_MINP)*(opus_int32)decay)>>15; + fs += LAPLACE_MINP; + val++; + } + /* Everything beyond that has probability LAPLACE_MINP. */ + if (fs <= LAPLACE_MINP) + { + int di; + di = (fm-fl)>>(LAPLACE_LOG_MINP+1); + val += di; + fl += 2*di*LAPLACE_MINP; + } + if (fm < fl+fs) + val = -val; + else + fl += fs; + } + celt_assert(fl<32768); + celt_assert(fs>0); + celt_assert(fl<=fm); + celt_assert(fm>1; + b=1U<>=1; + bshift--; + } + while(bshift>=0); + return g; +} + +#ifdef FIXED_POINT + +opus_val32 frac_div32(opus_val32 a, opus_val32 b) +{ + opus_val16 rcp; + opus_val32 result, rem; + int shift = celt_ilog2(b)-29; + a = VSHR32(a,shift); + b = VSHR32(b,shift); + /* 16-bit reciprocal */ + rcp = ROUND16(celt_rcp(ROUND16(b,16)),3); + result = MULT16_32_Q15(rcp, a); + rem = PSHR32(a,2)-MULT32_32_Q31(result, b); + result = ADD32(result, SHL32(MULT16_32_Q15(rcp, rem),2)); + if (result >= 536870912) /* 2^29 */ + return 2147483647; /* 2^31 - 1 */ + else if (result <= -536870912) /* -2^29 */ + return -2147483647; /* -2^31 */ + else + return SHL32(result, 2); +} + +/** Reciprocal sqrt approximation in the range [0.25,1) (Q16 in, Q14 out) */ +opus_val16 celt_rsqrt_norm(opus_val32 x) +{ + opus_val16 n; + opus_val16 r; + opus_val16 r2; + opus_val16 y; + /* Range of n is [-16384,32767] ([-0.5,1) in Q15). */ + n = x-32768; + /* Get a rough initial guess for the root. + The optimal minimax quadratic approximation (using relative error) is + r = 1.437799046117536+n*(-0.823394375837328+n*0.4096419668459485). + Coefficients here, and the final result r, are Q14.*/ + r = ADD16(23557, MULT16_16_Q15(n, ADD16(-13490, MULT16_16_Q15(n, 6713)))); + /* We want y = x*r*r-1 in Q15, but x is 32-bit Q16 and r is Q14. + We can compute the result from n and r using Q15 multiplies with some + adjustment, carefully done to avoid overflow. + Range of y is [-1564,1594]. */ + r2 = MULT16_16_Q15(r, r); + y = SHL16(SUB16(ADD16(MULT16_16_Q15(r2, n), r2), 16384), 1); + /* Apply a 2nd-order Householder iteration: r += r*y*(y*0.375-0.5). + This yields the Q14 reciprocal square root of the Q16 x, with a maximum + relative error of 1.04956E-4, a (relative) RMSE of 2.80979E-5, and a + peak absolute error of 2.26591/16384. */ + return ADD16(r, MULT16_16_Q15(r, MULT16_16_Q15(y, + SUB16(MULT16_16_Q15(y, 12288), 16384)))); +} + +/** Sqrt approximation (QX input, QX/2 output) */ +opus_val32 celt_sqrt(opus_val32 x) +{ + int k; + opus_val16 n; + opus_val32 rt; + static const opus_val16 C[5] = {23175, 11561, -3011, 1699, -664}; + if (x==0) + return 0; + else if (x>=1073741824) + return 32767; + k = (celt_ilog2(x)>>1)-7; + x = VSHR32(x, 2*k); + n = x-32768; + rt = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], + MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, (C[4]))))))))); + rt = VSHR32(rt,7-k); + return rt; +} + +#define L1 32767 +#define L2 -7651 +#define L3 8277 +#define L4 -626 + +static OPUS_INLINE opus_val16 _celt_cos_pi_2(opus_val16 x) +{ + opus_val16 x2; + + x2 = MULT16_16_P15(x,x); + return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2 + )))))))); +} + +#undef L1 +#undef L2 +#undef L3 +#undef L4 + +opus_val16 celt_cos_norm(opus_val32 x) +{ + x = x&0x0001ffff; + if (x>SHL32(EXTEND32(1), 16)) + x = SUB32(SHL32(EXTEND32(1), 17),x); + if (x&0x00007fff) + { + if (x0); + i = celt_ilog2(x); + /* n is Q15 with range [0,1). */ + n = VSHR32(x,i-15)-32768; + /* Start with a linear approximation: + r = 1.8823529411764706-0.9411764705882353*n. + The coefficients and the result are Q14 in the range [15420,30840].*/ + r = ADD16(30840, MULT16_16_Q15(-15420, n)); + /* Perform two Newton iterations: + r -= r*((r*n)-1.Q15) + = r*((r*n)+(r-1.Q15)). */ + r = SUB16(r, MULT16_16_Q15(r, + ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768)))); + /* We subtract an extra 1 in the second iteration to avoid overflow; it also + neatly compensates for truncation error in the rest of the process. */ + r = SUB16(r, ADD16(1, MULT16_16_Q15(r, + ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768))))); + /* r is now the Q15 solution to 2/(n+1), with a maximum relative error + of 7.05346E-5, a (relative) RMSE of 2.14418E-5, and a peak absolute + error of 1.24665/32768. */ + return VSHR32(EXTEND32(r),i-16); +} + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mathops.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mathops.h new file mode 100644 index 000000000..fe29dac1c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mathops.h @@ -0,0 +1,290 @@ +/* Copyright (c) 2002-2008 Jean-Marc Valin + Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file mathops.h + @brief Various math functions +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef MATHOPS_H +#define MATHOPS_H + +#include "arch.h" +#include "entcode.h" +#include "os_support.h" + +#define PI 3.141592653f + +/* Multiplies two 16-bit fractional values. Bit-exactness of this macro is important */ +#define FRAC_MUL16(a,b) ((16384+((opus_int32)(opus_int16)(a)*(opus_int16)(b)))>>15) + +unsigned isqrt32(opus_uint32 _val); + +/* CELT doesn't need it for fixed-point, by analysis.c does. */ +#if !defined(FIXED_POINT) || defined(ANALYSIS_C) +#define cA 0.43157974f +#define cB 0.67848403f +#define cC 0.08595542f +#define cE ((float)PI/2) +static OPUS_INLINE float fast_atan2f(float y, float x) { + float x2, y2; + x2 = x*x; + y2 = y*y; + /* For very small values, we don't care about the answer, so + we can just return 0. */ + if (x2 + y2 < 1e-18f) + { + return 0; + } + if(x2>23)-127; + in.i -= (opus_uint32)integer<<23; + frac = in.f - 1.5f; + frac = -0.41445418f + frac*(0.95909232f + + frac*(-0.33951290f + frac*0.16541097f)); + return 1+integer+frac; +} + +/** Base-2 exponential approximation (2^x). */ +static OPUS_INLINE float celt_exp2(float x) +{ + int integer; + float frac; + union { + float f; + opus_uint32 i; + } res; + integer = floor(x); + if (integer < -50) + return 0; + frac = x-integer; + /* K0 = 1, K1 = log(2), K2 = 3-4*log(2), K3 = 3*log(2) - 2 */ + res.f = 0.99992522f + frac * (0.69583354f + + frac * (0.22606716f + 0.078024523f*frac)); + res.i = (res.i + ((opus_uint32)integer<<23)) & 0x7fffffff; + return res.f; +} + +#else +#define celt_log2(x) ((float)(1.442695040888963387*log(x))) +#define celt_exp2(x) ((float)exp(0.6931471805599453094*(x))) +#endif + +#endif + +#ifdef FIXED_POINT + +#include "os_support.h" + +#ifndef OVERRIDE_CELT_ILOG2 +/** Integer log in base2. Undefined for zero and negative numbers */ +static OPUS_INLINE opus_int16 celt_ilog2(opus_int32 x) +{ + celt_sig_assert(x>0); + return EC_ILOG(x)-1; +} +#endif + + +/** Integer log in base2. Defined for zero, but not for negative numbers */ +static OPUS_INLINE opus_int16 celt_zlog2(opus_val32 x) +{ + return x <= 0 ? 0 : celt_ilog2(x); +} + +opus_val16 celt_rsqrt_norm(opus_val32 x); + +opus_val32 celt_sqrt(opus_val32 x); + +opus_val16 celt_cos_norm(opus_val32 x); + +/** Base-2 logarithm approximation (log2(x)). (Q14 input, Q10 output) */ +static OPUS_INLINE opus_val16 celt_log2(opus_val32 x) +{ + int i; + opus_val16 n, frac; + /* -0.41509302963303146, 0.9609890551383969, -0.31836011537636605, + 0.15530808010959576, -0.08556153059057618 */ + static const opus_val16 C[5] = {-6801+(1<<(13-DB_SHIFT)), 15746, -5217, 2545, -1401}; + if (x==0) + return -32767; + i = celt_ilog2(x); + n = VSHR32(x,i-15)-32768-16384; + frac = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, C[4])))))))); + return SHL16(i-13,DB_SHIFT)+SHR16(frac,14-DB_SHIFT); +} + +/* + K0 = 1 + K1 = log(2) + K2 = 3-4*log(2) + K3 = 3*log(2) - 2 +*/ +#define D0 16383 +#define D1 22804 +#define D2 14819 +#define D3 10204 + +static OPUS_INLINE opus_val32 celt_exp2_frac(opus_val16 x) +{ + opus_val16 frac; + frac = SHL16(x, 4); + return ADD16(D0, MULT16_16_Q15(frac, ADD16(D1, MULT16_16_Q15(frac, ADD16(D2 , MULT16_16_Q15(D3,frac)))))); +} +/** Base-2 exponential approximation (2^x). (Q10 input, Q16 output) */ +static OPUS_INLINE opus_val32 celt_exp2(opus_val16 x) +{ + int integer; + opus_val16 frac; + integer = SHR16(x,10); + if (integer>14) + return 0x7f000000; + else if (integer < -15) + return 0; + frac = celt_exp2_frac(x-SHL16(integer,10)); + return VSHR32(EXTEND32(frac), -integer-2); +} + +opus_val32 celt_rcp(opus_val32 x); + +#define celt_div(a,b) MULT32_32_Q31((opus_val32)(a),celt_rcp(b)) + +opus_val32 frac_div32(opus_val32 a, opus_val32 b); + +#define M1 32767 +#define M2 -21 +#define M3 -11943 +#define M4 4936 + +/* Atan approximation using a 4th order polynomial. Input is in Q15 format + and normalized by pi/4. Output is in Q15 format */ +static OPUS_INLINE opus_val16 celt_atan01(opus_val16 x) +{ + return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x))))))); +} + +#undef M1 +#undef M2 +#undef M3 +#undef M4 + +/* atan2() approximation valid for positive input values */ +static OPUS_INLINE opus_val16 celt_atan2p(opus_val16 y, opus_val16 x) +{ + if (y < x) + { + opus_val32 arg; + arg = celt_div(SHL32(EXTEND32(y),15),x); + if (arg >= 32767) + arg = 32767; + return SHR16(celt_atan01(EXTRACT16(arg)),1); + } else { + opus_val32 arg; + arg = celt_div(SHL32(EXTEND32(x),15),y); + if (arg >= 32767) + arg = 32767; + return 25736-SHR16(celt_atan01(EXTRACT16(arg)),1); + } +} + +#endif /* FIXED_POINT */ +#endif /* MATHOPS_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mdct.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mdct.c new file mode 100644 index 000000000..5c6dab5b7 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mdct.c @@ -0,0 +1,343 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +/* This is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ + +#ifndef SKIP_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +#include "mdct.h" +#include "kiss_fft.h" +#include "_kiss_fft_guts.h" +#include +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" + +#if defined(MIPSr1_ASM) +#include "mips/mdct_mipsr1.h" +#endif + + +#ifdef CUSTOM_MODES + +int clt_mdct_init(mdct_lookup *l,int N, int maxshift, int arch) +{ + int i; + kiss_twiddle_scalar *trig; + int shift; + int N2=N>>1; + l->n = N; + l->maxshift = maxshift; + for (i=0;i<=maxshift;i++) + { + if (i==0) + l->kfft[i] = opus_fft_alloc(N>>2>>i, 0, 0, arch); + else + l->kfft[i] = opus_fft_alloc_twiddles(N>>2>>i, 0, 0, l->kfft[0], arch); +#ifndef ENABLE_TI_DSPLIB55 + if (l->kfft[i]==NULL) + return 0; +#endif + } + l->trig = trig = (kiss_twiddle_scalar*)opus_alloc((N-(N2>>maxshift))*sizeof(kiss_twiddle_scalar)); + if (l->trig==NULL) + return 0; + for (shift=0;shift<=maxshift;shift++) + { + /* We have enough points that sine isn't necessary */ +#if defined(FIXED_POINT) +#if 1 + for (i=0;i>= 1; + N >>= 1; + } + return 1; +} + +void clt_mdct_clear(mdct_lookup *l, int arch) +{ + int i; + for (i=0;i<=l->maxshift;i++) + opus_fft_free(l->kfft[i], arch); + opus_free((kiss_twiddle_scalar*)l->trig); +} + +#endif /* CUSTOM_MODES */ + +/* Forward MDCT trashes the input array */ +#ifndef OVERRIDE_clt_mdct_forward +void clt_mdct_forward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + VARDECL(kiss_fft_scalar, f); + VARDECL(kiss_fft_cpx, f2); + const kiss_fft_state *st = l->kfft[shift]; + const kiss_twiddle_scalar *trig; + opus_val16 scale; +#ifdef FIXED_POINT + /* Allows us to scale with MULT16_32_Q16(), which is faster than + MULT16_32_Q15() on ARM. */ + int scale_shift = st->scale_shift-1; +#endif + SAVE_STACK; + (void)arch; + scale = st->scale; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + ALLOC(f, N2, kiss_fft_scalar); + ALLOC(f2, N4, kiss_fft_cpx); + + /* Consider the input to be composed of four blocks: [a, b, c, d] */ + /* Window, shuffle, fold */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1); + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1); + kiss_fft_scalar * OPUS_RESTRICT yp = f; + const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1); + const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1; + for(i=0;i<((overlap+3)>>2);i++) + { + /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/ + *yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2); + *yp++ = MULT16_32_Q15(*wp1, *xp1) - MULT16_32_Q15(*wp2, xp2[-N2]); + xp1+=2; + xp2-=2; + wp1+=2; + wp2-=2; + } + wp1 = window; + wp2 = window+overlap-1; + for(;i>2);i++) + { + /* Real part arranged as a-bR, Imag part arranged as -c-dR */ + *yp++ = *xp2; + *yp++ = *xp1; + xp1+=2; + xp2-=2; + } + for(;ibitrev[i]] = yc; + } + } + + /* N/4 complex FFT, does not downscale anymore */ + opus_fft_impl(st, f2); + + /* Post-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_cpx * OPUS_RESTRICT fp = f2; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1); + const kiss_twiddle_scalar *t = &trig[0]; + /* Temp pointers to make it really clear to the compiler what we're doing */ + for(i=0;ii,t[N4+i]) - S_MUL(fp->r,t[i]); + yi = S_MUL(fp->r,t[N4+i]) + S_MUL(fp->i,t[i]); + *yp1 = yr; + *yp2 = yi; + fp++; + yp1 += 2*stride; + yp2 -= 2*stride; + } + } + RESTORE_STACK; +} +#endif /* OVERRIDE_clt_mdct_forward */ + +#ifndef OVERRIDE_clt_mdct_backward +void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 * OPUS_RESTRICT window, int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + const kiss_twiddle_scalar *trig; + (void) arch; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + /* Pre-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in; + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1); + kiss_fft_scalar * OPUS_RESTRICT yp = out+(overlap>>1); + const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0]; + const opus_int16 * OPUS_RESTRICT bitrev = l->kfft[shift]->bitrev; + for(i=0;ikfft[shift], (kiss_fft_cpx*)(out+(overlap>>1))); + + /* Post-rotate and de-shuffle from both ends of the buffer at once to make + it in-place. */ + { + kiss_fft_scalar * yp0 = out+(overlap>>1); + kiss_fft_scalar * yp1 = out+(overlap>>1)+N2-2; + const kiss_twiddle_scalar *t = &trig[0]; + /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the + middle pair will be computed twice. */ + for(i=0;i<(N4+1)>>1;i++) + { + kiss_fft_scalar re, im, yr, yi; + kiss_twiddle_scalar t0, t1; + /* We swap real and imag because we're using an FFT instead of an IFFT. */ + re = yp0[1]; + im = yp0[0]; + t0 = t[i]; + t1 = t[N4+i]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = ADD32_ovflw(S_MUL(re,t0), S_MUL(im,t1)); + yi = SUB32_ovflw(S_MUL(re,t1), S_MUL(im,t0)); + /* We swap real and imag because we're using an FFT instead of an IFFT. */ + re = yp1[1]; + im = yp1[0]; + yp0[0] = yr; + yp1[1] = yi; + + t0 = t[(N4-i-1)]; + t1 = t[(N2-i-1)]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = ADD32_ovflw(S_MUL(re,t0), S_MUL(im,t1)); + yi = SUB32_ovflw(S_MUL(re,t1), S_MUL(im,t0)); + yp1[0] = yr; + yp0[1] = yi; + yp0 += 2; + yp1 -= 2; + } + } + + /* Mirror on both sides for TDAC */ + { + kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + const opus_val16 * OPUS_RESTRICT wp1 = window; + const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1; + + for(i = 0; i < overlap/2; i++) + { + kiss_fft_scalar x1, x2; + x1 = *xp1; + x2 = *yp1; + *yp1++ = SUB32_ovflw(MULT16_32_Q15(*wp2, x2), MULT16_32_Q15(*wp1, x1)); + *xp1-- = ADD32_ovflw(MULT16_32_Q15(*wp1, x2), MULT16_32_Q15(*wp2, x1)); + wp1++; + wp2--; + } + } +} +#endif /* OVERRIDE_clt_mdct_backward */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mdct.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mdct.h new file mode 100644 index 000000000..160ae4e0f --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mdct.h @@ -0,0 +1,112 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +/* This is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ + +#ifndef MDCT_H +#define MDCT_H + +#include "opus_defines.h" +#include "kiss_fft.h" +#include "arch.h" + +typedef struct { + int n; + int maxshift; + const kiss_fft_state *kfft[4]; + const kiss_twiddle_scalar * OPUS_RESTRICT trig; +} mdct_lookup; + +#if defined(HAVE_ARM_NE10) +#include "arm/mdct_arm.h" +#endif + + +int clt_mdct_init(mdct_lookup *l,int N, int maxshift, int arch); +void clt_mdct_clear(mdct_lookup *l, int arch); + +/** Compute a forward MDCT and scale by 4/N, trashes the input array */ +void clt_mdct_forward_c(const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, + int shift, int stride, int arch); + +/** Compute a backward MDCT (no scaling) and performs weighted overlap-add + (scales implicitly by 1/2) */ +void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 * OPUS_RESTRICT window, + int overlap, int shift, int stride, int arch); + +#if !defined(OVERRIDE_OPUS_MDCT) +/* Is run-time CPU detection enabled on this platform? */ +#if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10) + +extern void (*const CLT_MDCT_FORWARD_IMPL[OPUS_ARCHMASK+1])( + const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, const opus_val16 *window, + int overlap, int shift, int stride, int arch); + +#define clt_mdct_forward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \ + ((*CLT_MDCT_FORWARD_IMPL[(arch)&OPUS_ARCHMASK])(_l, _in, _out, \ + _window, _overlap, _shift, \ + _stride, _arch)) + +extern void (*const CLT_MDCT_BACKWARD_IMPL[OPUS_ARCHMASK+1])( + const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, const opus_val16 *window, + int overlap, int shift, int stride, int arch); + +#define clt_mdct_backward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \ + (*CLT_MDCT_BACKWARD_IMPL[(arch)&OPUS_ARCHMASK])(_l, _in, _out, \ + _window, _overlap, _shift, \ + _stride, _arch) + +#else /* if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10) */ + +#define clt_mdct_forward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \ + clt_mdct_forward_c(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) + +#define clt_mdct_backward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \ + clt_mdct_backward_c(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) + +#endif /* end if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10) && !defined(FIXED_POINT) */ +#endif /* end if !defined(OVERRIDE_OPUS_MDCT) */ + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/meson.build b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/meson.build new file mode 100644 index 000000000..370ea1fe0 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/meson.build @@ -0,0 +1,63 @@ +celt_sources = sources['CELT_SOURCES'] + +celt_sse_sources = sources['CELT_SOURCES_SSE'] + +celt_sse2_sources = sources['CELT_SOURCES_SSE2'] + +celt_sse4_1_sources = sources['CELT_SOURCES_SSE4_1'] + +celt_neon_intr_sources = sources['CELT_SOURCES_ARM_NEON_INTR'] + +celt_static_libs = [] + +foreach intr_name : ['sse', 'sse2', 'sse4_1', 'neon_intr'] + have_intr = get_variable('have_' + intr_name) + if not have_intr + continue + endif + + intr_sources = get_variable('celt_@0@_sources'.format(intr_name)) + intr_args = get_variable('opus_@0@_args'.format(intr_name), []) + celt_static_libs += static_library('celt_' + intr_name, intr_sources, + c_args: intr_args, + include_directories: opus_includes, + install: false) +endforeach + +have_arm_intrinsics_or_asm = have_arm_ne10 +if (intrinsics_support.length() + asm_optimization.length() + inline_optimization.length()) > 0 + have_arm_intrinsics_or_asm = true +endif + +if host_cpu_family in ['arm', 'aarch64'] and have_arm_intrinsics_or_asm + celt_sources += sources['CELT_SOURCES_ARM'] + if have_arm_ne10 + celt_sources += sources['CELT_SOURCES_ARM_NE10'] + endif + if opus_arm_external_asm + arm2gnu = [find_program('arm/arm2gnu.pl')] + arm2gnu_args + celt_sources_arm_asm = configure_file(input: 'arm/celt_pitch_xcorr_arm.s', + output: '@BASENAME@-gnu.S', + command: arm2gnu + ['@INPUT@'], + capture: true) + celt_arm_armopts_s = configure_file(input: 'arm/armopts.s.in', + output: 'arm/armopts.s', + configuration: opus_conf) + celt_static_libs += static_library('celt-armasm', + celt_arm_armopts_s, celt_sources_arm_asm, + install: false) + endif +endif + +celt_c_args = [] +if host_system == 'windows' + celt_c_args += ['-DDLL_EXPORT'] +endif + +celt_lib = static_library('opus-celt', + celt_sources, + c_args: celt_c_args, + include_directories: opus_includes, + link_whole: celt_static_libs, + dependencies: libm, + install: false) diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mfrngcod.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mfrngcod.h new file mode 100644 index 000000000..809152a59 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mfrngcod.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2001-2008 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#if !defined(_mfrngcode_H) +# define _mfrngcode_H (1) +# include "entcode.h" + +/*Constants used by the entropy encoder/decoder.*/ + +/*The number of bits to output at a time.*/ +# define EC_SYM_BITS (8) +/*The total number of bits in each of the state registers.*/ +# define EC_CODE_BITS (32) +/*The maximum symbol value.*/ +# define EC_SYM_MAX ((1U<>EC_SYM_BITS) +/*The number of bits available for the last, partial symbol in the code field.*/ +# define EC_CODE_EXTRA ((EC_CODE_BITS-2)%EC_SYM_BITS+1) +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mips/celt_mipsr1.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mips/celt_mipsr1.h new file mode 100644 index 000000000..c332fe047 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mips/celt_mipsr1.h @@ -0,0 +1,152 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2010 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef __CELT_MIPSR1_H__ +#define __CELT_MIPSR1_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define CELT_C + +#include "os_support.h" +#include "mdct.h" +#include +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + +#define OVERRIDE_COMB_FILTER_CONST +#define OVERRIDE_comb_filter +void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N, + opus_val16 g0, opus_val16 g1, int tapset0, int tapset1, + const opus_val16 *window, int overlap, int arch) +{ + int i; + opus_val32 x0, x1, x2, x3, x4; + + (void)arch; + + /* printf ("%d %d %f %f\n", T0, T1, g0, g1); */ + opus_val16 g00, g01, g02, g10, g11, g12; + static const opus_val16 gains[3][3] = { + {QCONST16(0.3066406250f, 15), QCONST16(0.2170410156f, 15), QCONST16(0.1296386719f, 15)}, + {QCONST16(0.4638671875f, 15), QCONST16(0.2680664062f, 15), QCONST16(0.f, 15)}, + {QCONST16(0.7998046875f, 15), QCONST16(0.1000976562f, 15), QCONST16(0.f, 15)}}; + + if (g0==0 && g1==0) + { + /* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */ + if (x!=y) + OPUS_MOVE(y, x, N); + return; + } + + g00 = MULT16_16_P15(g0, gains[tapset0][0]); + g01 = MULT16_16_P15(g0, gains[tapset0][1]); + g02 = MULT16_16_P15(g0, gains[tapset0][2]); + g10 = MULT16_16_P15(g1, gains[tapset1][0]); + g11 = MULT16_16_P15(g1, gains[tapset1][1]); + g12 = MULT16_16_P15(g1, gains[tapset1][2]); + x1 = x[-T1+1]; + x2 = x[-T1 ]; + x3 = x[-T1-1]; + x4 = x[-T1-2]; + /* If the filter didn't change, we don't need the overlap */ + if (g0==g1 && T0==T1 && tapset0==tapset1) + overlap=0; + + for (i=0;itwiddles[fstride*m]; + yb = st->twiddles[fstride*2*m]; +#endif + + tw=st->twiddles; + + for (i=0;ir += scratch[7].r + scratch[8].r; + Fout0->i += scratch[7].i + scratch[8].i; + scratch[5].r = scratch[0].r + S_MUL_ADD(scratch[7].r,ya.r,scratch[8].r,yb.r); + scratch[5].i = scratch[0].i + S_MUL_ADD(scratch[7].i,ya.r,scratch[8].i,yb.r); + + scratch[6].r = S_MUL_ADD(scratch[10].i,ya.i,scratch[9].i,yb.i); + scratch[6].i = -S_MUL_ADD(scratch[10].r,ya.i,scratch[9].r,yb.i); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = scratch[0].r + S_MUL_ADD(scratch[7].r,yb.r,scratch[8].r,ya.r); + scratch[11].i = scratch[0].i + S_MUL_ADD(scratch[7].i,yb.r,scratch[8].i,ya.r); + + scratch[12].r = S_MUL_SUB(scratch[9].i,ya.i,scratch[10].i,yb.i); + scratch[12].i = S_MUL_SUB(scratch[10].r,yb.i,scratch[9].r,ya.i); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } + } +} + + +#endif /* KISS_FFT_MIPSR1_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mips/mdct_mipsr1.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mips/mdct_mipsr1.h new file mode 100644 index 000000000..2934dab77 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mips/mdct_mipsr1.h @@ -0,0 +1,288 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +/* This is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ +#ifndef __MDCT_MIPSR1_H__ +#define __MDCT_MIPSR1_H__ + +#ifndef SKIP_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +#include "mdct.h" +#include "kiss_fft.h" +#include "_kiss_fft_guts.h" +#include +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" + +/* Forward MDCT trashes the input array */ +#define OVERRIDE_clt_mdct_forward +void clt_mdct_forward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + VARDECL(kiss_fft_scalar, f); + VARDECL(kiss_fft_cpx, f2); + const kiss_fft_state *st = l->kfft[shift]; + const kiss_twiddle_scalar *trig; + opus_val16 scale; +#ifdef FIXED_POINT + /* Allows us to scale with MULT16_32_Q16(), which is faster than + MULT16_32_Q15() on ARM. */ + int scale_shift = st->scale_shift-1; +#endif + + (void)arch; + + SAVE_STACK; + scale = st->scale; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + ALLOC(f, N2, kiss_fft_scalar); + ALLOC(f2, N4, kiss_fft_cpx); + + /* Consider the input to be composed of four blocks: [a, b, c, d] */ + /* Window, shuffle, fold */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1); + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1); + kiss_fft_scalar * OPUS_RESTRICT yp = f; + const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1); + const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1; + for(i=0;i<((overlap+3)>>2);i++) + { + /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/ + *yp++ = S_MUL_ADD(*wp2, xp1[N2],*wp1,*xp2); + *yp++ = S_MUL_SUB(*wp1, *xp1,*wp2, xp2[-N2]); + xp1+=2; + xp2-=2; + wp1+=2; + wp2-=2; + } + wp1 = window; + wp2 = window+overlap-1; + for(;i>2);i++) + { + /* Real part arranged as a-bR, Imag part arranged as -c-dR */ + *yp++ = *xp2; + *yp++ = *xp1; + xp1+=2; + xp2-=2; + } + for(;ibitrev[i]] = yc; + } + } + + /* N/4 complex FFT, does not downscale anymore */ + opus_fft_impl(st, f2); + + /* Post-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_cpx * OPUS_RESTRICT fp = f2; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1); + const kiss_twiddle_scalar *t = &trig[0]; + /* Temp pointers to make it really clear to the compiler what we're doing */ + for(i=0;ii,t[N4+i] , fp->r,t[i]); + yi = S_MUL_ADD(fp->r,t[N4+i] ,fp->i,t[i]); + *yp1 = yr; + *yp2 = yi; + fp++; + yp1 += 2*stride; + yp2 -= 2*stride; + } + } + RESTORE_STACK; +} + +#define OVERRIDE_clt_mdct_backward +void clt_mdct_backward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 * OPUS_RESTRICT window, int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + const kiss_twiddle_scalar *trig; + + (void)arch; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + /* Pre-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in; + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1); + kiss_fft_scalar * OPUS_RESTRICT yp = out+(overlap>>1); + const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0]; + const opus_int16 * OPUS_RESTRICT bitrev = l->kfft[shift]->bitrev; + for(i=0;ikfft[shift], (kiss_fft_cpx*)(out+(overlap>>1))); + + /* Post-rotate and de-shuffle from both ends of the buffer at once to make + it in-place. */ + { + kiss_fft_scalar * OPUS_RESTRICT yp0 = out+(overlap>>1); + kiss_fft_scalar * OPUS_RESTRICT yp1 = out+(overlap>>1)+N2-2; + const kiss_twiddle_scalar *t = &trig[0]; + /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the + middle pair will be computed twice. */ + for(i=0;i<(N4+1)>>1;i++) + { + kiss_fft_scalar re, im, yr, yi; + kiss_twiddle_scalar t0, t1; + /* We swap real and imag because we're using an FFT instead of an IFFT. */ + re = yp0[1]; + im = yp0[0]; + t0 = t[i]; + t1 = t[N4+i]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = S_MUL_ADD(re,t0 , im,t1); + yi = S_MUL_SUB(re,t1 , im,t0); + /* We swap real and imag because we're using an FFT instead of an IFFT. */ + re = yp1[1]; + im = yp1[0]; + yp0[0] = yr; + yp1[1] = yi; + + t0 = t[(N4-i-1)]; + t1 = t[(N2-i-1)]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = S_MUL_ADD(re,t0,im,t1); + yi = S_MUL_SUB(re,t1,im,t0); + yp1[0] = yr; + yp0[1] = yi; + yp0 += 2; + yp1 -= 2; + } + } + + /* Mirror on both sides for TDAC */ + { + kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + const opus_val16 * OPUS_RESTRICT wp1 = window; + const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1; + + for(i = 0; i < overlap/2; i++) + { + kiss_fft_scalar x1, x2; + x1 = *xp1; + x2 = *yp1; + *yp1++ = MULT16_32_Q15(*wp2, x2) - MULT16_32_Q15(*wp1, x1); + *xp1-- = MULT16_32_Q15(*wp1, x2) + MULT16_32_Q15(*wp2, x1); + wp1++; + wp2--; + } + } +} +#endif /* __MDCT_MIPSR1_H__ */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mips/pitch_mipsr1.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mips/pitch_mipsr1.h new file mode 100644 index 000000000..a9500aff5 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/mips/pitch_mipsr1.h @@ -0,0 +1,161 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file pitch.h + @brief Pitch analysis + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef PITCH_MIPSR1_H +#define PITCH_MIPSR1_H + +#define OVERRIDE_DUAL_INNER_PROD +static inline void dual_inner_prod(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2, int arch) +{ + int j; + opus_val32 xy01=0; + opus_val32 xy02=0; + + (void)arch; + + asm volatile("MULT $ac1, $0, $0"); + asm volatile("MULT $ac2, $0, $0"); + /* Compute the norm of X+Y and X-Y as |X|^2 + |Y|^2 +/- sum(xy) */ + for (j=0;j=0;i--) + { + celt_norm x1, x2; + x1 = Xptr[0]; + x2 = Xptr[stride]; + Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2), s, x1), 15)); + *Xptr-- = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15)); + } +} + +#define OVERRIDE_renormalise_vector +void renormalise_vector(celt_norm *X, int N, opus_val16 gain, int arch) +{ + int i; +#ifdef FIXED_POINT + int k; +#endif + opus_val32 E = EPSILON; + opus_val16 g; + opus_val32 t; + celt_norm *xptr = X; + int X0, X1; + + (void)arch; + + asm volatile("mult $ac1, $0, $0"); + asm volatile("MTLO %0, $ac1" : :"r" (E)); + /*if(N %4) + printf("error");*/ + for (i=0;i>1; +#endif + t = VSHR32(E, 2*(k-7)); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + xptr = X; + for (i=0;i= Fs) + break; + + /* Find where the linear part ends (i.e. where the spacing is more than min_width */ + for (lin=0;lin= res) + break; + + low = (bark_freq[lin]+res/2)/res; + high = nBark-lin; + *nbEBands = low+high; + eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+2)); + + if (eBands==NULL) + return NULL; + + /* Linear spacing (min_width) */ + for (i=0;i0) + offset = eBands[low-1]*res - bark_freq[lin-1]; + /* Spacing follows critical bands */ + for (i=0;i frame_size) + eBands[*nbEBands] = frame_size; + for (i=1;i<*nbEBands-1;i++) + { + if (eBands[i+1]-eBands[i] < eBands[i]-eBands[i-1]) + { + eBands[i] -= (2*eBands[i]-eBands[i-1]-eBands[i+1])/2; + } + } + /* Remove any empty bands. */ + for (i=j=0;i<*nbEBands;i++) + if(eBands[i+1]>eBands[j]) + eBands[++j]=eBands[i+1]; + *nbEBands=j; + + for (i=1;i<*nbEBands;i++) + { + /* Every band must be smaller than the last band. */ + celt_assert(eBands[i]-eBands[i-1]<=eBands[*nbEBands]-eBands[*nbEBands-1]); + /* Each band must be no larger than twice the size of the previous one. */ + celt_assert(eBands[i+1]-eBands[i]<=2*(eBands[i]-eBands[i-1])); + } + + return eBands; +} + +static void compute_allocation_table(CELTMode *mode) +{ + int i, j; + unsigned char *allocVectors; + int maxBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1; + + mode->nbAllocVectors = BITALLOC_SIZE; + allocVectors = opus_alloc(sizeof(unsigned char)*(BITALLOC_SIZE*mode->nbEBands)); + if (allocVectors==NULL) + return; + + /* Check for standard mode */ + if (mode->Fs == 400*(opus_int32)mode->shortMdctSize) + { + for (i=0;inbEBands;i++) + allocVectors[i] = band_allocation[i]; + mode->allocVectors = allocVectors; + return; + } + /* If not the standard mode, interpolate */ + /* Compute per-codec-band allocation from per-critical-band matrix */ + for (i=0;inbEBands;j++) + { + int k; + for (k=0;k mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize) + break; + } + if (k>maxBands-1) + allocVectors[i*mode->nbEBands+j] = band_allocation[i*maxBands + maxBands-1]; + else { + opus_int32 a0, a1; + a1 = mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize - 400*(opus_int32)eband5ms[k-1]; + a0 = 400*(opus_int32)eband5ms[k] - mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize; + allocVectors[i*mode->nbEBands+j] = (a0*band_allocation[i*maxBands+k-1] + + a1*band_allocation[i*maxBands+k])/(a0+a1); + } + } + } + + /*printf ("\n"); + for (i=0;inbEBands;j++) + printf ("%d ", allocVectors[i*mode->nbEBands+j]); + printf ("\n"); + } + exit(0);*/ + + mode->allocVectors = allocVectors; +} + +#endif /* CUSTOM_MODES */ + +CELTMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error) +{ + int i; +#ifdef CUSTOM_MODES + CELTMode *mode=NULL; + int res; + opus_val16 *window; + opus_int16 *logN; + int LM; + int arch = opus_select_arch(); + ALLOC_STACK; +#if !defined(VAR_ARRAYS) && !defined(USE_ALLOCA) + if (global_stack==NULL) + goto failure; +#endif +#endif + +#ifndef CUSTOM_MODES_ONLY + for (i=0;iFs && + (frame_size<shortMdctSize*static_mode_list[i]->nbShortMdcts) + { + if (error) + *error = OPUS_OK; + return (CELTMode*)static_mode_list[i]; + } + } + } +#endif /* CUSTOM_MODES_ONLY */ + +#ifndef CUSTOM_MODES + if (error) + *error = OPUS_BAD_ARG; + return NULL; +#else + + /* The good thing here is that permutation of the arguments will automatically be invalid */ + + if (Fs < 8000 || Fs > 96000) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + if (frame_size < 40 || frame_size > 1024 || frame_size%2!=0) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + /* Frames of less than 1ms are not supported. */ + if ((opus_int32)frame_size*1000 < Fs) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + + if ((opus_int32)frame_size*75 >= Fs && (frame_size%16)==0) + { + LM = 3; + } else if ((opus_int32)frame_size*150 >= Fs && (frame_size%8)==0) + { + LM = 2; + } else if ((opus_int32)frame_size*300 >= Fs && (frame_size%4)==0) + { + LM = 1; + } else + { + LM = 0; + } + + /* Shorts longer than 3.3ms are not supported. */ + if ((opus_int32)(frame_size>>LM)*300 > Fs) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + + mode = opus_alloc(sizeof(CELTMode)); + if (mode==NULL) + goto failure; + mode->Fs = Fs; + + /* Pre/de-emphasis depends on sampling rate. The "standard" pre-emphasis + is defined as A(z) = 1 - 0.85*z^-1 at 48 kHz. Other rates should + approximate that. */ + if(Fs < 12000) /* 8 kHz */ + { + mode->preemph[0] = QCONST16(0.3500061035f, 15); + mode->preemph[1] = -QCONST16(0.1799926758f, 15); + mode->preemph[2] = QCONST16(0.2719968125f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(3.6765136719f, 13); + } else if(Fs < 24000) /* 16 kHz */ + { + mode->preemph[0] = QCONST16(0.6000061035f, 15); + mode->preemph[1] = -QCONST16(0.1799926758f, 15); + mode->preemph[2] = QCONST16(0.4424998650f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(2.2598876953f, 13); + } else if(Fs < 40000) /* 32 kHz */ + { + mode->preemph[0] = QCONST16(0.7799987793f, 15); + mode->preemph[1] = -QCONST16(0.1000061035f, 15); + mode->preemph[2] = QCONST16(0.7499771125f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(1.3333740234f, 13); + } else /* 48 kHz */ + { + mode->preemph[0] = QCONST16(0.8500061035f, 15); + mode->preemph[1] = QCONST16(0.0f, 15); + mode->preemph[2] = QCONST16(1.f, SIG_SHIFT); + mode->preemph[3] = QCONST16(1.f, 13); + } + + mode->maxLM = LM; + mode->nbShortMdcts = 1<shortMdctSize = frame_size/mode->nbShortMdcts; + res = (mode->Fs+mode->shortMdctSize)/(2*mode->shortMdctSize); + + mode->eBands = compute_ebands(Fs, mode->shortMdctSize, res, &mode->nbEBands); + if (mode->eBands==NULL) + goto failure; +#if !defined(SMALL_FOOTPRINT) + /* Make sure we don't allocate a band larger than our PVQ table. + 208 should be enough, but let's be paranoid. */ + if ((mode->eBands[mode->nbEBands] - mode->eBands[mode->nbEBands-1])< + 208) { + goto failure; + } +#endif + + mode->effEBands = mode->nbEBands; + while (mode->eBands[mode->effEBands] > mode->shortMdctSize) + mode->effEBands--; + + /* Overlap must be divisible by 4 */ + mode->overlap = ((mode->shortMdctSize>>2)<<2); + + compute_allocation_table(mode); + if (mode->allocVectors==NULL) + goto failure; + + window = (opus_val16*)opus_alloc(mode->overlap*sizeof(opus_val16)); + if (window==NULL) + goto failure; + +#ifndef FIXED_POINT + for (i=0;ioverlap;i++) + window[i] = Q15ONE*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap)); +#else + for (i=0;ioverlap;i++) + window[i] = MIN32(32767,floor(.5+32768.*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap)))); +#endif + mode->window = window; + + logN = (opus_int16*)opus_alloc(mode->nbEBands*sizeof(opus_int16)); + if (logN==NULL) + goto failure; + + for (i=0;inbEBands;i++) + logN[i] = log2_frac(mode->eBands[i+1]-mode->eBands[i], BITRES); + mode->logN = logN; + + compute_pulse_cache(mode, mode->maxLM); + + if (clt_mdct_init(&mode->mdct, 2*mode->shortMdctSize*mode->nbShortMdcts, + mode->maxLM, arch) == 0) + goto failure; + + if (error) + *error = OPUS_OK; + + return mode; +failure: + if (error) + *error = OPUS_ALLOC_FAIL; + if (mode!=NULL) + opus_custom_mode_destroy(mode); + return NULL; +#endif /* !CUSTOM_MODES */ +} + +#ifdef CUSTOM_MODES +void opus_custom_mode_destroy(CELTMode *mode) +{ + int arch = opus_select_arch(); + + if (mode == NULL) + return; +#ifndef CUSTOM_MODES_ONLY + { + int i; + for (i=0;ieBands); + opus_free((unsigned char*)mode->allocVectors); + + opus_free((opus_val16*)mode->window); + opus_free((opus_int16*)mode->logN); + + opus_free((opus_int16*)mode->cache.index); + opus_free((unsigned char*)mode->cache.bits); + opus_free((unsigned char*)mode->cache.caps); + clt_mdct_clear(&mode->mdct, arch); + + opus_free((CELTMode *)mode); +} +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/modes.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/modes.h new file mode 100644 index 000000000..be813ccc8 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/modes.h @@ -0,0 +1,75 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef MODES_H +#define MODES_H + +#include "opus_types.h" +#include "celt.h" +#include "arch.h" +#include "mdct.h" +#include "entenc.h" +#include "entdec.h" + +#define MAX_PERIOD 1024 + +typedef struct { + int size; + const opus_int16 *index; + const unsigned char *bits; + const unsigned char *caps; +} PulseCache; + +/** Mode definition (opaque) + @brief Mode definition + */ +struct OpusCustomMode { + opus_int32 Fs; + int overlap; + + int nbEBands; + int effEBands; + opus_val16 preemph[4]; + const opus_int16 *eBands; /**< Definition for each "pseudo-critical band" */ + + int maxLM; + int nbShortMdcts; + int shortMdctSize; + + int nbAllocVectors; /**< Number of lines in the matrix below */ + const unsigned char *allocVectors; /**< Number of bits in each band for several rates */ + const opus_int16 *logN; + + const opus_val16 *window; + mdct_lookup mdct; + PulseCache cache; +}; + + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/opus_custom_demo.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/opus_custom_demo.c new file mode 100644 index 000000000..ae41c0de5 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/opus_custom_demo.c @@ -0,0 +1,210 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_custom.h" +#include "arch.h" +#include +#include +#include +#include + +#define MAX_PACKET 1275 + +int main(int argc, char *argv[]) +{ + int err; + char *inFile, *outFile; + FILE *fin, *fout; + OpusCustomMode *mode=NULL; + OpusCustomEncoder *enc; + OpusCustomDecoder *dec; + int len; + opus_int32 frame_size, channels, rate; + int bytes_per_packet; + unsigned char data[MAX_PACKET]; + int complexity; +#if !(defined (FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH) + int i; + double rmsd = 0; +#endif + int count = 0; + opus_int32 skip; + opus_int16 *in, *out; + if (argc != 9 && argc != 8 && argc != 7) + { + fprintf (stderr, "Usage: test_opus_custom " + " [ [packet loss rate]] " + " \n"); + return 1; + } + + rate = (opus_int32)atol(argv[1]); + channels = atoi(argv[2]); + frame_size = atoi(argv[3]); + mode = opus_custom_mode_create(rate, frame_size, NULL); + if (mode == NULL) + { + fprintf(stderr, "failed to create a mode\n"); + return 1; + } + + bytes_per_packet = atoi(argv[4]); + if (bytes_per_packet < 0 || bytes_per_packet > MAX_PACKET) + { + fprintf (stderr, "bytes per packet must be between 0 and %d\n", + MAX_PACKET); + return 1; + } + + inFile = argv[argc-2]; + fin = fopen(inFile, "rb"); + if (!fin) + { + fprintf (stderr, "Could not open input file %s\n", argv[argc-2]); + return 1; + } + outFile = argv[argc-1]; + fout = fopen(outFile, "wb+"); + if (!fout) + { + fprintf (stderr, "Could not open output file %s\n", argv[argc-1]); + fclose(fin); + return 1; + } + + enc = opus_custom_encoder_create(mode, channels, &err); + if (err != 0) + { + fprintf(stderr, "Failed to create the encoder: %s\n", opus_strerror(err)); + fclose(fin); + fclose(fout); + return 1; + } + dec = opus_custom_decoder_create(mode, channels, &err); + if (err != 0) + { + fprintf(stderr, "Failed to create the decoder: %s\n", opus_strerror(err)); + fclose(fin); + fclose(fout); + return 1; + } + opus_custom_decoder_ctl(dec, OPUS_GET_LOOKAHEAD(&skip)); + + if (argc>7) + { + complexity=atoi(argv[5]); + opus_custom_encoder_ctl(enc,OPUS_SET_COMPLEXITY(complexity)); + } + + in = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16)); + out = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16)); + + while (!feof(fin)) + { + int ret; + err = fread(in, sizeof(short), frame_size*channels, fin); + if (feof(fin)) + break; + len = opus_custom_encode(enc, in, frame_size, data, bytes_per_packet); + if (len <= 0) + fprintf (stderr, "opus_custom_encode() failed: %s\n", opus_strerror(len)); + + /* This is for simulating bit errors */ +#if 0 + int errors = 0; + int eid = 0; + /* This simulates random bit error */ + for (i=0;i 0) + { + rmsd = sqrt(rmsd/(1.0*frame_size*channels*count)); + fprintf (stderr, "Error: encoder doesn't match decoder\n"); + fprintf (stderr, "RMS mismatch is %f\n", rmsd); + return 1; + } else { + fprintf (stderr, "Encoder matches decoder!!\n"); + } +#endif + return 0; +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/os_support.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/os_support.h new file mode 100644 index 000000000..009bf861d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/os_support.h @@ -0,0 +1,91 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: os_support.h + This is the (tiny) OS abstraction layer. Aside from math.h, this is the + only place where system headers are allowed. + + 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. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +#ifndef OS_SUPPORT_H +#define OS_SUPPORT_H + +#ifdef CUSTOM_SUPPORT +# include "custom_support.h" +#endif + +#include "opus_types.h" +#include "opus_defines.h" + +#include +#include + +/** Opus wrapper for malloc(). To do your own dynamic allocation, all you need to do is replace this function and opus_free */ +#ifndef OVERRIDE_OPUS_ALLOC +static OPUS_INLINE void *opus_alloc (size_t size) +{ + return malloc(size); +} +#endif + +/** Same as celt_alloc(), except that the area is only needed inside a CELT call (might cause problem with wideband though) */ +#ifndef OVERRIDE_OPUS_ALLOC_SCRATCH +static OPUS_INLINE void *opus_alloc_scratch (size_t size) +{ + /* Scratch space doesn't need to be cleared */ + return opus_alloc(size); +} +#endif + +/** Opus wrapper for free(). To do your own dynamic allocation, all you need to do is replace this function and opus_alloc */ +#ifndef OVERRIDE_OPUS_FREE +static OPUS_INLINE void opus_free (void *ptr) +{ + free(ptr); +} +#endif + +/** Copy n elements from src to dst. The 0* term provides compile-time type checking */ +#ifndef OVERRIDE_OPUS_COPY +#define OPUS_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Copy n elements from src to dst, allowing overlapping regions. The 0* term + provides compile-time type checking */ +#ifndef OVERRIDE_OPUS_MOVE +#define OPUS_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Set n elements of dst to zero */ +#ifndef OVERRIDE_OPUS_CLEAR +#define OPUS_CLEAR(dst, n) (memset((dst), 0, (n)*sizeof(*(dst)))) +#endif + +/*#ifdef __GNUC__ +#pragma GCC poison printf sprintf +#pragma GCC poison malloc free realloc calloc +#endif*/ + +#endif /* OS_SUPPORT_H */ + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/pitch.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/pitch.c new file mode 100644 index 000000000..872582a48 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/pitch.c @@ -0,0 +1,537 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file pitch.c + @brief Pitch analysis + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pitch.h" +#include "os_support.h" +#include "modes.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "celt_lpc.h" + +static void find_best_pitch(opus_val32 *xcorr, opus_val16 *y, int len, + int max_pitch, int *best_pitch +#ifdef FIXED_POINT + , int yshift, opus_val32 maxcorr +#endif + ) +{ + int i, j; + opus_val32 Syy=1; + opus_val16 best_num[2]; + opus_val32 best_den[2]; +#ifdef FIXED_POINT + int xshift; + + xshift = celt_ilog2(maxcorr)-14; +#endif + + best_num[0] = -1; + best_num[1] = -1; + best_den[0] = 0; + best_den[1] = 0; + best_pitch[0] = 0; + best_pitch[1] = 1; + for (j=0;j0) + { + opus_val16 num; + opus_val32 xcorr16; + xcorr16 = EXTRACT16(VSHR32(xcorr[i], xshift)); +#ifndef FIXED_POINT + /* Considering the range of xcorr16, this should avoid both underflows + and overflows (inf) when squaring xcorr16 */ + xcorr16 *= 1e-12f; +#endif + num = MULT16_16_Q15(xcorr16,xcorr16); + if (MULT16_32_Q15(num,best_den[1]) > MULT16_32_Q15(best_num[1],Syy)) + { + if (MULT16_32_Q15(num,best_den[0]) > MULT16_32_Q15(best_num[0],Syy)) + { + best_num[1] = best_num[0]; + best_den[1] = best_den[0]; + best_pitch[1] = best_pitch[0]; + best_num[0] = num; + best_den[0] = Syy; + best_pitch[0] = i; + } else { + best_num[1] = num; + best_den[1] = Syy; + best_pitch[1] = i; + } + } + } + Syy += SHR32(MULT16_16(y[i+len],y[i+len]),yshift) - SHR32(MULT16_16(y[i],y[i]),yshift); + Syy = MAX32(1, Syy); + } +} + +static void celt_fir5(opus_val16 *x, + const opus_val16 *num, + int N) +{ + int i; + opus_val16 num0, num1, num2, num3, num4; + opus_val32 mem0, mem1, mem2, mem3, mem4; + num0=num[0]; + num1=num[1]; + num2=num[2]; + num3=num[3]; + num4=num[4]; + mem0=0; + mem1=0; + mem2=0; + mem3=0; + mem4=0; + for (i=0;i>1;i++) + x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), shift); + x_lp[0] = SHR32(HALF32(HALF32(x[0][1])+x[0][0]), shift); + if (C==2) + { + for (i=1;i>1;i++) + x_lp[i] += SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), shift); + x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), shift); + } + + _celt_autocorr(x_lp, ac, NULL, 0, + 4, len>>1, arch); + + /* Noise floor -40 dB */ +#ifdef FIXED_POINT + ac[0] += SHR32(ac[0],13); +#else + ac[0] *= 1.0001f; +#endif + /* Lag windowing */ + for (i=1;i<=4;i++) + { + /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ +#ifdef FIXED_POINT + ac[i] -= MULT16_32_Q15(2*i*i, ac[i]); +#else + ac[i] -= ac[i]*(.008f*i)*(.008f*i); +#endif + } + + _celt_lpc(lpc, ac, 4); + for (i=0;i<4;i++) + { + tmp = MULT16_16_Q15(QCONST16(.9f,15), tmp); + lpc[i] = MULT16_16_Q15(lpc[i], tmp); + } + /* Add a zero */ + lpc2[0] = lpc[0] + QCONST16(.8f,SIG_SHIFT); + lpc2[1] = lpc[1] + MULT16_16_Q15(c1,lpc[0]); + lpc2[2] = lpc[2] + MULT16_16_Q15(c1,lpc[1]); + lpc2[3] = lpc[3] + MULT16_16_Q15(c1,lpc[2]); + lpc2[4] = MULT16_16_Q15(c1,lpc[3]); + celt_fir5(x_lp, lpc2, len>>1); +} + +/* Pure C implementation. */ +#ifdef FIXED_POINT +opus_val32 +#else +void +#endif +celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch, int arch) +{ + +#if 0 /* This is a simple version of the pitch correlation that should work + well on DSPs like Blackfin and TI C5x/C6x */ + int i, j; +#ifdef FIXED_POINT + opus_val32 maxcorr=1; +#endif +#if !defined(OVERRIDE_PITCH_XCORR) + (void)arch; +#endif + for (i=0;i0); + celt_sig_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0); + for (i=0;i0); + celt_assert(max_pitch>0); + lag = len+max_pitch; + + ALLOC(x_lp4, len>>2, opus_val16); + ALLOC(y_lp4, lag>>2, opus_val16); + ALLOC(xcorr, max_pitch>>1, opus_val32); + + /* Downsample by 2 again */ + for (j=0;j>2;j++) + x_lp4[j] = x_lp[2*j]; + for (j=0;j>2;j++) + y_lp4[j] = y[2*j]; + +#ifdef FIXED_POINT + xmax = celt_maxabs16(x_lp4, len>>2); + ymax = celt_maxabs16(y_lp4, lag>>2); + shift = celt_ilog2(MAX32(1, MAX32(xmax, ymax)))-11; + if (shift>0) + { + for (j=0;j>2;j++) + x_lp4[j] = SHR16(x_lp4[j], shift); + for (j=0;j>2;j++) + y_lp4[j] = SHR16(y_lp4[j], shift); + /* Use double the shift for a MAC */ + shift *= 2; + } else { + shift = 0; + } +#endif + + /* Coarse search with 4x decimation */ + +#ifdef FIXED_POINT + maxcorr = +#endif + celt_pitch_xcorr(x_lp4, y_lp4, xcorr, len>>2, max_pitch>>2, arch); + + find_best_pitch(xcorr, y_lp4, len>>2, max_pitch>>2, best_pitch +#ifdef FIXED_POINT + , 0, maxcorr +#endif + ); + + /* Finer search with 2x decimation */ +#ifdef FIXED_POINT + maxcorr=1; +#endif + for (i=0;i>1;i++) + { + opus_val32 sum; + xcorr[i] = 0; + if (abs(i-2*best_pitch[0])>2 && abs(i-2*best_pitch[1])>2) + continue; +#ifdef FIXED_POINT + sum = 0; + for (j=0;j>1;j++) + sum += SHR32(MULT16_16(x_lp[j],y[i+j]), shift); +#else + sum = celt_inner_prod(x_lp, y+i, len>>1, arch); +#endif + xcorr[i] = MAX32(-1, sum); +#ifdef FIXED_POINT + maxcorr = MAX32(maxcorr, sum); +#endif + } + find_best_pitch(xcorr, y, len>>1, max_pitch>>1, best_pitch +#ifdef FIXED_POINT + , shift+1, maxcorr +#endif + ); + + /* Refine by pseudo-interpolation */ + if (best_pitch[0]>0 && best_pitch[0]<(max_pitch>>1)-1) + { + opus_val32 a, b, c; + a = xcorr[best_pitch[0]-1]; + b = xcorr[best_pitch[0]]; + c = xcorr[best_pitch[0]+1]; + if ((c-a) > MULT16_32_Q15(QCONST16(.7f,15),b-a)) + offset = 1; + else if ((a-c) > MULT16_32_Q15(QCONST16(.7f,15),b-c)) + offset = -1; + else + offset = 0; + } else { + offset = 0; + } + *pitch = 2*best_pitch[0]-offset; + + RESTORE_STACK; +} + +#ifdef FIXED_POINT +static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy) +{ + opus_val32 x2y2; + int sx, sy, shift; + opus_val32 g; + opus_val16 den; + if (xy == 0 || xx == 0 || yy == 0) + return 0; + sx = celt_ilog2(xx)-14; + sy = celt_ilog2(yy)-14; + shift = sx + sy; + x2y2 = SHR32(MULT16_16(VSHR32(xx, sx), VSHR32(yy, sy)), 14); + if (shift & 1) { + if (x2y2 < 32768) + { + x2y2 <<= 1; + shift--; + } else { + x2y2 >>= 1; + shift++; + } + } + den = celt_rsqrt_norm(x2y2); + g = MULT16_32_Q15(den, xy); + g = VSHR32(g, (shift>>1)-1); + return EXTRACT16(MIN32(g, Q15ONE)); +} +#else +static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy) +{ + return xy/celt_sqrt(1+xx*yy); +} +#endif + +static const int second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2}; +opus_val16 remove_doubling(opus_val16 *x, int maxperiod, int minperiod, + int N, int *T0_, int prev_period, opus_val16 prev_gain, int arch) +{ + int k, i, T, T0; + opus_val16 g, g0; + opus_val16 pg; + opus_val32 xy,xx,yy,xy2; + opus_val32 xcorr[3]; + opus_val32 best_xy, best_yy; + int offset; + int minperiod0; + VARDECL(opus_val32, yy_lookup); + SAVE_STACK; + + minperiod0 = minperiod; + maxperiod /= 2; + minperiod /= 2; + *T0_ /= 2; + prev_period /= 2; + N /= 2; + x += maxperiod; + if (*T0_>=maxperiod) + *T0_=maxperiod-1; + + T = T0 = *T0_; + ALLOC(yy_lookup, maxperiod+1, opus_val32); + dual_inner_prod(x, x, x-T0, N, &xx, &xy, arch); + yy_lookup[0] = xx; + yy=xx; + for (i=1;i<=maxperiod;i++) + { + yy = yy+MULT16_16(x[-i],x[-i])-MULT16_16(x[N-i],x[N-i]); + yy_lookup[i] = MAX32(0, yy); + } + yy = yy_lookup[T0]; + best_xy = xy; + best_yy = yy; + g = g0 = compute_pitch_gain(xy, xx, yy); + /* Look for any pitch at T/k */ + for (k=2;k<=15;k++) + { + int T1, T1b; + opus_val16 g1; + opus_val16 cont=0; + opus_val16 thresh; + T1 = celt_udiv(2*T0+k, 2*k); + if (T1 < minperiod) + break; + /* Look for another strong correlation at T1b */ + if (k==2) + { + if (T1+T0>maxperiod) + T1b = T0; + else + T1b = T0+T1; + } else + { + T1b = celt_udiv(2*second_check[k]*T0+k, 2*k); + } + dual_inner_prod(x, &x[-T1], &x[-T1b], N, &xy, &xy2, arch); + xy = HALF32(xy + xy2); + yy = HALF32(yy_lookup[T1] + yy_lookup[T1b]); + g1 = compute_pitch_gain(xy, xx, yy); + if (abs(T1-prev_period)<=1) + cont = prev_gain; + else if (abs(T1-prev_period)<=2 && 5*k*k < T0) + cont = HALF16(prev_gain); + else + cont = 0; + thresh = MAX16(QCONST16(.3f,15), MULT16_16_Q15(QCONST16(.7f,15),g0)-cont); + /* Bias against very high pitch (very short period) to avoid false-positives + due to short-term correlation */ + if (T1<3*minperiod) + thresh = MAX16(QCONST16(.4f,15), MULT16_16_Q15(QCONST16(.85f,15),g0)-cont); + else if (T1<2*minperiod) + thresh = MAX16(QCONST16(.5f,15), MULT16_16_Q15(QCONST16(.9f,15),g0)-cont); + if (g1 > thresh) + { + best_xy = xy; + best_yy = yy; + T = T1; + g = g1; + } + } + best_xy = MAX32(0, best_xy); + if (best_yy <= best_xy) + pg = Q15ONE; + else + pg = SHR32(frac_div32(best_xy,best_yy+1),16); + + for (k=0;k<3;k++) + xcorr[k] = celt_inner_prod(x, x-(T+k-1), N, arch); + if ((xcorr[2]-xcorr[0]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[0])) + offset = 1; + else if ((xcorr[0]-xcorr[2]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[2])) + offset = -1; + else + offset = 0; + if (pg > g) + pg = g; + *T0_ = 2*T+offset; + + if (*T0_=3); + y_3=0; /* gcc doesn't realize that y_3 can't be used uninitialized */ + y_0=*y++; + y_1=*y++; + y_2=*y++; + for (j=0;j +#include "os_support.h" +#include "arch.h" +#include "mathops.h" +#include "stack_alloc.h" +#include "rate.h" + +#ifdef FIXED_POINT +/* Mean energy in each band quantized in Q4 */ +const signed char eMeans[25] = { + 103,100, 92, 85, 81, + 77, 72, 70, 78, 75, + 73, 71, 78, 74, 69, + 72, 70, 74, 76, 71, + 60, 60, 60, 60, 60 +}; +#else +/* Mean energy in each band quantized in Q4 and converted back to float */ +const opus_val16 eMeans[25] = { + 6.437500f, 6.250000f, 5.750000f, 5.312500f, 5.062500f, + 4.812500f, 4.500000f, 4.375000f, 4.875000f, 4.687500f, + 4.562500f, 4.437500f, 4.875000f, 4.625000f, 4.312500f, + 4.500000f, 4.375000f, 4.625000f, 4.750000f, 4.437500f, + 3.750000f, 3.750000f, 3.750000f, 3.750000f, 3.750000f +}; +#endif +/* prediction coefficients: 0.9, 0.8, 0.65, 0.5 */ +#ifdef FIXED_POINT +static const opus_val16 pred_coef[4] = {29440, 26112, 21248, 16384}; +static const opus_val16 beta_coef[4] = {30147, 22282, 12124, 6554}; +static const opus_val16 beta_intra = 4915; +#else +static const opus_val16 pred_coef[4] = {29440/32768., 26112/32768., 21248/32768., 16384/32768.}; +static const opus_val16 beta_coef[4] = {30147/32768., 22282/32768., 12124/32768., 6554/32768.}; +static const opus_val16 beta_intra = 4915/32768.; +#endif + +/*Parameters of the Laplace-like probability models used for the coarse energy. + There is one pair of parameters for each frame size, prediction type + (inter/intra), and band number. + The first number of each pair is the probability of 0, and the second is the + decay rate, both in Q8 precision.*/ +static const unsigned char e_prob_model[4][2][42] = { + /*120 sample frames.*/ + { + /*Inter*/ + { + 72, 127, 65, 129, 66, 128, 65, 128, 64, 128, 62, 128, 64, 128, + 64, 128, 92, 78, 92, 79, 92, 78, 90, 79, 116, 41, 115, 40, + 114, 40, 132, 26, 132, 26, 145, 17, 161, 12, 176, 10, 177, 11 + }, + /*Intra*/ + { + 24, 179, 48, 138, 54, 135, 54, 132, 53, 134, 56, 133, 55, 132, + 55, 132, 61, 114, 70, 96, 74, 88, 75, 88, 87, 74, 89, 66, + 91, 67, 100, 59, 108, 50, 120, 40, 122, 37, 97, 43, 78, 50 + } + }, + /*240 sample frames.*/ + { + /*Inter*/ + { + 83, 78, 84, 81, 88, 75, 86, 74, 87, 71, 90, 73, 93, 74, + 93, 74, 109, 40, 114, 36, 117, 34, 117, 34, 143, 17, 145, 18, + 146, 19, 162, 12, 165, 10, 178, 7, 189, 6, 190, 8, 177, 9 + }, + /*Intra*/ + { + 23, 178, 54, 115, 63, 102, 66, 98, 69, 99, 74, 89, 71, 91, + 73, 91, 78, 89, 86, 80, 92, 66, 93, 64, 102, 59, 103, 60, + 104, 60, 117, 52, 123, 44, 138, 35, 133, 31, 97, 38, 77, 45 + } + }, + /*480 sample frames.*/ + { + /*Inter*/ + { + 61, 90, 93, 60, 105, 42, 107, 41, 110, 45, 116, 38, 113, 38, + 112, 38, 124, 26, 132, 27, 136, 19, 140, 20, 155, 14, 159, 16, + 158, 18, 170, 13, 177, 10, 187, 8, 192, 6, 175, 9, 159, 10 + }, + /*Intra*/ + { + 21, 178, 59, 110, 71, 86, 75, 85, 84, 83, 91, 66, 88, 73, + 87, 72, 92, 75, 98, 72, 105, 58, 107, 54, 115, 52, 114, 55, + 112, 56, 129, 51, 132, 40, 150, 33, 140, 29, 98, 35, 77, 42 + } + }, + /*960 sample frames.*/ + { + /*Inter*/ + { + 42, 121, 96, 66, 108, 43, 111, 40, 117, 44, 123, 32, 120, 36, + 119, 33, 127, 33, 134, 34, 139, 21, 147, 23, 152, 20, 158, 25, + 154, 26, 166, 21, 173, 16, 184, 13, 184, 10, 150, 13, 139, 15 + }, + /*Intra*/ + { + 22, 178, 63, 114, 74, 82, 84, 83, 92, 82, 103, 62, 96, 72, + 96, 67, 101, 73, 107, 72, 113, 55, 118, 52, 125, 52, 118, 52, + 117, 55, 135, 49, 137, 39, 157, 32, 145, 29, 97, 33, 77, 40 + } + } +}; + +static const unsigned char small_energy_icdf[3]={2,1,0}; + +static opus_val32 loss_distortion(const opus_val16 *eBands, opus_val16 *oldEBands, int start, int end, int len, int C) +{ + int c, i; + opus_val32 dist = 0; + c=0; do { + for (i=start;inbEBands]; + oldE = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]); +#ifdef FIXED_POINT + f = SHL32(EXTEND32(x),7) - PSHR32(MULT16_16(coef,oldE), 8) - prev[c]; + /* Rounding to nearest integer here is really important! */ + qi = (f+QCONST32(.5f,DB_SHIFT+7))>>(DB_SHIFT+7); + decay_bound = EXTRACT16(MAX32(-QCONST16(28.f,DB_SHIFT), + SUB32((opus_val32)oldEBands[i+c*m->nbEBands],max_decay))); +#else + f = x-coef*oldE-prev[c]; + /* Rounding to nearest integer here is really important! */ + qi = (int)floor(.5f+f); + decay_bound = MAX16(-QCONST16(28.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]) - max_decay; +#endif + /* Prevent the energy from going down too quickly (e.g. for bands + that have just one bin) */ + if (qi < 0 && x < decay_bound) + { + qi += (int)SHR16(SUB16(decay_bound,x), DB_SHIFT); + if (qi > 0) + qi = 0; + } + qi0 = qi; + /* If we don't have enough bits to encode all the energy, just assume + something safe. */ + tell = ec_tell(enc); + bits_left = budget-tell-3*C*(end-i); + if (i!=start && bits_left < 30) + { + if (bits_left < 24) + qi = IMIN(1, qi); + if (bits_left < 16) + qi = IMAX(-1, qi); + } + if (lfe && i>=2) + qi = IMIN(qi, 0); + if (budget-tell >= 15) + { + int pi; + pi = 2*IMIN(i,20); + ec_laplace_encode(enc, &qi, + prob_model[pi]<<7, prob_model[pi+1]<<6); + } + else if(budget-tell >= 2) + { + qi = IMAX(-1, IMIN(qi, 1)); + ec_enc_icdf(enc, 2*qi^-(qi<0), small_energy_icdf, 2); + } + else if(budget-tell >= 1) + { + qi = IMIN(0, qi); + ec_enc_bit_logp(enc, -qi, 1); + } + else + qi = -1; + error[i+c*m->nbEBands] = PSHR32(f,7) - SHL16(qi,DB_SHIFT); + badness += abs(qi0-qi); + q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT); + + tmp = PSHR32(MULT16_16(coef,oldE),8) + prev[c] + SHL32(q,7); +#ifdef FIXED_POINT + tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp); +#endif + oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7); + prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8)); + } while (++c < C); + } + return lfe ? 0 : badness; +} + +void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd, + const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget, + opus_val16 *error, ec_enc *enc, int C, int LM, int nbAvailableBytes, + int force_intra, opus_val32 *delayedIntra, int two_pass, int loss_rate, int lfe) +{ + int intra; + opus_val16 max_decay; + VARDECL(opus_val16, oldEBands_intra); + VARDECL(opus_val16, error_intra); + ec_enc enc_start_state; + opus_uint32 tell; + int badness1=0; + opus_int32 intra_bias; + opus_val32 new_distortion; + SAVE_STACK; + + intra = force_intra || (!two_pass && *delayedIntra>2*C*(end-start) && nbAvailableBytes > (end-start)*C); + intra_bias = (opus_int32)((budget**delayedIntra*loss_rate)/(C*512)); + new_distortion = loss_distortion(eBands, oldEBands, start, effEnd, m->nbEBands, C); + + tell = ec_tell(enc); + if (tell+3 > budget) + two_pass = intra = 0; + + max_decay = QCONST16(16.f,DB_SHIFT); + if (end-start>10) + { +#ifdef FIXED_POINT + max_decay = MIN32(max_decay, SHL32(EXTEND32(nbAvailableBytes),DB_SHIFT-3)); +#else + max_decay = MIN32(max_decay, .125f*nbAvailableBytes); +#endif + } + if (lfe) + max_decay = QCONST16(3.f,DB_SHIFT); + enc_start_state = *enc; + + ALLOC(oldEBands_intra, C*m->nbEBands, opus_val16); + ALLOC(error_intra, C*m->nbEBands, opus_val16); + OPUS_COPY(oldEBands_intra, oldEBands, C*m->nbEBands); + + if (two_pass || intra) + { + badness1 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, budget, + tell, e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay, lfe); + } + + if (!intra) + { + unsigned char *intra_buf; + ec_enc enc_intra_state; + opus_int32 tell_intra; + opus_uint32 nstart_bytes; + opus_uint32 nintra_bytes; + opus_uint32 save_bytes; + int badness2; + VARDECL(unsigned char, intra_bits); + + tell_intra = ec_tell_frac(enc); + + enc_intra_state = *enc; + + nstart_bytes = ec_range_bytes(&enc_start_state); + nintra_bytes = ec_range_bytes(&enc_intra_state); + intra_buf = ec_get_buffer(&enc_intra_state) + nstart_bytes; + save_bytes = nintra_bytes-nstart_bytes; + if (save_bytes == 0) + save_bytes = ALLOC_NONE; + ALLOC(intra_bits, save_bytes, unsigned char); + /* Copy bits from intra bit-stream */ + OPUS_COPY(intra_bits, intra_buf, nintra_bytes - nstart_bytes); + + *enc = enc_start_state; + + badness2 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands, budget, + tell, e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay, lfe); + + if (two_pass && (badness1 < badness2 || (badness1 == badness2 && ((opus_int32)ec_tell_frac(enc))+intra_bias > tell_intra))) + { + *enc = enc_intra_state; + /* Copy intra bits to bit-stream */ + OPUS_COPY(intra_buf, intra_bits, nintra_bytes - nstart_bytes); + OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands); + OPUS_COPY(error, error_intra, C*m->nbEBands); + intra = 1; + } + } else { + OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands); + OPUS_COPY(error, error_intra, C*m->nbEBands); + } + + if (intra) + *delayedIntra = new_distortion; + else + *delayedIntra = ADD32(MULT16_32_Q15(MULT16_16_Q15(pred_coef[LM], pred_coef[LM]),*delayedIntra), + new_distortion); + + RESTORE_STACK; +} + +void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C) +{ + int i, c; + + /* Encode finer resolution */ + for (i=start;inbEBands]+QCONST16(.5f,DB_SHIFT))>>(DB_SHIFT-fine_quant[i]); +#else + q2 = (int)floor((error[i+c*m->nbEBands]+.5f)*frac); +#endif + if (q2 > frac-1) + q2 = frac-1; + if (q2<0) + q2 = 0; + ec_enc_bits(enc, q2, fine_quant[i]); +#ifdef FIXED_POINT + offset = SUB16(SHR32(SHL32(EXTEND32(q2),DB_SHIFT)+QCONST16(.5f,DB_SHIFT),fine_quant[i]),QCONST16(.5f,DB_SHIFT)); +#else + offset = (q2+.5f)*(1<<(14-fine_quant[i]))*(1.f/16384) - .5f; +#endif + oldEBands[i+c*m->nbEBands] += offset; + error[i+c*m->nbEBands] -= offset; + /*printf ("%f ", error[i] - offset);*/ + } while (++c < C); + } +} + +void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C) +{ + int i, prio, c; + + /* Use up the remaining bits */ + for (prio=0;prio<2;prio++) + { + for (i=start;i=C ;i++) + { + if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio) + continue; + c=0; + do { + int q2; + opus_val16 offset; + q2 = error[i+c*m->nbEBands]<0 ? 0 : 1; + ec_enc_bits(enc, q2, 1); +#ifdef FIXED_POINT + offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1); +#else + offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384); +#endif + oldEBands[i+c*m->nbEBands] += offset; + error[i+c*m->nbEBands] -= offset; + bits_left--; + } while (++c < C); + } + } +} + +void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM) +{ + const unsigned char *prob_model = e_prob_model[LM][intra]; + int i, c; + opus_val32 prev[2] = {0, 0}; + opus_val16 coef; + opus_val16 beta; + opus_int32 budget; + opus_int32 tell; + + if (intra) + { + coef = 0; + beta = beta_intra; + } else { + beta = beta_coef[LM]; + coef = pred_coef[LM]; + } + + budget = dec->storage*8; + + /* Decode at a fixed coarse resolution */ + for (i=start;i=15) + { + int pi; + pi = 2*IMIN(i,20); + qi = ec_laplace_decode(dec, + prob_model[pi]<<7, prob_model[pi+1]<<6); + } + else if(budget-tell>=2) + { + qi = ec_dec_icdf(dec, small_energy_icdf, 2); + qi = (qi>>1)^-(qi&1); + } + else if(budget-tell>=1) + { + qi = -ec_dec_bit_logp(dec, 1); + } + else + qi = -1; + q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT); + + oldEBands[i+c*m->nbEBands] = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]); + tmp = PSHR32(MULT16_16(coef,oldEBands[i+c*m->nbEBands]),8) + prev[c] + SHL32(q,7); +#ifdef FIXED_POINT + tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp); +#endif + oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7); + prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8)); + } while (++c < C); + } +} + +void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C) +{ + int i, c; + /* Decode finer resolution */ + for (i=start;inbEBands] += offset; + } while (++c < C); + } +} + +void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C) +{ + int i, prio, c; + + /* Use up the remaining bits */ + for (prio=0;prio<2;prio++) + { + for (i=start;i=C ;i++) + { + if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio) + continue; + c=0; + do { + int q2; + opus_val16 offset; + q2 = ec_dec_bits(dec, 1); +#ifdef FIXED_POINT + offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1); +#else + offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384); +#endif + oldEBands[i+c*m->nbEBands] += offset; + bits_left--; + } while (++c < C); + } + } +} + +void amp2Log2(const CELTMode *m, int effEnd, int end, + celt_ener *bandE, opus_val16 *bandLogE, int C) +{ + int c, i; + c=0; + do { + for (i=0;inbEBands] = + celt_log2(bandE[i+c*m->nbEBands]) + - SHL16((opus_val16)eMeans[i],6); +#ifdef FIXED_POINT + /* Compensate for bandE[] being Q12 but celt_log2() taking a Q14 input. */ + bandLogE[i+c*m->nbEBands] += QCONST16(2.f, DB_SHIFT); +#endif + } + for (i=effEnd;inbEBands+i] = -QCONST16(14.f,DB_SHIFT); + } while (++c < C); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/quant_bands.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/quant_bands.h new file mode 100644 index 000000000..0490bca4b --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/quant_bands.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef QUANT_BANDS +#define QUANT_BANDS + +#include "arch.h" +#include "modes.h" +#include "entenc.h" +#include "entdec.h" +#include "mathops.h" + +#ifdef FIXED_POINT +extern const signed char eMeans[25]; +#else +extern const opus_val16 eMeans[25]; +#endif + +void amp2Log2(const CELTMode *m, int effEnd, int end, + celt_ener *bandE, opus_val16 *bandLogE, int C); + +void log2Amp(const CELTMode *m, int start, int end, + celt_ener *eBands, const opus_val16 *oldEBands, int C); + +void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd, + const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget, + opus_val16 *error, ec_enc *enc, int C, int LM, + int nbAvailableBytes, int force_intra, opus_val32 *delayedIntra, + int two_pass, int loss_rate, int lfe); + +void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C); + +void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C); + +void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM); + +void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C); + +void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C); + +#endif /* QUANT_BANDS */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/rate.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/rate.c new file mode 100644 index 000000000..465e1ba26 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/rate.c @@ -0,0 +1,644 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "modes.h" +#include "cwrs.h" +#include "arch.h" +#include "os_support.h" + +#include "entcode.h" +#include "rate.h" + +static const unsigned char LOG2_FRAC_TABLE[24]={ + 0, + 8,13, + 16,19,21,23, + 24,26,27,28,29,30,31,32, + 32,33,34,34,35,36,36,37,37 +}; + +#ifdef CUSTOM_MODES + +/*Determines if V(N,K) fits in a 32-bit unsigned integer. + N and K are themselves limited to 15 bits.*/ +static int fits_in32(int _n, int _k) +{ + static const opus_int16 maxN[15] = { + 32767, 32767, 32767, 1476, 283, 109, 60, 40, + 29, 24, 20, 18, 16, 14, 13}; + static const opus_int16 maxK[15] = { + 32767, 32767, 32767, 32767, 1172, 238, 95, 53, + 36, 27, 22, 18, 16, 15, 13}; + if (_n>=14) + { + if (_k>=14) + return 0; + else + return _n <= maxN[_k]; + } else { + return _k <= maxK[_n]; + } +} + +void compute_pulse_cache(CELTMode *m, int LM) +{ + int C; + int i; + int j; + int curr=0; + int nbEntries=0; + int entryN[100], entryK[100], entryI[100]; + const opus_int16 *eBands = m->eBands; + PulseCache *cache = &m->cache; + opus_int16 *cindex; + unsigned char *bits; + unsigned char *cap; + + cindex = (opus_int16 *)opus_alloc(sizeof(cache->index[0])*m->nbEBands*(LM+2)); + cache->index = cindex; + + /* Scan for all unique band sizes */ + for (i=0;i<=LM+1;i++) + { + for (j=0;jnbEBands;j++) + { + int k; + int N = (eBands[j+1]-eBands[j])<>1; + cindex[i*m->nbEBands+j] = -1; + /* Find other bands that have the same size */ + for (k=0;k<=i;k++) + { + int n; + for (n=0;nnbEBands && (k!=i || n>1) + { + cindex[i*m->nbEBands+j] = cindex[k*m->nbEBands+n]; + break; + } + } + } + if (cache->index[i*m->nbEBands+j] == -1 && N!=0) + { + int K; + entryN[nbEntries] = N; + K = 0; + while (fits_in32(N,get_pulses(K+1)) && KnbEBands+j] = curr; + entryI[nbEntries] = curr; + + curr += K+1; + nbEntries++; + } + } + } + bits = (unsigned char *)opus_alloc(sizeof(unsigned char)*curr); + cache->bits = bits; + cache->size = curr; + /* Compute the cache for all unique sizes */ + for (i=0;icaps = cap = (unsigned char *)opus_alloc(sizeof(cache->caps[0])*(LM+1)*2*m->nbEBands); + for (i=0;i<=LM;i++) + { + for (C=1;C<=2;C++) + { + for (j=0;jnbEBands;j++) + { + int N0; + int max_bits; + N0 = m->eBands[j+1]-m->eBands[j]; + /* N=1 bands only have a sign bit and fine bits. */ + if (N0<1 are even, including custom modes.*/ + if (N0 > 2) + { + N0>>=1; + LM0--; + } + /* N0=1 bands can't be split down to N<2. */ + else if (N0 <= 1) + { + LM0=IMIN(i,1); + N0<<=LM0; + } + /* Compute the cost for the lowest-level PVQ of a fully split + band. */ + pcache = bits + cindex[(LM0+1)*m->nbEBands+j]; + max_bits = pcache[pcache[0]]+1; + /* Add in the cost of coding regular splits. */ + N = N0; + for(k=0;klogN[j]+((LM0+k)<>1)-QTHETA_OFFSET; + /* The number of qtheta bits we'll allocate if the remainder + is to be max_bits. + The average measured cost for theta is 0.89701 times qb, + approximated here as 459/512. */ + num=459*(opus_int32)((2*N-1)*offset+max_bits); + den=((opus_int32)(2*N-1)<<9)-459; + qb = IMIN((num+(den>>1))/den, 57); + celt_assert(qb >= 0); + max_bits += qb; + N <<= 1; + } + /* Add in the cost of a stereo split, if necessary. */ + if (C==2) + { + max_bits <<= 1; + offset = ((m->logN[j]+(i<>1)-(N==2?QTHETA_OFFSET_TWOPHASE:QTHETA_OFFSET); + ndof = 2*N-1-(N==2); + /* The average measured cost for theta with the step PDF is + 0.95164 times qb, approximated here as 487/512. */ + num = (N==2?512:487)*(opus_int32)(max_bits+ndof*offset); + den = ((opus_int32)ndof<<9)-(N==2?512:487); + qb = IMIN((num+(den>>1))/den, (N==2?64:61)); + celt_assert(qb >= 0); + max_bits += qb; + } + /* Add the fine bits we'll use. */ + /* Compensate for the extra DoF in stereo */ + ndof = C*N + ((C==2 && N>2) ? 1 : 0); + /* Offset the number of fine bits by log2(N)/2 + FINE_OFFSET + compared to their "fair share" of total/N */ + offset = ((m->logN[j] + (i<>1)-FINE_OFFSET; + /* N=2 is the only point that doesn't match the curve */ + if (N==2) + offset += 1<>2; + /* The number of fine bits we'll allocate if the remainder is + to be max_bits. */ + num = max_bits+ndof*offset; + den = (ndof-1)<>1))/den, MAX_FINE_BITS); + celt_assert(qb >= 0); + max_bits += C*qb<eBands[j+1]-m->eBands[j])<= 0); + celt_assert(max_bits < 256); + *cap++ = (unsigned char)max_bits; + } + } + } +} + +#endif /* CUSTOM_MODES */ + +#define ALLOC_STEPS 6 + +static OPUS_INLINE int interp_bits2pulses(const CELTMode *m, int start, int end, int skip_start, + const int *bits1, const int *bits2, const int *thresh, const int *cap, opus_int32 total, opus_int32 *_balance, + int skip_rsv, int *intensity, int intensity_rsv, int *dual_stereo, int dual_stereo_rsv, int *bits, + int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth) +{ + opus_int32 psum; + int lo, hi; + int i, j; + int logM; + int stereo; + int codedBands=-1; + int alloc_floor; + opus_int32 left, percoeff; + int done; + opus_int32 balance; + SAVE_STACK; + + alloc_floor = C<1; + + logM = LM<>1; + psum = 0; + done = 0; + for (j=end;j-->start;) + { + int tmp = bits1[j] + (mid*(opus_int32)bits2[j]>>ALLOC_STEPS); + if (tmp >= thresh[j] || done) + { + done = 1; + /* Don't allocate more than we can actually use */ + psum += IMIN(tmp, cap[j]); + } else { + if (tmp >= alloc_floor) + psum += alloc_floor; + } + } + if (psum > total) + hi = mid; + else + lo = mid; + } + psum = 0; + /*printf ("interp bisection gave %d\n", lo);*/ + done = 0; + for (j=end;j-->start;) + { + int tmp = bits1[j] + ((opus_int32)lo*bits2[j]>>ALLOC_STEPS); + if (tmp < thresh[j] && !done) + { + if (tmp >= alloc_floor) + tmp = alloc_floor; + else + tmp = 0; + } else + done = 1; + /* Don't allocate more than we can actually use */ + tmp = IMIN(tmp, cap[j]); + bits[j] = tmp; + psum += tmp; + } + + /* Decide which bands to skip, working backwards from the end. */ + for (codedBands=end;;codedBands--) + { + int band_width; + int band_bits; + int rem; + j = codedBands-1; + /* Never skip the first band, nor a band that has been boosted by + dynalloc. + In the first case, we'd be coding a bit to signal we're going to waste + all the other bits. + In the second case, we'd be coding a bit to redistribute all the bits + we just signaled should be cocentrated in this band. */ + if (j<=skip_start) + { + /* Give the bit we reserved to end skipping back. */ + total += skip_rsv; + break; + } + /*Figure out how many left-over bits we would be adding to this band. + This can include bits we've stolen back from higher, skipped bands.*/ + left = total-psum; + percoeff = celt_udiv(left, m->eBands[codedBands]-m->eBands[start]); + left -= (m->eBands[codedBands]-m->eBands[start])*percoeff; + rem = IMAX(left-(m->eBands[j]-m->eBands[start]),0); + band_width = m->eBands[codedBands]-m->eBands[j]; + band_bits = (int)(bits[j] + percoeff*band_width + rem); + /*Only code a skip decision if we're above the threshold for this band. + Otherwise it is force-skipped. + This ensures that we have enough bits to code the skip flag.*/ + if (band_bits >= IMAX(thresh[j], alloc_floor+(1< 17) + depth_threshold = j (depth_threshold*band_width<>4 && j<=signalBandwidth)) +#endif + { + ec_enc_bit_logp(ec, 1, 1); + break; + } + ec_enc_bit_logp(ec, 0, 1); + } else if (ec_dec_bit_logp(ec, 1)) { + break; + } + /*We used a bit to skip this band.*/ + psum += 1< 0) + intensity_rsv = LOG2_FRAC_TABLE[j-start]; + psum += intensity_rsv; + if (band_bits >= alloc_floor) + { + /*If we have enough for a fine energy bit per channel, use it.*/ + psum += alloc_floor; + bits[j] = alloc_floor; + } else { + /*Otherwise this band gets nothing at all.*/ + bits[j] = 0; + } + } + + celt_assert(codedBands > start); + /* Code the intensity and dual stereo parameters. */ + if (intensity_rsv > 0) + { + if (encode) + { + *intensity = IMIN(*intensity, codedBands); + ec_enc_uint(ec, *intensity-start, codedBands+1-start); + } + else + *intensity = start+ec_dec_uint(ec, codedBands+1-start); + } + else + *intensity = 0; + if (*intensity <= start) + { + total += dual_stereo_rsv; + dual_stereo_rsv = 0; + } + if (dual_stereo_rsv > 0) + { + if (encode) + ec_enc_bit_logp(ec, *dual_stereo, 1); + else + *dual_stereo = ec_dec_bit_logp(ec, 1); + } + else + *dual_stereo = 0; + + /* Allocate the remaining bits */ + left = total-psum; + percoeff = celt_udiv(left, m->eBands[codedBands]-m->eBands[start]); + left -= (m->eBands[codedBands]-m->eBands[start])*percoeff; + for (j=start;jeBands[j+1]-m->eBands[j])); + for (j=start;jeBands[j+1]-m->eBands[j]); + bits[j] += tmp; + left -= tmp; + } + /*for (j=0;j= 0); + N0 = m->eBands[j+1]-m->eBands[j]; + N=N0<1) + { + excess = MAX32(bit-cap[j],0); + bits[j] = bit-excess; + + /* Compensate for the extra DoF in stereo */ + den=(C*N+ ((C==2 && N>2 && !*dual_stereo && j<*intensity) ? 1 : 0)); + + NClogN = den*(m->logN[j] + logM); + + /* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET + compared to their "fair share" of total/N */ + offset = (NClogN>>1)-den*FINE_OFFSET; + + /* N=2 is the only point that doesn't match the curve */ + if (N==2) + offset += den<>2; + + /* Changing the offset for allocating the second and third + fine energy bit */ + if (bits[j] + offset < den*2<>2; + else if (bits[j] + offset < den*3<>3; + + /* Divide with rounding */ + ebits[j] = IMAX(0, (bits[j] + offset + (den<<(BITRES-1)))); + ebits[j] = celt_udiv(ebits[j], den)>>BITRES; + + /* Make sure not to bust */ + if (C*ebits[j] > (bits[j]>>BITRES)) + ebits[j] = bits[j] >> stereo >> BITRES; + + /* More than that is useless because that's about as far as PVQ can go */ + ebits[j] = IMIN(ebits[j], MAX_FINE_BITS); + + /* If we rounded down or capped this band, make it a candidate for the + final fine energy pass */ + fine_priority[j] = ebits[j]*(den<= bits[j]+offset; + + /* Remove the allocated fine bits; the rest are assigned to PVQ */ + bits[j] -= C*ebits[j]< 0) + { + int extra_fine; + int extra_bits; + extra_fine = IMIN(excess>>(stereo+BITRES),MAX_FINE_BITS-ebits[j]); + ebits[j] += extra_fine; + extra_bits = extra_fine*C<= excess-balance; + excess -= extra_bits; + } + balance = excess; + + celt_assert(bits[j] >= 0); + celt_assert(ebits[j] >= 0); + } + /* Save any remaining bits over the cap for the rebalancing in + quant_all_bands(). */ + *_balance = balance; + + /* The skipped bands use all their bits for fine energy. */ + for (;j> stereo >> BITRES; + celt_assert(C*ebits[j]<nbEBands; + skip_start = start; + /* Reserve a bit to signal the end of manually skipped bands. */ + skip_rsv = total >= 1<total) + intensity_rsv = 0; + else + { + total -= intensity_rsv; + dual_stereo_rsv = total>=1<eBands[j+1]-m->eBands[j])<>4); + /* Tilt of the allocation curve */ + trim_offset[j] = C*(m->eBands[j+1]-m->eBands[j])*(alloc_trim-5-LM)*(end-j-1) + *(1<<(LM+BITRES))>>6; + /* Giving less resolution to single-coefficient bands because they get + more benefit from having one coarse value per coefficient*/ + if ((m->eBands[j+1]-m->eBands[j])<nbAllocVectors - 1; + do + { + int done = 0; + int psum = 0; + int mid = (lo+hi) >> 1; + for (j=end;j-->start;) + { + int bitsj; + int N = m->eBands[j+1]-m->eBands[j]; + bitsj = C*N*m->allocVectors[mid*len+j]<>2; + if (bitsj > 0) + bitsj = IMAX(0, bitsj + trim_offset[j]); + bitsj += offsets[j]; + if (bitsj >= thresh[j] || done) + { + done = 1; + /* Don't allocate more than we can actually use */ + psum += IMIN(bitsj, cap[j]); + } else { + if (bitsj >= C< total) + hi = mid - 1; + else + lo = mid + 1; + /*printf ("lo = %d, hi = %d\n", lo, hi);*/ + } + while (lo <= hi); + hi = lo--; + /*printf ("interp between %d and %d\n", lo, hi);*/ + for (j=start;jeBands[j+1]-m->eBands[j]; + bits1j = C*N*m->allocVectors[lo*len+j]<>2; + bits2j = hi>=m->nbAllocVectors ? + cap[j] : C*N*m->allocVectors[hi*len+j]<>2; + if (bits1j > 0) + bits1j = IMAX(0, bits1j + trim_offset[j]); + if (bits2j > 0) + bits2j = IMAX(0, bits2j + trim_offset[j]); + if (lo > 0) + bits1j += offsets[j]; + bits2j += offsets[j]; + if (offsets[j]>0) + skip_start = j; + bits2j = IMAX(0,bits2j-bits1j); + bits1[j] = bits1j; + bits2[j] = bits2j; + } + codedBands = interp_bits2pulses(m, start, end, skip_start, bits1, bits2, thresh, cap, + total, balance, skip_rsv, intensity, intensity_rsv, dual_stereo, dual_stereo_rsv, + pulses, ebits, fine_priority, C, LM, ec, encode, prev, signalBandwidth); + RESTORE_STACK; + return codedBands; +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/rate.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/rate.h new file mode 100644 index 000000000..fad5e412d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/rate.h @@ -0,0 +1,101 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef RATE_H +#define RATE_H + +#define MAX_PSEUDO 40 +#define LOG_MAX_PSEUDO 6 + +#define CELT_MAX_PULSES 128 + +#define MAX_FINE_BITS 8 + +#define FINE_OFFSET 21 +#define QTHETA_OFFSET 4 +#define QTHETA_OFFSET_TWOPHASE 16 + +#include "cwrs.h" +#include "modes.h" + +void compute_pulse_cache(CELTMode *m, int LM); + +static OPUS_INLINE int get_pulses(int i) +{ + return i<8 ? i : (8 + (i&7)) << ((i>>3)-1); +} + +static OPUS_INLINE int bits2pulses(const CELTMode *m, int band, int LM, int bits) +{ + int i; + int lo, hi; + const unsigned char *cache; + + LM++; + cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band]; + + lo = 0; + hi = cache[0]; + bits--; + for (i=0;i>1; + /* OPT: Make sure this is implemented with a conditional move */ + if ((int)cache[mid] >= bits) + hi = mid; + else + lo = mid; + } + if (bits- (lo == 0 ? -1 : (int)cache[lo]) <= (int)cache[hi]-bits) + return lo; + else + return hi; +} + +static OPUS_INLINE int pulses2bits(const CELTMode *m, int band, int LM, int pulses) +{ + const unsigned char *cache; + + LM++; + cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band]; + return pulses == 0 ? 0 : cache[pulses]+1; +} + +/** Compute the pulse allocation, i.e. how many pulses will go in each + * band. + @param m mode + @param offsets Requested increase or decrease in the number of bits for + each band + @param total Number of bands + @param pulses Number of pulses per band (returned) + @return Total number of bits allocated +*/ +int clt_compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stereo, + opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth); + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/stack_alloc.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/stack_alloc.h new file mode 100644 index 000000000..ae40e2a16 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/stack_alloc.h @@ -0,0 +1,184 @@ +/* Copyright (C) 2002-2003 Jean-Marc Valin + Copyright (C) 2007-2009 Xiph.Org Foundation */ +/** + @file stack_alloc.h + @brief Temporary memory allocation on stack +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef STACK_ALLOC_H +#define STACK_ALLOC_H + +#include "opus_types.h" +#include "opus_defines.h" + +#if (!defined (VAR_ARRAYS) && !defined (USE_ALLOCA) && !defined (NONTHREADSAFE_PSEUDOSTACK)) +#error "Opus requires one of VAR_ARRAYS, USE_ALLOCA, or NONTHREADSAFE_PSEUDOSTACK be defined to select the temporary allocation mode." +#endif + +#ifdef USE_ALLOCA +# ifdef _WIN32 +# include +# else +# ifdef HAVE_ALLOCA_H +# include +# else +# include +# endif +# endif +#endif + +/** + * @def ALIGN(stack, size) + * + * Aligns the stack to a 'size' boundary + * + * @param stack Stack + * @param size New size boundary + */ + +/** + * @def PUSH(stack, size, type) + * + * Allocates 'size' elements of type 'type' on the stack + * + * @param stack Stack + * @param size Number of elements + * @param type Type of element + */ + +/** + * @def VARDECL(var) + * + * Declare variable on stack + * + * @param var Variable to declare + */ + +/** + * @def ALLOC(var, size, type) + * + * Allocate 'size' elements of 'type' on stack + * + * @param var Name of variable to allocate + * @param size Number of elements + * @param type Type of element + */ + +#if defined(VAR_ARRAYS) + +#define VARDECL(type, var) +#define ALLOC(var, size, type) type var[size] +#define SAVE_STACK +#define RESTORE_STACK +#define ALLOC_STACK +/* C99 does not allow VLAs of size zero */ +#define ALLOC_NONE 1 + +#elif defined(USE_ALLOCA) + +#define VARDECL(type, var) type *var + +# ifdef _WIN32 +# define ALLOC(var, size, type) var = ((type*)_alloca(sizeof(type)*(size))) +# else +# define ALLOC(var, size, type) var = ((type*)alloca(sizeof(type)*(size))) +# endif + +#define SAVE_STACK +#define RESTORE_STACK +#define ALLOC_STACK +#define ALLOC_NONE 0 + +#else + +#ifdef CELT_C +char *scratch_ptr=0; +char *global_stack=0; +#else +extern char *global_stack; +extern char *scratch_ptr; +#endif /* CELT_C */ + +#ifdef ENABLE_VALGRIND + +#include + +#ifdef CELT_C +char *global_stack_top=0; +#else +extern char *global_stack_top; +#endif /* CELT_C */ + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) +#define PUSH(stack, size, type) (VALGRIND_MAKE_MEM_NOACCESS(stack, global_stack_top-stack),ALIGN((stack),sizeof(type)/sizeof(char)),VALGRIND_MAKE_MEM_UNDEFINED(stack, ((size)*sizeof(type)/sizeof(char))),(stack)+=(2*(size)*sizeof(type)/sizeof(char)),(type*)((stack)-(2*(size)*sizeof(type)/sizeof(char)))) +#define RESTORE_STACK ((global_stack = _saved_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)) +#define ALLOC_STACK char *_saved_stack; ((global_stack = (global_stack==0) ? ((global_stack_top=opus_alloc_scratch(GLOBAL_STACK_SIZE*2)+(GLOBAL_STACK_SIZE*2))-(GLOBAL_STACK_SIZE*2)) : global_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)); _saved_stack = global_stack; + +#else + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) +#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)/sizeof(char)),(stack)+=(size)*(sizeof(type)/sizeof(char)),(type*)((stack)-(size)*(sizeof(type)/sizeof(char)))) +#if 0 /* Set this to 1 to instrument pseudostack usage */ +#define RESTORE_STACK (printf("%ld %s:%d\n", global_stack-scratch_ptr, __FILE__, __LINE__),global_stack = _saved_stack) +#else +#define RESTORE_STACK (global_stack = _saved_stack) +#endif +#define ALLOC_STACK char *_saved_stack; (global_stack = (global_stack==0) ? (scratch_ptr=opus_alloc_scratch(GLOBAL_STACK_SIZE)) : global_stack); _saved_stack = global_stack; + +#endif /* ENABLE_VALGRIND */ + +#include "os_support.h" +#define VARDECL(type, var) type *var +#define ALLOC(var, size, type) var = PUSH(global_stack, size, type) +#define SAVE_STACK char *_saved_stack = global_stack; +#define ALLOC_NONE 0 + +#endif /* VAR_ARRAYS */ + + +#ifdef ENABLE_VALGRIND + +#include +#define OPUS_CHECK_ARRAY(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr)) +#define OPUS_CHECK_VALUE(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value) +#define OPUS_CHECK_ARRAY_COND(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr)) +#define OPUS_CHECK_VALUE_COND(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value) +#define OPUS_PRINT_INT(value) do {fprintf(stderr, #value " = %d at %s:%d\n", value, __FILE__, __LINE__);}while(0) +#define OPUS_FPRINTF fprintf + +#else + +static OPUS_INLINE int _opus_false(void) {return 0;} +#define OPUS_CHECK_ARRAY(ptr, len) _opus_false() +#define OPUS_CHECK_VALUE(value) _opus_false() +#define OPUS_PRINT_INT(value) do{}while(0) +#define OPUS_FPRINTF (void) + +#endif + + +#endif /* STACK_ALLOC_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/static_modes_fixed.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/static_modes_fixed.h new file mode 100644 index 000000000..8717d626c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/static_modes_fixed.h @@ -0,0 +1,892 @@ +/* The contents of this file was automatically generated by dump_modes.c + with arguments: 48000 960 + It contains static definitions for some pre-defined modes. */ +#include "modes.h" +#include "rate.h" + +#ifdef HAVE_ARM_NE10 +#define OVERRIDE_FFT 1 +#include "static_modes_fixed_arm_ne10.h" +#endif + +#ifndef DEF_WINDOW120 +#define DEF_WINDOW120 +static const opus_val16 window120[120] = { +2, 20, 55, 108, 178, +266, 372, 494, 635, 792, +966, 1157, 1365, 1590, 1831, +2089, 2362, 2651, 2956, 3276, +3611, 3961, 4325, 4703, 5094, +5499, 5916, 6346, 6788, 7241, +7705, 8179, 8663, 9156, 9657, +10167, 10684, 11207, 11736, 12271, +12810, 13353, 13899, 14447, 14997, +15547, 16098, 16648, 17197, 17744, +18287, 18827, 19363, 19893, 20418, +20936, 21447, 21950, 22445, 22931, +23407, 23874, 24330, 24774, 25208, +25629, 26039, 26435, 26819, 27190, +27548, 27893, 28224, 28541, 28845, +29135, 29411, 29674, 29924, 30160, +30384, 30594, 30792, 30977, 31151, +31313, 31463, 31602, 31731, 31849, +31958, 32057, 32148, 32229, 32303, +32370, 32429, 32481, 32528, 32568, +32604, 32634, 32661, 32683, 32701, +32717, 32729, 32740, 32748, 32754, +32758, 32762, 32764, 32766, 32767, +32767, 32767, 32767, 32767, 32767, +}; +#endif + +#ifndef DEF_LOGN400 +#define DEF_LOGN400 +static const opus_int16 logN400[21] = { +0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, }; +#endif + +#ifndef DEF_PULSE_CACHE50 +#define DEF_PULSE_CACHE50 +static const opus_int16 cache_index50[105] = { +-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41, +82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41, +41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41, +41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305, +318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240, +305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240, +240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387, +}; +static const unsigned char cache_bits50[392] = { +40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28, +31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50, +51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65, +66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61, +64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92, +94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123, +124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94, +97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139, +142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35, +28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149, +153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225, +229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157, +166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63, +86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250, +25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180, +185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89, +110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41, +74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138, +163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214, +228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49, +90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47, +87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57, +106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187, +224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127, +182, 234, }; +static const unsigned char cache_caps50[168] = { +224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185, +178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240, +240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160, +160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172, +138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207, +204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185, +185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39, +207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201, +188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204, +204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175, +140, 66, 40, }; +#endif + +#ifndef FFT_TWIDDLES48000_960 +#define FFT_TWIDDLES48000_960 +static const kiss_twiddle_cpx fft_twiddles48000_960[480] = { +{32767, 0}, {32766, -429}, +{32757, -858}, {32743, -1287}, +{32724, -1715}, {32698, -2143}, +{32667, -2570}, {32631, -2998}, +{32588, -3425}, {32541, -3851}, +{32488, -4277}, {32429, -4701}, +{32364, -5125}, {32295, -5548}, +{32219, -5971}, {32138, -6393}, +{32051, -6813}, {31960, -7231}, +{31863, -7650}, {31760, -8067}, +{31652, -8481}, {31539, -8895}, +{31419, -9306}, {31294, -9716}, +{31165, -10126}, {31030, -10532}, +{30889, -10937}, {30743, -11340}, +{30592, -11741}, {30436, -12141}, +{30274, -12540}, {30107, -12935}, +{29936, -13328}, {29758, -13718}, +{29577, -14107}, {29390, -14493}, +{29197, -14875}, {29000, -15257}, +{28797, -15635}, {28590, -16010}, +{28379, -16384}, {28162, -16753}, +{27940, -17119}, {27714, -17484}, +{27482, -17845}, {27246, -18205}, +{27006, -18560}, {26760, -18911}, +{26510, -19260}, {26257, -19606}, +{25997, -19947}, {25734, -20286}, +{25466, -20621}, {25194, -20952}, +{24918, -21281}, {24637, -21605}, +{24353, -21926}, {24063, -22242}, +{23770, -22555}, {23473, -22865}, +{23171, -23171}, {22866, -23472}, +{22557, -23769}, {22244, -24063}, +{21927, -24352}, {21606, -24636}, +{21282, -24917}, {20954, -25194}, +{20622, -25465}, {20288, -25733}, +{19949, -25997}, {19607, -26255}, +{19261, -26509}, {18914, -26760}, +{18561, -27004}, {18205, -27246}, +{17846, -27481}, {17485, -27713}, +{17122, -27940}, {16755, -28162}, +{16385, -28378}, {16012, -28590}, +{15636, -28797}, {15258, -28999}, +{14878, -29197}, {14494, -29389}, +{14108, -29576}, {13720, -29757}, +{13329, -29934}, {12937, -30107}, +{12540, -30274}, {12142, -30435}, +{11744, -30592}, {11342, -30743}, +{10939, -30889}, {10534, -31030}, +{10127, -31164}, {9718, -31294}, +{9307, -31418}, {8895, -31537}, +{8482, -31652}, {8067, -31759}, +{7650, -31862}, {7233, -31960}, +{6815, -32051}, {6393, -32138}, +{5973, -32219}, {5549, -32294}, +{5127, -32364}, {4703, -32429}, +{4278, -32487}, {3852, -32541}, +{3426, -32588}, {2999, -32630}, +{2572, -32667}, {2144, -32698}, +{1716, -32724}, {1287, -32742}, +{860, -32757}, {430, -32766}, +{0, -32767}, {-429, -32766}, +{-858, -32757}, {-1287, -32743}, +{-1715, -32724}, {-2143, -32698}, +{-2570, -32667}, {-2998, -32631}, +{-3425, -32588}, {-3851, -32541}, +{-4277, -32488}, {-4701, -32429}, +{-5125, -32364}, {-5548, -32295}, +{-5971, -32219}, {-6393, -32138}, +{-6813, -32051}, {-7231, -31960}, +{-7650, -31863}, {-8067, -31760}, +{-8481, -31652}, {-8895, -31539}, +{-9306, -31419}, {-9716, -31294}, +{-10126, -31165}, {-10532, -31030}, +{-10937, -30889}, {-11340, -30743}, +{-11741, -30592}, {-12141, -30436}, +{-12540, -30274}, {-12935, -30107}, +{-13328, -29936}, {-13718, -29758}, +{-14107, -29577}, {-14493, -29390}, +{-14875, -29197}, {-15257, -29000}, +{-15635, -28797}, {-16010, -28590}, +{-16384, -28379}, {-16753, -28162}, +{-17119, -27940}, {-17484, -27714}, +{-17845, -27482}, {-18205, -27246}, +{-18560, -27006}, {-18911, -26760}, +{-19260, -26510}, {-19606, -26257}, +{-19947, -25997}, {-20286, -25734}, +{-20621, -25466}, {-20952, -25194}, +{-21281, -24918}, {-21605, -24637}, +{-21926, -24353}, {-22242, -24063}, +{-22555, -23770}, {-22865, -23473}, +{-23171, -23171}, {-23472, -22866}, +{-23769, -22557}, {-24063, -22244}, +{-24352, -21927}, {-24636, -21606}, +{-24917, -21282}, {-25194, -20954}, +{-25465, -20622}, {-25733, -20288}, +{-25997, -19949}, {-26255, -19607}, +{-26509, -19261}, {-26760, -18914}, +{-27004, -18561}, {-27246, -18205}, +{-27481, -17846}, {-27713, -17485}, +{-27940, -17122}, {-28162, -16755}, +{-28378, -16385}, {-28590, -16012}, +{-28797, -15636}, {-28999, -15258}, +{-29197, -14878}, {-29389, -14494}, +{-29576, -14108}, {-29757, -13720}, +{-29934, -13329}, {-30107, -12937}, +{-30274, -12540}, {-30435, -12142}, +{-30592, -11744}, {-30743, -11342}, +{-30889, -10939}, {-31030, -10534}, +{-31164, -10127}, {-31294, -9718}, +{-31418, -9307}, {-31537, -8895}, +{-31652, -8482}, {-31759, -8067}, +{-31862, -7650}, {-31960, -7233}, +{-32051, -6815}, {-32138, -6393}, +{-32219, -5973}, {-32294, -5549}, +{-32364, -5127}, {-32429, -4703}, +{-32487, -4278}, {-32541, -3852}, +{-32588, -3426}, {-32630, -2999}, +{-32667, -2572}, {-32698, -2144}, +{-32724, -1716}, {-32742, -1287}, +{-32757, -860}, {-32766, -430}, +{-32767, 0}, {-32766, 429}, +{-32757, 858}, {-32743, 1287}, +{-32724, 1715}, {-32698, 2143}, +{-32667, 2570}, {-32631, 2998}, +{-32588, 3425}, {-32541, 3851}, +{-32488, 4277}, {-32429, 4701}, +{-32364, 5125}, {-32295, 5548}, +{-32219, 5971}, {-32138, 6393}, +{-32051, 6813}, {-31960, 7231}, +{-31863, 7650}, {-31760, 8067}, +{-31652, 8481}, {-31539, 8895}, +{-31419, 9306}, {-31294, 9716}, +{-31165, 10126}, {-31030, 10532}, +{-30889, 10937}, {-30743, 11340}, +{-30592, 11741}, {-30436, 12141}, +{-30274, 12540}, {-30107, 12935}, +{-29936, 13328}, {-29758, 13718}, +{-29577, 14107}, {-29390, 14493}, +{-29197, 14875}, {-29000, 15257}, +{-28797, 15635}, {-28590, 16010}, +{-28379, 16384}, {-28162, 16753}, +{-27940, 17119}, {-27714, 17484}, +{-27482, 17845}, {-27246, 18205}, +{-27006, 18560}, {-26760, 18911}, +{-26510, 19260}, {-26257, 19606}, +{-25997, 19947}, {-25734, 20286}, +{-25466, 20621}, {-25194, 20952}, +{-24918, 21281}, {-24637, 21605}, +{-24353, 21926}, {-24063, 22242}, +{-23770, 22555}, {-23473, 22865}, +{-23171, 23171}, {-22866, 23472}, +{-22557, 23769}, {-22244, 24063}, +{-21927, 24352}, {-21606, 24636}, +{-21282, 24917}, {-20954, 25194}, +{-20622, 25465}, {-20288, 25733}, +{-19949, 25997}, {-19607, 26255}, +{-19261, 26509}, {-18914, 26760}, +{-18561, 27004}, {-18205, 27246}, +{-17846, 27481}, {-17485, 27713}, +{-17122, 27940}, {-16755, 28162}, +{-16385, 28378}, {-16012, 28590}, +{-15636, 28797}, {-15258, 28999}, +{-14878, 29197}, {-14494, 29389}, +{-14108, 29576}, {-13720, 29757}, +{-13329, 29934}, {-12937, 30107}, +{-12540, 30274}, {-12142, 30435}, +{-11744, 30592}, {-11342, 30743}, +{-10939, 30889}, {-10534, 31030}, +{-10127, 31164}, {-9718, 31294}, +{-9307, 31418}, {-8895, 31537}, +{-8482, 31652}, {-8067, 31759}, +{-7650, 31862}, {-7233, 31960}, +{-6815, 32051}, {-6393, 32138}, +{-5973, 32219}, {-5549, 32294}, +{-5127, 32364}, {-4703, 32429}, +{-4278, 32487}, {-3852, 32541}, +{-3426, 32588}, {-2999, 32630}, +{-2572, 32667}, {-2144, 32698}, +{-1716, 32724}, {-1287, 32742}, +{-860, 32757}, {-430, 32766}, +{0, 32767}, {429, 32766}, +{858, 32757}, {1287, 32743}, +{1715, 32724}, {2143, 32698}, +{2570, 32667}, {2998, 32631}, +{3425, 32588}, {3851, 32541}, +{4277, 32488}, {4701, 32429}, +{5125, 32364}, {5548, 32295}, +{5971, 32219}, {6393, 32138}, +{6813, 32051}, {7231, 31960}, +{7650, 31863}, {8067, 31760}, +{8481, 31652}, {8895, 31539}, +{9306, 31419}, {9716, 31294}, +{10126, 31165}, {10532, 31030}, +{10937, 30889}, {11340, 30743}, +{11741, 30592}, {12141, 30436}, +{12540, 30274}, {12935, 30107}, +{13328, 29936}, {13718, 29758}, +{14107, 29577}, {14493, 29390}, +{14875, 29197}, {15257, 29000}, +{15635, 28797}, {16010, 28590}, +{16384, 28379}, {16753, 28162}, +{17119, 27940}, {17484, 27714}, +{17845, 27482}, {18205, 27246}, +{18560, 27006}, {18911, 26760}, +{19260, 26510}, {19606, 26257}, +{19947, 25997}, {20286, 25734}, +{20621, 25466}, {20952, 25194}, +{21281, 24918}, {21605, 24637}, +{21926, 24353}, {22242, 24063}, +{22555, 23770}, {22865, 23473}, +{23171, 23171}, {23472, 22866}, +{23769, 22557}, {24063, 22244}, +{24352, 21927}, {24636, 21606}, +{24917, 21282}, {25194, 20954}, +{25465, 20622}, {25733, 20288}, +{25997, 19949}, {26255, 19607}, +{26509, 19261}, {26760, 18914}, +{27004, 18561}, {27246, 18205}, +{27481, 17846}, {27713, 17485}, +{27940, 17122}, {28162, 16755}, +{28378, 16385}, {28590, 16012}, +{28797, 15636}, {28999, 15258}, +{29197, 14878}, {29389, 14494}, +{29576, 14108}, {29757, 13720}, +{29934, 13329}, {30107, 12937}, +{30274, 12540}, {30435, 12142}, +{30592, 11744}, {30743, 11342}, +{30889, 10939}, {31030, 10534}, +{31164, 10127}, {31294, 9718}, +{31418, 9307}, {31537, 8895}, +{31652, 8482}, {31759, 8067}, +{31862, 7650}, {31960, 7233}, +{32051, 6815}, {32138, 6393}, +{32219, 5973}, {32294, 5549}, +{32364, 5127}, {32429, 4703}, +{32487, 4278}, {32541, 3852}, +{32588, 3426}, {32630, 2999}, +{32667, 2572}, {32698, 2144}, +{32724, 1716}, {32742, 1287}, +{32757, 860}, {32766, 430}, +}; +#ifndef FFT_BITREV480 +#define FFT_BITREV480 +static const opus_int16 fft_bitrev480[480] = { +0, 96, 192, 288, 384, 32, 128, 224, 320, 416, 64, 160, 256, 352, 448, +8, 104, 200, 296, 392, 40, 136, 232, 328, 424, 72, 168, 264, 360, 456, +16, 112, 208, 304, 400, 48, 144, 240, 336, 432, 80, 176, 272, 368, 464, +24, 120, 216, 312, 408, 56, 152, 248, 344, 440, 88, 184, 280, 376, 472, +4, 100, 196, 292, 388, 36, 132, 228, 324, 420, 68, 164, 260, 356, 452, +12, 108, 204, 300, 396, 44, 140, 236, 332, 428, 76, 172, 268, 364, 460, +20, 116, 212, 308, 404, 52, 148, 244, 340, 436, 84, 180, 276, 372, 468, +28, 124, 220, 316, 412, 60, 156, 252, 348, 444, 92, 188, 284, 380, 476, +1, 97, 193, 289, 385, 33, 129, 225, 321, 417, 65, 161, 257, 353, 449, +9, 105, 201, 297, 393, 41, 137, 233, 329, 425, 73, 169, 265, 361, 457, +17, 113, 209, 305, 401, 49, 145, 241, 337, 433, 81, 177, 273, 369, 465, +25, 121, 217, 313, 409, 57, 153, 249, 345, 441, 89, 185, 281, 377, 473, +5, 101, 197, 293, 389, 37, 133, 229, 325, 421, 69, 165, 261, 357, 453, +13, 109, 205, 301, 397, 45, 141, 237, 333, 429, 77, 173, 269, 365, 461, +21, 117, 213, 309, 405, 53, 149, 245, 341, 437, 85, 181, 277, 373, 469, +29, 125, 221, 317, 413, 61, 157, 253, 349, 445, 93, 189, 285, 381, 477, +2, 98, 194, 290, 386, 34, 130, 226, 322, 418, 66, 162, 258, 354, 450, +10, 106, 202, 298, 394, 42, 138, 234, 330, 426, 74, 170, 266, 362, 458, +18, 114, 210, 306, 402, 50, 146, 242, 338, 434, 82, 178, 274, 370, 466, +26, 122, 218, 314, 410, 58, 154, 250, 346, 442, 90, 186, 282, 378, 474, +6, 102, 198, 294, 390, 38, 134, 230, 326, 422, 70, 166, 262, 358, 454, +14, 110, 206, 302, 398, 46, 142, 238, 334, 430, 78, 174, 270, 366, 462, +22, 118, 214, 310, 406, 54, 150, 246, 342, 438, 86, 182, 278, 374, 470, +30, 126, 222, 318, 414, 62, 158, 254, 350, 446, 94, 190, 286, 382, 478, +3, 99, 195, 291, 387, 35, 131, 227, 323, 419, 67, 163, 259, 355, 451, +11, 107, 203, 299, 395, 43, 139, 235, 331, 427, 75, 171, 267, 363, 459, +19, 115, 211, 307, 403, 51, 147, 243, 339, 435, 83, 179, 275, 371, 467, +27, 123, 219, 315, 411, 59, 155, 251, 347, 443, 91, 187, 283, 379, 475, +7, 103, 199, 295, 391, 39, 135, 231, 327, 423, 71, 167, 263, 359, 455, +15, 111, 207, 303, 399, 47, 143, 239, 335, 431, 79, 175, 271, 367, 463, +23, 119, 215, 311, 407, 55, 151, 247, 343, 439, 87, 183, 279, 375, 471, +31, 127, 223, 319, 415, 63, 159, 255, 351, 447, 95, 191, 287, 383, 479, +}; +#endif + +#ifndef FFT_BITREV240 +#define FFT_BITREV240 +static const opus_int16 fft_bitrev240[240] = { +0, 48, 96, 144, 192, 16, 64, 112, 160, 208, 32, 80, 128, 176, 224, +4, 52, 100, 148, 196, 20, 68, 116, 164, 212, 36, 84, 132, 180, 228, +8, 56, 104, 152, 200, 24, 72, 120, 168, 216, 40, 88, 136, 184, 232, +12, 60, 108, 156, 204, 28, 76, 124, 172, 220, 44, 92, 140, 188, 236, +1, 49, 97, 145, 193, 17, 65, 113, 161, 209, 33, 81, 129, 177, 225, +5, 53, 101, 149, 197, 21, 69, 117, 165, 213, 37, 85, 133, 181, 229, +9, 57, 105, 153, 201, 25, 73, 121, 169, 217, 41, 89, 137, 185, 233, +13, 61, 109, 157, 205, 29, 77, 125, 173, 221, 45, 93, 141, 189, 237, +2, 50, 98, 146, 194, 18, 66, 114, 162, 210, 34, 82, 130, 178, 226, +6, 54, 102, 150, 198, 22, 70, 118, 166, 214, 38, 86, 134, 182, 230, +10, 58, 106, 154, 202, 26, 74, 122, 170, 218, 42, 90, 138, 186, 234, +14, 62, 110, 158, 206, 30, 78, 126, 174, 222, 46, 94, 142, 190, 238, +3, 51, 99, 147, 195, 19, 67, 115, 163, 211, 35, 83, 131, 179, 227, +7, 55, 103, 151, 199, 23, 71, 119, 167, 215, 39, 87, 135, 183, 231, +11, 59, 107, 155, 203, 27, 75, 123, 171, 219, 43, 91, 139, 187, 235, +15, 63, 111, 159, 207, 31, 79, 127, 175, 223, 47, 95, 143, 191, 239, +}; +#endif + +#ifndef FFT_BITREV120 +#define FFT_BITREV120 +static const opus_int16 fft_bitrev120[120] = { +0, 24, 48, 72, 96, 8, 32, 56, 80, 104, 16, 40, 64, 88, 112, +4, 28, 52, 76, 100, 12, 36, 60, 84, 108, 20, 44, 68, 92, 116, +1, 25, 49, 73, 97, 9, 33, 57, 81, 105, 17, 41, 65, 89, 113, +5, 29, 53, 77, 101, 13, 37, 61, 85, 109, 21, 45, 69, 93, 117, +2, 26, 50, 74, 98, 10, 34, 58, 82, 106, 18, 42, 66, 90, 114, +6, 30, 54, 78, 102, 14, 38, 62, 86, 110, 22, 46, 70, 94, 118, +3, 27, 51, 75, 99, 11, 35, 59, 83, 107, 19, 43, 67, 91, 115, +7, 31, 55, 79, 103, 15, 39, 63, 87, 111, 23, 47, 71, 95, 119, +}; +#endif + +#ifndef FFT_BITREV60 +#define FFT_BITREV60 +static const opus_int16 fft_bitrev60[60] = { +0, 12, 24, 36, 48, 4, 16, 28, 40, 52, 8, 20, 32, 44, 56, +1, 13, 25, 37, 49, 5, 17, 29, 41, 53, 9, 21, 33, 45, 57, +2, 14, 26, 38, 50, 6, 18, 30, 42, 54, 10, 22, 34, 46, 58, +3, 15, 27, 39, 51, 7, 19, 31, 43, 55, 11, 23, 35, 47, 59, +}; +#endif + +#ifndef FFT_STATE48000_960_0 +#define FFT_STATE48000_960_0 +static const kiss_fft_state fft_state48000_960_0 = { +480, /* nfft */ +17476, /* scale */ +8, /* scale_shift */ +-1, /* shift */ +{5, 96, 3, 32, 4, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev480, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_480, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_1 +#define FFT_STATE48000_960_1 +static const kiss_fft_state fft_state48000_960_1 = { +240, /* nfft */ +17476, /* scale */ +7, /* scale_shift */ +1, /* shift */ +{5, 48, 3, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev240, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_240, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_2 +#define FFT_STATE48000_960_2 +static const kiss_fft_state fft_state48000_960_2 = { +120, /* nfft */ +17476, /* scale */ +6, /* scale_shift */ +2, /* shift */ +{5, 24, 3, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev120, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_120, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_3 +#define FFT_STATE48000_960_3 +static const kiss_fft_state fft_state48000_960_3 = { +60, /* nfft */ +17476, /* scale */ +5, /* scale_shift */ +3, /* shift */ +{5, 12, 3, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev60, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_60, +#else +NULL, +#endif +}; +#endif + +#endif + +#ifndef MDCT_TWIDDLES960 +#define MDCT_TWIDDLES960 +static const opus_val16 mdct_twiddles960[1800] = { +32767, 32767, 32767, 32766, 32765, +32763, 32761, 32759, 32756, 32753, +32750, 32746, 32742, 32738, 32733, +32728, 32722, 32717, 32710, 32704, +32697, 32690, 32682, 32674, 32666, +32657, 32648, 32639, 32629, 32619, +32609, 32598, 32587, 32576, 32564, +32552, 32539, 32526, 32513, 32500, +32486, 32472, 32457, 32442, 32427, +32411, 32395, 32379, 32362, 32345, +32328, 32310, 32292, 32274, 32255, +32236, 32217, 32197, 32177, 32157, +32136, 32115, 32093, 32071, 32049, +32027, 32004, 31981, 31957, 31933, +31909, 31884, 31859, 31834, 31809, +31783, 31756, 31730, 31703, 31676, +31648, 31620, 31592, 31563, 31534, +31505, 31475, 31445, 31415, 31384, +31353, 31322, 31290, 31258, 31226, +31193, 31160, 31127, 31093, 31059, +31025, 30990, 30955, 30920, 30884, +30848, 30812, 30775, 30738, 30701, +30663, 30625, 30587, 30548, 30509, +30470, 30430, 30390, 30350, 30309, +30269, 30227, 30186, 30144, 30102, +30059, 30016, 29973, 29930, 29886, +29842, 29797, 29752, 29707, 29662, +29616, 29570, 29524, 29477, 29430, +29383, 29335, 29287, 29239, 29190, +29142, 29092, 29043, 28993, 28943, +28892, 28842, 28791, 28739, 28688, +28636, 28583, 28531, 28478, 28425, +28371, 28317, 28263, 28209, 28154, +28099, 28044, 27988, 27932, 27876, +27820, 27763, 27706, 27648, 27591, +27533, 27474, 27416, 27357, 27298, +27238, 27178, 27118, 27058, 26997, +26936, 26875, 26814, 26752, 26690, +26628, 26565, 26502, 26439, 26375, +26312, 26247, 26183, 26119, 26054, +25988, 25923, 25857, 25791, 25725, +25658, 25592, 25524, 25457, 25389, +25322, 25253, 25185, 25116, 25047, +24978, 24908, 24838, 24768, 24698, +24627, 24557, 24485, 24414, 24342, +24270, 24198, 24126, 24053, 23980, +23907, 23834, 23760, 23686, 23612, +23537, 23462, 23387, 23312, 23237, +23161, 23085, 23009, 22932, 22856, +22779, 22701, 22624, 22546, 22468, +22390, 22312, 22233, 22154, 22075, +21996, 21916, 21836, 21756, 21676, +21595, 21515, 21434, 21352, 21271, +21189, 21107, 21025, 20943, 20860, +20777, 20694, 20611, 20528, 20444, +20360, 20276, 20192, 20107, 20022, +19937, 19852, 19767, 19681, 19595, +19509, 19423, 19336, 19250, 19163, +19076, 18988, 18901, 18813, 18725, +18637, 18549, 18460, 18372, 18283, +18194, 18104, 18015, 17925, 17835, +17745, 17655, 17565, 17474, 17383, +17292, 17201, 17110, 17018, 16927, +16835, 16743, 16650, 16558, 16465, +16372, 16279, 16186, 16093, 15999, +15906, 15812, 15718, 15624, 15529, +15435, 15340, 15245, 15150, 15055, +14960, 14864, 14769, 14673, 14577, +14481, 14385, 14288, 14192, 14095, +13998, 13901, 13804, 13706, 13609, +13511, 13414, 13316, 13218, 13119, +13021, 12923, 12824, 12725, 12626, +12527, 12428, 12329, 12230, 12130, +12030, 11930, 11831, 11730, 11630, +11530, 11430, 11329, 11228, 11128, +11027, 10926, 10824, 10723, 10622, +10520, 10419, 10317, 10215, 10113, +10011, 9909, 9807, 9704, 9602, +9499, 9397, 9294, 9191, 9088, +8985, 8882, 8778, 8675, 8572, +8468, 8364, 8261, 8157, 8053, +7949, 7845, 7741, 7637, 7532, +7428, 7323, 7219, 7114, 7009, +6905, 6800, 6695, 6590, 6485, +6380, 6274, 6169, 6064, 5958, +5853, 5747, 5642, 5536, 5430, +5325, 5219, 5113, 5007, 4901, +4795, 4689, 4583, 4476, 4370, +4264, 4157, 4051, 3945, 3838, +3732, 3625, 3518, 3412, 3305, +3198, 3092, 2985, 2878, 2771, +2664, 2558, 2451, 2344, 2237, +2130, 2023, 1916, 1809, 1702, +1594, 1487, 1380, 1273, 1166, +1059, 952, 844, 737, 630, +523, 416, 308, 201, 94, +-13, -121, -228, -335, -442, +-550, -657, -764, -871, -978, +-1086, -1193, -1300, -1407, -1514, +-1621, -1728, -1835, -1942, -2049, +-2157, -2263, -2370, -2477, -2584, +-2691, -2798, -2905, -3012, -3118, +-3225, -3332, -3439, -3545, -3652, +-3758, -3865, -3971, -4078, -4184, +-4290, -4397, -4503, -4609, -4715, +-4821, -4927, -5033, -5139, -5245, +-5351, -5457, -5562, -5668, -5774, +-5879, -5985, -6090, -6195, -6301, +-6406, -6511, -6616, -6721, -6826, +-6931, -7036, -7140, -7245, -7349, +-7454, -7558, -7663, -7767, -7871, +-7975, -8079, -8183, -8287, -8390, +-8494, -8597, -8701, -8804, -8907, +-9011, -9114, -9217, -9319, -9422, +-9525, -9627, -9730, -9832, -9934, +-10037, -10139, -10241, -10342, -10444, +-10546, -10647, -10748, -10850, -10951, +-11052, -11153, -11253, -11354, -11455, +-11555, -11655, -11756, -11856, -11955, +-12055, -12155, -12254, -12354, -12453, +-12552, -12651, -12750, -12849, -12947, +-13046, -13144, -13242, -13340, -13438, +-13536, -13633, -13731, -13828, -13925, +-14022, -14119, -14216, -14312, -14409, +-14505, -14601, -14697, -14793, -14888, +-14984, -15079, -15174, -15269, -15364, +-15459, -15553, -15647, -15741, -15835, +-15929, -16023, -16116, -16210, -16303, +-16396, -16488, -16581, -16673, -16766, +-16858, -16949, -17041, -17133, -17224, +-17315, -17406, -17497, -17587, -17678, +-17768, -17858, -17948, -18037, -18127, +-18216, -18305, -18394, -18483, -18571, +-18659, -18747, -18835, -18923, -19010, +-19098, -19185, -19271, -19358, -19444, +-19531, -19617, -19702, -19788, -19873, +-19959, -20043, -20128, -20213, -20297, +-20381, -20465, -20549, -20632, -20715, +-20798, -20881, -20963, -21046, -21128, +-21210, -21291, -21373, -21454, -21535, +-21616, -21696, -21776, -21856, -21936, +-22016, -22095, -22174, -22253, -22331, +-22410, -22488, -22566, -22643, -22721, +-22798, -22875, -22951, -23028, -23104, +-23180, -23256, -23331, -23406, -23481, +-23556, -23630, -23704, -23778, -23852, +-23925, -23998, -24071, -24144, -24216, +-24288, -24360, -24432, -24503, -24574, +-24645, -24716, -24786, -24856, -24926, +-24995, -25064, -25133, -25202, -25270, +-25339, -25406, -25474, -25541, -25608, +-25675, -25742, -25808, -25874, -25939, +-26005, -26070, -26135, -26199, -26264, +-26327, -26391, -26455, -26518, -26581, +-26643, -26705, -26767, -26829, -26891, +-26952, -27013, -27073, -27133, -27193, +-27253, -27312, -27372, -27430, -27489, +-27547, -27605, -27663, -27720, -27777, +-27834, -27890, -27946, -28002, -28058, +-28113, -28168, -28223, -28277, -28331, +-28385, -28438, -28491, -28544, -28596, +-28649, -28701, -28752, -28803, -28854, +-28905, -28955, -29006, -29055, -29105, +-29154, -29203, -29251, -29299, -29347, +-29395, -29442, -29489, -29535, -29582, +-29628, -29673, -29719, -29764, -29808, +-29853, -29897, -29941, -29984, -30027, +-30070, -30112, -30154, -30196, -30238, +-30279, -30320, -30360, -30400, -30440, +-30480, -30519, -30558, -30596, -30635, +-30672, -30710, -30747, -30784, -30821, +-30857, -30893, -30929, -30964, -30999, +-31033, -31068, -31102, -31135, -31168, +-31201, -31234, -31266, -31298, -31330, +-31361, -31392, -31422, -31453, -31483, +-31512, -31541, -31570, -31599, -31627, +-31655, -31682, -31710, -31737, -31763, +-31789, -31815, -31841, -31866, -31891, +-31915, -31939, -31963, -31986, -32010, +-32032, -32055, -32077, -32099, -32120, +-32141, -32162, -32182, -32202, -32222, +-32241, -32260, -32279, -32297, -32315, +-32333, -32350, -32367, -32383, -32399, +-32415, -32431, -32446, -32461, -32475, +-32489, -32503, -32517, -32530, -32542, +-32555, -32567, -32579, -32590, -32601, +-32612, -32622, -32632, -32641, -32651, +-32659, -32668, -32676, -32684, -32692, +-32699, -32706, -32712, -32718, -32724, +-32729, -32734, -32739, -32743, -32747, +-32751, -32754, -32757, -32760, -32762, +-32764, -32765, -32767, -32767, -32767, +32767, 32767, 32765, 32761, 32756, +32750, 32742, 32732, 32722, 32710, +32696, 32681, 32665, 32647, 32628, +32608, 32586, 32562, 32538, 32512, +32484, 32455, 32425, 32393, 32360, +32326, 32290, 32253, 32214, 32174, +32133, 32090, 32046, 32001, 31954, +31906, 31856, 31805, 31753, 31700, +31645, 31588, 31530, 31471, 31411, +31349, 31286, 31222, 31156, 31089, +31020, 30951, 30880, 30807, 30733, +30658, 30582, 30504, 30425, 30345, +30263, 30181, 30096, 30011, 29924, +29836, 29747, 29656, 29564, 29471, +29377, 29281, 29184, 29086, 28987, +28886, 28784, 28681, 28577, 28471, +28365, 28257, 28147, 28037, 27925, +27812, 27698, 27583, 27467, 27349, +27231, 27111, 26990, 26868, 26744, +26620, 26494, 26367, 26239, 26110, +25980, 25849, 25717, 25583, 25449, +25313, 25176, 25038, 24900, 24760, +24619, 24477, 24333, 24189, 24044, +23898, 23751, 23602, 23453, 23303, +23152, 22999, 22846, 22692, 22537, +22380, 22223, 22065, 21906, 21746, +21585, 21423, 21261, 21097, 20933, +20767, 20601, 20434, 20265, 20096, +19927, 19756, 19584, 19412, 19239, +19065, 18890, 18714, 18538, 18361, +18183, 18004, 17824, 17644, 17463, +17281, 17098, 16915, 16731, 16546, +16361, 16175, 15988, 15800, 15612, +15423, 15234, 15043, 14852, 14661, +14469, 14276, 14083, 13889, 13694, +13499, 13303, 13107, 12910, 12713, +12515, 12317, 12118, 11918, 11718, +11517, 11316, 11115, 10913, 10710, +10508, 10304, 10100, 9896, 9691, +9486, 9281, 9075, 8869, 8662, +8455, 8248, 8040, 7832, 7623, +7415, 7206, 6996, 6787, 6577, +6366, 6156, 5945, 5734, 5523, +5311, 5100, 4888, 4675, 4463, +4251, 4038, 3825, 3612, 3399, +3185, 2972, 2758, 2544, 2330, +2116, 1902, 1688, 1474, 1260, +1045, 831, 617, 402, 188, +-27, -241, -456, -670, -885, +-1099, -1313, -1528, -1742, -1956, +-2170, -2384, -2598, -2811, -3025, +-3239, -3452, -3665, -3878, -4091, +-4304, -4516, -4728, -4941, -5153, +-5364, -5576, -5787, -5998, -6209, +-6419, -6629, -6839, -7049, -7258, +-7467, -7676, -7884, -8092, -8300, +-8507, -8714, -8920, -9127, -9332, +-9538, -9743, -9947, -10151, -10355, +-10558, -10761, -10963, -11165, -11367, +-11568, -11768, -11968, -12167, -12366, +-12565, -12762, -12960, -13156, -13352, +-13548, -13743, -13937, -14131, -14324, +-14517, -14709, -14900, -15091, -15281, +-15470, -15659, -15847, -16035, -16221, +-16407, -16593, -16777, -16961, -17144, +-17326, -17508, -17689, -17869, -18049, +-18227, -18405, -18582, -18758, -18934, +-19108, -19282, -19455, -19627, -19799, +-19969, -20139, -20308, -20475, -20642, +-20809, -20974, -21138, -21301, -21464, +-21626, -21786, -21946, -22105, -22263, +-22420, -22575, -22730, -22884, -23037, +-23189, -23340, -23490, -23640, -23788, +-23935, -24080, -24225, -24369, -24512, +-24654, -24795, -24934, -25073, -25211, +-25347, -25482, -25617, -25750, -25882, +-26013, -26143, -26272, -26399, -26526, +-26651, -26775, -26898, -27020, -27141, +-27260, -27379, -27496, -27612, -27727, +-27841, -27953, -28065, -28175, -28284, +-28391, -28498, -28603, -28707, -28810, +-28911, -29012, -29111, -29209, -29305, +-29401, -29495, -29587, -29679, -29769, +-29858, -29946, -30032, -30118, -30201, +-30284, -30365, -30445, -30524, -30601, +-30677, -30752, -30825, -30897, -30968, +-31038, -31106, -31172, -31238, -31302, +-31365, -31426, -31486, -31545, -31602, +-31658, -31713, -31766, -31818, -31869, +-31918, -31966, -32012, -32058, -32101, +-32144, -32185, -32224, -32262, -32299, +-32335, -32369, -32401, -32433, -32463, +-32491, -32518, -32544, -32568, -32591, +-32613, -32633, -32652, -32669, -32685, +-32700, -32713, -32724, -32735, -32744, +-32751, -32757, -32762, -32766, -32767, +32767, 32764, 32755, 32741, 32720, +32694, 32663, 32626, 32583, 32535, +32481, 32421, 32356, 32286, 32209, +32128, 32041, 31948, 31850, 31747, +31638, 31523, 31403, 31278, 31148, +31012, 30871, 30724, 30572, 30415, +30253, 30086, 29913, 29736, 29553, +29365, 29172, 28974, 28771, 28564, +28351, 28134, 27911, 27684, 27452, +27216, 26975, 26729, 26478, 26223, +25964, 25700, 25432, 25159, 24882, +24601, 24315, 24026, 23732, 23434, +23133, 22827, 22517, 22204, 21886, +21565, 21240, 20912, 20580, 20244, +19905, 19563, 19217, 18868, 18516, +18160, 17802, 17440, 17075, 16708, +16338, 15964, 15588, 15210, 14829, +14445, 14059, 13670, 13279, 12886, +12490, 12093, 11693, 11291, 10888, +10482, 10075, 9666, 9255, 8843, +8429, 8014, 7597, 7180, 6760, +6340, 5919, 5496, 5073, 4649, +4224, 3798, 3372, 2945, 2517, +2090, 1661, 1233, 804, 375, +-54, -483, -911, -1340, -1768, +-2197, -2624, -3052, -3479, -3905, +-4330, -4755, -5179, -5602, -6024, +-6445, -6865, -7284, -7702, -8118, +-8533, -8946, -9358, -9768, -10177, +-10584, -10989, -11392, -11793, -12192, +-12589, -12984, -13377, -13767, -14155, +-14541, -14924, -15305, -15683, -16058, +-16430, -16800, -17167, -17531, -17892, +-18249, -18604, -18956, -19304, -19649, +-19990, -20329, -20663, -20994, -21322, +-21646, -21966, -22282, -22595, -22904, +-23208, -23509, -23806, -24099, -24387, +-24672, -24952, -25228, -25499, -25766, +-26029, -26288, -26541, -26791, -27035, +-27275, -27511, -27741, -27967, -28188, +-28405, -28616, -28823, -29024, -29221, +-29412, -29599, -29780, -29957, -30128, +-30294, -30455, -30611, -30761, -30906, +-31046, -31181, -31310, -31434, -31552, +-31665, -31773, -31875, -31972, -32063, +-32149, -32229, -32304, -32373, -32437, +-32495, -32547, -32594, -32635, -32671, +-32701, -32726, -32745, -32758, -32766, +32767, 32754, 32717, 32658, 32577, +32473, 32348, 32200, 32029, 31837, +31624, 31388, 31131, 30853, 30553, +30232, 29891, 29530, 29148, 28746, +28324, 27883, 27423, 26944, 26447, +25931, 25398, 24847, 24279, 23695, +23095, 22478, 21846, 21199, 20538, +19863, 19174, 18472, 17757, 17030, +16291, 15541, 14781, 14010, 13230, +12441, 11643, 10837, 10024, 9204, +8377, 7545, 6708, 5866, 5020, +4171, 3319, 2464, 1608, 751, +-107, -965, -1822, -2678, -3532, +-4383, -5232, -6077, -6918, -7754, +-8585, -9409, -10228, -11039, -11843, +-12639, -13426, -14204, -14972, -15730, +-16477, -17213, -17937, -18648, -19347, +-20033, -20705, -21363, -22006, -22634, +-23246, -23843, -24423, -24986, -25533, +-26062, -26573, -27066, -27540, -27995, +-28431, -28848, -29245, -29622, -29979, +-30315, -30630, -30924, -31197, -31449, +-31679, -31887, -32074, -32239, -32381, +-32501, -32600, -32675, -32729, -32759, +}; +#endif + +static const CELTMode mode48000_960_120 = { +48000, /* Fs */ +120, /* overlap */ +21, /* nbEBands */ +21, /* effEBands */ +{27853, 0, 4096, 8192, }, /* preemph */ +eband5ms, /* eBands */ +3, /* maxLM */ +8, /* nbShortMdcts */ +120, /* shortMdctSize */ +11, /* nbAllocVectors */ +band_allocation, /* allocVectors */ +logN400, /* logN */ +window120, /* window */ +{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */ +{392, cache_index50, cache_bits50, cache_caps50}, /* cache */ +}; + +/* List of all the available modes */ +#define TOTAL_MODES 1 +static const CELTMode * const static_mode_list[TOTAL_MODES] = { +&mode48000_960_120, +}; diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/static_modes_fixed_arm_ne10.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/static_modes_fixed_arm_ne10.h new file mode 100644 index 000000000..762309219 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/static_modes_fixed_arm_ne10.h @@ -0,0 +1,388 @@ +/* The contents of this file was automatically generated by + * dump_mode_arm_ne10.c with arguments: 48000 960 + * It contains static definitions for some pre-defined modes. */ +#include + +#ifndef NE10_FFT_PARAMS48000_960 +#define NE10_FFT_PARAMS48000_960 +static const ne10_int32_t ne10_factors_480[64] = { +4, 40, 4, 30, 2, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_240[64] = { +3, 20, 4, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_120[64] = { +3, 10, 2, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_60[64] = { +2, 5, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_fft_cpx_int32_t ne10_twiddles_480[480] = { +{0,0}, {2147483647,0}, {2147483647,0}, +{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394}, +{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496}, +{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096}, +{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152}, +{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313}, +{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424}, +{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496}, +{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268}, +{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785}, +{2147483647,0}, {2144540595,-112390613}, {2135719506,-224473172}, +{2121044558,-335940465}, {2100555974,-446486968}, {2074309912,-555809682}, +{2042378310,-663608960}, {2004848691,-769589332}, {1961823921,-873460313}, +{1913421927,-974937199}, {1859775377,-1073741851}, {1801031311,-1169603450}, +{1737350743,-1262259248}, {1668908218,-1351455280}, {1595891331,-1436947067}, +{1518500216,-1518500282}, {1436946998,-1595891394}, {1351455207,-1668908277}, +{1262259172,-1737350799}, {1169603371,-1801031362}, {1073741769,-1859775424}, +{974937230,-1913421912}, {873460227,-1961823959}, {769589125,-2004848771}, +{663608871,-2042378339}, {555809715,-2074309903}, {446486876,-2100555994}, +{335940246,-2121044593}, {224473078,-2135719516}, {112390647,-2144540593}, +{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968}, +{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851}, +{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394}, +{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959}, +{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516}, +{-94,-2147483647}, {-224473265,-2135719496}, {-446487060,-2100555955}, +{-663609049,-2042378281}, {-873460398,-1961823883}, {-1073741932,-1859775330}, +{-1262259116,-1737350839}, {-1436947137,-1595891268}, {-1595891628,-1436946738}, +{-1737350854,-1262259096}, {-1859775343,-1073741910}, {-1961823997,-873460141}, +{-2042378447,-663608538}, {-2100556013,-446486785}, {-2135719499,-224473240}, +{2147483647,0}, {2121044558,-335940465}, {2042378310,-663608960}, +{1913421927,-974937199}, {1737350743,-1262259248}, {1518500216,-1518500282}, +{1262259172,-1737350799}, {974937230,-1913421912}, {663608871,-2042378339}, +{335940246,-2121044593}, {-94,-2147483647}, {-335940431,-2121044564}, +{-663609049,-2042378281}, {-974937397,-1913421827}, {-1262259116,-1737350839}, +{-1518500258,-1518500240}, {-1737350854,-1262259096}, {-1913422071,-974936918}, +{-2042378447,-663608538}, {-2121044568,-335940406}, {-2147483647,188}, +{-2121044509,335940777}, {-2042378331,663608895}, {-1913421900,974937252}, +{-1737350633,1262259400}, {-1518499993,1518500506}, {-1262258813,1737351059}, +{-974936606,1913422229}, {-663609179,2042378239}, {-335940566,2121044542}, +{2147483647,0}, {2147299667,-28109693}, {2146747758,-56214570}, +{2145828015,-84309815}, {2144540595,-112390613}, {2142885719,-140452154}, +{2140863671,-168489630}, {2138474797,-196498235}, {2135719506,-224473172}, +{2132598271,-252409646}, {2129111626,-280302871}, {2125260168,-308148068}, +{2121044558,-335940465}, {2116465518,-363675300}, {2111523833,-391347822}, +{2106220349,-418953288}, {2100555974,-446486968}, {2094531681,-473944146}, +{2088148500,-501320115}, {2081407525,-528610186}, {2074309912,-555809682}, +{2066856885,-582913912}, {2059049696,-609918325}, {2050889698,-636818231}, +{2042378310,-663608960}, {2033516972,-690285983}, {2024307180,-716844791}, +{2014750533,-743280770}, {2004848691,-769589332}, {1994603329,-795766029}, +{1984016179,-821806435}, {1973089077,-847706028}, {1961823921,-873460313}, +{1950222618,-899064934}, {1938287127,-924515564}, {1926019520,-949807783}, +{1913421927,-974937199}, {1900496481,-999899565}, {1887245364,-1024690661}, +{1873670877,-1049306180}, {1859775377,-1073741851}, {1845561215,-1097993541}, +{1831030826,-1122057097}, {1816186632,-1145928502}, {1801031311,-1169603450}, +{1785567394,-1193077993}, {1769797456,-1216348214}, {1753724345,-1239409914}, +{1737350743,-1262259248}, {1720679456,-1284892300}, {1703713340,-1307305194}, +{1686455222,-1329494189}, {1668908218,-1351455280}, {1651075255,-1373184807}, +{1632959307,-1394679144}, {1614563642,-1415934412}, {1595891331,-1436947067}, +{1576945572,-1457713510}, {1557729613,-1478230181}, {1538246655,-1498493658}, +{1518500216,-1518500282}, {1498493590,-1538246721}, {1478230113,-1557729677}, +{1457713441,-1576945636}, {1436946998,-1595891394}, {1415934341,-1614563704}, +{1394679073,-1632959368}, {1373184735,-1651075315}, {1351455207,-1668908277}, +{1329494115,-1686455280}, {1307305120,-1703713397}, {1284892225,-1720679512}, +{1262259172,-1737350799}, {1239409837,-1753724400}, {1216348136,-1769797510}, +{1193077915,-1785567446}, {1169603371,-1801031362}, {1145928423,-1816186682}, +{1122057017,-1831030875}, {1097993571,-1845561197}, {1073741769,-1859775424}, +{1049305987,-1873670985}, {1024690635,-1887245378}, {999899482,-1900496524}, +{974937230,-1913421912}, {949807699,-1926019561}, {924515422,-1938287195}, +{899064965,-1950222603}, {873460227,-1961823959}, {847705824,-1973089164}, +{821806407,-1984016190}, {795765941,-1994603364}, {769589125,-2004848771}, +{743280682,-2014750566}, {716844642,-2024307233}, {690286016,-2033516961}, +{663608871,-2042378339}, {636818019,-2050889764}, {609918296,-2059049705}, +{582913822,-2066856911}, {555809715,-2074309903}, {528610126,-2081407540}, +{501319962,-2088148536}, {473944148,-2094531680}, {446486876,-2100555994}, +{418953102,-2106220386}, {391347792,-2111523838}, {363675176,-2116465540}, +{335940246,-2121044593}, {308148006,-2125260177}, {280302715,-2129111646}, +{252409648,-2132598271}, {224473078,-2135719516}, {196498046,-2138474814}, +{168489600,-2140863674}, {140452029,-2142885728}, {112390647,-2144540593}, +{84309753,-2145828017}, {56214412,-2146747762}, {28109695,-2147299667}, +{2147483647,0}, {2146747758,-56214570}, {2144540595,-112390613}, +{2140863671,-168489630}, {2135719506,-224473172}, {2129111626,-280302871}, +{2121044558,-335940465}, {2111523833,-391347822}, {2100555974,-446486968}, +{2088148500,-501320115}, {2074309912,-555809682}, {2059049696,-609918325}, +{2042378310,-663608960}, {2024307180,-716844791}, {2004848691,-769589332}, +{1984016179,-821806435}, {1961823921,-873460313}, {1938287127,-924515564}, +{1913421927,-974937199}, {1887245364,-1024690661}, {1859775377,-1073741851}, +{1831030826,-1122057097}, {1801031311,-1169603450}, {1769797456,-1216348214}, +{1737350743,-1262259248}, {1703713340,-1307305194}, {1668908218,-1351455280}, +{1632959307,-1394679144}, {1595891331,-1436947067}, {1557729613,-1478230181}, +{1518500216,-1518500282}, {1478230113,-1557729677}, {1436946998,-1595891394}, +{1394679073,-1632959368}, {1351455207,-1668908277}, {1307305120,-1703713397}, +{1262259172,-1737350799}, {1216348136,-1769797510}, {1169603371,-1801031362}, +{1122057017,-1831030875}, {1073741769,-1859775424}, {1024690635,-1887245378}, +{974937230,-1913421912}, {924515422,-1938287195}, {873460227,-1961823959}, +{821806407,-1984016190}, {769589125,-2004848771}, {716844642,-2024307233}, +{663608871,-2042378339}, {609918296,-2059049705}, {555809715,-2074309903}, +{501319962,-2088148536}, {446486876,-2100555994}, {391347792,-2111523838}, +{335940246,-2121044593}, {280302715,-2129111646}, {224473078,-2135719516}, +{168489600,-2140863674}, {112390647,-2144540593}, {56214412,-2146747762}, +{-94,-2147483647}, {-56214600,-2146747757}, {-112390835,-2144540584}, +{-168489787,-2140863659}, {-224473265,-2135719496}, {-280302901,-2129111622}, +{-335940431,-2121044564}, {-391347977,-2111523804}, {-446487060,-2100555955}, +{-501320144,-2088148493}, {-555809896,-2074309855}, {-609918476,-2059049651}, +{-663609049,-2042378281}, {-716844819,-2024307170}, {-769589300,-2004848703}, +{-821806581,-1984016118}, {-873460398,-1961823883}, {-924515591,-1938287114}, +{-974937397,-1913421827}, {-1024690575,-1887245411}, {-1073741932,-1859775330}, +{-1122057395,-1831030643}, {-1169603421,-1801031330}, {-1216348291,-1769797403}, +{-1262259116,-1737350839}, {-1307305268,-1703713283}, {-1351455453,-1668908078}, +{-1394679021,-1632959413}, {-1436947137,-1595891268}, {-1478230435,-1557729372}, +{-1518500258,-1518500240}, {-1557729742,-1478230045}, {-1595891628,-1436946738}, +{-1632959429,-1394679001}, {-1668908417,-1351455035}, {-1703713298,-1307305248}, +{-1737350854,-1262259096}, {-1769797708,-1216347848}, {-1801031344,-1169603400}, +{-1831030924,-1122056937}, {-1859775343,-1073741910}, {-1887245423,-1024690552}, +{-1913422071,-974936918}, {-1938287125,-924515568}, {-1961823997,-873460141}, +{-1984016324,-821806084}, {-2004848713,-769589276}, {-2024307264,-716844553}, +{-2042378447,-663608538}, {-2059049731,-609918206}, {-2074309994,-555809377}, +{-2088148499,-501320119}, {-2100556013,-446486785}, {-2111523902,-391347448}, +{-2121044568,-335940406}, {-2129111659,-280302621}, {-2135719499,-224473240}, +{-2140863681,-168489506}, {-2144540612,-112390298}, {-2146747758,-56214574}, +{2147483647,0}, {2145828015,-84309815}, {2140863671,-168489630}, +{2132598271,-252409646}, {2121044558,-335940465}, {2106220349,-418953288}, +{2088148500,-501320115}, {2066856885,-582913912}, {2042378310,-663608960}, +{2014750533,-743280770}, {1984016179,-821806435}, {1950222618,-899064934}, +{1913421927,-974937199}, {1873670877,-1049306180}, {1831030826,-1122057097}, +{1785567394,-1193077993}, {1737350743,-1262259248}, {1686455222,-1329494189}, +{1632959307,-1394679144}, {1576945572,-1457713510}, {1518500216,-1518500282}, +{1457713441,-1576945636}, {1394679073,-1632959368}, {1329494115,-1686455280}, +{1262259172,-1737350799}, {1193077915,-1785567446}, {1122057017,-1831030875}, +{1049305987,-1873670985}, {974937230,-1913421912}, {899064965,-1950222603}, +{821806407,-1984016190}, {743280682,-2014750566}, {663608871,-2042378339}, +{582913822,-2066856911}, {501319962,-2088148536}, {418953102,-2106220386}, +{335940246,-2121044593}, {252409648,-2132598271}, {168489600,-2140863674}, +{84309753,-2145828017}, {-94,-2147483647}, {-84309940,-2145828010}, +{-168489787,-2140863659}, {-252409834,-2132598249}, {-335940431,-2121044564}, +{-418953286,-2106220349}, {-501320144,-2088148493}, {-582914003,-2066856860}, +{-663609049,-2042378281}, {-743280858,-2014750501}, {-821806581,-1984016118}, +{-899065136,-1950222525}, {-974937397,-1913421827}, {-1049306374,-1873670768}, +{-1122057395,-1831030643}, {-1193078284,-1785567199}, {-1262259116,-1737350839}, +{-1329494061,-1686455323}, {-1394679021,-1632959413}, {-1457713485,-1576945595}, +{-1518500258,-1518500240}, {-1576945613,-1457713466}, {-1632959429,-1394679001}, +{-1686455338,-1329494041}, {-1737350854,-1262259096}, {-1785567498,-1193077837}, +{-1831030924,-1122056937}, {-1873671031,-1049305905}, {-1913422071,-974936918}, +{-1950222750,-899064648}, {-1984016324,-821806084}, {-2014750687,-743280354}, +{-2042378447,-663608538}, {-2066856867,-582913978}, {-2088148499,-501320119}, +{-2106220354,-418953261}, {-2121044568,-335940406}, {-2132598282,-252409555}, +{-2140863681,-168489506}, {-2145828021,-84309659}, {-2147483647,188}, +{-2145828006,84310034}, {-2140863651,168489881}, {-2132598237,252409928}, +{-2121044509,335940777}, {-2106220281,418953629}, {-2088148411,501320484}, +{-2066856765,582914339}, {-2042378331,663608895}, {-2014750557,743280706}, +{-1984016181,821806431}, {-1950222593,899064989}, {-1913421900,974937252}, +{-1873670848,1049306232}, {-1831030728,1122057257}, {-1785567289,1193078149}, +{-1737350633,1262259400}, {-1686455106,1329494336}, {-1632959185,1394679287}, +{-1576945358,1457713742}, {-1518499993,1518500506}, {-1457713209,1576945850}, +{-1394678735,1632959656}, {-1329493766,1686455555}, {-1262258813,1737351059}, +{-1193077546,1785567692}, {-1122056638,1831031107}, {-1049305599,1873671202}, +{-974936606,1913422229}, {-899064330,1950222896}, {-821805761,1984016458}, +{-743280025,2014750808}, {-663609179,2042378239}, {-582914134,2066856823}, +{-501320277,2088148461}, {-418953420,2106220322}, {-335940566,2121044542}, +{-252409716,2132598263}, {-168489668,2140863668}, {-84309821,2145828015}, +}; +static const ne10_fft_cpx_int32_t ne10_twiddles_240[240] = { +{0,0}, {2147483647,0}, {2147483647,0}, +{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394}, +{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496}, +{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096}, +{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152}, +{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968}, +{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851}, +{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394}, +{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959}, +{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516}, +{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313}, +{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424}, +{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496}, +{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268}, +{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785}, +{2147483647,0}, {2042378310,-663608960}, {1737350743,-1262259248}, +{1262259172,-1737350799}, {663608871,-2042378339}, {-94,-2147483647}, +{-663609049,-2042378281}, {-1262259116,-1737350839}, {-1737350854,-1262259096}, +{-2042378447,-663608538}, {-2147483647,188}, {-2042378331,663608895}, +{-1737350633,1262259400}, {-1262258813,1737351059}, {-663609179,2042378239}, +{2147483647,0}, {2146747758,-56214570}, {2144540595,-112390613}, +{2140863671,-168489630}, {2135719506,-224473172}, {2129111626,-280302871}, +{2121044558,-335940465}, {2111523833,-391347822}, {2100555974,-446486968}, +{2088148500,-501320115}, {2074309912,-555809682}, {2059049696,-609918325}, +{2042378310,-663608960}, {2024307180,-716844791}, {2004848691,-769589332}, +{1984016179,-821806435}, {1961823921,-873460313}, {1938287127,-924515564}, +{1913421927,-974937199}, {1887245364,-1024690661}, {1859775377,-1073741851}, +{1831030826,-1122057097}, {1801031311,-1169603450}, {1769797456,-1216348214}, +{1737350743,-1262259248}, {1703713340,-1307305194}, {1668908218,-1351455280}, +{1632959307,-1394679144}, {1595891331,-1436947067}, {1557729613,-1478230181}, +{1518500216,-1518500282}, {1478230113,-1557729677}, {1436946998,-1595891394}, +{1394679073,-1632959368}, {1351455207,-1668908277}, {1307305120,-1703713397}, +{1262259172,-1737350799}, {1216348136,-1769797510}, {1169603371,-1801031362}, +{1122057017,-1831030875}, {1073741769,-1859775424}, {1024690635,-1887245378}, +{974937230,-1913421912}, {924515422,-1938287195}, {873460227,-1961823959}, +{821806407,-1984016190}, {769589125,-2004848771}, {716844642,-2024307233}, +{663608871,-2042378339}, {609918296,-2059049705}, {555809715,-2074309903}, +{501319962,-2088148536}, {446486876,-2100555994}, {391347792,-2111523838}, +{335940246,-2121044593}, {280302715,-2129111646}, {224473078,-2135719516}, +{168489600,-2140863674}, {112390647,-2144540593}, {56214412,-2146747762}, +{2147483647,0}, {2144540595,-112390613}, {2135719506,-224473172}, +{2121044558,-335940465}, {2100555974,-446486968}, {2074309912,-555809682}, +{2042378310,-663608960}, {2004848691,-769589332}, {1961823921,-873460313}, +{1913421927,-974937199}, {1859775377,-1073741851}, {1801031311,-1169603450}, +{1737350743,-1262259248}, {1668908218,-1351455280}, {1595891331,-1436947067}, +{1518500216,-1518500282}, {1436946998,-1595891394}, {1351455207,-1668908277}, +{1262259172,-1737350799}, {1169603371,-1801031362}, {1073741769,-1859775424}, +{974937230,-1913421912}, {873460227,-1961823959}, {769589125,-2004848771}, +{663608871,-2042378339}, {555809715,-2074309903}, {446486876,-2100555994}, +{335940246,-2121044593}, {224473078,-2135719516}, {112390647,-2144540593}, +{-94,-2147483647}, {-112390835,-2144540584}, {-224473265,-2135719496}, +{-335940431,-2121044564}, {-446487060,-2100555955}, {-555809896,-2074309855}, +{-663609049,-2042378281}, {-769589300,-2004848703}, {-873460398,-1961823883}, +{-974937397,-1913421827}, {-1073741932,-1859775330}, {-1169603421,-1801031330}, +{-1262259116,-1737350839}, {-1351455453,-1668908078}, {-1436947137,-1595891268}, +{-1518500258,-1518500240}, {-1595891628,-1436946738}, {-1668908417,-1351455035}, +{-1737350854,-1262259096}, {-1801031344,-1169603400}, {-1859775343,-1073741910}, +{-1913422071,-974936918}, {-1961823997,-873460141}, {-2004848713,-769589276}, +{-2042378447,-663608538}, {-2074309994,-555809377}, {-2100556013,-446486785}, +{-2121044568,-335940406}, {-2135719499,-224473240}, {-2144540612,-112390298}, +{2147483647,0}, {2140863671,-168489630}, {2121044558,-335940465}, +{2088148500,-501320115}, {2042378310,-663608960}, {1984016179,-821806435}, +{1913421927,-974937199}, {1831030826,-1122057097}, {1737350743,-1262259248}, +{1632959307,-1394679144}, {1518500216,-1518500282}, {1394679073,-1632959368}, +{1262259172,-1737350799}, {1122057017,-1831030875}, {974937230,-1913421912}, +{821806407,-1984016190}, {663608871,-2042378339}, {501319962,-2088148536}, +{335940246,-2121044593}, {168489600,-2140863674}, {-94,-2147483647}, +{-168489787,-2140863659}, {-335940431,-2121044564}, {-501320144,-2088148493}, +{-663609049,-2042378281}, {-821806581,-1984016118}, {-974937397,-1913421827}, +{-1122057395,-1831030643}, {-1262259116,-1737350839}, {-1394679021,-1632959413}, +{-1518500258,-1518500240}, {-1632959429,-1394679001}, {-1737350854,-1262259096}, +{-1831030924,-1122056937}, {-1913422071,-974936918}, {-1984016324,-821806084}, +{-2042378447,-663608538}, {-2088148499,-501320119}, {-2121044568,-335940406}, +{-2140863681,-168489506}, {-2147483647,188}, {-2140863651,168489881}, +{-2121044509,335940777}, {-2088148411,501320484}, {-2042378331,663608895}, +{-1984016181,821806431}, {-1913421900,974937252}, {-1831030728,1122057257}, +{-1737350633,1262259400}, {-1632959185,1394679287}, {-1518499993,1518500506}, +{-1394678735,1632959656}, {-1262258813,1737351059}, {-1122056638,1831031107}, +{-974936606,1913422229}, {-821805761,1984016458}, {-663609179,2042378239}, +{-501320277,2088148461}, {-335940566,2121044542}, {-168489668,2140863668}, +}; +static const ne10_fft_cpx_int32_t ne10_twiddles_120[120] = { +{0,0}, {2147483647,0}, {2147483647,0}, +{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394}, +{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496}, +{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096}, +{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152}, +{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313}, +{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424}, +{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496}, +{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268}, +{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785}, +{2147483647,0}, {2144540595,-112390613}, {2135719506,-224473172}, +{2121044558,-335940465}, {2100555974,-446486968}, {2074309912,-555809682}, +{2042378310,-663608960}, {2004848691,-769589332}, {1961823921,-873460313}, +{1913421927,-974937199}, {1859775377,-1073741851}, {1801031311,-1169603450}, +{1737350743,-1262259248}, {1668908218,-1351455280}, {1595891331,-1436947067}, +{1518500216,-1518500282}, {1436946998,-1595891394}, {1351455207,-1668908277}, +{1262259172,-1737350799}, {1169603371,-1801031362}, {1073741769,-1859775424}, +{974937230,-1913421912}, {873460227,-1961823959}, {769589125,-2004848771}, +{663608871,-2042378339}, {555809715,-2074309903}, {446486876,-2100555994}, +{335940246,-2121044593}, {224473078,-2135719516}, {112390647,-2144540593}, +{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968}, +{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851}, +{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394}, +{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959}, +{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516}, +{-94,-2147483647}, {-224473265,-2135719496}, {-446487060,-2100555955}, +{-663609049,-2042378281}, {-873460398,-1961823883}, {-1073741932,-1859775330}, +{-1262259116,-1737350839}, {-1436947137,-1595891268}, {-1595891628,-1436946738}, +{-1737350854,-1262259096}, {-1859775343,-1073741910}, {-1961823997,-873460141}, +{-2042378447,-663608538}, {-2100556013,-446486785}, {-2135719499,-224473240}, +{2147483647,0}, {2121044558,-335940465}, {2042378310,-663608960}, +{1913421927,-974937199}, {1737350743,-1262259248}, {1518500216,-1518500282}, +{1262259172,-1737350799}, {974937230,-1913421912}, {663608871,-2042378339}, +{335940246,-2121044593}, {-94,-2147483647}, {-335940431,-2121044564}, +{-663609049,-2042378281}, {-974937397,-1913421827}, {-1262259116,-1737350839}, +{-1518500258,-1518500240}, {-1737350854,-1262259096}, {-1913422071,-974936918}, +{-2042378447,-663608538}, {-2121044568,-335940406}, {-2147483647,188}, +{-2121044509,335940777}, {-2042378331,663608895}, {-1913421900,974937252}, +{-1737350633,1262259400}, {-1518499993,1518500506}, {-1262258813,1737351059}, +{-974936606,1913422229}, {-663609179,2042378239}, {-335940566,2121044542}, +}; +static const ne10_fft_cpx_int32_t ne10_twiddles_60[60] = { +{0,0}, {2147483647,0}, {2147483647,0}, +{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394}, +{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496}, +{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096}, +{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152}, +{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968}, +{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851}, +{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394}, +{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959}, +{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516}, +{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313}, +{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424}, +{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496}, +{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268}, +{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785}, +{2147483647,0}, {2042378310,-663608960}, {1737350743,-1262259248}, +{1262259172,-1737350799}, {663608871,-2042378339}, {-94,-2147483647}, +{-663609049,-2042378281}, {-1262259116,-1737350839}, {-1737350854,-1262259096}, +{-2042378447,-663608538}, {-2147483647,188}, {-2042378331,663608895}, +{-1737350633,1262259400}, {-1262258813,1737351059}, {-663609179,2042378239}, +}; +static const ne10_fft_state_int32_t ne10_fft_state_int32_t_480 = { +120, +(ne10_int32_t *)ne10_factors_480, +(ne10_fft_cpx_int32_t *)ne10_twiddles_480, +NULL, +(ne10_fft_cpx_int32_t *)&ne10_twiddles_480[120], +}; +static const arch_fft_state cfg_arch_480 = { +1, +(void *)&ne10_fft_state_int32_t_480, +}; + +static const ne10_fft_state_int32_t ne10_fft_state_int32_t_240 = { +60, +(ne10_int32_t *)ne10_factors_240, +(ne10_fft_cpx_int32_t *)ne10_twiddles_240, +NULL, +(ne10_fft_cpx_int32_t *)&ne10_twiddles_240[60], +}; +static const arch_fft_state cfg_arch_240 = { +1, +(void *)&ne10_fft_state_int32_t_240, +}; + +static const ne10_fft_state_int32_t ne10_fft_state_int32_t_120 = { +30, +(ne10_int32_t *)ne10_factors_120, +(ne10_fft_cpx_int32_t *)ne10_twiddles_120, +NULL, +(ne10_fft_cpx_int32_t *)&ne10_twiddles_120[30], +}; +static const arch_fft_state cfg_arch_120 = { +1, +(void *)&ne10_fft_state_int32_t_120, +}; + +static const ne10_fft_state_int32_t ne10_fft_state_int32_t_60 = { +15, +(ne10_int32_t *)ne10_factors_60, +(ne10_fft_cpx_int32_t *)ne10_twiddles_60, +NULL, +(ne10_fft_cpx_int32_t *)&ne10_twiddles_60[15], +}; +static const arch_fft_state cfg_arch_60 = { +1, +(void *)&ne10_fft_state_int32_t_60, +}; + +#endif /* end NE10_FFT_PARAMS48000_960 */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/static_modes_float.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/static_modes_float.h new file mode 100644 index 000000000..e102a3839 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/static_modes_float.h @@ -0,0 +1,888 @@ +/* The contents of this file was automatically generated by dump_modes.c + with arguments: 48000 960 + It contains static definitions for some pre-defined modes. */ +#include "modes.h" +#include "rate.h" + +#ifdef HAVE_ARM_NE10 +#define OVERRIDE_FFT 1 +#include "static_modes_float_arm_ne10.h" +#endif + +#ifndef DEF_WINDOW120 +#define DEF_WINDOW120 +static const opus_val16 window120[120] = { +6.7286966e-05f, 0.00060551348f, 0.0016815970f, 0.0032947962f, 0.0054439943f, +0.0081276923f, 0.011344001f, 0.015090633f, 0.019364886f, 0.024163635f, +0.029483315f, 0.035319905f, 0.041668911f, 0.048525347f, 0.055883718f, +0.063737999f, 0.072081616f, 0.080907428f, 0.090207705f, 0.099974111f, +0.11019769f, 0.12086883f, 0.13197729f, 0.14351214f, 0.15546177f, +0.16781389f, 0.18055550f, 0.19367290f, 0.20715171f, 0.22097682f, +0.23513243f, 0.24960208f, 0.26436860f, 0.27941419f, 0.29472040f, +0.31026818f, 0.32603788f, 0.34200931f, 0.35816177f, 0.37447407f, +0.39092462f, 0.40749142f, 0.42415215f, 0.44088423f, 0.45766484f, +0.47447104f, 0.49127978f, 0.50806798f, 0.52481261f, 0.54149077f, +0.55807973f, 0.57455701f, 0.59090049f, 0.60708841f, 0.62309951f, +0.63891306f, 0.65450896f, 0.66986776f, 0.68497077f, 0.69980010f, +0.71433873f, 0.72857055f, 0.74248043f, 0.75605424f, 0.76927895f, +0.78214257f, 0.79463430f, 0.80674445f, 0.81846456f, 0.82978733f, +0.84070669f, 0.85121779f, 0.86131698f, 0.87100183f, 0.88027111f, +0.88912479f, 0.89756398f, 0.90559094f, 0.91320904f, 0.92042270f, +0.92723738f, 0.93365955f, 0.93969656f, 0.94535671f, 0.95064907f, +0.95558353f, 0.96017067f, 0.96442171f, 0.96834849f, 0.97196334f, +0.97527906f, 0.97830883f, 0.98106616f, 0.98356480f, 0.98581869f, +0.98784191f, 0.98964856f, 0.99125274f, 0.99266849f, 0.99390969f, +0.99499004f, 0.99592297f, 0.99672162f, 0.99739874f, 0.99796667f, +0.99843728f, 0.99882195f, 0.99913147f, 0.99937606f, 0.99956527f, +0.99970802f, 0.99981248f, 0.99988613f, 0.99993565f, 0.99996697f, +0.99998518f, 0.99999457f, 0.99999859f, 0.99999982f, 1.0000000f, +}; +#endif + +#ifndef DEF_LOGN400 +#define DEF_LOGN400 +static const opus_int16 logN400[21] = { +0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, }; +#endif + +#ifndef DEF_PULSE_CACHE50 +#define DEF_PULSE_CACHE50 +static const opus_int16 cache_index50[105] = { +-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41, +82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41, +41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41, +41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305, +318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240, +305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240, +240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387, +}; +static const unsigned char cache_bits50[392] = { +40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28, +31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50, +51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65, +66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61, +64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92, +94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123, +124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94, +97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139, +142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35, +28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149, +153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225, +229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157, +166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63, +86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250, +25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180, +185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89, +110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41, +74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138, +163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214, +228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49, +90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47, +87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57, +106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187, +224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127, +182, 234, }; +static const unsigned char cache_caps50[168] = { +224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185, +178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240, +240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160, +160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172, +138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207, +204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185, +185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39, +207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201, +188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204, +204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175, +140, 66, 40, }; +#endif + +#ifndef FFT_TWIDDLES48000_960 +#define FFT_TWIDDLES48000_960 +static const kiss_twiddle_cpx fft_twiddles48000_960[480] = { +{1.0000000f, -0.0000000f}, {0.99991433f, -0.013089596f}, +{0.99965732f, -0.026176948f}, {0.99922904f, -0.039259816f}, +{0.99862953f, -0.052335956f}, {0.99785892f, -0.065403129f}, +{0.99691733f, -0.078459096f}, {0.99580493f, -0.091501619f}, +{0.99452190f, -0.10452846f}, {0.99306846f, -0.11753740f}, +{0.99144486f, -0.13052619f}, {0.98965139f, -0.14349262f}, +{0.98768834f, -0.15643447f}, {0.98555606f, -0.16934950f}, +{0.98325491f, -0.18223553f}, {0.98078528f, -0.19509032f}, +{0.97814760f, -0.20791169f}, {0.97534232f, -0.22069744f}, +{0.97236992f, -0.23344536f}, {0.96923091f, -0.24615329f}, +{0.96592583f, -0.25881905f}, {0.96245524f, -0.27144045f}, +{0.95881973f, -0.28401534f}, {0.95501994f, -0.29654157f}, +{0.95105652f, -0.30901699f}, {0.94693013f, -0.32143947f}, +{0.94264149f, -0.33380686f}, {0.93819134f, -0.34611706f}, +{0.93358043f, -0.35836795f}, {0.92880955f, -0.37055744f}, +{0.92387953f, -0.38268343f}, {0.91879121f, -0.39474386f}, +{0.91354546f, -0.40673664f}, {0.90814317f, -0.41865974f}, +{0.90258528f, -0.43051110f}, {0.89687274f, -0.44228869f}, +{0.89100652f, -0.45399050f}, {0.88498764f, -0.46561452f}, +{0.87881711f, -0.47715876f}, {0.87249601f, -0.48862124f}, +{0.86602540f, -0.50000000f}, {0.85940641f, -0.51129309f}, +{0.85264016f, -0.52249856f}, {0.84572782f, -0.53361452f}, +{0.83867057f, -0.54463904f}, {0.83146961f, -0.55557023f}, +{0.82412619f, -0.56640624f}, {0.81664156f, -0.57714519f}, +{0.80901699f, -0.58778525f}, {0.80125381f, -0.59832460f}, +{0.79335334f, -0.60876143f}, {0.78531693f, -0.61909395f}, +{0.77714596f, -0.62932039f}, {0.76884183f, -0.63943900f}, +{0.76040597f, -0.64944805f}, {0.75183981f, -0.65934582f}, +{0.74314483f, -0.66913061f}, {0.73432251f, -0.67880075f}, +{0.72537437f, -0.68835458f}, {0.71630194f, -0.69779046f}, +{0.70710678f, -0.70710678f}, {0.69779046f, -0.71630194f}, +{0.68835458f, -0.72537437f}, {0.67880075f, -0.73432251f}, +{0.66913061f, -0.74314483f}, {0.65934582f, -0.75183981f}, +{0.64944805f, -0.76040597f}, {0.63943900f, -0.76884183f}, +{0.62932039f, -0.77714596f}, {0.61909395f, -0.78531693f}, +{0.60876143f, -0.79335334f}, {0.59832460f, -0.80125381f}, +{0.58778525f, -0.80901699f}, {0.57714519f, -0.81664156f}, +{0.56640624f, -0.82412619f}, {0.55557023f, -0.83146961f}, +{0.54463904f, -0.83867057f}, {0.53361452f, -0.84572782f}, +{0.52249856f, -0.85264016f}, {0.51129309f, -0.85940641f}, +{0.50000000f, -0.86602540f}, {0.48862124f, -0.87249601f}, +{0.47715876f, -0.87881711f}, {0.46561452f, -0.88498764f}, +{0.45399050f, -0.89100652f}, {0.44228869f, -0.89687274f}, +{0.43051110f, -0.90258528f}, {0.41865974f, -0.90814317f}, +{0.40673664f, -0.91354546f}, {0.39474386f, -0.91879121f}, +{0.38268343f, -0.92387953f}, {0.37055744f, -0.92880955f}, +{0.35836795f, -0.93358043f}, {0.34611706f, -0.93819134f}, +{0.33380686f, -0.94264149f}, {0.32143947f, -0.94693013f}, +{0.30901699f, -0.95105652f}, {0.29654157f, -0.95501994f}, +{0.28401534f, -0.95881973f}, {0.27144045f, -0.96245524f}, +{0.25881905f, -0.96592583f}, {0.24615329f, -0.96923091f}, +{0.23344536f, -0.97236992f}, {0.22069744f, -0.97534232f}, +{0.20791169f, -0.97814760f}, {0.19509032f, -0.98078528f}, +{0.18223553f, -0.98325491f}, {0.16934950f, -0.98555606f}, +{0.15643447f, -0.98768834f}, {0.14349262f, -0.98965139f}, +{0.13052619f, -0.99144486f}, {0.11753740f, -0.99306846f}, +{0.10452846f, -0.99452190f}, {0.091501619f, -0.99580493f}, +{0.078459096f, -0.99691733f}, {0.065403129f, -0.99785892f}, +{0.052335956f, -0.99862953f}, {0.039259816f, -0.99922904f}, +{0.026176948f, -0.99965732f}, {0.013089596f, -0.99991433f}, +{6.1230318e-17f, -1.0000000f}, {-0.013089596f, -0.99991433f}, +{-0.026176948f, -0.99965732f}, {-0.039259816f, -0.99922904f}, +{-0.052335956f, -0.99862953f}, {-0.065403129f, -0.99785892f}, +{-0.078459096f, -0.99691733f}, {-0.091501619f, -0.99580493f}, +{-0.10452846f, -0.99452190f}, {-0.11753740f, -0.99306846f}, +{-0.13052619f, -0.99144486f}, {-0.14349262f, -0.98965139f}, +{-0.15643447f, -0.98768834f}, {-0.16934950f, -0.98555606f}, +{-0.18223553f, -0.98325491f}, {-0.19509032f, -0.98078528f}, +{-0.20791169f, -0.97814760f}, {-0.22069744f, -0.97534232f}, +{-0.23344536f, -0.97236992f}, {-0.24615329f, -0.96923091f}, +{-0.25881905f, -0.96592583f}, {-0.27144045f, -0.96245524f}, +{-0.28401534f, -0.95881973f}, {-0.29654157f, -0.95501994f}, +{-0.30901699f, -0.95105652f}, {-0.32143947f, -0.94693013f}, +{-0.33380686f, -0.94264149f}, {-0.34611706f, -0.93819134f}, +{-0.35836795f, -0.93358043f}, {-0.37055744f, -0.92880955f}, +{-0.38268343f, -0.92387953f}, {-0.39474386f, -0.91879121f}, +{-0.40673664f, -0.91354546f}, {-0.41865974f, -0.90814317f}, +{-0.43051110f, -0.90258528f}, {-0.44228869f, -0.89687274f}, +{-0.45399050f, -0.89100652f}, {-0.46561452f, -0.88498764f}, +{-0.47715876f, -0.87881711f}, {-0.48862124f, -0.87249601f}, +{-0.50000000f, -0.86602540f}, {-0.51129309f, -0.85940641f}, +{-0.52249856f, -0.85264016f}, {-0.53361452f, -0.84572782f}, +{-0.54463904f, -0.83867057f}, {-0.55557023f, -0.83146961f}, +{-0.56640624f, -0.82412619f}, {-0.57714519f, -0.81664156f}, +{-0.58778525f, -0.80901699f}, {-0.59832460f, -0.80125381f}, +{-0.60876143f, -0.79335334f}, {-0.61909395f, -0.78531693f}, +{-0.62932039f, -0.77714596f}, {-0.63943900f, -0.76884183f}, +{-0.64944805f, -0.76040597f}, {-0.65934582f, -0.75183981f}, +{-0.66913061f, -0.74314483f}, {-0.67880075f, -0.73432251f}, +{-0.68835458f, -0.72537437f}, {-0.69779046f, -0.71630194f}, +{-0.70710678f, -0.70710678f}, {-0.71630194f, -0.69779046f}, +{-0.72537437f, -0.68835458f}, {-0.73432251f, -0.67880075f}, +{-0.74314483f, -0.66913061f}, {-0.75183981f, -0.65934582f}, +{-0.76040597f, -0.64944805f}, {-0.76884183f, -0.63943900f}, +{-0.77714596f, -0.62932039f}, {-0.78531693f, -0.61909395f}, +{-0.79335334f, -0.60876143f}, {-0.80125381f, -0.59832460f}, +{-0.80901699f, -0.58778525f}, {-0.81664156f, -0.57714519f}, +{-0.82412619f, -0.56640624f}, {-0.83146961f, -0.55557023f}, +{-0.83867057f, -0.54463904f}, {-0.84572782f, -0.53361452f}, +{-0.85264016f, -0.52249856f}, {-0.85940641f, -0.51129309f}, +{-0.86602540f, -0.50000000f}, {-0.87249601f, -0.48862124f}, +{-0.87881711f, -0.47715876f}, {-0.88498764f, -0.46561452f}, +{-0.89100652f, -0.45399050f}, {-0.89687274f, -0.44228869f}, +{-0.90258528f, -0.43051110f}, {-0.90814317f, -0.41865974f}, +{-0.91354546f, -0.40673664f}, {-0.91879121f, -0.39474386f}, +{-0.92387953f, -0.38268343f}, {-0.92880955f, -0.37055744f}, +{-0.93358043f, -0.35836795f}, {-0.93819134f, -0.34611706f}, +{-0.94264149f, -0.33380686f}, {-0.94693013f, -0.32143947f}, +{-0.95105652f, -0.30901699f}, {-0.95501994f, -0.29654157f}, +{-0.95881973f, -0.28401534f}, {-0.96245524f, -0.27144045f}, +{-0.96592583f, -0.25881905f}, {-0.96923091f, -0.24615329f}, +{-0.97236992f, -0.23344536f}, {-0.97534232f, -0.22069744f}, +{-0.97814760f, -0.20791169f}, {-0.98078528f, -0.19509032f}, +{-0.98325491f, -0.18223553f}, {-0.98555606f, -0.16934950f}, +{-0.98768834f, -0.15643447f}, {-0.98965139f, -0.14349262f}, +{-0.99144486f, -0.13052619f}, {-0.99306846f, -0.11753740f}, +{-0.99452190f, -0.10452846f}, {-0.99580493f, -0.091501619f}, +{-0.99691733f, -0.078459096f}, {-0.99785892f, -0.065403129f}, +{-0.99862953f, -0.052335956f}, {-0.99922904f, -0.039259816f}, +{-0.99965732f, -0.026176948f}, {-0.99991433f, -0.013089596f}, +{-1.0000000f, -1.2246064e-16f}, {-0.99991433f, 0.013089596f}, +{-0.99965732f, 0.026176948f}, {-0.99922904f, 0.039259816f}, +{-0.99862953f, 0.052335956f}, {-0.99785892f, 0.065403129f}, +{-0.99691733f, 0.078459096f}, {-0.99580493f, 0.091501619f}, +{-0.99452190f, 0.10452846f}, {-0.99306846f, 0.11753740f}, +{-0.99144486f, 0.13052619f}, {-0.98965139f, 0.14349262f}, +{-0.98768834f, 0.15643447f}, {-0.98555606f, 0.16934950f}, +{-0.98325491f, 0.18223553f}, {-0.98078528f, 0.19509032f}, +{-0.97814760f, 0.20791169f}, {-0.97534232f, 0.22069744f}, +{-0.97236992f, 0.23344536f}, {-0.96923091f, 0.24615329f}, +{-0.96592583f, 0.25881905f}, {-0.96245524f, 0.27144045f}, +{-0.95881973f, 0.28401534f}, {-0.95501994f, 0.29654157f}, +{-0.95105652f, 0.30901699f}, {-0.94693013f, 0.32143947f}, +{-0.94264149f, 0.33380686f}, {-0.93819134f, 0.34611706f}, +{-0.93358043f, 0.35836795f}, {-0.92880955f, 0.37055744f}, +{-0.92387953f, 0.38268343f}, {-0.91879121f, 0.39474386f}, +{-0.91354546f, 0.40673664f}, {-0.90814317f, 0.41865974f}, +{-0.90258528f, 0.43051110f}, {-0.89687274f, 0.44228869f}, +{-0.89100652f, 0.45399050f}, {-0.88498764f, 0.46561452f}, +{-0.87881711f, 0.47715876f}, {-0.87249601f, 0.48862124f}, +{-0.86602540f, 0.50000000f}, {-0.85940641f, 0.51129309f}, +{-0.85264016f, 0.52249856f}, {-0.84572782f, 0.53361452f}, +{-0.83867057f, 0.54463904f}, {-0.83146961f, 0.55557023f}, +{-0.82412619f, 0.56640624f}, {-0.81664156f, 0.57714519f}, +{-0.80901699f, 0.58778525f}, {-0.80125381f, 0.59832460f}, +{-0.79335334f, 0.60876143f}, {-0.78531693f, 0.61909395f}, +{-0.77714596f, 0.62932039f}, {-0.76884183f, 0.63943900f}, +{-0.76040597f, 0.64944805f}, {-0.75183981f, 0.65934582f}, +{-0.74314483f, 0.66913061f}, {-0.73432251f, 0.67880075f}, +{-0.72537437f, 0.68835458f}, {-0.71630194f, 0.69779046f}, +{-0.70710678f, 0.70710678f}, {-0.69779046f, 0.71630194f}, +{-0.68835458f, 0.72537437f}, {-0.67880075f, 0.73432251f}, +{-0.66913061f, 0.74314483f}, {-0.65934582f, 0.75183981f}, +{-0.64944805f, 0.76040597f}, {-0.63943900f, 0.76884183f}, +{-0.62932039f, 0.77714596f}, {-0.61909395f, 0.78531693f}, +{-0.60876143f, 0.79335334f}, {-0.59832460f, 0.80125381f}, +{-0.58778525f, 0.80901699f}, {-0.57714519f, 0.81664156f}, +{-0.56640624f, 0.82412619f}, {-0.55557023f, 0.83146961f}, +{-0.54463904f, 0.83867057f}, {-0.53361452f, 0.84572782f}, +{-0.52249856f, 0.85264016f}, {-0.51129309f, 0.85940641f}, +{-0.50000000f, 0.86602540f}, {-0.48862124f, 0.87249601f}, +{-0.47715876f, 0.87881711f}, {-0.46561452f, 0.88498764f}, +{-0.45399050f, 0.89100652f}, {-0.44228869f, 0.89687274f}, +{-0.43051110f, 0.90258528f}, {-0.41865974f, 0.90814317f}, +{-0.40673664f, 0.91354546f}, {-0.39474386f, 0.91879121f}, +{-0.38268343f, 0.92387953f}, {-0.37055744f, 0.92880955f}, +{-0.35836795f, 0.93358043f}, {-0.34611706f, 0.93819134f}, +{-0.33380686f, 0.94264149f}, {-0.32143947f, 0.94693013f}, +{-0.30901699f, 0.95105652f}, {-0.29654157f, 0.95501994f}, +{-0.28401534f, 0.95881973f}, {-0.27144045f, 0.96245524f}, +{-0.25881905f, 0.96592583f}, {-0.24615329f, 0.96923091f}, +{-0.23344536f, 0.97236992f}, {-0.22069744f, 0.97534232f}, +{-0.20791169f, 0.97814760f}, {-0.19509032f, 0.98078528f}, +{-0.18223553f, 0.98325491f}, {-0.16934950f, 0.98555606f}, +{-0.15643447f, 0.98768834f}, {-0.14349262f, 0.98965139f}, +{-0.13052619f, 0.99144486f}, {-0.11753740f, 0.99306846f}, +{-0.10452846f, 0.99452190f}, {-0.091501619f, 0.99580493f}, +{-0.078459096f, 0.99691733f}, {-0.065403129f, 0.99785892f}, +{-0.052335956f, 0.99862953f}, {-0.039259816f, 0.99922904f}, +{-0.026176948f, 0.99965732f}, {-0.013089596f, 0.99991433f}, +{-1.8369095e-16f, 1.0000000f}, {0.013089596f, 0.99991433f}, +{0.026176948f, 0.99965732f}, {0.039259816f, 0.99922904f}, +{0.052335956f, 0.99862953f}, {0.065403129f, 0.99785892f}, +{0.078459096f, 0.99691733f}, {0.091501619f, 0.99580493f}, +{0.10452846f, 0.99452190f}, {0.11753740f, 0.99306846f}, +{0.13052619f, 0.99144486f}, {0.14349262f, 0.98965139f}, +{0.15643447f, 0.98768834f}, {0.16934950f, 0.98555606f}, +{0.18223553f, 0.98325491f}, {0.19509032f, 0.98078528f}, +{0.20791169f, 0.97814760f}, {0.22069744f, 0.97534232f}, +{0.23344536f, 0.97236992f}, {0.24615329f, 0.96923091f}, +{0.25881905f, 0.96592583f}, {0.27144045f, 0.96245524f}, +{0.28401534f, 0.95881973f}, {0.29654157f, 0.95501994f}, +{0.30901699f, 0.95105652f}, {0.32143947f, 0.94693013f}, +{0.33380686f, 0.94264149f}, {0.34611706f, 0.93819134f}, +{0.35836795f, 0.93358043f}, {0.37055744f, 0.92880955f}, +{0.38268343f, 0.92387953f}, {0.39474386f, 0.91879121f}, +{0.40673664f, 0.91354546f}, {0.41865974f, 0.90814317f}, +{0.43051110f, 0.90258528f}, {0.44228869f, 0.89687274f}, +{0.45399050f, 0.89100652f}, {0.46561452f, 0.88498764f}, +{0.47715876f, 0.87881711f}, {0.48862124f, 0.87249601f}, +{0.50000000f, 0.86602540f}, {0.51129309f, 0.85940641f}, +{0.52249856f, 0.85264016f}, {0.53361452f, 0.84572782f}, +{0.54463904f, 0.83867057f}, {0.55557023f, 0.83146961f}, +{0.56640624f, 0.82412619f}, {0.57714519f, 0.81664156f}, +{0.58778525f, 0.80901699f}, {0.59832460f, 0.80125381f}, +{0.60876143f, 0.79335334f}, {0.61909395f, 0.78531693f}, +{0.62932039f, 0.77714596f}, {0.63943900f, 0.76884183f}, +{0.64944805f, 0.76040597f}, {0.65934582f, 0.75183981f}, +{0.66913061f, 0.74314483f}, {0.67880075f, 0.73432251f}, +{0.68835458f, 0.72537437f}, {0.69779046f, 0.71630194f}, +{0.70710678f, 0.70710678f}, {0.71630194f, 0.69779046f}, +{0.72537437f, 0.68835458f}, {0.73432251f, 0.67880075f}, +{0.74314483f, 0.66913061f}, {0.75183981f, 0.65934582f}, +{0.76040597f, 0.64944805f}, {0.76884183f, 0.63943900f}, +{0.77714596f, 0.62932039f}, {0.78531693f, 0.61909395f}, +{0.79335334f, 0.60876143f}, {0.80125381f, 0.59832460f}, +{0.80901699f, 0.58778525f}, {0.81664156f, 0.57714519f}, +{0.82412619f, 0.56640624f}, {0.83146961f, 0.55557023f}, +{0.83867057f, 0.54463904f}, {0.84572782f, 0.53361452f}, +{0.85264016f, 0.52249856f}, {0.85940641f, 0.51129309f}, +{0.86602540f, 0.50000000f}, {0.87249601f, 0.48862124f}, +{0.87881711f, 0.47715876f}, {0.88498764f, 0.46561452f}, +{0.89100652f, 0.45399050f}, {0.89687274f, 0.44228869f}, +{0.90258528f, 0.43051110f}, {0.90814317f, 0.41865974f}, +{0.91354546f, 0.40673664f}, {0.91879121f, 0.39474386f}, +{0.92387953f, 0.38268343f}, {0.92880955f, 0.37055744f}, +{0.93358043f, 0.35836795f}, {0.93819134f, 0.34611706f}, +{0.94264149f, 0.33380686f}, {0.94693013f, 0.32143947f}, +{0.95105652f, 0.30901699f}, {0.95501994f, 0.29654157f}, +{0.95881973f, 0.28401534f}, {0.96245524f, 0.27144045f}, +{0.96592583f, 0.25881905f}, {0.96923091f, 0.24615329f}, +{0.97236992f, 0.23344536f}, {0.97534232f, 0.22069744f}, +{0.97814760f, 0.20791169f}, {0.98078528f, 0.19509032f}, +{0.98325491f, 0.18223553f}, {0.98555606f, 0.16934950f}, +{0.98768834f, 0.15643447f}, {0.98965139f, 0.14349262f}, +{0.99144486f, 0.13052619f}, {0.99306846f, 0.11753740f}, +{0.99452190f, 0.10452846f}, {0.99580493f, 0.091501619f}, +{0.99691733f, 0.078459096f}, {0.99785892f, 0.065403129f}, +{0.99862953f, 0.052335956f}, {0.99922904f, 0.039259816f}, +{0.99965732f, 0.026176948f}, {0.99991433f, 0.013089596f}, +}; +#ifndef FFT_BITREV480 +#define FFT_BITREV480 +static const opus_int16 fft_bitrev480[480] = { +0, 96, 192, 288, 384, 32, 128, 224, 320, 416, 64, 160, 256, 352, 448, +8, 104, 200, 296, 392, 40, 136, 232, 328, 424, 72, 168, 264, 360, 456, +16, 112, 208, 304, 400, 48, 144, 240, 336, 432, 80, 176, 272, 368, 464, +24, 120, 216, 312, 408, 56, 152, 248, 344, 440, 88, 184, 280, 376, 472, +4, 100, 196, 292, 388, 36, 132, 228, 324, 420, 68, 164, 260, 356, 452, +12, 108, 204, 300, 396, 44, 140, 236, 332, 428, 76, 172, 268, 364, 460, +20, 116, 212, 308, 404, 52, 148, 244, 340, 436, 84, 180, 276, 372, 468, +28, 124, 220, 316, 412, 60, 156, 252, 348, 444, 92, 188, 284, 380, 476, +1, 97, 193, 289, 385, 33, 129, 225, 321, 417, 65, 161, 257, 353, 449, +9, 105, 201, 297, 393, 41, 137, 233, 329, 425, 73, 169, 265, 361, 457, +17, 113, 209, 305, 401, 49, 145, 241, 337, 433, 81, 177, 273, 369, 465, +25, 121, 217, 313, 409, 57, 153, 249, 345, 441, 89, 185, 281, 377, 473, +5, 101, 197, 293, 389, 37, 133, 229, 325, 421, 69, 165, 261, 357, 453, +13, 109, 205, 301, 397, 45, 141, 237, 333, 429, 77, 173, 269, 365, 461, +21, 117, 213, 309, 405, 53, 149, 245, 341, 437, 85, 181, 277, 373, 469, +29, 125, 221, 317, 413, 61, 157, 253, 349, 445, 93, 189, 285, 381, 477, +2, 98, 194, 290, 386, 34, 130, 226, 322, 418, 66, 162, 258, 354, 450, +10, 106, 202, 298, 394, 42, 138, 234, 330, 426, 74, 170, 266, 362, 458, +18, 114, 210, 306, 402, 50, 146, 242, 338, 434, 82, 178, 274, 370, 466, +26, 122, 218, 314, 410, 58, 154, 250, 346, 442, 90, 186, 282, 378, 474, +6, 102, 198, 294, 390, 38, 134, 230, 326, 422, 70, 166, 262, 358, 454, +14, 110, 206, 302, 398, 46, 142, 238, 334, 430, 78, 174, 270, 366, 462, +22, 118, 214, 310, 406, 54, 150, 246, 342, 438, 86, 182, 278, 374, 470, +30, 126, 222, 318, 414, 62, 158, 254, 350, 446, 94, 190, 286, 382, 478, +3, 99, 195, 291, 387, 35, 131, 227, 323, 419, 67, 163, 259, 355, 451, +11, 107, 203, 299, 395, 43, 139, 235, 331, 427, 75, 171, 267, 363, 459, +19, 115, 211, 307, 403, 51, 147, 243, 339, 435, 83, 179, 275, 371, 467, +27, 123, 219, 315, 411, 59, 155, 251, 347, 443, 91, 187, 283, 379, 475, +7, 103, 199, 295, 391, 39, 135, 231, 327, 423, 71, 167, 263, 359, 455, +15, 111, 207, 303, 399, 47, 143, 239, 335, 431, 79, 175, 271, 367, 463, +23, 119, 215, 311, 407, 55, 151, 247, 343, 439, 87, 183, 279, 375, 471, +31, 127, 223, 319, 415, 63, 159, 255, 351, 447, 95, 191, 287, 383, 479, +}; +#endif + +#ifndef FFT_BITREV240 +#define FFT_BITREV240 +static const opus_int16 fft_bitrev240[240] = { +0, 48, 96, 144, 192, 16, 64, 112, 160, 208, 32, 80, 128, 176, 224, +4, 52, 100, 148, 196, 20, 68, 116, 164, 212, 36, 84, 132, 180, 228, +8, 56, 104, 152, 200, 24, 72, 120, 168, 216, 40, 88, 136, 184, 232, +12, 60, 108, 156, 204, 28, 76, 124, 172, 220, 44, 92, 140, 188, 236, +1, 49, 97, 145, 193, 17, 65, 113, 161, 209, 33, 81, 129, 177, 225, +5, 53, 101, 149, 197, 21, 69, 117, 165, 213, 37, 85, 133, 181, 229, +9, 57, 105, 153, 201, 25, 73, 121, 169, 217, 41, 89, 137, 185, 233, +13, 61, 109, 157, 205, 29, 77, 125, 173, 221, 45, 93, 141, 189, 237, +2, 50, 98, 146, 194, 18, 66, 114, 162, 210, 34, 82, 130, 178, 226, +6, 54, 102, 150, 198, 22, 70, 118, 166, 214, 38, 86, 134, 182, 230, +10, 58, 106, 154, 202, 26, 74, 122, 170, 218, 42, 90, 138, 186, 234, +14, 62, 110, 158, 206, 30, 78, 126, 174, 222, 46, 94, 142, 190, 238, +3, 51, 99, 147, 195, 19, 67, 115, 163, 211, 35, 83, 131, 179, 227, +7, 55, 103, 151, 199, 23, 71, 119, 167, 215, 39, 87, 135, 183, 231, +11, 59, 107, 155, 203, 27, 75, 123, 171, 219, 43, 91, 139, 187, 235, +15, 63, 111, 159, 207, 31, 79, 127, 175, 223, 47, 95, 143, 191, 239, +}; +#endif + +#ifndef FFT_BITREV120 +#define FFT_BITREV120 +static const opus_int16 fft_bitrev120[120] = { +0, 24, 48, 72, 96, 8, 32, 56, 80, 104, 16, 40, 64, 88, 112, +4, 28, 52, 76, 100, 12, 36, 60, 84, 108, 20, 44, 68, 92, 116, +1, 25, 49, 73, 97, 9, 33, 57, 81, 105, 17, 41, 65, 89, 113, +5, 29, 53, 77, 101, 13, 37, 61, 85, 109, 21, 45, 69, 93, 117, +2, 26, 50, 74, 98, 10, 34, 58, 82, 106, 18, 42, 66, 90, 114, +6, 30, 54, 78, 102, 14, 38, 62, 86, 110, 22, 46, 70, 94, 118, +3, 27, 51, 75, 99, 11, 35, 59, 83, 107, 19, 43, 67, 91, 115, +7, 31, 55, 79, 103, 15, 39, 63, 87, 111, 23, 47, 71, 95, 119, +}; +#endif + +#ifndef FFT_BITREV60 +#define FFT_BITREV60 +static const opus_int16 fft_bitrev60[60] = { +0, 12, 24, 36, 48, 4, 16, 28, 40, 52, 8, 20, 32, 44, 56, +1, 13, 25, 37, 49, 5, 17, 29, 41, 53, 9, 21, 33, 45, 57, +2, 14, 26, 38, 50, 6, 18, 30, 42, 54, 10, 22, 34, 46, 58, +3, 15, 27, 39, 51, 7, 19, 31, 43, 55, 11, 23, 35, 47, 59, +}; +#endif + +#ifndef FFT_STATE48000_960_0 +#define FFT_STATE48000_960_0 +static const kiss_fft_state fft_state48000_960_0 = { +480, /* nfft */ +0.002083333f, /* scale */ +-1, /* shift */ +{5, 96, 3, 32, 4, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev480, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_480, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_1 +#define FFT_STATE48000_960_1 +static const kiss_fft_state fft_state48000_960_1 = { +240, /* nfft */ +0.004166667f, /* scale */ +1, /* shift */ +{5, 48, 3, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev240, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_240, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_2 +#define FFT_STATE48000_960_2 +static const kiss_fft_state fft_state48000_960_2 = { +120, /* nfft */ +0.008333333f, /* scale */ +2, /* shift */ +{5, 24, 3, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev120, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_120, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_3 +#define FFT_STATE48000_960_3 +static const kiss_fft_state fft_state48000_960_3 = { +60, /* nfft */ +0.016666667f, /* scale */ +3, /* shift */ +{5, 12, 3, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev60, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_60, +#else +NULL, +#endif +}; +#endif + +#endif + +#ifndef MDCT_TWIDDLES960 +#define MDCT_TWIDDLES960 +static const opus_val16 mdct_twiddles960[1800] = { +0.99999994f, 0.99999321f, 0.99997580f, 0.99994773f, 0.99990886f, +0.99985933f, 0.99979913f, 0.99972820f, 0.99964654f, 0.99955416f, +0.99945110f, 0.99933738f, 0.99921292f, 0.99907774f, 0.99893188f, +0.99877530f, 0.99860805f, 0.99843007f, 0.99824142f, 0.99804211f, +0.99783206f, 0.99761140f, 0.99737996f, 0.99713790f, 0.99688518f, +0.99662173f, 0.99634761f, 0.99606287f, 0.99576741f, 0.99546129f, +0.99514455f, 0.99481714f, 0.99447906f, 0.99413031f, 0.99377096f, +0.99340093f, 0.99302030f, 0.99262899f, 0.99222708f, 0.99181455f, +0.99139136f, 0.99095762f, 0.99051321f, 0.99005818f, 0.98959261f, +0.98911643f, 0.98862964f, 0.98813224f, 0.98762429f, 0.98710573f, +0.98657662f, 0.98603696f, 0.98548669f, 0.98492593f, 0.98435456f, +0.98377270f, 0.98318028f, 0.98257732f, 0.98196387f, 0.98133987f, +0.98070538f, 0.98006040f, 0.97940493f, 0.97873890f, 0.97806245f, +0.97737551f, 0.97667813f, 0.97597027f, 0.97525197f, 0.97452319f, +0.97378403f, 0.97303438f, 0.97227436f, 0.97150391f, 0.97072303f, +0.96993178f, 0.96913016f, 0.96831810f, 0.96749574f, 0.96666300f, +0.96581990f, 0.96496642f, 0.96410263f, 0.96322852f, 0.96234411f, +0.96144938f, 0.96054435f, 0.95962906f, 0.95870346f, 0.95776761f, +0.95682150f, 0.95586514f, 0.95489854f, 0.95392174f, 0.95293468f, +0.95193744f, 0.95093000f, 0.94991243f, 0.94888461f, 0.94784665f, +0.94679856f, 0.94574034f, 0.94467193f, 0.94359344f, 0.94250488f, +0.94140619f, 0.94029742f, 0.93917859f, 0.93804967f, 0.93691075f, +0.93576175f, 0.93460274f, 0.93343377f, 0.93225473f, 0.93106574f, +0.92986679f, 0.92865789f, 0.92743903f, 0.92621022f, 0.92497152f, +0.92372292f, 0.92246443f, 0.92119598f, 0.91991776f, 0.91862965f, +0.91733170f, 0.91602397f, 0.91470635f, 0.91337901f, 0.91204184f, +0.91069490f, 0.90933824f, 0.90797186f, 0.90659571f, 0.90520984f, +0.90381432f, 0.90240908f, 0.90099424f, 0.89956969f, 0.89813554f, +0.89669174f, 0.89523834f, 0.89377540f, 0.89230281f, 0.89082074f, +0.88932908f, 0.88782793f, 0.88631725f, 0.88479710f, 0.88326746f, +0.88172835f, 0.88017982f, 0.87862182f, 0.87705445f, 0.87547767f, +0.87389153f, 0.87229604f, 0.87069118f, 0.86907703f, 0.86745358f, +0.86582077f, 0.86417878f, 0.86252749f, 0.86086690f, 0.85919720f, +0.85751826f, 0.85583007f, 0.85413277f, 0.85242635f, 0.85071075f, +0.84898609f, 0.84725231f, 0.84550947f, 0.84375757f, 0.84199661f, +0.84022665f, 0.83844769f, 0.83665979f, 0.83486289f, 0.83305705f, +0.83124226f, 0.82941860f, 0.82758605f, 0.82574469f, 0.82389444f, +0.82203537f, 0.82016748f, 0.81829083f, 0.81640542f, 0.81451124f, +0.81260836f, 0.81069672f, 0.80877650f, 0.80684757f, 0.80490994f, +0.80296379f, 0.80100900f, 0.79904562f, 0.79707366f, 0.79509324f, +0.79310423f, 0.79110676f, 0.78910083f, 0.78708643f, 0.78506362f, +0.78303236f, 0.78099275f, 0.77894479f, 0.77688843f, 0.77482378f, +0.77275085f, 0.77066964f, 0.76858020f, 0.76648247f, 0.76437658f, +0.76226246f, 0.76014024f, 0.75800985f, 0.75587130f, 0.75372469f, +0.75157005f, 0.74940729f, 0.74723655f, 0.74505776f, 0.74287105f, +0.74067634f, 0.73847371f, 0.73626316f, 0.73404479f, 0.73181850f, +0.72958434f, 0.72734243f, 0.72509271f, 0.72283524f, 0.72057003f, +0.71829706f, 0.71601641f, 0.71372813f, 0.71143216f, 0.70912862f, +0.70681745f, 0.70449871f, 0.70217246f, 0.69983864f, 0.69749737f, +0.69514859f, 0.69279242f, 0.69042879f, 0.68805778f, 0.68567938f, +0.68329364f, 0.68090063f, 0.67850029f, 0.67609268f, 0.67367786f, +0.67125577f, 0.66882652f, 0.66639012f, 0.66394657f, 0.66149592f, +0.65903819f, 0.65657341f, 0.65410155f, 0.65162271f, 0.64913690f, +0.64664418f, 0.64414448f, 0.64163786f, 0.63912445f, 0.63660413f, +0.63407701f, 0.63154310f, 0.62900239f, 0.62645501f, 0.62390089f, +0.62134010f, 0.61877263f, 0.61619854f, 0.61361790f, 0.61103064f, +0.60843682f, 0.60583651f, 0.60322970f, 0.60061646f, 0.59799677f, +0.59537065f, 0.59273821f, 0.59009939f, 0.58745426f, 0.58480281f, +0.58214509f, 0.57948118f, 0.57681108f, 0.57413477f, 0.57145232f, +0.56876373f, 0.56606907f, 0.56336832f, 0.56066155f, 0.55794877f, +0.55523002f, 0.55250537f, 0.54977477f, 0.54703826f, 0.54429591f, +0.54154772f, 0.53879374f, 0.53603399f, 0.53326851f, 0.53049731f, +0.52772039f, 0.52493787f, 0.52214974f, 0.51935595f, 0.51655668f, +0.51375180f, 0.51094145f, 0.50812566f, 0.50530440f, 0.50247771f, +0.49964568f, 0.49680826f, 0.49396557f, 0.49111754f, 0.48826426f, +0.48540577f, 0.48254207f, 0.47967321f, 0.47679919f, 0.47392011f, +0.47103590f, 0.46814668f, 0.46525243f, 0.46235323f, 0.45944905f, +0.45653993f, 0.45362595f, 0.45070711f, 0.44778344f, 0.44485497f, +0.44192174f, 0.43898380f, 0.43604112f, 0.43309379f, 0.43014181f, +0.42718524f, 0.42422408f, 0.42125839f, 0.41828820f, 0.41531351f, +0.41233435f, 0.40935081f, 0.40636289f, 0.40337059f, 0.40037400f, +0.39737311f, 0.39436796f, 0.39135858f, 0.38834500f, 0.38532731f, +0.38230544f, 0.37927949f, 0.37624949f, 0.37321547f, 0.37017745f, +0.36713544f, 0.36408952f, 0.36103970f, 0.35798600f, 0.35492846f, +0.35186714f, 0.34880206f, 0.34573323f, 0.34266070f, 0.33958447f, +0.33650464f, 0.33342120f, 0.33033419f, 0.32724363f, 0.32414958f, +0.32105204f, 0.31795108f, 0.31484672f, 0.31173897f, 0.30862790f, +0.30551350f, 0.30239585f, 0.29927495f, 0.29615086f, 0.29302359f, +0.28989318f, 0.28675964f, 0.28362307f, 0.28048345f, 0.27734083f, +0.27419522f, 0.27104670f, 0.26789525f, 0.26474094f, 0.26158381f, +0.25842386f, 0.25526115f, 0.25209570f, 0.24892756f, 0.24575676f, +0.24258332f, 0.23940729f, 0.23622867f, 0.23304754f, 0.22986393f, +0.22667783f, 0.22348931f, 0.22029841f, 0.21710514f, 0.21390954f, +0.21071166f, 0.20751151f, 0.20430915f, 0.20110460f, 0.19789790f, +0.19468907f, 0.19147816f, 0.18826519f, 0.18505022f, 0.18183327f, +0.17861435f, 0.17539354f, 0.17217083f, 0.16894630f, 0.16571994f, +0.16249183f, 0.15926196f, 0.15603039f, 0.15279715f, 0.14956227f, +0.14632578f, 0.14308774f, 0.13984816f, 0.13660708f, 0.13336454f, +0.13012058f, 0.12687522f, 0.12362850f, 0.12038045f, 0.11713112f, +0.11388054f, 0.11062872f, 0.10737573f, 0.10412160f, 0.10086634f, +0.097609997f, 0.094352618f, 0.091094226f, 0.087834857f, 0.084574550f, +0.081313334f, 0.078051247f, 0.074788325f, 0.071524605f, 0.068260118f, +0.064994894f, 0.061728980f, 0.058462404f, 0.055195201f, 0.051927410f, +0.048659060f, 0.045390189f, 0.042120833f, 0.038851023f, 0.035580799f, +0.032310195f, 0.029039243f, 0.025767982f, 0.022496443f, 0.019224664f, +0.015952680f, 0.012680525f, 0.0094082337f, 0.0061358409f, 0.0028633832f, +-0.00040910527f, -0.0036815894f, -0.0069540343f, -0.010226404f, -0.013498665f, +-0.016770782f, -0.020042717f, -0.023314439f, -0.026585912f, -0.029857099f, +-0.033127967f, -0.036398482f, -0.039668605f, -0.042938303f, -0.046207540f, +-0.049476285f, -0.052744497f, -0.056012146f, -0.059279196f, -0.062545612f, +-0.065811358f, -0.069076397f, -0.072340697f, -0.075604223f, -0.078866936f, +-0.082128808f, -0.085389800f, -0.088649876f, -0.091909006f, -0.095167145f, +-0.098424271f, -0.10168034f, -0.10493532f, -0.10818918f, -0.11144188f, +-0.11469338f, -0.11794366f, -0.12119267f, -0.12444039f, -0.12768677f, +-0.13093179f, -0.13417540f, -0.13741758f, -0.14065829f, -0.14389749f, +-0.14713514f, -0.15037122f, -0.15360570f, -0.15683852f, -0.16006967f, +-0.16329910f, -0.16652679f, -0.16975269f, -0.17297678f, -0.17619900f, +-0.17941935f, -0.18263777f, -0.18585424f, -0.18906870f, -0.19228116f, +-0.19549155f, -0.19869985f, -0.20190603f, -0.20511003f, -0.20831184f, +-0.21151142f, -0.21470875f, -0.21790376f, -0.22109644f, -0.22428675f, +-0.22747467f, -0.23066014f, -0.23384315f, -0.23702365f, -0.24020162f, +-0.24337701f, -0.24654980f, -0.24971995f, -0.25288740f, -0.25605217f, +-0.25921419f, -0.26237345f, -0.26552987f, -0.26868346f, -0.27183419f, +-0.27498198f, -0.27812684f, -0.28126872f, -0.28440759f, -0.28754342f, +-0.29067615f, -0.29380578f, -0.29693225f, -0.30005556f, -0.30317566f, +-0.30629250f, -0.30940607f, -0.31251630f, -0.31562322f, -0.31872672f, +-0.32182685f, -0.32492352f, -0.32801670f, -0.33110636f, -0.33419248f, +-0.33727503f, -0.34035397f, -0.34342924f, -0.34650084f, -0.34956875f, +-0.35263291f, -0.35569328f, -0.35874987f, -0.36180258f, -0.36485144f, +-0.36789638f, -0.37093741f, -0.37397444f, -0.37700745f, -0.38003644f, +-0.38306138f, -0.38608220f, -0.38909888f, -0.39211139f, -0.39511973f, +-0.39812380f, -0.40112361f, -0.40411916f, -0.40711036f, -0.41009718f, +-0.41307965f, -0.41605768f, -0.41903123f, -0.42200032f, -0.42496487f, +-0.42792490f, -0.43088034f, -0.43383113f, -0.43677729f, -0.43971881f, +-0.44265559f, -0.44558764f, -0.44851488f, -0.45143735f, -0.45435500f, +-0.45726776f, -0.46017563f, -0.46307856f, -0.46597654f, -0.46886954f, +-0.47175750f, -0.47464043f, -0.47751826f, -0.48039100f, -0.48325855f, +-0.48612097f, -0.48897815f, -0.49183011f, -0.49467680f, -0.49751821f, +-0.50035429f, -0.50318497f, -0.50601029f, -0.50883019f, -0.51164466f, +-0.51445359f, -0.51725709f, -0.52005500f, -0.52284735f, -0.52563411f, +-0.52841520f, -0.53119069f, -0.53396046f, -0.53672451f, -0.53948283f, +-0.54223537f, -0.54498214f, -0.54772300f, -0.55045801f, -0.55318713f, +-0.55591035f, -0.55862761f, -0.56133890f, -0.56404412f, -0.56674337f, +-0.56943649f, -0.57212353f, -0.57480448f, -0.57747924f, -0.58014780f, +-0.58281022f, -0.58546633f, -0.58811617f, -0.59075975f, -0.59339696f, +-0.59602785f, -0.59865236f, -0.60127044f, -0.60388207f, -0.60648727f, +-0.60908598f, -0.61167812f, -0.61426371f, -0.61684275f, -0.61941516f, +-0.62198097f, -0.62454009f, -0.62709254f, -0.62963831f, -0.63217729f, +-0.63470948f, -0.63723493f, -0.63975352f, -0.64226526f, -0.64477009f, +-0.64726806f, -0.64975911f, -0.65224314f, -0.65472025f, -0.65719032f, +-0.65965337f, -0.66210932f, -0.66455823f, -0.66700000f, -0.66943461f, +-0.67186207f, -0.67428231f, -0.67669535f, -0.67910111f, -0.68149966f, +-0.68389088f, -0.68627477f, -0.68865126f, -0.69102043f, -0.69338220f, +-0.69573659f, -0.69808346f, -0.70042288f, -0.70275480f, -0.70507920f, +-0.70739603f, -0.70970529f, -0.71200693f, -0.71430099f, -0.71658736f, +-0.71886611f, -0.72113711f, -0.72340041f, -0.72565591f, -0.72790372f, +-0.73014367f, -0.73237586f, -0.73460019f, -0.73681659f, -0.73902518f, +-0.74122584f, -0.74341851f, -0.74560326f, -0.74778003f, -0.74994880f, +-0.75210953f, -0.75426215f, -0.75640678f, -0.75854325f, -0.76067162f, +-0.76279181f, -0.76490390f, -0.76700771f, -0.76910341f, -0.77119076f, +-0.77326995f, -0.77534080f, -0.77740335f, -0.77945763f, -0.78150350f, +-0.78354102f, -0.78557014f, -0.78759086f, -0.78960317f, -0.79160696f, +-0.79360235f, -0.79558921f, -0.79756755f, -0.79953730f, -0.80149853f, +-0.80345118f, -0.80539525f, -0.80733067f, -0.80925739f, -0.81117553f, +-0.81308490f, -0.81498563f, -0.81687760f, -0.81876087f, -0.82063532f, +-0.82250100f, -0.82435787f, -0.82620591f, -0.82804507f, -0.82987541f, +-0.83169687f, -0.83350939f, -0.83531296f, -0.83710766f, -0.83889335f, +-0.84067005f, -0.84243774f, -0.84419644f, -0.84594607f, -0.84768665f, +-0.84941816f, -0.85114056f, -0.85285389f, -0.85455805f, -0.85625303f, +-0.85793889f, -0.85961550f, -0.86128294f, -0.86294121f, -0.86459017f, +-0.86622989f, -0.86786032f, -0.86948150f, -0.87109333f, -0.87269586f, +-0.87428904f, -0.87587279f, -0.87744725f, -0.87901229f, -0.88056785f, +-0.88211405f, -0.88365078f, -0.88517809f, -0.88669586f, -0.88820416f, +-0.88970292f, -0.89119220f, -0.89267188f, -0.89414203f, -0.89560264f, +-0.89705360f, -0.89849502f, -0.89992678f, -0.90134889f, -0.90276134f, +-0.90416414f, -0.90555727f, -0.90694070f, -0.90831441f, -0.90967834f, +-0.91103262f, -0.91237706f, -0.91371179f, -0.91503674f, -0.91635185f, +-0.91765714f, -0.91895264f, -0.92023826f, -0.92151409f, -0.92277998f, +-0.92403603f, -0.92528218f, -0.92651838f, -0.92774469f, -0.92896110f, +-0.93016750f, -0.93136400f, -0.93255049f, -0.93372697f, -0.93489349f, +-0.93604994f, -0.93719643f, -0.93833286f, -0.93945926f, -0.94057560f, +-0.94168180f, -0.94277799f, -0.94386405f, -0.94494003f, -0.94600588f, +-0.94706154f, -0.94810712f, -0.94914252f, -0.95016778f, -0.95118284f, +-0.95218778f, -0.95318246f, -0.95416695f, -0.95514119f, -0.95610523f, +-0.95705903f, -0.95800257f, -0.95893586f, -0.95985889f, -0.96077162f, +-0.96167403f, -0.96256620f, -0.96344805f, -0.96431959f, -0.96518075f, +-0.96603161f, -0.96687216f, -0.96770233f, -0.96852213f, -0.96933156f, +-0.97013056f, -0.97091925f, -0.97169751f, -0.97246534f, -0.97322279f, +-0.97396982f, -0.97470641f, -0.97543252f, -0.97614825f, -0.97685349f, +-0.97754824f, -0.97823256f, -0.97890645f, -0.97956979f, -0.98022264f, +-0.98086500f, -0.98149687f, -0.98211825f, -0.98272908f, -0.98332942f, +-0.98391914f, -0.98449844f, -0.98506713f, -0.98562527f, -0.98617285f, +-0.98670989f, -0.98723638f, -0.98775226f, -0.98825759f, -0.98875231f, +-0.98923647f, -0.98971003f, -0.99017298f, -0.99062532f, -0.99106705f, +-0.99149817f, -0.99191868f, -0.99232858f, -0.99272782f, -0.99311644f, +-0.99349445f, -0.99386179f, -0.99421853f, -0.99456459f, -0.99489999f, +-0.99522477f, -0.99553883f, -0.99584228f, -0.99613506f, -0.99641716f, +-0.99668860f, -0.99694937f, -0.99719942f, -0.99743885f, -0.99766755f, +-0.99788558f, -0.99809295f, -0.99828959f, -0.99847561f, -0.99865085f, +-0.99881548f, -0.99896932f, -0.99911255f, -0.99924499f, -0.99936682f, +-0.99947786f, -0.99957830f, -0.99966794f, -0.99974692f, -0.99981517f, +-0.99987274f, -0.99991959f, -0.99995571f, -0.99998116f, -0.99999589f, +0.99999964f, 0.99997288f, 0.99990326f, 0.99979085f, 0.99963558f, +0.99943751f, 0.99919659f, 0.99891287f, 0.99858636f, 0.99821711f, +0.99780506f, 0.99735034f, 0.99685282f, 0.99631262f, 0.99572974f, +0.99510419f, 0.99443603f, 0.99372530f, 0.99297196f, 0.99217612f, +0.99133772f, 0.99045694f, 0.98953366f, 0.98856801f, 0.98756003f, +0.98650974f, 0.98541719f, 0.98428243f, 0.98310548f, 0.98188645f, +0.98062533f, 0.97932225f, 0.97797716f, 0.97659022f, 0.97516143f, +0.97369087f, 0.97217858f, 0.97062469f, 0.96902919f, 0.96739221f, +0.96571374f, 0.96399397f, 0.96223283f, 0.96043050f, 0.95858705f, +0.95670253f, 0.95477700f, 0.95281059f, 0.95080340f, 0.94875544f, +0.94666684f, 0.94453770f, 0.94236809f, 0.94015813f, 0.93790787f, +0.93561745f, 0.93328691f, 0.93091643f, 0.92850608f, 0.92605597f, +0.92356616f, 0.92103678f, 0.91846794f, 0.91585976f, 0.91321236f, +0.91052586f, 0.90780038f, 0.90503591f, 0.90223277f, 0.89939094f, +0.89651060f, 0.89359182f, 0.89063478f, 0.88763964f, 0.88460642f, +0.88153529f, 0.87842643f, 0.87527996f, 0.87209594f, 0.86887461f, +0.86561602f, 0.86232042f, 0.85898781f, 0.85561842f, 0.85221243f, +0.84876984f, 0.84529096f, 0.84177583f, 0.83822471f, 0.83463764f, +0.83101481f, 0.82735640f, 0.82366252f, 0.81993335f, 0.81616908f, +0.81236988f, 0.80853581f, 0.80466717f, 0.80076402f, 0.79682660f, +0.79285502f, 0.78884947f, 0.78481019f, 0.78073722f, 0.77663082f, +0.77249116f, 0.76831841f, 0.76411277f, 0.75987434f, 0.75560343f, +0.75130010f, 0.74696463f, 0.74259710f, 0.73819780f, 0.73376691f, +0.72930455f, 0.72481096f, 0.72028631f, 0.71573079f, 0.71114463f, +0.70652801f, 0.70188117f, 0.69720417f, 0.69249737f, 0.68776089f, +0.68299496f, 0.67819971f, 0.67337549f, 0.66852236f, 0.66364062f, +0.65873051f, 0.65379208f, 0.64882571f, 0.64383155f, 0.63880974f, +0.63376063f, 0.62868434f, 0.62358117f, 0.61845124f, 0.61329484f, +0.60811216f, 0.60290343f, 0.59766883f, 0.59240872f, 0.58712316f, +0.58181250f, 0.57647687f, 0.57111657f, 0.56573176f, 0.56032276f, +0.55488980f, 0.54943299f, 0.54395270f, 0.53844911f, 0.53292239f, +0.52737290f, 0.52180082f, 0.51620632f, 0.51058978f, 0.50495136f, +0.49929130f, 0.49360985f, 0.48790723f, 0.48218375f, 0.47643960f, +0.47067502f, 0.46489030f, 0.45908567f, 0.45326138f, 0.44741765f, +0.44155475f, 0.43567297f, 0.42977250f, 0.42385364f, 0.41791660f, +0.41196167f, 0.40598908f, 0.39999911f, 0.39399201f, 0.38796803f, +0.38192743f, 0.37587047f, 0.36979741f, 0.36370850f, 0.35760403f, +0.35148421f, 0.34534934f, 0.33919969f, 0.33303553f, 0.32685706f, +0.32066461f, 0.31445843f, 0.30823877f, 0.30200592f, 0.29576012f, +0.28950164f, 0.28323078f, 0.27694780f, 0.27065292f, 0.26434645f, +0.25802869f, 0.25169984f, 0.24536023f, 0.23901010f, 0.23264973f, +0.22627939f, 0.21989937f, 0.21350993f, 0.20711134f, 0.20070387f, +0.19428782f, 0.18786344f, 0.18143101f, 0.17499080f, 0.16854310f, +0.16208819f, 0.15562633f, 0.14915779f, 0.14268288f, 0.13620184f, +0.12971498f, 0.12322257f, 0.11672486f, 0.11022217f, 0.10371475f, +0.097202882f, 0.090686858f, 0.084166944f, 0.077643424f, 0.071116582f, +0.064586692f, 0.058054037f, 0.051518895f, 0.044981543f, 0.038442269f, +0.031901345f, 0.025359053f, 0.018815678f, 0.012271495f, 0.0057267868f, +-0.00081816671f, -0.0073630852f, -0.013907688f, -0.020451695f, -0.026994826f, +-0.033536803f, -0.040077340f, -0.046616159f, -0.053152986f, -0.059687532f, +-0.066219524f, -0.072748676f, -0.079274714f, -0.085797355f, -0.092316322f, +-0.098831341f, -0.10534211f, -0.11184838f, -0.11834986f, -0.12484626f, +-0.13133731f, -0.13782275f, -0.14430228f, -0.15077563f, -0.15724251f, +-0.16370267f, -0.17015581f, -0.17660165f, -0.18303993f, -0.18947038f, +-0.19589271f, -0.20230664f, -0.20871192f, -0.21510825f, -0.22149536f, +-0.22787298f, -0.23424086f, -0.24059868f, -0.24694622f, -0.25328314f, +-0.25960925f, -0.26592422f, -0.27222782f, -0.27851975f, -0.28479972f, +-0.29106751f, -0.29732284f, -0.30356544f, -0.30979502f, -0.31601134f, +-0.32221413f, -0.32840309f, -0.33457801f, -0.34073856f, -0.34688455f, +-0.35301566f, -0.35913166f, -0.36523229f, -0.37131724f, -0.37738630f, +-0.38343921f, -0.38947567f, -0.39549544f, -0.40149832f, -0.40748394f, +-0.41345215f, -0.41940263f, -0.42533514f, -0.43124944f, -0.43714526f, +-0.44302234f, -0.44888046f, -0.45471936f, -0.46053877f, -0.46633846f, +-0.47211814f, -0.47787762f, -0.48361665f, -0.48933494f, -0.49503228f, +-0.50070840f, -0.50636309f, -0.51199609f, -0.51760709f, -0.52319598f, +-0.52876246f, -0.53430629f, -0.53982723f, -0.54532504f, -0.55079949f, +-0.55625033f, -0.56167740f, -0.56708032f, -0.57245898f, -0.57781315f, +-0.58314258f, -0.58844697f, -0.59372622f, -0.59897995f, -0.60420811f, +-0.60941035f, -0.61458647f, -0.61973625f, -0.62485951f, -0.62995601f, +-0.63502556f, -0.64006782f, -0.64508271f, -0.65007001f, -0.65502942f, +-0.65996075f, -0.66486382f, -0.66973841f, -0.67458433f, -0.67940134f, +-0.68418926f, -0.68894786f, -0.69367695f, -0.69837630f, -0.70304573f, +-0.70768511f, -0.71229410f, -0.71687263f, -0.72142041f, -0.72593731f, +-0.73042315f, -0.73487765f, -0.73930067f, -0.74369204f, -0.74805158f, +-0.75237900f, -0.75667429f, -0.76093709f, -0.76516730f, -0.76936477f, +-0.77352923f, -0.77766061f, -0.78175867f, -0.78582323f, -0.78985411f, +-0.79385114f, -0.79781419f, -0.80174309f, -0.80563760f, -0.80949765f, +-0.81332302f, -0.81711352f, -0.82086903f, -0.82458937f, -0.82827437f, +-0.83192390f, -0.83553779f, -0.83911592f, -0.84265804f, -0.84616417f, +-0.84963393f, -0.85306740f, -0.85646427f, -0.85982448f, -0.86314780f, +-0.86643422f, -0.86968350f, -0.87289548f, -0.87607014f, -0.87920725f, +-0.88230664f, -0.88536829f, -0.88839203f, -0.89137769f, -0.89432514f, +-0.89723432f, -0.90010506f, -0.90293723f, -0.90573072f, -0.90848541f, +-0.91120118f, -0.91387796f, -0.91651553f, -0.91911387f, -0.92167282f, +-0.92419231f, -0.92667222f, -0.92911243f, -0.93151283f, -0.93387336f, +-0.93619382f, -0.93847424f, -0.94071442f, -0.94291431f, -0.94507378f, +-0.94719279f, -0.94927126f, -0.95130903f, -0.95330608f, -0.95526224f, +-0.95717752f, -0.95905179f, -0.96088499f, -0.96267700f, -0.96442777f, +-0.96613729f, -0.96780539f, -0.96943200f, -0.97101706f, -0.97256058f, +-0.97406244f, -0.97552258f, -0.97694093f, -0.97831738f, -0.97965199f, +-0.98094457f, -0.98219514f, -0.98340368f, -0.98457009f, -0.98569429f, +-0.98677629f, -0.98781598f, -0.98881340f, -0.98976845f, -0.99068111f, +-0.99155134f, -0.99237907f, -0.99316430f, -0.99390697f, -0.99460709f, +-0.99526459f, -0.99587947f, -0.99645168f, -0.99698120f, -0.99746799f, +-0.99791211f, -0.99831343f, -0.99867201f, -0.99898779f, -0.99926084f, +-0.99949104f, -0.99967843f, -0.99982297f, -0.99992472f, -0.99998361f, +0.99999869f, 0.99989158f, 0.99961317f, 0.99916345f, 0.99854255f, +0.99775058f, 0.99678761f, 0.99565387f, 0.99434954f, 0.99287480f, +0.99122995f, 0.98941529f, 0.98743105f, 0.98527765f, 0.98295540f, +0.98046476f, 0.97780609f, 0.97497988f, 0.97198665f, 0.96882683f, +0.96550101f, 0.96200979f, 0.95835376f, 0.95453346f, 0.95054960f, +0.94640291f, 0.94209403f, 0.93762374f, 0.93299282f, 0.92820197f, +0.92325211f, 0.91814411f, 0.91287869f, 0.90745693f, 0.90187967f, +0.89614785f, 0.89026248f, 0.88422459f, 0.87803519f, 0.87169534f, +0.86520612f, 0.85856867f, 0.85178405f, 0.84485358f, 0.83777827f, +0.83055943f, 0.82319832f, 0.81569612f, 0.80805415f, 0.80027372f, +0.79235619f, 0.78430289f, 0.77611518f, 0.76779449f, 0.75934225f, +0.75075996f, 0.74204898f, 0.73321080f, 0.72424710f, 0.71515924f, +0.70594883f, 0.69661748f, 0.68716675f, 0.67759830f, 0.66791373f, +0.65811473f, 0.64820296f, 0.63818014f, 0.62804794f, 0.61780810f, +0.60746247f, 0.59701276f, 0.58646071f, 0.57580817f, 0.56505698f, +0.55420899f, 0.54326600f, 0.53222996f, 0.52110273f, 0.50988621f, +0.49858227f, 0.48719296f, 0.47572014f, 0.46416581f, 0.45253196f, +0.44082057f, 0.42903364f, 0.41717321f, 0.40524128f, 0.39323992f, +0.38117120f, 0.36903715f, 0.35683987f, 0.34458145f, 0.33226398f, +0.31988961f, 0.30746040f, 0.29497850f, 0.28244606f, 0.26986524f, +0.25723818f, 0.24456702f, 0.23185398f, 0.21910121f, 0.20631088f, +0.19348522f, 0.18062639f, 0.16773662f, 0.15481812f, 0.14187308f, +0.12890373f, 0.11591230f, 0.10290100f, 0.089872077f, 0.076827750f, +0.063770257f, 0.050701842f, 0.037624735f, 0.024541186f, 0.011453429f, +-0.0016362892f, -0.014725727f, -0.027812643f, -0.040894791f, -0.053969935f, +-0.067035832f, -0.080090240f, -0.093130924f, -0.10615565f, -0.11916219f, +-0.13214831f, -0.14511178f, -0.15805040f, -0.17096193f, -0.18384418f, +-0.19669491f, -0.20951195f, -0.22229309f, -0.23503613f, -0.24773891f, +-0.26039925f, -0.27301496f, -0.28558388f, -0.29810387f, -0.31057280f, +-0.32298848f, -0.33534884f, -0.34765175f, -0.35989508f, -0.37207675f, +-0.38419467f, -0.39624676f, -0.40823093f, -0.42014518f, -0.43198743f, +-0.44375566f, -0.45544785f, -0.46706200f, -0.47859612f, -0.49004826f, +-0.50141639f, -0.51269865f, -0.52389306f, -0.53499764f, -0.54601061f, +-0.55693001f, -0.56775403f, -0.57848072f, -0.58910829f, -0.59963489f, +-0.61005878f, -0.62037814f, -0.63059121f, -0.64069623f, -0.65069145f, +-0.66057515f, -0.67034572f, -0.68000144f, -0.68954057f, -0.69896162f, +-0.70826286f, -0.71744281f, -0.72649974f, -0.73543227f, -0.74423873f, +-0.75291771f, -0.76146764f, -0.76988715f, -0.77817470f, -0.78632891f, +-0.79434842f, -0.80223179f, -0.80997771f, -0.81758487f, -0.82505190f, +-0.83237761f, -0.83956063f, -0.84659988f, -0.85349399f, -0.86024189f, +-0.86684239f, -0.87329435f, -0.87959671f, -0.88574833f, -0.89174819f, +-0.89759529f, -0.90328854f, -0.90882701f, -0.91420978f, -0.91943592f, +-0.92450452f, -0.92941469f, -0.93416560f, -0.93875647f, -0.94318646f, +-0.94745487f, -0.95156091f, -0.95550388f, -0.95928317f, -0.96289814f, +-0.96634805f, -0.96963239f, -0.97275060f, -0.97570217f, -0.97848648f, +-0.98110318f, -0.98355180f, -0.98583186f, -0.98794299f, -0.98988485f, +-0.99165714f, -0.99325943f, -0.99469161f, -0.99595332f, -0.99704438f, +-0.99796462f, -0.99871385f, -0.99929196f, -0.99969882f, -0.99993443f, +0.99999464f, 0.99956632f, 0.99845290f, 0.99665523f, 0.99417448f, +0.99101239f, 0.98717111f, 0.98265326f, 0.97746199f, 0.97160077f, +0.96507365f, 0.95788515f, 0.95004016f, 0.94154406f, 0.93240267f, +0.92262226f, 0.91220951f, 0.90117162f, 0.88951606f, 0.87725091f, +0.86438453f, 0.85092574f, 0.83688372f, 0.82226819f, 0.80708915f, +0.79135692f, 0.77508235f, 0.75827658f, 0.74095112f, 0.72311783f, +0.70478898f, 0.68597710f, 0.66669506f, 0.64695615f, 0.62677377f, +0.60616189f, 0.58513457f, 0.56370622f, 0.54189157f, 0.51970547f, +0.49716324f, 0.47428027f, 0.45107225f, 0.42755505f, 0.40374488f, +0.37965798f, 0.35531086f, 0.33072025f, 0.30590299f, 0.28087607f, +0.25565663f, 0.23026201f, 0.20470956f, 0.17901683f, 0.15320139f, +0.12728097f, 0.10127331f, 0.075196236f, 0.049067631f, 0.022905400f, +-0.0032725304f, -0.029448219f, -0.055603724f, -0.081721120f, -0.10778251f, +-0.13377003f, -0.15966587f, -0.18545228f, -0.21111161f, -0.23662624f, +-0.26197869f, -0.28715160f, -0.31212771f, -0.33688989f, -0.36142120f, +-0.38570482f, -0.40972409f, -0.43346253f, -0.45690393f, -0.48003218f, +-0.50283146f, -0.52528608f, -0.54738069f, -0.56910020f, -0.59042966f, +-0.61135447f, -0.63186026f, -0.65193301f, -0.67155898f, -0.69072473f, +-0.70941705f, -0.72762316f, -0.74533063f, -0.76252723f, -0.77920127f, +-0.79534131f, -0.81093621f, -0.82597536f, -0.84044844f, -0.85434550f, +-0.86765707f, -0.88037395f, -0.89248747f, -0.90398932f, -0.91487163f, +-0.92512697f, -0.93474823f, -0.94372886f, -0.95206273f, -0.95974404f, +-0.96676767f, -0.97312868f, -0.97882277f, -0.98384601f, -0.98819500f, +-0.99186671f, -0.99485862f, -0.99716878f, -0.99879545f, -0.99973762f, +}; +#endif + +static const CELTMode mode48000_960_120 = { +48000, /* Fs */ +120, /* overlap */ +21, /* nbEBands */ +21, /* effEBands */ +{0.85000610f, 0.0000000f, 1.0000000f, 1.0000000f, }, /* preemph */ +eband5ms, /* eBands */ +3, /* maxLM */ +8, /* nbShortMdcts */ +120, /* shortMdctSize */ +11, /* nbAllocVectors */ +band_allocation, /* allocVectors */ +logN400, /* logN */ +window120, /* window */ +{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */ +{392, cache_index50, cache_bits50, cache_caps50}, /* cache */ +}; + +/* List of all the available modes */ +#define TOTAL_MODES 1 +static const CELTMode * const static_mode_list[TOTAL_MODES] = { +&mode48000_960_120, +}; diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/static_modes_float_arm_ne10.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/static_modes_float_arm_ne10.h new file mode 100644 index 000000000..66e1abb10 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/static_modes_float_arm_ne10.h @@ -0,0 +1,404 @@ +/* The contents of this file was automatically generated by + * dump_mode_arm_ne10.c with arguments: 48000 960 + * It contains static definitions for some pre-defined modes. */ +#include + +#ifndef NE10_FFT_PARAMS48000_960 +#define NE10_FFT_PARAMS48000_960 +static const ne10_int32_t ne10_factors_480[64] = { +4, 40, 4, 30, 2, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_240[64] = { +3, 20, 4, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_120[64] = { +3, 10, 2, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_60[64] = { +2, 5, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_fft_cpx_float32_t ne10_twiddles_480[480] = { +{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f}, +{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f}, +{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f}, +{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f}, +{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f}, +{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f}, +{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f}, +{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f}, +{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f}, +{1.0000000f,-0.0000000f}, {0.99862951f,-0.052335959f}, {0.99452192f,-0.10452846f}, +{0.98768836f,-0.15643448f}, {0.97814763f,-0.20791170f}, {0.96592581f,-0.25881904f}, +{0.95105648f,-0.30901700f}, {0.93358040f,-0.35836795f}, {0.91354543f,-0.40673664f}, +{0.89100653f,-0.45399052f}, {0.86602545f,-0.50000000f}, {0.83867055f,-0.54463905f}, +{0.80901700f,-0.58778524f}, {0.77714598f,-0.62932038f}, {0.74314475f,-0.66913062f}, +{0.70710677f,-0.70710683f}, {0.66913056f,-0.74314487f}, {0.62932038f,-0.77714598f}, +{0.58778524f,-0.80901700f}, {0.54463899f,-0.83867055f}, {0.49999997f,-0.86602545f}, +{0.45399052f,-0.89100653f}, {0.40673661f,-0.91354549f}, {0.35836786f,-0.93358046f}, +{0.30901697f,-0.95105654f}, {0.25881907f,-0.96592581f}, {0.20791166f,-0.97814763f}, +{0.15643437f,-0.98768836f}, {0.10452842f,-0.99452192f}, {0.052335974f,-0.99862951f}, +{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f}, +{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f}, +{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f}, +{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f}, +{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f}, +{-4.3711388e-08f,-1.0000000f}, {-0.10452851f,-0.99452192f}, {-0.20791174f,-0.97814757f}, +{-0.30901703f,-0.95105648f}, {-0.40673670f,-0.91354543f}, {-0.50000006f,-0.86602533f}, +{-0.58778518f,-0.80901700f}, {-0.66913068f,-0.74314475f}, {-0.74314493f,-0.66913044f}, +{-0.80901700f,-0.58778518f}, {-0.86602539f,-0.50000006f}, {-0.91354549f,-0.40673658f}, +{-0.95105654f,-0.30901679f}, {-0.97814763f,-0.20791161f}, {-0.99452192f,-0.10452849f}, +{1.0000000f,-0.0000000f}, {0.98768836f,-0.15643448f}, {0.95105648f,-0.30901700f}, +{0.89100653f,-0.45399052f}, {0.80901700f,-0.58778524f}, {0.70710677f,-0.70710683f}, +{0.58778524f,-0.80901700f}, {0.45399052f,-0.89100653f}, {0.30901697f,-0.95105654f}, +{0.15643437f,-0.98768836f}, {-4.3711388e-08f,-1.0000000f}, {-0.15643445f,-0.98768836f}, +{-0.30901703f,-0.95105648f}, {-0.45399061f,-0.89100647f}, {-0.58778518f,-0.80901700f}, +{-0.70710677f,-0.70710677f}, {-0.80901700f,-0.58778518f}, {-0.89100659f,-0.45399037f}, +{-0.95105654f,-0.30901679f}, {-0.98768836f,-0.15643445f}, {-1.0000000f,8.7422777e-08f}, +{-0.98768830f,0.15643461f}, {-0.95105654f,0.30901697f}, {-0.89100653f,0.45399055f}, +{-0.80901694f,0.58778536f}, {-0.70710665f,0.70710689f}, {-0.58778507f,0.80901712f}, +{-0.45399022f,0.89100665f}, {-0.30901709f,0.95105648f}, {-0.15643452f,0.98768830f}, +{1.0000000f,-0.0000000f}, {0.99991435f,-0.013089596f}, {0.99965733f,-0.026176950f}, +{0.99922901f,-0.039259817f}, {0.99862951f,-0.052335959f}, {0.99785894f,-0.065403134f}, +{0.99691731f,-0.078459099f}, {0.99580491f,-0.091501623f}, {0.99452192f,-0.10452846f}, +{0.99306846f,-0.11753740f}, {0.99144489f,-0.13052620f}, {0.98965138f,-0.14349262f}, +{0.98768836f,-0.15643448f}, {0.98555607f,-0.16934951f}, {0.98325491f,-0.18223552f}, +{0.98078525f,-0.19509032f}, {0.97814763f,-0.20791170f}, {0.97534233f,-0.22069745f}, +{0.97236991f,-0.23344538f}, {0.96923089f,-0.24615330f}, {0.96592581f,-0.25881904f}, +{0.96245521f,-0.27144045f}, {0.95881975f,-0.28401536f}, {0.95501995f,-0.29654160f}, +{0.95105648f,-0.30901700f}, {0.94693011f,-0.32143945f}, {0.94264150f,-0.33380687f}, +{0.93819129f,-0.34611708f}, {0.93358040f,-0.35836795f}, {0.92880952f,-0.37055743f}, +{0.92387956f,-0.38268346f}, {0.91879117f,-0.39474389f}, {0.91354543f,-0.40673664f}, +{0.90814316f,-0.41865975f}, {0.90258527f,-0.43051112f}, {0.89687270f,-0.44228873f}, +{0.89100653f,-0.45399052f}, {0.88498765f,-0.46561453f}, {0.87881708f,-0.47715878f}, +{0.87249601f,-0.48862126f}, {0.86602545f,-0.50000000f}, {0.85940641f,-0.51129311f}, +{0.85264015f,-0.52249855f}, {0.84572786f,-0.53361452f}, {0.83867055f,-0.54463905f}, +{0.83146960f,-0.55557024f}, {0.82412618f,-0.56640625f}, {0.81664151f,-0.57714522f}, +{0.80901700f,-0.58778524f}, {0.80125380f,-0.59832460f}, {0.79335332f,-0.60876143f}, +{0.78531694f,-0.61909395f}, {0.77714598f,-0.62932038f}, {0.76884180f,-0.63943899f}, +{0.76040596f,-0.64944810f}, {0.75183982f,-0.65934587f}, {0.74314475f,-0.66913062f}, +{0.73432249f,-0.67880076f}, {0.72537434f,-0.68835455f}, {0.71630192f,-0.69779050f}, +{0.70710677f,-0.70710683f}, {0.69779044f,-0.71630198f}, {0.68835455f,-0.72537440f}, +{0.67880070f,-0.73432255f}, {0.66913056f,-0.74314487f}, {0.65934581f,-0.75183982f}, +{0.64944804f,-0.76040596f}, {0.63943899f,-0.76884186f}, {0.62932038f,-0.77714598f}, +{0.61909395f,-0.78531694f}, {0.60876137f,-0.79335338f}, {0.59832460f,-0.80125386f}, +{0.58778524f,-0.80901700f}, {0.57714516f,-0.81664151f}, {0.56640625f,-0.82412618f}, +{0.55557019f,-0.83146960f}, {0.54463899f,-0.83867055f}, {0.53361452f,-0.84572786f}, +{0.52249849f,-0.85264015f}, {0.51129311f,-0.85940641f}, {0.49999997f,-0.86602545f}, +{0.48862118f,-0.87249601f}, {0.47715876f,-0.87881708f}, {0.46561447f,-0.88498765f}, +{0.45399052f,-0.89100653f}, {0.44228867f,-0.89687276f}, {0.43051103f,-0.90258533f}, +{0.41865975f,-0.90814316f}, {0.40673661f,-0.91354549f}, {0.39474380f,-0.91879129f}, +{0.38268343f,-0.92387956f}, {0.37055740f,-0.92880958f}, {0.35836786f,-0.93358046f}, +{0.34611705f,-0.93819135f}, {0.33380681f,-0.94264150f}, {0.32143947f,-0.94693011f}, +{0.30901697f,-0.95105654f}, {0.29654151f,-0.95501995f}, {0.28401533f,-0.95881975f}, +{0.27144039f,-0.96245527f}, {0.25881907f,-0.96592581f}, {0.24615327f,-0.96923089f}, +{0.23344530f,-0.97236991f}, {0.22069745f,-0.97534233f}, {0.20791166f,-0.97814763f}, +{0.19509023f,-0.98078531f}, {0.18223552f,-0.98325491f}, {0.16934945f,-0.98555607f}, +{0.15643437f,-0.98768836f}, {0.14349259f,-0.98965138f}, {0.13052613f,-0.99144489f}, +{0.11753740f,-0.99306846f}, {0.10452842f,-0.99452192f}, {0.091501534f,-0.99580491f}, +{0.078459084f,-0.99691731f}, {0.065403074f,-0.99785894f}, {0.052335974f,-0.99862951f}, +{0.039259788f,-0.99922901f}, {0.026176875f,-0.99965733f}, {0.013089597f,-0.99991435f}, +{1.0000000f,-0.0000000f}, {0.99965733f,-0.026176950f}, {0.99862951f,-0.052335959f}, +{0.99691731f,-0.078459099f}, {0.99452192f,-0.10452846f}, {0.99144489f,-0.13052620f}, +{0.98768836f,-0.15643448f}, {0.98325491f,-0.18223552f}, {0.97814763f,-0.20791170f}, +{0.97236991f,-0.23344538f}, {0.96592581f,-0.25881904f}, {0.95881975f,-0.28401536f}, +{0.95105648f,-0.30901700f}, {0.94264150f,-0.33380687f}, {0.93358040f,-0.35836795f}, +{0.92387956f,-0.38268346f}, {0.91354543f,-0.40673664f}, {0.90258527f,-0.43051112f}, +{0.89100653f,-0.45399052f}, {0.87881708f,-0.47715878f}, {0.86602545f,-0.50000000f}, +{0.85264015f,-0.52249855f}, {0.83867055f,-0.54463905f}, {0.82412618f,-0.56640625f}, +{0.80901700f,-0.58778524f}, {0.79335332f,-0.60876143f}, {0.77714598f,-0.62932038f}, +{0.76040596f,-0.64944810f}, {0.74314475f,-0.66913062f}, {0.72537434f,-0.68835455f}, +{0.70710677f,-0.70710683f}, {0.68835455f,-0.72537440f}, {0.66913056f,-0.74314487f}, +{0.64944804f,-0.76040596f}, {0.62932038f,-0.77714598f}, {0.60876137f,-0.79335338f}, +{0.58778524f,-0.80901700f}, {0.56640625f,-0.82412618f}, {0.54463899f,-0.83867055f}, +{0.52249849f,-0.85264015f}, {0.49999997f,-0.86602545f}, {0.47715876f,-0.87881708f}, +{0.45399052f,-0.89100653f}, {0.43051103f,-0.90258533f}, {0.40673661f,-0.91354549f}, +{0.38268343f,-0.92387956f}, {0.35836786f,-0.93358046f}, {0.33380681f,-0.94264150f}, +{0.30901697f,-0.95105654f}, {0.28401533f,-0.95881975f}, {0.25881907f,-0.96592581f}, +{0.23344530f,-0.97236991f}, {0.20791166f,-0.97814763f}, {0.18223552f,-0.98325491f}, +{0.15643437f,-0.98768836f}, {0.13052613f,-0.99144489f}, {0.10452842f,-0.99452192f}, +{0.078459084f,-0.99691731f}, {0.052335974f,-0.99862951f}, {0.026176875f,-0.99965733f}, +{-4.3711388e-08f,-1.0000000f}, {-0.026176963f,-0.99965733f}, {-0.052336060f,-0.99862951f}, +{-0.078459173f,-0.99691731f}, {-0.10452851f,-0.99452192f}, {-0.13052621f,-0.99144489f}, +{-0.15643445f,-0.98768836f}, {-0.18223560f,-0.98325491f}, {-0.20791174f,-0.97814757f}, +{-0.23344538f,-0.97236991f}, {-0.25881916f,-0.96592581f}, {-0.28401542f,-0.95881969f}, +{-0.30901703f,-0.95105648f}, {-0.33380687f,-0.94264150f}, {-0.35836795f,-0.93358040f}, +{-0.38268352f,-0.92387950f}, {-0.40673670f,-0.91354543f}, {-0.43051112f,-0.90258527f}, +{-0.45399061f,-0.89100647f}, {-0.47715873f,-0.87881708f}, {-0.50000006f,-0.86602533f}, +{-0.52249867f,-0.85264009f}, {-0.54463905f,-0.83867055f}, {-0.56640631f,-0.82412612f}, +{-0.58778518f,-0.80901700f}, {-0.60876143f,-0.79335332f}, {-0.62932050f,-0.77714586f}, +{-0.64944804f,-0.76040596f}, {-0.66913068f,-0.74314475f}, {-0.68835467f,-0.72537428f}, +{-0.70710677f,-0.70710677f}, {-0.72537446f,-0.68835449f}, {-0.74314493f,-0.66913044f}, +{-0.76040596f,-0.64944804f}, {-0.77714604f,-0.62932026f}, {-0.79335332f,-0.60876143f}, +{-0.80901700f,-0.58778518f}, {-0.82412624f,-0.56640613f}, {-0.83867055f,-0.54463899f}, +{-0.85264021f,-0.52249849f}, {-0.86602539f,-0.50000006f}, {-0.87881714f,-0.47715873f}, +{-0.89100659f,-0.45399037f}, {-0.90258527f,-0.43051112f}, {-0.91354549f,-0.40673658f}, +{-0.92387956f,-0.38268328f}, {-0.93358040f,-0.35836792f}, {-0.94264150f,-0.33380675f}, +{-0.95105654f,-0.30901679f}, {-0.95881975f,-0.28401530f}, {-0.96592587f,-0.25881892f}, +{-0.97236991f,-0.23344538f}, {-0.97814763f,-0.20791161f}, {-0.98325491f,-0.18223536f}, +{-0.98768836f,-0.15643445f}, {-0.99144489f,-0.13052608f}, {-0.99452192f,-0.10452849f}, +{-0.99691737f,-0.078459039f}, {-0.99862957f,-0.052335810f}, {-0.99965733f,-0.026176952f}, +{1.0000000f,-0.0000000f}, {0.99922901f,-0.039259817f}, {0.99691731f,-0.078459099f}, +{0.99306846f,-0.11753740f}, {0.98768836f,-0.15643448f}, {0.98078525f,-0.19509032f}, +{0.97236991f,-0.23344538f}, {0.96245521f,-0.27144045f}, {0.95105648f,-0.30901700f}, +{0.93819129f,-0.34611708f}, {0.92387956f,-0.38268346f}, {0.90814316f,-0.41865975f}, +{0.89100653f,-0.45399052f}, {0.87249601f,-0.48862126f}, {0.85264015f,-0.52249855f}, +{0.83146960f,-0.55557024f}, {0.80901700f,-0.58778524f}, {0.78531694f,-0.61909395f}, +{0.76040596f,-0.64944810f}, {0.73432249f,-0.67880076f}, {0.70710677f,-0.70710683f}, +{0.67880070f,-0.73432255f}, {0.64944804f,-0.76040596f}, {0.61909395f,-0.78531694f}, +{0.58778524f,-0.80901700f}, {0.55557019f,-0.83146960f}, {0.52249849f,-0.85264015f}, +{0.48862118f,-0.87249601f}, {0.45399052f,-0.89100653f}, {0.41865975f,-0.90814316f}, +{0.38268343f,-0.92387956f}, {0.34611705f,-0.93819135f}, {0.30901697f,-0.95105654f}, +{0.27144039f,-0.96245527f}, {0.23344530f,-0.97236991f}, {0.19509023f,-0.98078531f}, +{0.15643437f,-0.98768836f}, {0.11753740f,-0.99306846f}, {0.078459084f,-0.99691731f}, +{0.039259788f,-0.99922901f}, {-4.3711388e-08f,-1.0000000f}, {-0.039259877f,-0.99922901f}, +{-0.078459173f,-0.99691731f}, {-0.11753749f,-0.99306846f}, {-0.15643445f,-0.98768836f}, +{-0.19509032f,-0.98078525f}, {-0.23344538f,-0.97236991f}, {-0.27144048f,-0.96245521f}, +{-0.30901703f,-0.95105648f}, {-0.34611711f,-0.93819129f}, {-0.38268352f,-0.92387950f}, +{-0.41865984f,-0.90814310f}, {-0.45399061f,-0.89100647f}, {-0.48862135f,-0.87249595f}, +{-0.52249867f,-0.85264009f}, {-0.55557036f,-0.83146954f}, {-0.58778518f,-0.80901700f}, +{-0.61909389f,-0.78531694f}, {-0.64944804f,-0.76040596f}, {-0.67880076f,-0.73432249f}, +{-0.70710677f,-0.70710677f}, {-0.73432249f,-0.67880070f}, {-0.76040596f,-0.64944804f}, +{-0.78531694f,-0.61909389f}, {-0.80901700f,-0.58778518f}, {-0.83146966f,-0.55557019f}, +{-0.85264021f,-0.52249849f}, {-0.87249607f,-0.48862115f}, {-0.89100659f,-0.45399037f}, +{-0.90814322f,-0.41865960f}, {-0.92387956f,-0.38268328f}, {-0.93819135f,-0.34611690f}, +{-0.95105654f,-0.30901679f}, {-0.96245521f,-0.27144048f}, {-0.97236991f,-0.23344538f}, +{-0.98078531f,-0.19509031f}, {-0.98768836f,-0.15643445f}, {-0.99306846f,-0.11753736f}, +{-0.99691737f,-0.078459039f}, {-0.99922901f,-0.039259743f}, {-1.0000000f,8.7422777e-08f}, +{-0.99922901f,0.039259918f}, {-0.99691731f,0.078459218f}, {-0.99306846f,0.11753753f}, +{-0.98768830f,0.15643461f}, {-0.98078525f,0.19509049f}, {-0.97236985f,0.23344554f}, +{-0.96245515f,0.27144065f}, {-0.95105654f,0.30901697f}, {-0.93819135f,0.34611705f}, +{-0.92387956f,0.38268346f}, {-0.90814316f,0.41865975f}, {-0.89100653f,0.45399055f}, +{-0.87249601f,0.48862129f}, {-0.85264015f,0.52249861f}, {-0.83146960f,0.55557030f}, +{-0.80901694f,0.58778536f}, {-0.78531688f,0.61909401f}, {-0.76040590f,0.64944816f}, +{-0.73432243f,0.67880082f}, {-0.70710665f,0.70710689f}, {-0.67880058f,0.73432261f}, +{-0.64944792f,0.76040608f}, {-0.61909378f,0.78531706f}, {-0.58778507f,0.80901712f}, +{-0.55557001f,0.83146977f}, {-0.52249837f,0.85264033f}, {-0.48862100f,0.87249613f}, +{-0.45399022f,0.89100665f}, {-0.41865945f,0.90814328f}, {-0.38268313f,0.92387968f}, +{-0.34611672f,0.93819147f}, {-0.30901709f,0.95105648f}, {-0.27144054f,0.96245521f}, +{-0.23344545f,0.97236991f}, {-0.19509038f,0.98078525f}, {-0.15643452f,0.98768830f}, +{-0.11753743f,0.99306846f}, {-0.078459114f,0.99691731f}, {-0.039259821f,0.99922901f}, +}; +static const ne10_fft_cpx_float32_t ne10_twiddles_240[240] = { +{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f}, +{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f}, +{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f}, +{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f}, +{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f}, +{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f}, +{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f}, +{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f}, +{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f}, +{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f}, +{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f}, +{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f}, +{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f}, +{1.0000000f,-0.0000000f}, {0.95105648f,-0.30901700f}, {0.80901700f,-0.58778524f}, +{0.58778524f,-0.80901700f}, {0.30901697f,-0.95105654f}, {-4.3711388e-08f,-1.0000000f}, +{-0.30901703f,-0.95105648f}, {-0.58778518f,-0.80901700f}, {-0.80901700f,-0.58778518f}, +{-0.95105654f,-0.30901679f}, {-1.0000000f,8.7422777e-08f}, {-0.95105654f,0.30901697f}, +{-0.80901694f,0.58778536f}, {-0.58778507f,0.80901712f}, {-0.30901709f,0.95105648f}, +{1.0000000f,-0.0000000f}, {0.99965733f,-0.026176950f}, {0.99862951f,-0.052335959f}, +{0.99691731f,-0.078459099f}, {0.99452192f,-0.10452846f}, {0.99144489f,-0.13052620f}, +{0.98768836f,-0.15643448f}, {0.98325491f,-0.18223552f}, {0.97814763f,-0.20791170f}, +{0.97236991f,-0.23344538f}, {0.96592581f,-0.25881904f}, {0.95881975f,-0.28401536f}, +{0.95105648f,-0.30901700f}, {0.94264150f,-0.33380687f}, {0.93358040f,-0.35836795f}, +{0.92387956f,-0.38268346f}, {0.91354543f,-0.40673664f}, {0.90258527f,-0.43051112f}, +{0.89100653f,-0.45399052f}, {0.87881708f,-0.47715878f}, {0.86602545f,-0.50000000f}, +{0.85264015f,-0.52249855f}, {0.83867055f,-0.54463905f}, {0.82412618f,-0.56640625f}, +{0.80901700f,-0.58778524f}, {0.79335332f,-0.60876143f}, {0.77714598f,-0.62932038f}, +{0.76040596f,-0.64944810f}, {0.74314475f,-0.66913062f}, {0.72537434f,-0.68835455f}, +{0.70710677f,-0.70710683f}, {0.68835455f,-0.72537440f}, {0.66913056f,-0.74314487f}, +{0.64944804f,-0.76040596f}, {0.62932038f,-0.77714598f}, {0.60876137f,-0.79335338f}, +{0.58778524f,-0.80901700f}, {0.56640625f,-0.82412618f}, {0.54463899f,-0.83867055f}, +{0.52249849f,-0.85264015f}, {0.49999997f,-0.86602545f}, {0.47715876f,-0.87881708f}, +{0.45399052f,-0.89100653f}, {0.43051103f,-0.90258533f}, {0.40673661f,-0.91354549f}, +{0.38268343f,-0.92387956f}, {0.35836786f,-0.93358046f}, {0.33380681f,-0.94264150f}, +{0.30901697f,-0.95105654f}, {0.28401533f,-0.95881975f}, {0.25881907f,-0.96592581f}, +{0.23344530f,-0.97236991f}, {0.20791166f,-0.97814763f}, {0.18223552f,-0.98325491f}, +{0.15643437f,-0.98768836f}, {0.13052613f,-0.99144489f}, {0.10452842f,-0.99452192f}, +{0.078459084f,-0.99691731f}, {0.052335974f,-0.99862951f}, {0.026176875f,-0.99965733f}, +{1.0000000f,-0.0000000f}, {0.99862951f,-0.052335959f}, {0.99452192f,-0.10452846f}, +{0.98768836f,-0.15643448f}, {0.97814763f,-0.20791170f}, {0.96592581f,-0.25881904f}, +{0.95105648f,-0.30901700f}, {0.93358040f,-0.35836795f}, {0.91354543f,-0.40673664f}, +{0.89100653f,-0.45399052f}, {0.86602545f,-0.50000000f}, {0.83867055f,-0.54463905f}, +{0.80901700f,-0.58778524f}, {0.77714598f,-0.62932038f}, {0.74314475f,-0.66913062f}, +{0.70710677f,-0.70710683f}, {0.66913056f,-0.74314487f}, {0.62932038f,-0.77714598f}, +{0.58778524f,-0.80901700f}, {0.54463899f,-0.83867055f}, {0.49999997f,-0.86602545f}, +{0.45399052f,-0.89100653f}, {0.40673661f,-0.91354549f}, {0.35836786f,-0.93358046f}, +{0.30901697f,-0.95105654f}, {0.25881907f,-0.96592581f}, {0.20791166f,-0.97814763f}, +{0.15643437f,-0.98768836f}, {0.10452842f,-0.99452192f}, {0.052335974f,-0.99862951f}, +{-4.3711388e-08f,-1.0000000f}, {-0.052336060f,-0.99862951f}, {-0.10452851f,-0.99452192f}, +{-0.15643445f,-0.98768836f}, {-0.20791174f,-0.97814757f}, {-0.25881916f,-0.96592581f}, +{-0.30901703f,-0.95105648f}, {-0.35836795f,-0.93358040f}, {-0.40673670f,-0.91354543f}, +{-0.45399061f,-0.89100647f}, {-0.50000006f,-0.86602533f}, {-0.54463905f,-0.83867055f}, +{-0.58778518f,-0.80901700f}, {-0.62932050f,-0.77714586f}, {-0.66913068f,-0.74314475f}, +{-0.70710677f,-0.70710677f}, {-0.74314493f,-0.66913044f}, {-0.77714604f,-0.62932026f}, +{-0.80901700f,-0.58778518f}, {-0.83867055f,-0.54463899f}, {-0.86602539f,-0.50000006f}, +{-0.89100659f,-0.45399037f}, {-0.91354549f,-0.40673658f}, {-0.93358040f,-0.35836792f}, +{-0.95105654f,-0.30901679f}, {-0.96592587f,-0.25881892f}, {-0.97814763f,-0.20791161f}, +{-0.98768836f,-0.15643445f}, {-0.99452192f,-0.10452849f}, {-0.99862957f,-0.052335810f}, +{1.0000000f,-0.0000000f}, {0.99691731f,-0.078459099f}, {0.98768836f,-0.15643448f}, +{0.97236991f,-0.23344538f}, {0.95105648f,-0.30901700f}, {0.92387956f,-0.38268346f}, +{0.89100653f,-0.45399052f}, {0.85264015f,-0.52249855f}, {0.80901700f,-0.58778524f}, +{0.76040596f,-0.64944810f}, {0.70710677f,-0.70710683f}, {0.64944804f,-0.76040596f}, +{0.58778524f,-0.80901700f}, {0.52249849f,-0.85264015f}, {0.45399052f,-0.89100653f}, +{0.38268343f,-0.92387956f}, {0.30901697f,-0.95105654f}, {0.23344530f,-0.97236991f}, +{0.15643437f,-0.98768836f}, {0.078459084f,-0.99691731f}, {-4.3711388e-08f,-1.0000000f}, +{-0.078459173f,-0.99691731f}, {-0.15643445f,-0.98768836f}, {-0.23344538f,-0.97236991f}, +{-0.30901703f,-0.95105648f}, {-0.38268352f,-0.92387950f}, {-0.45399061f,-0.89100647f}, +{-0.52249867f,-0.85264009f}, {-0.58778518f,-0.80901700f}, {-0.64944804f,-0.76040596f}, +{-0.70710677f,-0.70710677f}, {-0.76040596f,-0.64944804f}, {-0.80901700f,-0.58778518f}, +{-0.85264021f,-0.52249849f}, {-0.89100659f,-0.45399037f}, {-0.92387956f,-0.38268328f}, +{-0.95105654f,-0.30901679f}, {-0.97236991f,-0.23344538f}, {-0.98768836f,-0.15643445f}, +{-0.99691737f,-0.078459039f}, {-1.0000000f,8.7422777e-08f}, {-0.99691731f,0.078459218f}, +{-0.98768830f,0.15643461f}, {-0.97236985f,0.23344554f}, {-0.95105654f,0.30901697f}, +{-0.92387956f,0.38268346f}, {-0.89100653f,0.45399055f}, {-0.85264015f,0.52249861f}, +{-0.80901694f,0.58778536f}, {-0.76040590f,0.64944816f}, {-0.70710665f,0.70710689f}, +{-0.64944792f,0.76040608f}, {-0.58778507f,0.80901712f}, {-0.52249837f,0.85264033f}, +{-0.45399022f,0.89100665f}, {-0.38268313f,0.92387968f}, {-0.30901709f,0.95105648f}, +{-0.23344545f,0.97236991f}, {-0.15643452f,0.98768830f}, {-0.078459114f,0.99691731f}, +}; +static const ne10_fft_cpx_float32_t ne10_twiddles_120[120] = { +{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f}, +{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f}, +{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f}, +{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f}, +{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f}, +{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f}, +{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f}, +{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f}, +{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f}, +{1.0000000f,-0.0000000f}, {0.99862951f,-0.052335959f}, {0.99452192f,-0.10452846f}, +{0.98768836f,-0.15643448f}, {0.97814763f,-0.20791170f}, {0.96592581f,-0.25881904f}, +{0.95105648f,-0.30901700f}, {0.93358040f,-0.35836795f}, {0.91354543f,-0.40673664f}, +{0.89100653f,-0.45399052f}, {0.86602545f,-0.50000000f}, {0.83867055f,-0.54463905f}, +{0.80901700f,-0.58778524f}, {0.77714598f,-0.62932038f}, {0.74314475f,-0.66913062f}, +{0.70710677f,-0.70710683f}, {0.66913056f,-0.74314487f}, {0.62932038f,-0.77714598f}, +{0.58778524f,-0.80901700f}, {0.54463899f,-0.83867055f}, {0.49999997f,-0.86602545f}, +{0.45399052f,-0.89100653f}, {0.40673661f,-0.91354549f}, {0.35836786f,-0.93358046f}, +{0.30901697f,-0.95105654f}, {0.25881907f,-0.96592581f}, {0.20791166f,-0.97814763f}, +{0.15643437f,-0.98768836f}, {0.10452842f,-0.99452192f}, {0.052335974f,-0.99862951f}, +{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f}, +{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f}, +{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f}, +{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f}, +{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f}, +{-4.3711388e-08f,-1.0000000f}, {-0.10452851f,-0.99452192f}, {-0.20791174f,-0.97814757f}, +{-0.30901703f,-0.95105648f}, {-0.40673670f,-0.91354543f}, {-0.50000006f,-0.86602533f}, +{-0.58778518f,-0.80901700f}, {-0.66913068f,-0.74314475f}, {-0.74314493f,-0.66913044f}, +{-0.80901700f,-0.58778518f}, {-0.86602539f,-0.50000006f}, {-0.91354549f,-0.40673658f}, +{-0.95105654f,-0.30901679f}, {-0.97814763f,-0.20791161f}, {-0.99452192f,-0.10452849f}, +{1.0000000f,-0.0000000f}, {0.98768836f,-0.15643448f}, {0.95105648f,-0.30901700f}, +{0.89100653f,-0.45399052f}, {0.80901700f,-0.58778524f}, {0.70710677f,-0.70710683f}, +{0.58778524f,-0.80901700f}, {0.45399052f,-0.89100653f}, {0.30901697f,-0.95105654f}, +{0.15643437f,-0.98768836f}, {-4.3711388e-08f,-1.0000000f}, {-0.15643445f,-0.98768836f}, +{-0.30901703f,-0.95105648f}, {-0.45399061f,-0.89100647f}, {-0.58778518f,-0.80901700f}, +{-0.70710677f,-0.70710677f}, {-0.80901700f,-0.58778518f}, {-0.89100659f,-0.45399037f}, +{-0.95105654f,-0.30901679f}, {-0.98768836f,-0.15643445f}, {-1.0000000f,8.7422777e-08f}, +{-0.98768830f,0.15643461f}, {-0.95105654f,0.30901697f}, {-0.89100653f,0.45399055f}, +{-0.80901694f,0.58778536f}, {-0.70710665f,0.70710689f}, {-0.58778507f,0.80901712f}, +{-0.45399022f,0.89100665f}, {-0.30901709f,0.95105648f}, {-0.15643452f,0.98768830f}, +}; +static const ne10_fft_cpx_float32_t ne10_twiddles_60[60] = { +{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f}, +{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f}, +{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f}, +{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f}, +{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f}, +{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f}, +{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f}, +{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f}, +{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f}, +{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f}, +{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f}, +{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f}, +{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f}, +{1.0000000f,-0.0000000f}, {0.95105648f,-0.30901700f}, {0.80901700f,-0.58778524f}, +{0.58778524f,-0.80901700f}, {0.30901697f,-0.95105654f}, {-4.3711388e-08f,-1.0000000f}, +{-0.30901703f,-0.95105648f}, {-0.58778518f,-0.80901700f}, {-0.80901700f,-0.58778518f}, +{-0.95105654f,-0.30901679f}, {-1.0000000f,8.7422777e-08f}, {-0.95105654f,0.30901697f}, +{-0.80901694f,0.58778536f}, {-0.58778507f,0.80901712f}, {-0.30901709f,0.95105648f}, +}; +static const ne10_fft_state_float32_t ne10_fft_state_float32_t_480 = { +120, +(ne10_int32_t *)ne10_factors_480, +(ne10_fft_cpx_float32_t *)ne10_twiddles_480, +NULL, +(ne10_fft_cpx_float32_t *)&ne10_twiddles_480[120], +/* is_forward_scaled = true */ +(ne10_int32_t) 1, +/* is_backward_scaled = false */ +(ne10_int32_t) 0, +}; +static const arch_fft_state cfg_arch_480 = { +1, +(void *)&ne10_fft_state_float32_t_480, +}; + +static const ne10_fft_state_float32_t ne10_fft_state_float32_t_240 = { +60, +(ne10_int32_t *)ne10_factors_240, +(ne10_fft_cpx_float32_t *)ne10_twiddles_240, +NULL, +(ne10_fft_cpx_float32_t *)&ne10_twiddles_240[60], +/* is_forward_scaled = true */ +(ne10_int32_t) 1, +/* is_backward_scaled = false */ +(ne10_int32_t) 0, +}; +static const arch_fft_state cfg_arch_240 = { +1, +(void *)&ne10_fft_state_float32_t_240, +}; + +static const ne10_fft_state_float32_t ne10_fft_state_float32_t_120 = { +30, +(ne10_int32_t *)ne10_factors_120, +(ne10_fft_cpx_float32_t *)ne10_twiddles_120, +NULL, +(ne10_fft_cpx_float32_t *)&ne10_twiddles_120[30], +/* is_forward_scaled = true */ +(ne10_int32_t) 1, +/* is_backward_scaled = false */ +(ne10_int32_t) 0, +}; +static const arch_fft_state cfg_arch_120 = { +1, +(void *)&ne10_fft_state_float32_t_120, +}; + +static const ne10_fft_state_float32_t ne10_fft_state_float32_t_60 = { +15, +(ne10_int32_t *)ne10_factors_60, +(ne10_fft_cpx_float32_t *)ne10_twiddles_60, +NULL, +(ne10_fft_cpx_float32_t *)&ne10_twiddles_60[15], +/* is_forward_scaled = true */ +(ne10_int32_t) 1, +/* is_backward_scaled = false */ +(ne10_int32_t) 0, +}; +static const arch_fft_state cfg_arch_60 = { +1, +(void *)&ne10_fft_state_float32_t_60, +}; + +#endif /* end NE10_FFT_PARAMS48000_960 */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/meson.build b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/meson.build new file mode 100644 index 000000000..0e6d2e627 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/meson.build @@ -0,0 +1,19 @@ +tests = [ + 'test_unit_types', + 'test_unit_mathops', + 'test_unit_entropy', + 'test_unit_laplace', + 'test_unit_dft', + 'test_unit_mdct', + 'test_unit_rotation', + 'test_unit_cwrs32', +] + +foreach test_name : tests + exe = executable(test_name, '@0@.c'.format(test_name), + include_directories : opus_includes, + link_with : [celt_lib, celt_static_libs], + dependencies : libm, + install : false) + test(test_name, exe) +endforeach diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/test_unit_cwrs32.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/test_unit_cwrs32.c new file mode 100644 index 000000000..36dd8af5f --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/test_unit_cwrs32.c @@ -0,0 +1,161 @@ +/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation, + Gregory Maxwell + Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#ifndef CUSTOM_MODES +#define CUSTOM_MODES +#else +#define TEST_CUSTOM_MODES +#endif + +#define CELT_C +#include "stack_alloc.h" +#include "entenc.c" +#include "entdec.c" +#include "entcode.c" +#include "cwrs.c" +#include "mathops.c" +#include "rate.h" + +#define NMAX (240) +#define KMAX (128) + +#ifdef TEST_CUSTOM_MODES + +#define NDIMS (44) +static const int pn[NDIMS]={ + 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 18, 20, 22, + 24, 26, 28, 30, 32, 36, 40, 44, 48, + 52, 56, 60, 64, 72, 80, 88, 96, 104, + 112, 120, 128, 144, 160, 176, 192, 208 +}; +static const int pkmax[NDIMS]={ + 128, 128, 128, 128, 88, 52, 36, 26, 22, + 18, 16, 15, 13, 12, 12, 11, 10, 9, + 9, 8, 8, 7, 7, 7, 7, 6, 6, + 6, 6, 6, 5, 5, 5, 5, 5, 5, + 4, 4, 4, 4, 4, 4, 4, 4 +}; + +#else /* TEST_CUSTOM_MODES */ + +#define NDIMS (22) +static const int pn[NDIMS]={ + 2, 3, 4, 6, 8, 9, 11, 12, 16, + 18, 22, 24, 32, 36, 44, 48, 64, 72, + 88, 96, 144, 176 +}; +static const int pkmax[NDIMS]={ + 128, 128, 128, 88, 36, 26, 18, 16, 12, + 11, 9, 9, 7, 7, 6, 6, 5, 5, + 5, 5, 4, 4 +}; + +#endif + +int main(void){ + int t; + int n; + ALLOC_STACK; + for(t=0;tpkmax[t])break; + printf("Testing CWRS with N=%i, K=%i...\n",n,k); +#if defined(SMALL_FOOTPRINT) + nc=ncwrs_urow(n,k,uu); +#else + nc=CELT_PVQ_V(n,k); +#endif + inc=nc/20000; + if(inc<1)inc=1; + for(i=0;i");*/ +#if defined(SMALL_FOOTPRINT) + ii=icwrs(n,k,&v,y,u); +#else + ii=icwrs(n,y); + v=CELT_PVQ_V(n,k); +#endif + if(ii!=i){ + fprintf(stderr,"Combination-index mismatch (%lu!=%lu).\n", + (long)ii,(long)i); + return 1; + } + if(v!=nc){ + fprintf(stderr,"Combination count mismatch (%lu!=%lu).\n", + (long)v,(long)nc); + return 2; + } + /*printf(" %6u\n",i);*/ + } + /*printf("\n");*/ + } + } + return 0; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/test_unit_dft.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/test_unit_dft.c new file mode 100644 index 000000000..70f8f4937 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/test_unit_dft.c @@ -0,0 +1,179 @@ +/* Copyright (c) 2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "stack_alloc.h" +#include "kiss_fft.h" +#include "mathops.h" +#include "modes.h" + +#ifndef M_PI +#define M_PI 3.141592653 +#endif + +int ret = 0; + +void check(kiss_fft_cpx * in,kiss_fft_cpx * out,int nfft,int isinverse) +{ + int bin,k; + double errpow=0,sigpow=0, snr; + + for (bin=0;binmdct.kfft[id]; +#endif + + in = (kiss_fft_cpx*)malloc(buflen); + out = (kiss_fft_cpx*)malloc(buflen); + + for (k=0;k1) { + int k; + for (k=1;k +#include +#include +#include +#define CELT_C +#include "entcode.h" +#include "entenc.h" +#include "entdec.h" +#include + +#include "entenc.c" +#include "entdec.c" +#include "entcode.c" + +#ifndef M_LOG2E +# define M_LOG2E 1.4426950408889634074 +#endif +#define DATA_SIZE 10000000 +#define DATA_SIZE2 10000 + +int main(int _argc,char **_argv){ + ec_enc enc; + ec_dec dec; + long nbits; + long nbits2; + double entropy; + int ft; + int ftb; + int sz; + int i; + int ret; + unsigned int sym; + unsigned int seed; + unsigned char *ptr; + const char *env_seed; + ret=0; + entropy=0; + if (_argc > 2) { + fprintf(stderr, "Usage: %s []\n", _argv[0]); + return 1; + } + env_seed = getenv("SEED"); + if (_argc > 1) + seed = atoi(_argv[1]); + else if (env_seed) + seed = atoi(env_seed); + else + seed = time(NULL); + /*Testing encoding of raw bit values.*/ + ptr = (unsigned char *)malloc(DATA_SIZE); + ec_enc_init(&enc,ptr, DATA_SIZE); + for(ft=2;ft<1024;ft++){ + for(i=0;i>(rand()%11U))+1U)+10; + sz=rand()/((RAND_MAX>>(rand()%9U))+1U); + data=(unsigned *)malloc(sz*sizeof(*data)); + tell=(unsigned *)malloc((sz+1)*sizeof(*tell)); + ec_enc_init(&enc,ptr,DATA_SIZE2); + zeros = rand()%13==0; + tell[0]=ec_tell_frac(&enc); + for(j=0;j>(rand()%9U))+1U); + logp1=(unsigned *)malloc(sz*sizeof(*logp1)); + data=(unsigned *)malloc(sz*sizeof(*data)); + tell=(unsigned *)malloc((sz+1)*sizeof(*tell)); + enc_method=(unsigned *)malloc(sz*sizeof(*enc_method)); + ec_enc_init(&enc,ptr,DATA_SIZE2); + tell[0]=ec_tell_frac(&enc); + for(j=0;j>1)+1); + logp1[j]=(rand()%15)+1; + enc_method[j]=rand()/((RAND_MAX>>2)+1); + switch(enc_method[j]){ + case 0:{ + ec_encode(&enc,data[j]?(1<>2)+1); + switch(dec_method){ + case 0:{ + fs=ec_decode(&dec,1<=(1<=(1< +#include +#define CELT_C +#include "laplace.h" +#include "stack_alloc.h" + +#include "entenc.c" +#include "entdec.c" +#include "entcode.c" +#include "laplace.c" + +#define DATA_SIZE 40000 + +int ec_laplace_get_start_freq(int decay) +{ + opus_uint32 ft = 32768 - LAPLACE_MINP*(2*LAPLACE_NMIN+1); + int fs = (ft*(16384-decay))/(16384+decay); + return fs+LAPLACE_MINP; +} + +int main(void) +{ + int i; + int ret = 0; + ec_enc enc; + ec_dec dec; + unsigned char *ptr; + int val[10000], decay[10000]; + ALLOC_STACK; + ptr = (unsigned char *)malloc(DATA_SIZE); + ec_enc_init(&enc,ptr,DATA_SIZE); + + val[0] = 3; decay[0] = 6000; + val[1] = 0; decay[1] = 5800; + val[2] = -1; decay[2] = 5600; + for (i=3;i<10000;i++) + { + val[i] = rand()%15-7; + decay[i] = rand()%11000+5000; + } + for (i=0;i<10000;i++) + ec_laplace_encode(&enc, &val[i], + ec_laplace_get_start_freq(decay[i]), decay[i]); + + ec_enc_done(&enc); + + ec_dec_init(&dec,ec_get_buffer(&enc),ec_range_bytes(&enc)); + + for (i=0;i<10000;i++) + { + int d = ec_laplace_decode(&dec, + ec_laplace_get_start_freq(decay[i]), decay[i]); + if (d != val[i]) + { + fprintf (stderr, "Got %d instead of %d\n", d, val[i]); + ret = 1; + } + } + + free(ptr); + return ret; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/test_unit_mathops.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/test_unit_mathops.c new file mode 100644 index 000000000..0615448db --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/test_unit_mathops.c @@ -0,0 +1,266 @@ +/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation, + Gregory Maxwell + Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef CUSTOM_MODES +#define CUSTOM_MODES +#endif + +#include +#include +#include "mathops.h" +#include "bands.h" + +#ifdef FIXED_POINT +#define WORD "%d" +#else +#define WORD "%f" +#endif + +int ret = 0; + +void testdiv(void) +{ + opus_int32 i; + for (i=1;i<=327670;i++) + { + double prod; + opus_val32 val; + val = celt_rcp(i); +#ifdef FIXED_POINT + prod = (1./32768./65526.)*val*i; +#else + prod = val*i; +#endif + if (fabs(prod-1) > .00025) + { + fprintf (stderr, "div failed: 1/%d="WORD" (product = %f)\n", i, val, prod); + ret = 1; + } + } +} + +void testsqrt(void) +{ + opus_int32 i; + for (i=1;i<=1000000000;i++) + { + double ratio; + opus_val16 val; + val = celt_sqrt(i); + ratio = val/sqrt(i); + if (fabs(ratio - 1) > .0005 && fabs(val-sqrt(i)) > 2) + { + fprintf (stderr, "sqrt failed: sqrt(%d)="WORD" (ratio = %f)\n", i, val, ratio); + ret = 1; + } + i+= i>>10; + } +} + +void testbitexactcos(void) +{ + int i; + opus_int32 min_d,max_d,last,chk; + chk=max_d=0; + last=min_d=32767; + for(i=64;i<=16320;i++) + { + opus_int32 d; + opus_int32 q=bitexact_cos(i); + chk ^= q*i; + d = last - q; + if (d>max_d)max_d=d; + if (dmax_d)max_d=d; + if (d0.0009) + { + fprintf (stderr, "celt_log2 failed: fabs((1.442695040888963387*log(x))-celt_log2(x))>0.001 (x = %f, error = %f)\n", x,error); + ret = 1; + } + } +} + +void testexp2(void) +{ + float x; + for (x=-11.0;x<24.0;x+=0.0007f) + { + float error = fabs(x-(1.442695040888963387*log(celt_exp2(x)))); + if (error>0.0002) + { + fprintf (stderr, "celt_exp2 failed: fabs(x-(1.442695040888963387*log(celt_exp2(x))))>0.0005 (x = %f, error = %f)\n", x,error); + ret = 1; + } + } +} + +void testexp2log2(void) +{ + float x; + for (x=-11.0;x<24.0;x+=0.0007f) + { + float error = fabs(x-(celt_log2(celt_exp2(x)))); + if (error>0.001) + { + fprintf (stderr, "celt_log2/celt_exp2 failed: fabs(x-(celt_log2(celt_exp2(x))))>0.001 (x = %f, error = %f)\n", x,error); + ret = 1; + } + } +} +#else +void testlog2(void) +{ + opus_val32 x; + for (x=8;x<1073741824;x+=(x>>3)) + { + float error = fabs((1.442695040888963387*log(x/16384.0))-celt_log2(x)/1024.0); + if (error>0.003) + { + fprintf (stderr, "celt_log2 failed: x = %ld, error = %f\n", (long)x,error); + ret = 1; + } + } +} + +void testexp2(void) +{ + opus_val16 x; + for (x=-32768;x<15360;x++) + { + float error1 = fabs(x/1024.0-(1.442695040888963387*log(celt_exp2(x)/65536.0))); + float error2 = fabs(exp(0.6931471805599453094*x/1024.0)-celt_exp2(x)/65536.0); + if (error1>0.0002&&error2>0.00004) + { + fprintf (stderr, "celt_exp2 failed: x = "WORD", error1 = %f, error2 = %f\n", x,error1,error2); + ret = 1; + } + } +} + +void testexp2log2(void) +{ + opus_val32 x; + for (x=8;x<65536;x+=(x>>3)) + { + float error = fabs(x-0.25*celt_exp2(celt_log2(x)))/16384; + if (error>0.004) + { + fprintf (stderr, "celt_log2/celt_exp2 failed: fabs(x-(celt_exp2(celt_log2(x))))>0.001 (x = %ld, error = %f)\n", (long)x,error); + ret = 1; + } + } +} + +void testilog2(void) +{ + opus_val32 x; + for (x=1;x<=268435455;x+=127) + { + opus_val32 lg; + opus_val32 y; + + lg = celt_ilog2(x); + if (lg<0 || lg>=31) + { + printf("celt_ilog2 failed: 0<=celt_ilog2(x)<31 (x = %d, celt_ilog2(x) = %d)\n",x,lg); + ret = 1; + } + y = 1<>1)>=y) + { + printf("celt_ilog2 failed: 2**celt_ilog2(x)<=x<2**(celt_ilog2(x)+1) (x = %d, 2**celt_ilog2(x) = %d)\n",x,y); + ret = 1; + } + } +} +#endif + +int main(void) +{ + testbitexactcos(); + testbitexactlog2tan(); + testdiv(); + testsqrt(); + testlog2(); + testexp2(); + testexp2log2(); +#ifdef FIXED_POINT + testilog2(); +#endif + return ret; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/test_unit_mdct.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/test_unit_mdct.c new file mode 100644 index 000000000..4a563ccfe --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/test_unit_mdct.c @@ -0,0 +1,227 @@ +/* Copyright (c) 2008-2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "mdct.h" +#include "stack_alloc.h" +#include "kiss_fft.h" +#include "mdct.h" +#include "modes.h" + +#ifndef M_PI +#define M_PI 3.141592653 +#endif + +int ret = 0; +void check(kiss_fft_scalar * in,kiss_fft_scalar * out,int nfft,int isinverse) +{ + int bin,k; + double errpow=0,sigpow=0; + double snr; + for (bin=0;binmdct; +#endif + + in = (kiss_fft_scalar*)malloc(buflen); + in_copy = (kiss_fft_scalar*)malloc(buflen); + out = (kiss_fft_scalar*)malloc(buflen); + window = (opus_val16*)malloc(sizeof(opus_val16)*nfft/2); + + for (k=0;k1) { + int k; + for (k=1;k +#include +#include "vq.h" +#include "bands.h" +#include "stack_alloc.h" +#include + + +#define MAX_SIZE 100 + +int ret=0; +void test_rotation(int N, int K) +{ + int i; + double err = 0, ener = 0, snr, snr0; + opus_val16 x0[MAX_SIZE]; + opus_val16 x1[MAX_SIZE]; + for (i=0;i 20) + { + fprintf(stderr, "FAIL!\n"); + ret = 1; + } +} + +int main(void) +{ + ALLOC_STACK; + test_rotation(15, 3); + test_rotation(23, 5); + test_rotation(50, 3); + test_rotation(80, 1); + return ret; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/test_unit_types.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/test_unit_types.c new file mode 100644 index 000000000..67a0fb8ed --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/tests/test_unit_types.c @@ -0,0 +1,50 @@ +/* Copyright (c) 2008-2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_types.h" +#include + +int main(void) +{ + opus_int16 i = 1; + i <<= 14; + if (i>>14 != 1) + { + fprintf(stderr, "opus_int16 isn't 16 bits\n"); + return 1; + } + if (sizeof(opus_int16)*2 != sizeof(opus_int32)) + { + fprintf(stderr, "16*2 != 32\n"); + return 1; + } + return 0; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/vq.c b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/vq.c new file mode 100644 index 000000000..8011e2254 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/vq.c @@ -0,0 +1,442 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mathops.h" +#include "cwrs.h" +#include "vq.h" +#include "arch.h" +#include "os_support.h" +#include "bands.h" +#include "rate.h" +#include "pitch.h" + +#if defined(MIPSr1_ASM) +#include "mips/vq_mipsr1.h" +#endif + +#ifndef OVERRIDE_vq_exp_rotation1 +static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s) +{ + int i; + opus_val16 ms; + celt_norm *Xptr; + Xptr = X; + ms = NEG16(s); + for (i=0;i=0;i--) + { + celt_norm x1, x2; + x1 = Xptr[0]; + x2 = Xptr[stride]; + Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2), s, x1), 15)); + *Xptr-- = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15)); + } +} +#endif /* OVERRIDE_vq_exp_rotation1 */ + +void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread) +{ + static const int SPREAD_FACTOR[3]={15,10,5}; + int i; + opus_val16 c, s; + opus_val16 gain, theta; + int stride2=0; + int factor; + + if (2*K>=len || spread==SPREAD_NONE) + return; + factor = SPREAD_FACTOR[spread-1]; + + gain = celt_div((opus_val32)MULT16_16(Q15_ONE,len),(opus_val32)(len+factor*K)); + theta = HALF16(MULT16_16_Q15(gain,gain)); + + c = celt_cos_norm(EXTEND32(theta)); + s = celt_cos_norm(EXTEND32(SUB16(Q15ONE,theta))); /* sin(theta) */ + + if (len>=8*stride) + { + stride2 = 1; + /* This is just a simple (equivalent) way of computing sqrt(len/stride) with rounding. + It's basically incrementing long as (stride2+0.5)^2 < len/stride. */ + while ((stride2*stride2+stride2)*stride + (stride>>2) < len) + stride2++; + } + /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for + extract_collapse_mask().*/ + len = celt_udiv(len, stride); + for (i=0;i>1; +#endif + t = VSHR32(Ryy, 2*(k-7)); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + i=0; + do + X[i] = EXTRACT16(PSHR32(MULT16_16(g, iy[i]), k+1)); + while (++i < N); +} + +static unsigned extract_collapse_mask(int *iy, int N, int B) +{ + unsigned collapse_mask; + int N0; + int i; + if (B<=1) + return 1; + /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for + exp_rotation().*/ + N0 = celt_udiv(N, B); + collapse_mask = 0; + i=0; do { + int j; + unsigned tmp=0; + j=0; do { + tmp |= iy[i*N0+j]; + } while (++j (N>>1)) + { + opus_val16 rcp; + j=0; do { + sum += X[j]; + } while (++j EPSILON && sum < 64)) +#endif + { + X[0] = QCONST16(1.f,14); + j=1; do + X[j]=0; + while (++j=0); + + /* This should never happen, but just in case it does (e.g. on silence) + we fill the first bin with pulses. */ +#ifdef FIXED_POINT_DEBUG + celt_sig_assert(pulsesLeft<=N+3); +#endif + if (pulsesLeft > N+3) + { + opus_val16 tmp = (opus_val16)pulsesLeft; + yy = MAC16_16(yy, tmp, tmp); + yy = MAC16_16(yy, tmp, y[0]); + iy[0] += pulsesLeft; + pulsesLeft=0; + } + + for (i=0;i= best_num/best_den, but that way + we can do it without any division */ + /* OPT: It's not clear whether a cmov is faster than a branch here + since the condition is more often false than true and using + a cmov introduces data dependencies across iterations. The optimal + choice may be architecture-dependent. */ + if (opus_unlikely(MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num))) + { + best_den = Ryy; + best_num = Rxy; + best_id = j; + } + } while (++j0, "alg_quant() needs at least one pulse"); + celt_assert2(N>1, "alg_quant() needs at least two dimensions"); + + /* Covers vectorization by up to 4. */ + ALLOC(iy, N+3, int); + + exp_rotation(X, N, 1, B, K, spread); + + yy = op_pvq_search(X, iy, K, N, arch); + + encode_pulses(iy, N, K, enc); + + if (resynth) + { + normalise_residual(iy, X, N, yy, gain); + exp_rotation(X, N, -1, B, K, spread); + } + + collapse_mask = extract_collapse_mask(iy, N, B); + RESTORE_STACK; + return collapse_mask; +} + +/** Decode pulse vector and combine the result with the pitch vector to produce + the final normalised signal in the current band. */ +unsigned alg_unquant(celt_norm *X, int N, int K, int spread, int B, + ec_dec *dec, opus_val16 gain) +{ + opus_val32 Ryy; + unsigned collapse_mask; + VARDECL(int, iy); + SAVE_STACK; + + celt_assert2(K>0, "alg_unquant() needs at least one pulse"); + celt_assert2(N>1, "alg_unquant() needs at least two dimensions"); + ALLOC(iy, N, int); + Ryy = decode_pulses(iy, N, K, dec); + normalise_residual(iy, X, N, Ryy, gain); + exp_rotation(X, N, -1, B, K, spread); + collapse_mask = extract_collapse_mask(iy, N, B); + RESTORE_STACK; + return collapse_mask; +} + +#ifndef OVERRIDE_renormalise_vector +void renormalise_vector(celt_norm *X, int N, opus_val16 gain, int arch) +{ + int i; +#ifdef FIXED_POINT + int k; +#endif + opus_val32 E; + opus_val16 g; + opus_val32 t; + celt_norm *xptr; + E = EPSILON + celt_inner_prod(X, X, N, arch); +#ifdef FIXED_POINT + k = celt_ilog2(E)>>1; +#endif + t = VSHR32(E, 2*(k-7)); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + xptr = X; + for (i=0;i +#include +#include +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "pitch.h" +#include "x86cpu.h" + +#if defined(FIXED_POINT) + +void celt_fir_sse4_1(const opus_val16 *x, + const opus_val16 *num, + opus_val16 *y, + int N, + int ord, + int arch) +{ + int i,j; + VARDECL(opus_val16, rnum); + + __m128i vecNoA; + opus_int32 noA ; + SAVE_STACK; + + ALLOC(rnum, ord, opus_val16); + for(i=0;i> 1; + vecNoA = _mm_set_epi32(noA, noA, noA, noA); + + for (i=0;i +#include "arch.h" + +void xcorr_kernel_sse(const opus_val16 *x, const opus_val16 *y, opus_val32 sum[4], int len) +{ + int j; + __m128 xsum1, xsum2; + xsum1 = _mm_loadu_ps(sum); + xsum2 = _mm_setzero_ps(); + + for (j = 0; j < len-3; j += 4) + { + __m128 x0 = _mm_loadu_ps(x+j); + __m128 yj = _mm_loadu_ps(y+j); + __m128 y3 = _mm_loadu_ps(y+j+3); + + xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0x00),yj)); + xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0x55), + _mm_shuffle_ps(yj,y3,0x49))); + xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0xaa), + _mm_shuffle_ps(yj,y3,0x9e))); + xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0xff),y3)); + } + if (j < len) + { + xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j))); + if (++j < len) + { + xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j))); + if (++j < len) + { + xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j))); + } + } + } + _mm_storeu_ps(sum,_mm_add_ps(xsum1,xsum2)); +} + + +void dual_inner_prod_sse(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2) +{ + int i; + __m128 xsum1, xsum2; + xsum1 = _mm_setzero_ps(); + xsum2 = _mm_setzero_ps(); + for (i=0;i +#include + +#include "macros.h" +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "pitch.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE2) && defined(FIXED_POINT) +opus_val32 celt_inner_prod_sse2(const opus_val16 *x, const opus_val16 *y, + int N) +{ + opus_int i, dataSize16; + opus_int32 sum; + + __m128i inVec1_76543210, inVec1_FEDCBA98, acc1; + __m128i inVec2_76543210, inVec2_FEDCBA98, acc2; + + sum = 0; + dataSize16 = N & ~15; + + acc1 = _mm_setzero_si128(); + acc2 = _mm_setzero_si128(); + + for (i=0;i= 8) + { + inVec1_76543210 = _mm_loadu_si128((__m128i *)(&x[i + 0])); + inVec2_76543210 = _mm_loadu_si128((__m128i *)(&y[i + 0])); + + inVec1_76543210 = _mm_madd_epi16(inVec1_76543210, inVec2_76543210); + + acc1 = _mm_add_epi32(acc1, inVec1_76543210); + i += 8; + } + + acc1 = _mm_add_epi32(acc1, _mm_unpackhi_epi64( acc1, acc1)); + acc1 = _mm_add_epi32(acc1, _mm_shufflelo_epi16( acc1, 0x0E)); + sum += _mm_cvtsi128_si32(acc1); + + for (;i +#include + +#include "macros.h" +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "pitch.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) && defined(FIXED_POINT) +#include +#include "x86cpu.h" + +opus_val32 celt_inner_prod_sse4_1(const opus_val16 *x, const opus_val16 *y, + int N) +{ + opus_int i, dataSize16; + opus_int32 sum; + __m128i inVec1_76543210, inVec1_FEDCBA98, acc1; + __m128i inVec2_76543210, inVec2_FEDCBA98, acc2; + __m128i inVec1_3210, inVec2_3210; + + sum = 0; + dataSize16 = N & ~15; + + acc1 = _mm_setzero_si128(); + acc2 = _mm_setzero_si128(); + + for (i=0;i= 8) + { + inVec1_76543210 = _mm_loadu_si128((__m128i *)(&x[i + 0])); + inVec2_76543210 = _mm_loadu_si128((__m128i *)(&y[i + 0])); + + inVec1_76543210 = _mm_madd_epi16(inVec1_76543210, inVec2_76543210); + + acc1 = _mm_add_epi32(acc1, inVec1_76543210); + i += 8; + } + + if (N - i >= 4) + { + inVec1_3210 = OP_CVTEPI16_EPI32_M64(&x[i + 0]); + inVec2_3210 = OP_CVTEPI16_EPI32_M64(&y[i + 0]); + + inVec1_3210 = _mm_mullo_epi32(inVec1_3210, inVec2_3210); + + acc1 = _mm_add_epi32(acc1, inVec1_3210); + i += 4; + } + + acc1 = _mm_add_epi32(acc1, _mm_unpackhi_epi64(acc1, acc1)); + acc1 = _mm_add_epi32(acc1, _mm_shufflelo_epi16(acc1, 0x0E)); + + sum += _mm_cvtsi128_si32(acc1); + + for (;i= 3); + + sum0 = _mm_setzero_si128(); + sum1 = _mm_setzero_si128(); + sum2 = _mm_setzero_si128(); + sum3 = _mm_setzero_si128(); + + for (j=0;j<(len-7);j+=8) + { + vecX = _mm_loadu_si128((__m128i *)(&x[j + 0])); + vecY0 = _mm_loadu_si128((__m128i *)(&y[j + 0])); + vecY1 = _mm_loadu_si128((__m128i *)(&y[j + 1])); + vecY2 = _mm_loadu_si128((__m128i *)(&y[j + 2])); + vecY3 = _mm_loadu_si128((__m128i *)(&y[j + 3])); + + sum0 = _mm_add_epi32(sum0, _mm_madd_epi16(vecX, vecY0)); + sum1 = _mm_add_epi32(sum1, _mm_madd_epi16(vecX, vecY1)); + sum2 = _mm_add_epi32(sum2, _mm_madd_epi16(vecX, vecY2)); + sum3 = _mm_add_epi32(sum3, _mm_madd_epi16(vecX, vecY3)); + } + + sum0 = _mm_add_epi32(sum0, _mm_unpackhi_epi64( sum0, sum0)); + sum0 = _mm_add_epi32(sum0, _mm_shufflelo_epi16( sum0, 0x0E)); + + sum1 = _mm_add_epi32(sum1, _mm_unpackhi_epi64( sum1, sum1)); + sum1 = _mm_add_epi32(sum1, _mm_shufflelo_epi16( sum1, 0x0E)); + + sum2 = _mm_add_epi32(sum2, _mm_unpackhi_epi64( sum2, sum2)); + sum2 = _mm_add_epi32(sum2, _mm_shufflelo_epi16( sum2, 0x0E)); + + sum3 = _mm_add_epi32(sum3, _mm_unpackhi_epi64( sum3, sum3)); + sum3 = _mm_add_epi32(sum3, _mm_shufflelo_epi16( sum3, 0x0E)); + + vecSum = _mm_unpacklo_epi64(_mm_unpacklo_epi32(sum0, sum1), + _mm_unpacklo_epi32(sum2, sum3)); + + for (;j<(len-3);j+=4) + { + vecX = OP_CVTEPI16_EPI32_M64(&x[j + 0]); + vecX0 = _mm_shuffle_epi32(vecX, 0x00); + vecX1 = _mm_shuffle_epi32(vecX, 0x55); + vecX2 = _mm_shuffle_epi32(vecX, 0xaa); + vecX3 = _mm_shuffle_epi32(vecX, 0xff); + + vecY0 = OP_CVTEPI16_EPI32_M64(&y[j + 0]); + vecY1 = OP_CVTEPI16_EPI32_M64(&y[j + 1]); + vecY2 = OP_CVTEPI16_EPI32_M64(&y[j + 2]); + vecY3 = OP_CVTEPI16_EPI32_M64(&y[j + 3]); + + sum0 = _mm_mullo_epi32(vecX0, vecY0); + sum1 = _mm_mullo_epi32(vecX1, vecY1); + sum2 = _mm_mullo_epi32(vecX2, vecY2); + sum3 = _mm_mullo_epi32(vecX3, vecY3); + + sum0 = _mm_add_epi32(sum0, sum1); + sum2 = _mm_add_epi32(sum2, sum3); + vecSum = _mm_add_epi32(vecSum, sum0); + vecSum = _mm_add_epi32(vecSum, sum2); + } + + for (;j +#include +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "vq.h" +#include "x86cpu.h" + + +#ifndef FIXED_POINT + +opus_val16 op_pvq_search_sse2(celt_norm *_X, int *iy, int K, int N, int arch) +{ + int i, j; + int pulsesLeft; + float xy, yy; + VARDECL(celt_norm, y); + VARDECL(celt_norm, X); + VARDECL(float, signy); + __m128 signmask; + __m128 sums; + __m128i fours; + SAVE_STACK; + + (void)arch; + /* All bits set to zero, except for the sign bit. */ + signmask = _mm_set_ps1(-0.f); + fours = _mm_set_epi32(4, 4, 4, 4); + ALLOC(y, N+3, celt_norm); + ALLOC(X, N+3, celt_norm); + ALLOC(signy, N+3, float); + + OPUS_COPY(X, _X, N); + X[N] = X[N+1] = X[N+2] = 0; + sums = _mm_setzero_ps(); + for (j=0;j (N>>1)) + { + __m128i pulses_sum; + __m128 yy4, xy4; + __m128 rcp4; + opus_val32 sum = _mm_cvtss_f32(sums); + /* If X is too small, just replace it with a pulse at 0 */ + /* Prevents infinities and NaNs from causing too many pulses + to be allocated. 64 is an approximation of infinity here. */ + if (!(sum > EPSILON && sum < 64)) + { + X[0] = QCONST16(1.f,14); + j=1; do + X[j]=0; + while (++j=0); + + /* This should never happen, but just in case it does (e.g. on silence) + we fill the first bin with pulses. */ + if (pulsesLeft > N+3) + { + opus_val16 tmp = (opus_val16)pulsesLeft; + yy = MAC16_16(yy, tmp, tmp); + yy = MAC16_16(yy, tmp, y[0]); + iy[0] += pulsesLeft; + pulsesLeft=0; + } + + for (i=0;i +static _inline void cpuid(unsigned int CPUInfo[4], unsigned int InfoType) +{ + __cpuid((int*)CPUInfo, InfoType); +} + +#else + +#if defined(CPU_INFO_BY_C) +#include +#endif + +static void cpuid(unsigned int CPUInfo[4], unsigned int InfoType) +{ +#if defined(CPU_INFO_BY_ASM) +#if defined(__i386__) && defined(__PIC__) +/* %ebx is PIC register in 32-bit, so mustn't clobber it. */ + __asm__ __volatile__ ( + "xchg %%ebx, %1\n" + "cpuid\n" + "xchg %%ebx, %1\n": + "=a" (CPUInfo[0]), + "=r" (CPUInfo[1]), + "=c" (CPUInfo[2]), + "=d" (CPUInfo[3]) : + "0" (InfoType) + ); +#else + __asm__ __volatile__ ( + "cpuid": + "=a" (CPUInfo[0]), + "=b" (CPUInfo[1]), + "=c" (CPUInfo[2]), + "=d" (CPUInfo[3]) : + "0" (InfoType) + ); +#endif +#elif defined(CPU_INFO_BY_C) + __get_cpuid(InfoType, &(CPUInfo[0]), &(CPUInfo[1]), &(CPUInfo[2]), &(CPUInfo[3])); +#endif +} + +#endif + +typedef struct CPU_Feature{ + /* SIMD: 128-bit */ + int HW_SSE; + int HW_SSE2; + int HW_SSE41; + /* SIMD: 256-bit */ + int HW_AVX; +} CPU_Feature; + +static void opus_cpu_feature_check(CPU_Feature *cpu_feature) +{ + unsigned int info[4] = {0}; + unsigned int nIds = 0; + + cpuid(info, 0); + nIds = info[0]; + + if (nIds >= 1){ + cpuid(info, 1); + cpu_feature->HW_SSE = (info[3] & (1 << 25)) != 0; + cpu_feature->HW_SSE2 = (info[3] & (1 << 26)) != 0; + cpu_feature->HW_SSE41 = (info[2] & (1 << 19)) != 0; + cpu_feature->HW_AVX = (info[2] & (1 << 28)) != 0; + } + else { + cpu_feature->HW_SSE = 0; + cpu_feature->HW_SSE2 = 0; + cpu_feature->HW_SSE41 = 0; + cpu_feature->HW_AVX = 0; + } +} + +int opus_select_arch(void) +{ + CPU_Feature cpu_feature; + int arch; + + opus_cpu_feature_check(&cpu_feature); + + arch = 0; + if (!cpu_feature.HW_SSE) + { + return arch; + } + arch++; + + if (!cpu_feature.HW_SSE2) + { + return arch; + } + arch++; + + if (!cpu_feature.HW_SSE41) + { + return arch; + } + arch++; + + if (!cpu_feature.HW_AVX) + { + return arch; + } + arch++; + + return arch; +} + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt/x86/x86cpu.h b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/x86/x86cpu.h new file mode 100644 index 000000000..1e2bf17b9 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt/x86/x86cpu.h @@ -0,0 +1,95 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#if !defined(X86CPU_H) +# define X86CPU_H + +# if defined(OPUS_X86_MAY_HAVE_SSE) +# define MAY_HAVE_SSE(name) name ## _sse +# else +# define MAY_HAVE_SSE(name) name ## _c +# endif + +# if defined(OPUS_X86_MAY_HAVE_SSE2) +# define MAY_HAVE_SSE2(name) name ## _sse2 +# else +# define MAY_HAVE_SSE2(name) name ## _c +# endif + +# if defined(OPUS_X86_MAY_HAVE_SSE4_1) +# define MAY_HAVE_SSE4_1(name) name ## _sse4_1 +# else +# define MAY_HAVE_SSE4_1(name) name ## _c +# endif + +# if defined(OPUS_X86_MAY_HAVE_AVX) +# define MAY_HAVE_AVX(name) name ## _avx +# else +# define MAY_HAVE_AVX(name) name ## _c +# endif + +# if defined(OPUS_HAVE_RTCD) +int opus_select_arch(void); +# endif + +/*gcc appears to emit MOVDQA's to load the argument of an _mm_cvtepi8_epi32() + or _mm_cvtepi16_epi32() when optimizations are disabled, even though the + actual PMOVSXWD instruction takes an m32 or m64. Unlike a normal memory + reference, these require 16-byte alignment and load a full 16 bytes (instead + of 4 or 8), possibly reading out of bounds. + + We can insert an explicit MOVD or MOVQ using _mm_cvtsi32_si128() or + _mm_loadl_epi64(), which should have the same semantics as an m32 or m64 + reference in the PMOVSXWD instruction itself, but gcc is not smart enough to + optimize this out when optimizations ARE enabled. + + Clang, in contrast, requires us to do this always for _mm_cvtepi8_epi32 + (which is fair, since technically the compiler is always allowed to do the + dereference before invoking the function implementing the intrinsic). + However, it is smart enough to eliminate the extra MOVD instruction. + For _mm_cvtepi16_epi32, it does the right thing, though does *not* optimize out + the extra MOVQ if it's specified explicitly */ + +# if defined(__clang__) || !defined(__OPTIMIZE__) +# define OP_CVTEPI8_EPI32_M32(x) \ + (_mm_cvtepi8_epi32(_mm_cvtsi32_si128(*(int *)(x)))) +# else +# define OP_CVTEPI8_EPI32_M32(x) \ + (_mm_cvtepi8_epi32(*(__m128i *)(x))) +#endif + +/* similar reasoning about the instruction sequence as in the 32-bit macro above, + */ +# if defined(__clang__) || !defined(__OPTIMIZE__) +# define OP_CVTEPI16_EPI32_M64(x) \ + (_mm_cvtepi16_epi32(_mm_loadl_epi64((__m128i *)(x)))) +# else +# define OP_CVTEPI16_EPI32_M64(x) \ + (_mm_cvtepi16_epi32(*(__m128i *)(x))) +# endif + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt_headers.mk b/native/opennow-streamer/vendor/audiopus-sys/opus/celt_headers.mk new file mode 100644 index 000000000..706185da4 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt_headers.mk @@ -0,0 +1,53 @@ +CELT_HEAD = \ +celt/arch.h \ +celt/bands.h \ +celt/celt.h \ +celt/cpu_support.h \ +include/opus_types.h \ +include/opus_defines.h \ +include/opus_custom.h \ +celt/cwrs.h \ +celt/ecintrin.h \ +celt/entcode.h \ +celt/entdec.h \ +celt/entenc.h \ +celt/fixed_debug.h \ +celt/fixed_generic.h \ +celt/float_cast.h \ +celt/_kiss_fft_guts.h \ +celt/kiss_fft.h \ +celt/laplace.h \ +celt/mathops.h \ +celt/mdct.h \ +celt/mfrngcod.h \ +celt/modes.h \ +celt/os_support.h \ +celt/pitch.h \ +celt/celt_lpc.h \ +celt/x86/celt_lpc_sse.h \ +celt/quant_bands.h \ +celt/rate.h \ +celt/stack_alloc.h \ +celt/vq.h \ +celt/static_modes_float.h \ +celt/static_modes_fixed.h \ +celt/static_modes_float_arm_ne10.h \ +celt/static_modes_fixed_arm_ne10.h \ +celt/arm/armcpu.h \ +celt/arm/fixed_armv4.h \ +celt/arm/fixed_armv5e.h \ +celt/arm/fixed_arm64.h \ +celt/arm/kiss_fft_armv4.h \ +celt/arm/kiss_fft_armv5e.h \ +celt/arm/pitch_arm.h \ +celt/arm/fft_arm.h \ +celt/arm/mdct_arm.h \ +celt/mips/celt_mipsr1.h \ +celt/mips/fixed_generic_mipsr1.h \ +celt/mips/kiss_fft_mipsr1.h \ +celt/mips/mdct_mipsr1.h \ +celt/mips/pitch_mipsr1.h \ +celt/mips/vq_mipsr1.h \ +celt/x86/pitch_sse.h \ +celt/x86/vq_sse.h \ +celt/x86/x86cpu.h diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/celt_sources.mk b/native/opennow-streamer/vendor/audiopus-sys/opus/celt_sources.mk new file mode 100644 index 000000000..c9dab06ec --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/celt_sources.mk @@ -0,0 +1,50 @@ +CELT_SOURCES = \ +celt/bands.c \ +celt/celt.c \ +celt/celt_encoder.c \ +celt/celt_decoder.c \ +celt/cwrs.c \ +celt/entcode.c \ +celt/entdec.c \ +celt/entenc.c \ +celt/kiss_fft.c \ +celt/laplace.c \ +celt/mathops.c \ +celt/mdct.c \ +celt/modes.c \ +celt/pitch.c \ +celt/celt_lpc.c \ +celt/quant_bands.c \ +celt/rate.c \ +celt/vq.c + +CELT_SOURCES_SSE = \ +celt/x86/x86cpu.c \ +celt/x86/x86_celt_map.c \ +celt/x86/pitch_sse.c + +CELT_SOURCES_SSE2 = \ +celt/x86/pitch_sse2.c \ +celt/x86/vq_sse2.c + +CELT_SOURCES_SSE4_1 = \ +celt/x86/celt_lpc_sse4_1.c \ +celt/x86/pitch_sse4_1.c + +CELT_SOURCES_ARM = \ +celt/arm/armcpu.c \ +celt/arm/arm_celt_map.c + +CELT_SOURCES_ARM_ASM = \ +celt/arm/celt_pitch_xcorr_arm.s + +CELT_AM_SOURCES_ARM_ASM = \ +celt/arm/armopts.s.in + +CELT_SOURCES_ARM_NEON_INTR = \ +celt/arm/celt_neon_intr.c \ +celt/arm/pitch_neon_intr.c + +CELT_SOURCES_ARM_NE10 = \ +celt/arm/celt_fft_ne10.c \ +celt/arm/celt_mdct_ne10.c diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/CFeatureCheck.cmake b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/CFeatureCheck.cmake new file mode 100644 index 000000000..08828f585 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/CFeatureCheck.cmake @@ -0,0 +1,39 @@ +# - Compile and run code to check for C features +# +# This functions compiles a source file under the `cmake` folder +# and adds the corresponding `HAVE_[FILENAME]` flag to the CMake +# environment +# +# c_feature_check( []) +# +# - Example +# +# include(CFeatureCheck) +# c_feature_check(VLA) + +if(__c_feature_check) + return() +endif() +set(__c_feature_check INCLUDED) + +function(c_feature_check FILE) + string(TOLOWER ${FILE} FILE) + string(TOUPPER ${FILE} VAR) + string(TOUPPER "${VAR}_SUPPORTED" FEATURE) + if (DEFINED ${VAR}_SUPPORTED) + set(${VAR}_SUPPORTED 1 PARENT_SCOPE) + return() + endif() + + if (NOT DEFINED COMPILE_${FEATURE}) + message(STATUS "Performing Test ${FEATURE}") + try_compile(COMPILE_${FEATURE} ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/cmake/${FILE}.c) + endif() + + if(COMPILE_${FEATURE}) + message(STATUS "Performing Test ${FEATURE} -- success") + set(${VAR}_SUPPORTED 1 PARENT_SCOPE) + else() + message(STATUS "Performing Test ${FEATURE} -- failed to compile") + endif() +endfunction() diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusBuildtype.cmake b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusBuildtype.cmake new file mode 100644 index 000000000..557cc89b3 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusBuildtype.cmake @@ -0,0 +1,27 @@ +# Set a default build type if none was specified +if(__opus_buildtype) + return() +endif() +set(__opus_buildtype INCLUDED) + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + if(CMAKE_C_FLAGS) + message(STATUS "CMAKE_C_FLAGS: " ${CMAKE_C_FLAGS}) + else() + set(default_build_type "Release") + message( + STATUS + "Setting build type to '${default_build_type}' as none was specified and no CFLAGS was exported." + ) + set(CMAKE_BUILD_TYPE "${default_build_type}" + CACHE STRING "Choose the type of build." + FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE + PROPERTY STRINGS + "Debug" + "Release" + "MinSizeRel" + "RelWithDebInfo") + endif() +endif() diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusConfig.cmake b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusConfig.cmake new file mode 100644 index 000000000..8d19a5357 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusConfig.cmake @@ -0,0 +1,104 @@ +if(__opus_config) + return() +endif() +set(__opus_config INCLUDED) + +include(OpusFunctions) + +configure_file(cmake/config.h.cmake.in config.h @ONLY) +add_definitions(-DHAVE_CONFIG_H) + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set_property(GLOBAL PROPERTY C_STANDARD 99) + +if(MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +endif() + +include(CheckLibraryExists) +check_library_exists(m floor "" HAVE_LIBM) +if(HAVE_LIBM) + list(APPEND OPUS_REQUIRED_LIBRARIES m) +endif() + +include(CFeatureCheck) +c_feature_check(VLA) + +include(CheckIncludeFile) +check_include_file(alloca.h HAVE_ALLOCA_H) + +include(CheckSymbolExists) +if(HAVE_ALLOCA_H) + add_definitions(-DHAVE_ALLOCA_H) + check_symbol_exists(alloca "alloca.h" USE_ALLOCA_SUPPORTED) +else() + check_symbol_exists(alloca "stdlib.h;malloc.h" USE_ALLOCA_SUPPORTED) +endif() + +include(CheckFunctionExists) +check_function_exists(lrintf HAVE_LRINTF) +check_function_exists(lrint HAVE_LRINT) + +if(CMAKE_SYSTEM_PROCESSOR MATCHES "(i[0-9]86|x86|X86|amd64|AMD64|x86_64)") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(OPUS_CPU_X64 1) + else() + set(OPUS_CPU_X86 1) + endif() +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(arm|aarch64)") + set(OPUS_CPU_ARM 1) +endif() + +if(NOT OPUS_DISABLE_INTRINSICS) + opus_supports_cpu_detection(RUNTIME_CPU_CAPABILITY_DETECTION) +endif() + +if(OPUS_CPU_X86 OR OPUS_CPU_X64 AND NOT OPUS_DISABLE_INTRINSICS) + opus_detect_sse(COMPILER_SUPPORT_SIMD) +elseif(OPUS_CPU_ARM AND NOT OPUS_DISABLE_INTRINSICS) + opus_detect_neon(COMPILER_SUPPORT_NEON) + if(COMPILER_SUPPORT_NEON) + option(OPUS_USE_NEON "Option to enable NEON" ON) + option(OPUS_MAY_HAVE_NEON "Does runtime check for neon support" ON) + option(OPUS_PRESUME_NEON "Assume target CPU has NEON support" OFF) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") + set(OPUS_PRESUME_NEON ON) + elseif(CMAKE_SYSTEM_NAME MATCHES "iOS") + set(OPUS_PRESUME_NEON ON) + endif() + endif() +endif() + +if(MSVC) + check_flag(FAST_MATH /fp:fast) + check_flag(STACK_PROTECTOR /GS) + check_flag(STACK_PROTECTOR_DISABLED /GS-) +else() + check_flag(FAST_MATH -ffast-math) + check_flag(STACK_PROTECTOR -fstack-protector-strong) + check_flag(HIDDEN_VISIBILITY -fvisibility=hidden) + set(FORTIFY_SOURCE_SUPPORTED 1) +endif() + +if(MINGW) + # For MINGW we need to link ssp lib for security features such as + # stack protector and fortify_sources + check_library_exists(ssp __stack_chk_fail "" HAVE_LIBSSP) + if(NOT HAVE_LIBSSP) + message(WARNING "Could not find libssp in MinGW, disabling STACK_PROTECTOR and FORTIFY_SOURCE") + set(STACK_PROTECTOR_SUPPORTED 0) + set(FORTIFY_SOURCE_SUPPORTED 0) + endif() +endif() + +if(NOT MSVC) + set(WARNING_LIST -Wall -W -Wstrict-prototypes -Wextra -Wcast-align -Wnested-externs -Wshadow) + include(CheckCCompilerFlag) + foreach(WARNING_FLAG ${WARNING_LIST}) + string(REPLACE - "" WARNING_VAR ${WARNING_FLAG}) + check_c_compiler_flag(${WARNING_FLAG} ${WARNING_VAR}_SUPPORTED) + if(${WARNING_VAR}_SUPPORTED) + add_compile_options(${WARNING_FLAG}) + endif() + endforeach() +endif() diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusConfig.cmake.in b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusConfig.cmake.in new file mode 100644 index 000000000..0b21231d4 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusConfig.cmake.in @@ -0,0 +1,20 @@ +set(OPUS_VERSION @PROJECT_VERSION@) +set(OPUS_VERSION_STRING @PROJECT_VERSION@) +set(OPUS_VERSION_MAJOR @PROJECT_VERSION_MAJOR@) +set(OPUS_VERSION_MINOR @PROJECT_VERSION_MINOR@) +set(OPUS_VERSION_PATCH @PROJECT_VERSION_PATCH@) + +@PACKAGE_INIT@ + +set_and_check(OPUS_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") +set(OPUS_INCLUDE_DIR ${OPUS_INCLUDE_DIR};${OPUS_INCLUDE_DIR}/opus) +set(OPUS_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@;@PACKAGE_INCLUDE_INSTALL_DIR@/opus") + +include(${CMAKE_CURRENT_LIST_DIR}/OpusTargets.cmake) + +set(OPUS_LIBRARY Opus::opus) +set(OPUS_LIBRARIES Opus::opus) + +check_required_components(Opus) + +set(OPUS_FOUND 1) diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusFunctions.cmake b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusFunctions.cmake new file mode 100644 index 000000000..fcf3351fb --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusFunctions.cmake @@ -0,0 +1,215 @@ +if(__opus_functions) + return() +endif() +set(__opus_functions INCLUDED) + +function(get_library_version OPUS_LIBRARY_VERSION OPUS_LIBRARY_VERSION_MAJOR) + file(STRINGS configure.ac opus_lt_current_string + LIMIT_COUNT 1 + REGEX "OPUS_LT_CURRENT=") + string(REGEX MATCH + "OPUS_LT_CURRENT=([0-9]*)" + _ + ${opus_lt_current_string}) + set(OPUS_LT_CURRENT ${CMAKE_MATCH_1}) + + file(STRINGS configure.ac opus_lt_revision_string + LIMIT_COUNT 1 + REGEX "OPUS_LT_REVISION=") + string(REGEX MATCH + "OPUS_LT_REVISION=([0-9]*)" + _ + ${opus_lt_revision_string}) + set(OPUS_LT_REVISION ${CMAKE_MATCH_1}) + + file(STRINGS configure.ac opus_lt_age_string + LIMIT_COUNT 1 + REGEX "OPUS_LT_AGE=") + string(REGEX MATCH + "OPUS_LT_AGE=([0-9]*)" + _ + ${opus_lt_age_string}) + set(OPUS_LT_AGE ${CMAKE_MATCH_1}) + + math(EXPR OPUS_LIBRARY_VERSION_MAJOR "${OPUS_LT_CURRENT} - ${OPUS_LT_AGE}") + set(OPUS_LIBRARY_VERSION_MINOR ${OPUS_LT_AGE}) + set(OPUS_LIBRARY_VERSION_PATCH ${OPUS_LT_REVISION}) + set( + OPUS_LIBRARY_VERSION + "${OPUS_LIBRARY_VERSION_MAJOR}.${OPUS_LIBRARY_VERSION_MINOR}.${OPUS_LIBRARY_VERSION_PATCH}" + PARENT_SCOPE) + set(OPUS_LIBRARY_VERSION_MAJOR ${OPUS_LIBRARY_VERSION_MAJOR} PARENT_SCOPE) +endfunction() + +function(check_flag NAME FLAG) + include(CheckCCompilerFlag) + check_c_compiler_flag(${FLAG} ${NAME}_SUPPORTED) +endfunction() + +include(CheckIncludeFile) +# function to check if compiler supports SSE, SSE2, SSE4.1 and AVX if target +# systems may not have SSE support then use OPUS_MAY_HAVE_SSE option if target +# system is guaranteed to have SSE support then OPUS_PRESUME_SSE can be used to +# skip SSE runtime check +function(opus_detect_sse COMPILER_SUPPORT_SIMD) + message(STATUS "Check SIMD support by compiler") + check_include_file(xmmintrin.h HAVE_XMMINTRIN_H) # SSE1 + if(HAVE_XMMINTRIN_H) + if(MSVC) + # different arch options for 32 and 64 bit target for MSVC + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + check_flag(SSE1 /arch:SSE) + else() + set(SSE1_SUPPORTED + 1 + PARENT_SCOPE) + endif() + else() + check_flag(SSE1 -msse) + endif() + else() + set(SSE1_SUPPORTED + 0 + PARENT_SCOPE) + endif() + + check_include_file(emmintrin.h HAVE_EMMINTRIN_H) # SSE2 + if(HAVE_EMMINTRIN_H) + if(MSVC) + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + check_flag(SSE2 /arch:SSE2) + else() + set(SSE2_SUPPORTED + 1 + PARENT_SCOPE) + endif() + else() + check_flag(SSE2 -msse2) + endif() + else() + set(SSE2_SUPPORTED + 0 + PARENT_SCOPE) + endif() + + check_include_file(smmintrin.h HAVE_SMMINTRIN_H) # SSE4.1 + if(HAVE_SMMINTRIN_H) + if(MSVC) + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + check_flag(SSE4_1 /arch:SSE2) # SSE2 and above + else() + set(SSE4_1_SUPPORTED + 1 + PARENT_SCOPE) + endif() + else() + check_flag(SSE4_1 -msse4.1) + endif() + else() + set(SSE4_1_SUPPORTED + 0 + PARENT_SCOPE) + endif() + + check_include_file(immintrin.h HAVE_IMMINTRIN_H) # AVX + if(HAVE_IMMINTRIN_H) + if(MSVC) + check_flag(AVX /arch:AVX) + else() + check_flag(AVX -mavx) + endif() + else() + set(AVX_SUPPORTED + 0 + PARENT_SCOPE) + endif() + + if(SSE1_SUPPORTED OR SSE2_SUPPORTED OR SSE4_1_SUPPORTED OR AVX_SUPPORTED) + set(COMPILER_SUPPORT_SIMD 1 PARENT_SCOPE) + else() + message(STATUS "No SIMD support in compiler") + endif() +endfunction() + +function(opus_detect_neon COMPILER_SUPPORT_NEON) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "(arm|aarch64)") + message(STATUS "Check NEON support by compiler") + check_include_file(arm_neon.h HAVE_ARM_NEON_H) + if(HAVE_ARM_NEON_H) + set(COMPILER_SUPPORT_NEON ${HAVE_ARM_NEON_H} PARENT_SCOPE) + endif() + endif() +endfunction() + +function(opus_supports_cpu_detection RUNTIME_CPU_CAPABILITY_DETECTION) + if(MSVC) + check_include_file(intrin.h HAVE_INTRIN_H) + else() + check_include_file(cpuid.h HAVE_CPUID_H) + endif() + if(HAVE_INTRIN_H OR HAVE_CPUID_H) + set(RUNTIME_CPU_CAPABILITY_DETECTION 1 PARENT_SCOPE) + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(arm|aarch64)") + # ARM cpu detection is implemented for Windows and anything + # using a Linux kernel (such as Android). + if (CMAKE_SYSTEM_NAME MATCHES "(Windows|Linux|Android)") + set(RUNTIME_CPU_CAPABILITY_DETECTION 1 PARENT_SCOPE) + endif () + else() + set(RUNTIME_CPU_CAPABILITY_DETECTION 0 PARENT_SCOPE) + endif() +endfunction() + +function(add_sources_group target group) + target_sources(${target} PRIVATE ${ARGN}) + source_group(${group} FILES ${ARGN}) +endfunction() + +function(get_opus_sources SOURCE_GROUP MAKE_FILE SOURCES) + # read file, each item in list is one group + file(STRINGS ${MAKE_FILE} opus_sources) + + # add wildcard for regex match + string(CONCAT SOURCE_GROUP ${SOURCE_GROUP} ".*$") + + # find group + foreach(val IN LISTS opus_sources) + if(val MATCHES ${SOURCE_GROUP}) + list(LENGTH val list_length) + if(${list_length} EQUAL 1) + # for tests split by '=' and clean up the rest into a list + string(FIND ${val} "=" index) + math(EXPR index "${index} + 1") + string(SUBSTRING ${val} + ${index} + -1 + sources) + string(REPLACE " " + ";" + sources + ${sources}) + else() + # discard the group + list(REMOVE_AT val 0) + set(sources ${val}) + endif() + break() + endif() + endforeach() + + list(LENGTH sources list_length) + if(${list_length} LESS 1) + message( + FATAL_ERROR + "No files parsed succesfully from ${SOURCE_GROUP} in ${MAKE_FILE}") + endif() + + # remove trailing whitespaces + set(list_var "") + foreach(source ${sources}) + string(STRIP "${source}" source) + list(APPEND list_var "${source}") + endforeach() + + set(${SOURCES} ${list_var} PARENT_SCOPE) +endfunction() diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusPackageVersion.cmake b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusPackageVersion.cmake new file mode 100644 index 000000000..447ce3b17 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusPackageVersion.cmake @@ -0,0 +1,70 @@ +if(__opus_version) + return() +endif() +set(__opus_version INCLUDED) + +function(get_package_version PACKAGE_VERSION PROJECT_VERSION) + + find_package(Git) + if(GIT_FOUND AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/.git") + execute_process(COMMAND ${GIT_EXECUTABLE} + --git-dir=${CMAKE_CURRENT_LIST_DIR}/.git describe + --tags --match "v*" OUTPUT_VARIABLE OPUS_PACKAGE_VERSION) + if(OPUS_PACKAGE_VERSION) + string(STRIP ${OPUS_PACKAGE_VERSION}, OPUS_PACKAGE_VERSION) + string(REPLACE \n + "" + OPUS_PACKAGE_VERSION + ${OPUS_PACKAGE_VERSION}) + string(REPLACE , + "" + OPUS_PACKAGE_VERSION + ${OPUS_PACKAGE_VERSION}) + + string(SUBSTRING ${OPUS_PACKAGE_VERSION} + 1 + -1 + OPUS_PACKAGE_VERSION) + message(STATUS "Opus package version from git repo: ${OPUS_PACKAGE_VERSION}") + endif() + + elseif(EXISTS "${CMAKE_CURRENT_LIST_DIR}/package_version" + AND NOT OPUS_PACKAGE_VERSION) + # Not a git repo, lets' try to parse it from package_version file if exists + file(STRINGS package_version OPUS_PACKAGE_VERSION + LIMIT_COUNT 1 + REGEX "PACKAGE_VERSION=") + string(REPLACE "PACKAGE_VERSION=" + "" + OPUS_PACKAGE_VERSION + ${OPUS_PACKAGE_VERSION}) + string(REPLACE "\"" + "" + OPUS_PACKAGE_VERSION + ${OPUS_PACKAGE_VERSION}) + # In case we have a unknown dist here we just replace it with 0 + string(REPLACE "unknown" + "0" + OPUS_PACKAGE_VERSION + ${OPUS_PACKAGE_VERSION}) + message(STATUS "Opus package version from package_version file: ${OPUS_PACKAGE_VERSION}") + endif() + + if(OPUS_PACKAGE_VERSION) + string(REGEX + REPLACE "^([0-9]+.[0-9]+\\.?([0-9]+)?).*" + "\\1" + OPUS_PROJECT_VERSION + ${OPUS_PACKAGE_VERSION}) + else() + # fail to parse version from git and package version + message(WARNING "Could not get package version.") + set(OPUS_PACKAGE_VERSION 0) + set(OPUS_PROJECT_VERSION 0) + endif() + + message(STATUS "Opus project version: ${OPUS_PROJECT_VERSION}") + + set(PACKAGE_VERSION ${OPUS_PACKAGE_VERSION} PARENT_SCOPE) + set(PROJECT_VERSION ${OPUS_PROJECT_VERSION} PARENT_SCOPE) +endfunction() diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusSources.cmake b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusSources.cmake new file mode 100644 index 000000000..01e75d1a3 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/OpusSources.cmake @@ -0,0 +1,46 @@ +if(__opus_sources) + return() +endif() +set(__opus_sources INCLUDED) + +include(OpusFunctions) + +get_opus_sources(SILK_HEAD silk_headers.mk silk_headers) +get_opus_sources(SILK_SOURCES silk_sources.mk silk_sources) +get_opus_sources(SILK_SOURCES_FLOAT silk_sources.mk silk_sources_float) +get_opus_sources(SILK_SOURCES_FIXED silk_sources.mk silk_sources_fixed) +get_opus_sources(SILK_SOURCES_SSE4_1 silk_sources.mk silk_sources_sse4_1) +get_opus_sources(SILK_SOURCES_FIXED_SSE4_1 silk_sources.mk + silk_sources_fixed_sse4_1) +get_opus_sources(SILK_SOURCES_ARM_NEON_INTR silk_sources.mk + silk_sources_arm_neon_intr) +get_opus_sources(SILK_SOURCES_FIXED_ARM_NEON_INTR silk_sources.mk + silk_sources_fixed_arm_neon_intr) + +get_opus_sources(OPUS_HEAD opus_headers.mk opus_headers) +get_opus_sources(OPUS_SOURCES opus_sources.mk opus_sources) +get_opus_sources(OPUS_SOURCES_FLOAT opus_sources.mk opus_sources_float) + +get_opus_sources(CELT_HEAD celt_headers.mk celt_headers) +get_opus_sources(CELT_SOURCES celt_sources.mk celt_sources) +get_opus_sources(CELT_SOURCES_SSE celt_sources.mk celt_sources_sse) +get_opus_sources(CELT_SOURCES_SSE2 celt_sources.mk celt_sources_sse2) +get_opus_sources(CELT_SOURCES_SSE4_1 celt_sources.mk celt_sources_sse4_1) +get_opus_sources(CELT_SOURCES_ARM celt_sources.mk celt_sources_arm) +get_opus_sources(CELT_SOURCES_ARM_ASM celt_sources.mk celt_sources_arm_asm) +get_opus_sources(CELT_AM_SOURCES_ARM_ASM celt_sources.mk + celt_am_sources_arm_asm) +get_opus_sources(CELT_SOURCES_ARM_NEON_INTR celt_sources.mk + celt_sources_arm_neon_intr) +get_opus_sources(CELT_SOURCES_ARM_NE10 celt_sources.mk celt_sources_arm_ne10) + +get_opus_sources(opus_demo_SOURCES Makefile.am opus_demo_sources) +get_opus_sources(opus_custom_demo_SOURCES Makefile.am opus_custom_demo_sources) +get_opus_sources(opus_compare_SOURCES Makefile.am opus_compare_sources) +get_opus_sources(tests_test_opus_api_SOURCES Makefile.am test_opus_api_sources) +get_opus_sources(tests_test_opus_encode_SOURCES Makefile.am + test_opus_encode_sources) +get_opus_sources(tests_test_opus_decode_SOURCES Makefile.am + test_opus_decode_sources) +get_opus_sources(tests_test_opus_padding_SOURCES Makefile.am + test_opus_padding_sources) diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/config.h.cmake.in b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/config.h.cmake.in new file mode 100644 index 000000000..5550842c5 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/config.h.cmake.in @@ -0,0 +1 @@ +#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@" \ No newline at end of file diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/vla.c b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/vla.c new file mode 100644 index 000000000..05b211979 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/cmake/vla.c @@ -0,0 +1,7 @@ +int main() { + static int x; + char a[++x]; + a[sizeof a - 1] = 0; + int N; + return a[0]; +} \ No newline at end of file diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/configure.ac b/native/opennow-streamer/vendor/audiopus-sys/opus/configure.ac new file mode 100644 index 000000000..f12f0aa9a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/configure.ac @@ -0,0 +1,946 @@ +dnl Process this file with autoconf to produce a configure script. -*-m4-*- + +dnl The package_version file will be automatically synced to the git revision +dnl by the update_version script when configured in the repository, but will +dnl remain constant in tarball releases unless it is manually edited. +m4_define([CURRENT_VERSION], + m4_esyscmd([ ./update_version 2>/dev/null || true + if test -e package_version; then + . ./package_version + printf "$PACKAGE_VERSION" + else + printf "unknown" + fi ])) + +AC_INIT([opus],[CURRENT_VERSION],[opus@xiph.org]) + +AC_CONFIG_SRCDIR(src/opus_encoder.c) +AC_CONFIG_MACRO_DIR([m4]) + +dnl enable silent rules on automake 1.11 and later +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +# For libtool. +dnl Please update these for releases. +OPUS_LT_CURRENT=8 +OPUS_LT_REVISION=0 +OPUS_LT_AGE=8 + +AC_SUBST(OPUS_LT_CURRENT) +AC_SUBST(OPUS_LT_REVISION) +AC_SUBST(OPUS_LT_AGE) + +AM_INIT_AUTOMAKE([no-define]) +AM_MAINTAINER_MODE([enable]) + +AC_CANONICAL_HOST +AC_MINGW32 +AM_PROG_LIBTOOL +AM_PROG_CC_C_O + +AC_PROG_CC_C99 +AC_C_CONST +AC_C_INLINE + +AM_PROG_AS + +AC_DEFINE([OPUS_BUILD], [], [This is a build of OPUS]) + +#Use a hacked up version of autoconf's AC_C_RESTRICT because it's not +#strong enough a test to detect old buggy versions of GCC (e.g. 2.95.3) +#Note: Both this and the test for variable-size arrays below are also +# done by AC_PROG_CC_C99, but not thoroughly enough apparently. +AC_CACHE_CHECK([for C/C++ restrict keyword], ac_cv_c_restrict, + [ac_cv_c_restrict=no + # The order here caters to the fact that C++ does not require restrict. + for ac_kw in __restrict __restrict__ _Restrict restrict; do + AC_COMPILE_IFELSE([AC_LANG_PROGRAM( + [[typedef int * int_ptr; + int foo (int_ptr $ac_kw ip, int * $ac_kw baz[]) { + return ip[0]; + }]], + [[int s[1]; + int * $ac_kw t = s; + t[0] = 0; + return foo(t, (void *)0)]])], + [ac_cv_c_restrict=$ac_kw]) + test "$ac_cv_c_restrict" != no && break + done + ]) + +AH_VERBATIM([restrict], +[/* Define to the equivalent of the C99 'restrict' keyword, or to + nothing if this is not supported. Do not define if restrict is + supported directly. */ +#undef restrict +/* Work around a bug in Sun C++: it does not support _Restrict or + __restrict__, even though the corresponding Sun C compiler ends up with + "#define restrict _Restrict" or "#define restrict __restrict__" in the + previous line. Perhaps some future version of Sun C++ will work with + restrict; if so, hopefully it defines __RESTRICT like Sun C does. */ +#if defined __SUNPRO_CC && !defined __RESTRICT +# define _Restrict +# define __restrict__ +#endif]) + +case $ac_cv_c_restrict in + restrict) ;; + no) AC_DEFINE([restrict], []) ;; + *) AC_DEFINE_UNQUOTED([restrict], [$ac_cv_c_restrict]) ;; +esac + +AC_MSG_CHECKING(for C99 variable-size arrays) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], + [[static int x; char a[++x]; a[sizeof a - 1] = 0; int N; return a[0];]])], + [ has_var_arrays=yes + use_alloca="no (using var arrays)" + AC_DEFINE([VAR_ARRAYS], [1], [Use C99 variable-size arrays]) + ],[ + has_var_arrays=no + ]) +AC_MSG_RESULT([$has_var_arrays]) + +AS_IF([test "$has_var_arrays" = "no"], + [ + AC_CHECK_HEADERS([alloca.h]) + AC_MSG_CHECKING(for alloca) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[int foo=10; int *array = alloca(foo);]])], + [ use_alloca=yes; + AC_DEFINE([USE_ALLOCA], [], [Make use of alloca]) + ],[ + use_alloca=no + ]) + AC_MSG_RESULT([$use_alloca]) + ]) + +LT_LIB_M + +AC_ARG_ENABLE([fixed-point], + [AS_HELP_STRING([--enable-fixed-point], + [compile without floating point (for machines without a fast enough FPU)])],, + [enable_fixed_point=no]) + +AS_IF([test "$enable_fixed_point" = "yes"],[ + enable_float="no" + AC_DEFINE([FIXED_POINT], [1], [Compile as fixed-point (for machines without a fast enough FPU)]) + PC_BUILD="fixed-point" +],[ + enable_float="yes"; + PC_BUILD="floating-point" +]) + +AM_CONDITIONAL([FIXED_POINT], [test "$enable_fixed_point" = "yes"]) + +AC_ARG_ENABLE([fixed-point-debug], + [AS_HELP_STRING([--enable-fixed-point-debug], [debug fixed-point implementation])],, + [enable_fixed_point_debug=no]) + +AS_IF([test "$enable_fixed_point_debug" = "yes"],[ + AC_DEFINE([FIXED_DEBUG], [1], [Debug fixed-point implementation]) +]) + +AC_ARG_ENABLE([float_api], + [AS_HELP_STRING([--disable-float-api], + [compile without the floating point API (for machines with no float library)])],, + [enable_float_api=yes]) + +AM_CONDITIONAL([DISABLE_FLOAT_API], [test "$enable_float_api" = "no"]) + +AS_IF([test "$enable_float_api" = "no"],[ + AC_DEFINE([DISABLE_FLOAT_API], [1], [Do not build the float API]) +]) + +AC_ARG_ENABLE([custom-modes], + [AS_HELP_STRING([--enable-custom-modes], [enable non-Opus modes, e.g. 44.1 kHz & 2^n frames])],, + [enable_custom_modes=no]) + +AS_IF([test "$enable_custom_modes" = "yes"],[ + AC_DEFINE([CUSTOM_MODES], [1], [Custom modes]) + PC_BUILD="$PC_BUILD, custom modes" +]) + +AM_CONDITIONAL([CUSTOM_MODES], [test "$enable_custom_modes" = "yes"]) + +has_float_approx=no +#case "$host_cpu" in +#i[[3456]]86 | x86_64 | powerpc64 | powerpc32 | ia64) +# has_float_approx=yes +# ;; +#esac + +AC_ARG_ENABLE([float-approx], + [AS_HELP_STRING([--enable-float-approx], [enable fast approximations for floating point])], + [if test "$enable_float_approx" = "yes"; then + AC_WARN([Floating point approximations are not supported on all platforms.]) + fi + ], + [enable_float_approx=$has_float_approx]) + +AS_IF([test "$enable_float_approx" = "yes"],[ + AC_DEFINE([FLOAT_APPROX], [1], [Float approximations]) +]) + +AC_ARG_ENABLE([asm], + [AS_HELP_STRING([--disable-asm], [Disable assembly optimizations])],, + [enable_asm=yes]) + +AC_ARG_ENABLE([rtcd], + [AS_HELP_STRING([--disable-rtcd], [Disable run-time CPU capabilities detection])],, + [enable_rtcd=yes]) + +AC_ARG_ENABLE([intrinsics], + [AS_HELP_STRING([--disable-intrinsics], [Disable intrinsics optimizations])],, + [enable_intrinsics=yes]) + +rtcd_support=no +cpu_arm=no + +AS_IF([test x"${enable_asm}" = x"yes"],[ + inline_optimization="No inline ASM for your platform, please send patches" + case $host_cpu in + arm*) + dnl Currently we only have asm for fixed-point + AS_IF([test "$enable_float" != "yes"],[ + cpu_arm=yes + AC_DEFINE([OPUS_ARM_ASM], [], [Make use of ARM asm optimization]) + AS_GCC_INLINE_ASSEMBLY( + [inline_optimization="ARM"], + [inline_optimization="disabled"] + ) + AS_ASM_ARM_EDSP([OPUS_ARM_INLINE_EDSP=1],[OPUS_ARM_INLINE_EDSP=0]) + AS_ASM_ARM_MEDIA([OPUS_ARM_INLINE_MEDIA=1], + [OPUS_ARM_INLINE_MEDIA=0]) + AS_ASM_ARM_NEON([OPUS_ARM_INLINE_NEON=1],[OPUS_ARM_INLINE_NEON=0]) + AS_IF([test x"$inline_optimization" = x"ARM"],[ + AM_CONDITIONAL([OPUS_ARM_INLINE_ASM],[true]) + AC_DEFINE([OPUS_ARM_INLINE_ASM], 1, + [Use generic ARMv4 inline asm optimizations]) + AS_IF([test x"$OPUS_ARM_INLINE_EDSP" = x"1"],[ + AC_DEFINE([OPUS_ARM_INLINE_EDSP], [1], + [Use ARMv5E inline asm optimizations]) + inline_optimization="$inline_optimization (EDSP)" + ]) + AS_IF([test x"$OPUS_ARM_INLINE_MEDIA" = x"1"],[ + AC_DEFINE([OPUS_ARM_INLINE_MEDIA], [1], + [Use ARMv6 inline asm optimizations]) + inline_optimization="$inline_optimization (Media)" + ]) + AS_IF([test x"$OPUS_ARM_INLINE_NEON" = x"1"],[ + AC_DEFINE([OPUS_ARM_INLINE_NEON], 1, + [Use ARM NEON inline asm optimizations]) + inline_optimization="$inline_optimization (NEON)" + ]) + ]) + dnl We need Perl to translate RVCT-syntax asm to gas syntax. + AC_CHECK_PROG([HAVE_PERL], perl, yes, no) + AS_IF([test x"$HAVE_PERL" = x"yes"],[ + AM_CONDITIONAL([OPUS_ARM_EXTERNAL_ASM],[true]) + asm_optimization="ARM" + AS_IF([test x"$OPUS_ARM_INLINE_EDSP" = x"1"], [ + OPUS_ARM_PRESUME_EDSP=1 + OPUS_ARM_MAY_HAVE_EDSP=1 + ], + [ + OPUS_ARM_PRESUME_EDSP=0 + OPUS_ARM_MAY_HAVE_EDSP=0 + ]) + AS_IF([test x"$OPUS_ARM_INLINE_MEDIA" = x"1"], [ + OPUS_ARM_PRESUME_MEDIA=1 + OPUS_ARM_MAY_HAVE_MEDIA=1 + ], + [ + OPUS_ARM_PRESUME_MEDIA=0 + OPUS_ARM_MAY_HAVE_MEDIA=0 + ]) + AS_IF([test x"$OPUS_ARM_INLINE_NEON" = x"1"], [ + OPUS_ARM_PRESUME_NEON=1 + OPUS_ARM_MAY_HAVE_NEON=1 + ], + [ + OPUS_ARM_PRESUME_NEON=0 + OPUS_ARM_MAY_HAVE_NEON=0 + ]) + AS_IF([test x"$enable_rtcd" = x"yes"],[ + AS_IF([test x"$OPUS_ARM_MAY_HAVE_EDSP" != x"1"],[ + AC_MSG_NOTICE( + [Trying to force-enable armv5e EDSP instructions...]) + AS_ASM_ARM_EDSP_FORCE([OPUS_ARM_MAY_HAVE_EDSP=1]) + ]) + AS_IF([test x"$OPUS_ARM_MAY_HAVE_MEDIA" != x"1"],[ + AC_MSG_NOTICE( + [Trying to force-enable ARMv6 media instructions...]) + AS_ASM_ARM_MEDIA_FORCE([OPUS_ARM_MAY_HAVE_MEDIA=1]) + ]) + AS_IF([test x"$OPUS_ARM_MAY_HAVE_NEON" != x"1"],[ + AC_MSG_NOTICE( + [Trying to force-enable NEON instructions...]) + AS_ASM_ARM_NEON_FORCE([OPUS_ARM_MAY_HAVE_NEON=1]) + ]) + ]) + rtcd_support= + AS_IF([test x"$OPUS_ARM_MAY_HAVE_EDSP" = x"1"],[ + AC_DEFINE(OPUS_ARM_MAY_HAVE_EDSP, 1, + [Define if assembler supports EDSP instructions]) + AS_IF([test x"$OPUS_ARM_PRESUME_EDSP" = x"1"],[ + AC_DEFINE(OPUS_ARM_PRESUME_EDSP, 1, + [Define if binary requires EDSP instruction support]) + asm_optimization="$asm_optimization (EDSP)" + ], + [rtcd_support="$rtcd_support (EDSP)"] + ) + ]) + AC_SUBST(OPUS_ARM_MAY_HAVE_EDSP) + AS_IF([test x"$OPUS_ARM_MAY_HAVE_MEDIA" = x"1"],[ + AC_DEFINE(OPUS_ARM_MAY_HAVE_MEDIA, 1, + [Define if assembler supports ARMv6 media instructions]) + AS_IF([test x"$OPUS_ARM_PRESUME_MEDIA" = x"1"],[ + AC_DEFINE(OPUS_ARM_PRESUME_MEDIA, 1, + [Define if binary requires ARMv6 media instruction support]) + asm_optimization="$asm_optimization (Media)" + ], + [rtcd_support="$rtcd_support (Media)"] + ) + ]) + AC_SUBST(OPUS_ARM_MAY_HAVE_MEDIA) + AS_IF([test x"$OPUS_ARM_MAY_HAVE_NEON" = x"1"],[ + AC_DEFINE(OPUS_ARM_MAY_HAVE_NEON, 1, + [Define if compiler supports NEON instructions]) + AS_IF([test x"$OPUS_ARM_PRESUME_NEON" = x"1"], [ + AC_DEFINE(OPUS_ARM_PRESUME_NEON, 1, + [Define if binary requires NEON instruction support]) + asm_optimization="$asm_optimization (NEON)" + ], + [rtcd_support="$rtcd_support (NEON)"] + ) + ]) + AC_SUBST(OPUS_ARM_MAY_HAVE_NEON) + dnl Make sure turning on RTCD gets us at least one + dnl instruction set. + AS_IF([test x"$rtcd_support" != x""], + [rtcd_support=ARM"$rtcd_support"], + [rtcd_support="no"] + ) + AC_MSG_CHECKING([for apple style tools]) + AC_PREPROC_IFELSE([AC_LANG_PROGRAM([ +#ifndef __APPLE__ +#error 1 +#endif],[])], + [AC_MSG_RESULT([yes]); ARM2GNU_PARAMS="--apple"], + [AC_MSG_RESULT([no]); ARM2GNU_PARAMS=""]) + AC_SUBST(ARM2GNU_PARAMS) + ], + [ + AC_MSG_WARN( + [*** ARM assembly requires perl -- disabling optimizations]) + asm_optimization="(missing perl dependency for ARM)" + ]) + ]) + ;; + esac +],[ + inline_optimization="disabled" + asm_optimization="disabled" +]) + +AM_CONDITIONAL([OPUS_ARM_INLINE_ASM], + [test x"${inline_optimization%% *}" = x"ARM"]) +AM_CONDITIONAL([OPUS_ARM_EXTERNAL_ASM], + [test x"${asm_optimization%% *}" = x"ARM"]) + +AM_CONDITIONAL([HAVE_SSE], [false]) +AM_CONDITIONAL([HAVE_SSE2], [false]) +AM_CONDITIONAL([HAVE_SSE4_1], [false]) +AM_CONDITIONAL([HAVE_AVX], [false]) + +m4_define([DEFAULT_X86_SSE_CFLAGS], [-msse]) +m4_define([DEFAULT_X86_SSE2_CFLAGS], [-msse2]) +m4_define([DEFAULT_X86_SSE4_1_CFLAGS], [-msse4.1]) +m4_define([DEFAULT_X86_AVX_CFLAGS], [-mavx]) +m4_define([DEFAULT_ARM_NEON_INTR_CFLAGS], [-mfpu=neon]) +# With GCC on ARM32 softfp architectures (e.g. Android, or older Ubuntu) you need to specify +# -mfloat-abi=softfp for -mfpu=neon to work. However, on ARM32 hardfp architectures (e.g. newer Ubuntu), +# this option will break things. + +# As a heuristic, if host matches arm*eabi* but not arm*hf*, it's probably soft-float. +m4_define([DEFAULT_ARM_NEON_SOFTFP_INTR_CFLAGS], [-mfpu=neon -mfloat-abi=softfp]) + +AS_CASE([$host], + [arm*hf*], [AS_VAR_SET([RESOLVED_DEFAULT_ARM_NEON_INTR_CFLAGS], "DEFAULT_ARM_NEON_INTR_CFLAGS")], + [arm*eabi*], [AS_VAR_SET([RESOLVED_DEFAULT_ARM_NEON_INTR_CFLAGS], "DEFAULT_ARM_NEON_SOFTFP_INTR_CFLAGS")], + [AS_VAR_SET([RESOLVED_DEFAULT_ARM_NEON_INTR_CFLAGS], "DEFAULT_ARM_NEON_INTR_CFLAGS")]) + +AC_ARG_VAR([X86_SSE_CFLAGS], [C compiler flags to compile SSE intrinsics @<:@default=]DEFAULT_X86_SSE_CFLAGS[@:>@]) +AC_ARG_VAR([X86_SSE2_CFLAGS], [C compiler flags to compile SSE2 intrinsics @<:@default=]DEFAULT_X86_SSE2_CFLAGS[@:>@]) +AC_ARG_VAR([X86_SSE4_1_CFLAGS], [C compiler flags to compile SSE4.1 intrinsics @<:@default=]DEFAULT_X86_SSE4_1_CFLAGS[@:>@]) +AC_ARG_VAR([X86_AVX_CFLAGS], [C compiler flags to compile AVX intrinsics @<:@default=]DEFAULT_X86_AVX_CFLAGS[@:>@]) +AC_ARG_VAR([ARM_NEON_INTR_CFLAGS], [C compiler flags to compile ARM NEON intrinsics @<:@default=]DEFAULT_ARM_NEON_INTR_CFLAGS / DEFAULT_ARM_NEON_SOFTFP_INTR_CFLAGS[@:>@]) + +AS_VAR_SET_IF([X86_SSE_CFLAGS], [], [AS_VAR_SET([X86_SSE_CFLAGS], "DEFAULT_X86_SSE_CFLAGS")]) +AS_VAR_SET_IF([X86_SSE2_CFLAGS], [], [AS_VAR_SET([X86_SSE2_CFLAGS], "DEFAULT_X86_SSE2_CFLAGS")]) +AS_VAR_SET_IF([X86_SSE4_1_CFLAGS], [], [AS_VAR_SET([X86_SSE4_1_CFLAGS], "DEFAULT_X86_SSE4_1_CFLAGS")]) +AS_VAR_SET_IF([X86_AVX_CFLAGS], [], [AS_VAR_SET([X86_AVX_CFLAGS], "DEFAULT_X86_AVX_CFLAGS")]) +AS_VAR_SET_IF([ARM_NEON_INTR_CFLAGS], [], [AS_VAR_SET([ARM_NEON_INTR_CFLAGS], ["$RESOLVED_DEFAULT_ARM_NEON_INTR_CFLAGS"])]) + +AC_DEFUN([OPUS_PATH_NE10], + [ + AC_ARG_WITH(NE10, + AC_HELP_STRING([--with-NE10=PFX],[Prefix where libNE10 is installed (optional)]), + NE10_prefix="$withval", NE10_prefix="") + AC_ARG_WITH(NE10-libraries, + AC_HELP_STRING([--with-NE10-libraries=DIR], + [Directory where libNE10 library is installed (optional)]), + NE10_libraries="$withval", NE10_libraries="") + AC_ARG_WITH(NE10-includes, + AC_HELP_STRING([--with-NE10-includes=DIR], + [Directory where libNE10 header files are installed (optional)]), + NE10_includes="$withval", NE10_includes="") + + if test "x$NE10_libraries" != "x" ; then + NE10_LIBS="-L$NE10_libraries" + elif test "x$NE10_prefix" = "xno" || test "x$NE10_prefix" = "xyes" ; then + NE10_LIBS="" + elif test "x$NE10_prefix" != "x" ; then + NE10_LIBS="-L$NE10_prefix/lib" + elif test "x$prefix" != "xNONE" ; then + NE10_LIBS="-L$prefix/lib" + fi + + if test "x$NE10_prefix" != "xno" ; then + NE10_LIBS="$NE10_LIBS -lNE10" + fi + + if test "x$NE10_includes" != "x" ; then + NE10_CFLAGS="-I$NE10_includes" + elif test "x$NE10_prefix" = "xno" || test "x$NE10_prefix" = "xyes" ; then + NE10_CFLAGS="" + elif test "x$NE10_prefix" != "x" ; then + NE10_CFLAGS="-I$NE10_prefix/include" + elif test "x$prefix" != "xNONE"; then + NE10_CFLAGS="-I$prefix/include" + fi + + AC_MSG_CHECKING(for NE10) + save_CFLAGS="$CFLAGS"; CFLAGS="$CFLAGS $NE10_CFLAGS" + save_LIBS="$LIBS"; LIBS="$LIBS $NE10_LIBS $LIBM" + AC_LINK_IFELSE( + [ + AC_LANG_PROGRAM( + [[#include + ]], + [[ + ne10_fft_cfg_float32_t cfg; + cfg = ne10_fft_alloc_c2c_float32_neon(480); + ]] + ) + ],[ + HAVE_ARM_NE10=1 + AC_MSG_RESULT([yes]) + ],[ + HAVE_ARM_NE10=0 + AC_MSG_RESULT([no]) + NE10_CFLAGS="" + NE10_LIBS="" + ] + ) + CFLAGS="$save_CFLAGS"; LIBS="$save_LIBS" + #Now we know if libNE10 is installed or not + AS_IF([test x"$HAVE_ARM_NE10" = x"1"], + [ + AC_DEFINE([HAVE_ARM_NE10], 1, [NE10 library is installed on host. Make sure it is on target!]) + AC_SUBST(HAVE_ARM_NE10) + AC_SUBST(NE10_CFLAGS) + AC_SUBST(NE10_LIBS) + ] + ) + ] +) + +AS_IF([test x"$enable_intrinsics" = x"yes"],[ + intrinsics_support="" + AS_CASE([$host_cpu], + [arm*|aarch64*], + [ + cpu_arm=yes + OPUS_CHECK_INTRINSICS( + [ARM Neon], + [$ARM_NEON_INTR_CFLAGS], + [OPUS_ARM_MAY_HAVE_NEON_INTR], + [OPUS_ARM_PRESUME_NEON_INTR], + [[#include + ]], + [[ + static float32x4_t A0, A1, SUMM; + SUMM = vmlaq_f32(SUMM, A0, A1); + return (int)vgetq_lane_f32(SUMM, 0); + ]] + ) + AS_IF([test x"$OPUS_ARM_MAY_HAVE_NEON_INTR" = x"1" && test x"$OPUS_ARM_PRESUME_NEON_INTR" != x"1"], + [ + OPUS_ARM_NEON_INTR_CFLAGS="$ARM_NEON_INTR_CFLAGS" + AC_SUBST([OPUS_ARM_NEON_INTR_CFLAGS]) + ] + ) + + AS_IF([test x"$OPUS_ARM_MAY_HAVE_NEON_INTR" = x"1"], + [ + AC_DEFINE([OPUS_ARM_MAY_HAVE_NEON_INTR], 1, [Compiler supports ARMv7/Aarch64 Neon Intrinsics]) + intrinsics_support="$intrinsics_support (NEON)" + + AS_IF([test x"$enable_rtcd" != x"no" && test x"$OPUS_ARM_PRESUME_NEON_INTR" != x"1"], + [AS_IF([test x"$rtcd_support" = x"no"], + [rtcd_support="ARM (NEON Intrinsics)"], + [rtcd_support="$rtcd_support (NEON Intrinsics)"])]) + + AS_IF([test x"$OPUS_ARM_PRESUME_NEON_INTR" = x"1"], + [AC_DEFINE([OPUS_ARM_PRESUME_NEON_INTR], 1, [Define if binary requires NEON intrinsics support])]) + + OPUS_PATH_NE10() + AS_IF([test x"$NE10_LIBS" != x""], + [ + intrinsics_support="$intrinsics_support (NE10)" + AS_IF([test x"enable_rtcd" != x"" \ + && test x"$OPUS_ARM_PRESUME_NEON_INTR" != x"1"], + [rtcd_support="$rtcd_support (NE10)"]) + ]) + + OPUS_CHECK_INTRINSICS( + [Aarch64 Neon], + [$ARM_NEON_INTR_CFLAGS], + [OPUS_ARM_MAY_HAVE_AARCH64_NEON_INTR], + [OPUS_ARM_PRESUME_AARCH64_NEON_INTR], + [[#include + ]], + [[ + static int32_t IN; + static int16_t OUT; + OUT = vqmovns_s32(IN); + ]] + ) + + AS_IF([test x"$OPUS_ARM_PRESUME_AARCH64_NEON_INTR" = x"1"], + [ + AC_DEFINE([OPUS_ARM_PRESUME_AARCH64_NEON_INTR], 1, [Define if binary requires Aarch64 Neon Intrinsics]) + intrinsics_support="$intrinsics_support (NEON [Aarch64])" + ]) + + AS_IF([test x"$intrinsics_support" = x""], + [intrinsics_support=no], + [intrinsics_support="ARM$intrinsics_support"]) + ], + [ + AC_MSG_WARN([Compiler does not support ARM intrinsics]) + intrinsics_support=no + ]) + ], + [i?86|x86_64], + [ + OPUS_CHECK_INTRINSICS( + [SSE], + [$X86_SSE_CFLAGS], + [OPUS_X86_MAY_HAVE_SSE], + [OPUS_X86_PRESUME_SSE], + [[#include + #include + ]], + [[ + __m128 mtest; + mtest = _mm_set1_ps((float)time(NULL)); + mtest = _mm_mul_ps(mtest, mtest); + return _mm_cvtss_si32(mtest); + ]] + ) + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE" = x"1" && test x"$OPUS_X86_PRESUME_SSE" != x"1"], + [ + OPUS_X86_SSE_CFLAGS="$X86_SSE_CFLAGS" + AC_SUBST([OPUS_X86_SSE_CFLAGS]) + ] + ) + OPUS_CHECK_INTRINSICS( + [SSE2], + [$X86_SSE2_CFLAGS], + [OPUS_X86_MAY_HAVE_SSE2], + [OPUS_X86_PRESUME_SSE2], + [[#include + #include + ]], + [[ + __m128i mtest; + mtest = _mm_set1_epi32((int)time(NULL)); + mtest = _mm_mul_epu32(mtest, mtest); + return _mm_cvtsi128_si32(mtest); + ]] + ) + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE2" = x"1" && test x"$OPUS_X86_PRESUME_SSE2" != x"1"], + [ + OPUS_X86_SSE2_CFLAGS="$X86_SSE2_CFLAGS" + AC_SUBST([OPUS_X86_SSE2_CFLAGS]) + ] + ) + OPUS_CHECK_INTRINSICS( + [SSE4.1], + [$X86_SSE4_1_CFLAGS], + [OPUS_X86_MAY_HAVE_SSE4_1], + [OPUS_X86_PRESUME_SSE4_1], + [[#include + #include + ]], + [[ + __m128i mtest; + mtest = _mm_set1_epi32((int)time(NULL)); + mtest = _mm_mul_epi32(mtest, mtest); + return _mm_cvtsi128_si32(mtest); + ]] + ) + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE4_1" = x"1" && test x"$OPUS_X86_PRESUME_SSE4_1" != x"1"], + [ + OPUS_X86_SSE4_1_CFLAGS="$X86_SSE4_1_CFLAGS" + AC_SUBST([OPUS_X86_SSE4_1_CFLAGS]) + ] + ) + OPUS_CHECK_INTRINSICS( + [AVX], + [$X86_AVX_CFLAGS], + [OPUS_X86_MAY_HAVE_AVX], + [OPUS_X86_PRESUME_AVX], + [[#include + #include + ]], + [[ + __m256 mtest; + mtest = _mm256_set1_ps((float)time(NULL)); + mtest = _mm256_addsub_ps(mtest, mtest); + return _mm_cvtss_si32(_mm256_extractf128_ps(mtest, 0)); + ]] + ) + AS_IF([test x"$OPUS_X86_MAY_HAVE_AVX" = x"1" && test x"$OPUS_X86_PRESUME_AVX" != x"1"], + [ + OPUS_X86_AVX_CFLAGS="$X86_AVX_CFLAGS" + AC_SUBST([OPUS_X86_AVX_CFLAGS]) + ] + ) + AS_IF([test x"$rtcd_support" = x"no"], [rtcd_support=""]) + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE" = x"1"], + [ + AC_DEFINE([OPUS_X86_MAY_HAVE_SSE], 1, [Compiler supports X86 SSE Intrinsics]) + intrinsics_support="$intrinsics_support SSE" + + AS_IF([test x"$OPUS_X86_PRESUME_SSE" = x"1"], + [AC_DEFINE([OPUS_X86_PRESUME_SSE], 1, [Define if binary requires SSE intrinsics support])], + [rtcd_support="$rtcd_support SSE"]) + ], + [ + AC_MSG_WARN([Compiler does not support SSE intrinsics]) + ]) + + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE2" = x"1"], + [ + AC_DEFINE([OPUS_X86_MAY_HAVE_SSE2], 1, [Compiler supports X86 SSE2 Intrinsics]) + intrinsics_support="$intrinsics_support SSE2" + + AS_IF([test x"$OPUS_X86_PRESUME_SSE2" = x"1"], + [AC_DEFINE([OPUS_X86_PRESUME_SSE2], 1, [Define if binary requires SSE2 intrinsics support])], + [rtcd_support="$rtcd_support SSE2"]) + ], + [ + AC_MSG_WARN([Compiler does not support SSE2 intrinsics]) + ]) + + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE4_1" = x"1"], + [ + AC_DEFINE([OPUS_X86_MAY_HAVE_SSE4_1], 1, [Compiler supports X86 SSE4.1 Intrinsics]) + intrinsics_support="$intrinsics_support SSE4.1" + + AS_IF([test x"$OPUS_X86_PRESUME_SSE4_1" = x"1"], + [AC_DEFINE([OPUS_X86_PRESUME_SSE4_1], 1, [Define if binary requires SSE4.1 intrinsics support])], + [rtcd_support="$rtcd_support SSE4.1"]) + ], + [ + AC_MSG_WARN([Compiler does not support SSE4.1 intrinsics]) + ]) + AS_IF([test x"$OPUS_X86_MAY_HAVE_AVX" = x"1"], + [ + AC_DEFINE([OPUS_X86_MAY_HAVE_AVX], 1, [Compiler supports X86 AVX Intrinsics]) + intrinsics_support="$intrinsics_support AVX" + + AS_IF([test x"$OPUS_X86_PRESUME_AVX" = x"1"], + [AC_DEFINE([OPUS_X86_PRESUME_AVX], 1, [Define if binary requires AVX intrinsics support])], + [rtcd_support="$rtcd_support AVX"]) + ], + [ + AC_MSG_WARN([Compiler does not support AVX intrinsics]) + ]) + + AS_IF([test x"$intrinsics_support" = x""], + [intrinsics_support=no], + [intrinsics_support="x86$intrinsics_support"] + ) + AS_IF([test x"$rtcd_support" = x""], + [rtcd_support=no], + [rtcd_support="x86$rtcd_support"], + ) + + AS_IF([test x"$enable_rtcd" = x"yes" && test x"$rtcd_support" != x""],[ + get_cpuid_by_asm="no" + AC_MSG_CHECKING([How to get X86 CPU Info]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + ]],[[ + unsigned int CPUInfo0; + unsigned int CPUInfo1; + unsigned int CPUInfo2; + unsigned int CPUInfo3; + unsigned int InfoType; + #if defined(__i386__) && defined(__PIC__) + __asm__ __volatile__ ( + "xchg %%ebx, %1\n" + "cpuid\n" + "xchg %%ebx, %1\n": + "=a" (CPUInfo0), + "=r" (CPUInfo1), + "=c" (CPUInfo2), + "=d" (CPUInfo3) : + "a" (InfoType), "c" (0) + ); + #else + __asm__ __volatile__ ( + "cpuid": + "=a" (CPUInfo0), + "=b" (CPUInfo1), + "=c" (CPUInfo2), + "=d" (CPUInfo3) : + "a" (InfoType), "c" (0) + ); + #endif + ]])], + [get_cpuid_by_asm="yes" + AC_MSG_RESULT([Inline Assembly]) + AC_DEFINE([CPU_INFO_BY_ASM], [1], [Get CPU Info by asm method])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + ]],[[ + unsigned int CPUInfo0; + unsigned int CPUInfo1; + unsigned int CPUInfo2; + unsigned int CPUInfo3; + unsigned int InfoType; + __get_cpuid(InfoType, &CPUInfo0, &CPUInfo1, &CPUInfo2, &CPUInfo3); + ]])], + [AC_MSG_RESULT([C method]) + AC_DEFINE([CPU_INFO_BY_C], [1], [Get CPU Info by c method])], + [AC_MSG_ERROR([no supported Get CPU Info method, please disable run-time CPU capabilities detection or intrinsics])])])]) + ], + [ + AC_MSG_WARN([No intrinsics support for your architecture]) + intrinsics_support="no" + ]) +], +[ + intrinsics_support="no" +]) + +AM_CONDITIONAL([CPU_ARM], [test "$cpu_arm" = "yes"]) +AM_CONDITIONAL([HAVE_ARM_NEON_INTR], + [test x"$OPUS_ARM_MAY_HAVE_NEON_INTR" = x"1"]) +AM_CONDITIONAL([HAVE_ARM_NE10], + [test x"$HAVE_ARM_NE10" = x"1"]) +AM_CONDITIONAL([HAVE_SSE], + [test x"$OPUS_X86_MAY_HAVE_SSE" = x"1"]) +AM_CONDITIONAL([HAVE_SSE2], + [test x"$OPUS_X86_MAY_HAVE_SSE2" = x"1"]) +AM_CONDITIONAL([HAVE_SSE4_1], + [test x"$OPUS_X86_MAY_HAVE_SSE4_1" = x"1"]) +AM_CONDITIONAL([HAVE_AVX], + [test x"$OPUS_X86_MAY_HAVE_AVX" = x"1"]) + +AS_IF([test x"$enable_rtcd" = x"yes"],[ + AS_IF([test x"$rtcd_support" != x"no"],[ + AC_DEFINE([OPUS_HAVE_RTCD], [1], + [Use run-time CPU capabilities detection]) + OPUS_HAVE_RTCD=1 + AC_SUBST(OPUS_HAVE_RTCD) + ]) +],[ + rtcd_support="disabled" +]) + +AC_ARG_ENABLE([assertions], + [AS_HELP_STRING([--enable-assertions],[enable additional software error checking])],, + [enable_assertions=no]) + +AS_IF([test "$enable_assertions" = "yes"], [ + AC_DEFINE([ENABLE_ASSERTIONS], [1], [Assertions]) +]) + +AC_ARG_ENABLE([hardening], + [AS_HELP_STRING([--disable-hardening],[disable run-time checks that are cheap and safe for use in production])],, + [enable_hardening=yes]) + +AS_IF([test "$enable_hardening" = "yes"], [ + AC_DEFINE([ENABLE_HARDENING], [1], [Hardening]) +]) + +AC_ARG_ENABLE([fuzzing], + [AS_HELP_STRING([--enable-fuzzing],[causes the encoder to make random decisions (do not use in production)])],, + [enable_fuzzing=no]) + +AS_IF([test "$enable_fuzzing" = "yes"], [ + AC_DEFINE([FUZZING], [1], [Fuzzing]) +]) + +AC_ARG_ENABLE([check-asm], + [AS_HELP_STRING([--enable-check-asm], + [enable bit-exactness checks between optimized and c implementations])],, + [enable_check_asm=no]) + +AS_IF([test "$enable_check_asm" = "yes"], [ + AC_DEFINE([OPUS_CHECK_ASM], [1], [Run bit-exactness checks between optimized and c implementations]) +]) + +AC_ARG_ENABLE([doc], + [AS_HELP_STRING([--disable-doc], [Do not build API documentation])],, + [enable_doc=yes]) + +AS_IF([test "$enable_doc" = "yes"], [ + AC_CHECK_PROG(HAVE_DOXYGEN, [doxygen], [yes], [no]) + AC_CHECK_PROG(HAVE_DOT, [dot], [yes], [no]) +],[ + HAVE_DOXYGEN=no +]) + +AM_CONDITIONAL([HAVE_DOXYGEN], [test "$HAVE_DOXYGEN" = "yes"]) + +AC_ARG_ENABLE([extra-programs], + [AS_HELP_STRING([--disable-extra-programs], [Do not build extra programs (demo and tests)])],, + [enable_extra_programs=yes]) + +AM_CONDITIONAL([EXTRA_PROGRAMS], [test "$enable_extra_programs" = "yes"]) + + +AC_ARG_ENABLE([rfc8251], + AS_HELP_STRING([--disable-rfc8251], [Disable bitstream fixes from RFC 8251]),, + [enable_rfc8251=yes]) + +AS_IF([test "$enable_rfc8251" = "no"], [ + AC_DEFINE([DISABLE_UPDATE_DRAFT], [1], [Disable bitstream fixes from RFC 8251]) +]) + + +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fvisibility=hidden" +AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" + ]) + +on_x86=no +case "$host_cpu" in +i[[3456]]86 | x86_64) + on_x86=yes + ;; +esac + +on_windows=no +case $host in +*cygwin*|*mingw*) + on_windows=yes + ;; +esac + +dnl Enable stack-protector-all only on x86 where it's well supported. +dnl on some platforms it causes crashes. Hopefully the OS's default's +dnl include this on platforms that work but have been missed here. +AC_ARG_ENABLE([stack-protector], + [AS_HELP_STRING([--disable-stack-protector],[Disable compiler stack hardening])],, + [ + AS_IF([test "$ac_cv_c_compiler_gnu" = "yes" && test "$on_x86" = "yes" && test "$on_windows" = "no"], + [enable_stack_protector=yes],[enable_stack_protector=no]) + ]) + +AS_IF([test "$enable_stack_protector" = "yes"], + [ + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fstack-protector-strong" + AC_MSG_CHECKING([if ${CC} supports -fstack-protector-strong]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ + AC_MSG_RESULT([no]) + enable_stack_protector=no + CFLAGS="$saved_CFLAGS" + ]) + ]) + +AS_IF([test x$ac_cv_c_compiler_gnu = xyes], + [AX_ADD_FORTIFY_SOURCE] +) + +CFLAGS="$CFLAGS -W" + +warn_CFLAGS="-Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes" +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $warn_CFLAGS" +AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" + ]) + +saved_LIBS="$LIBS" +LIBS="$LIBS $LIBM" +AC_CHECK_FUNCS([lrintf]) +AC_CHECK_FUNCS([lrint]) +LIBS="$saved_LIBS" + +AC_CHECK_FUNCS([__malloc_hook]) + +AC_SUBST([PC_BUILD]) + +AC_CONFIG_FILES([ + Makefile + opus.pc + opus-uninstalled.pc + celt/arm/armopts.s + doc/Makefile + doc/Doxyfile +]) +AC_CONFIG_HEADERS([config.h]) + +AC_OUTPUT + +AC_MSG_NOTICE([ +------------------------------------------------------------------------ + $PACKAGE_NAME $PACKAGE_VERSION: Automatic configuration OK. + + Compiler support: + + C99 var arrays: ................ ${has_var_arrays} + C99 lrintf: .................... ${ac_cv_func_lrintf} + Use alloca: .................... ${use_alloca} + + General configuration: + + Floating point support: ........ ${enable_float} + Fast float approximations: ..... ${enable_float_approx} + Fixed point debugging: ......... ${enable_fixed_point_debug} + Inline Assembly Optimizations: . ${inline_optimization} + External Assembly Optimizations: ${asm_optimization} + Intrinsics Optimizations: ...... ${intrinsics_support} + Run-time CPU detection: ........ ${rtcd_support} + Custom modes: .................. ${enable_custom_modes} + Assertion checking: ............ ${enable_assertions} + Hardening: ..................... ${enable_hardening} + Fuzzing: ....................... ${enable_fuzzing} + Check ASM: ..................... ${enable_check_asm} + + API documentation: ............. ${enable_doc} + Extra programs: ................ ${enable_extra_programs} +------------------------------------------------------------------------ + + Type "make; make install" to compile and install + Type "make check" to run the test suite +]) + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/Doxyfile.in b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/Doxyfile.in new file mode 100644 index 000000000..6eef650b2 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/Doxyfile.in @@ -0,0 +1,340 @@ +# Doxyfile 1.8.18 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +# Only non-default options are included below to improve portability +# between doxygen versions. +# +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = Opus + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = @VERSION@ + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Opus audio codec (RFC 6716): API and operations manual" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 8 + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# (including Cygwin) ands Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = @top_srcdir@/include/opus.h \ + @top_srcdir@/include/opus_types.h \ + @top_srcdir@/include/opus_defines.h \ + @top_srcdir@/include/opus_multistream.h \ + @top_srcdir@/include/opus_custom.h + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = @top_srcdir@/doc/header.html + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = @top_srcdir@/doc/footer.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = @top_srcdir@/doc/customdoxygen.css + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = @top_srcdir@/doc/opus_logo.svg + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 0 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://www.mathjax.org/mathjax + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = letter + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = OPUS_EXPORT= \ + OPUS_CUSTOM_EXPORT= \ + OPUS_CUSTOM_EXPORT_STATIC= \ + OPUS_WARN_UNUSED_RESULT= \ + OPUS_ARG_NONNULL(_x)= + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: NO. + +# Debian defaults to YES here, while Fedora and Homebrew default to NO. +# So we set this based on whether the graphviz package is available at +# configure time. +# +HAVE_DOT = @HAVE_DOT@ + +# move docs to the correct place +OUTPUT_DIRECTORY = @top_builddir@/doc diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/Makefile.am b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/Makefile.am new file mode 100644 index 000000000..31fddab49 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/Makefile.am @@ -0,0 +1,45 @@ +## Process this file with automake to produce Makefile.in + +DOCINPUTS = $(top_srcdir)/include/opus.h \ + $(top_srcdir)/include/opus_multistream.h \ + $(top_srcdir)/include/opus_defines.h \ + $(top_srcdir)/include/opus_types.h \ + $(top_srcdir)/include/opus_custom.h \ + $(top_srcdir)/doc/header.html \ + $(top_srcdir)/doc/footer.html \ + $(top_srcdir)/doc/customdoxygen.css + +EXTRA_DIST = customdoxygen.css Doxyfile.in footer.html header.html \ + opus_logo.svg trivial_example.c + + +if HAVE_DOXYGEN + +all-local: doxygen-build.stamp + +doxygen-build.stamp: Doxyfile $(DOCINPUTS) + doxygen + touch $@ + +install-data-local: + $(INSTALL) -d $(DESTDIR)$(docdir)/html/search + for f in `find html -type f \! -name "installdox"`; do \ + $(INSTALL_DATA) $$f $(DESTDIR)$(docdir)/$$f; \ + done + + $(INSTALL) -d $(DESTDIR)$(mandir)/man3 + cd man && find man3 -type f -name opus_*.3 \ + -exec $(INSTALL_DATA) \{} $(DESTDIR)$(mandir)/man3 \; + +clean-local: + $(RM) -r html + $(RM) -r latex + $(RM) -r man + $(RM) doxygen-build.stamp + $(RM) doxygen_sqlite3.db + +uninstall-local: + $(RM) -r $(DESTDIR)$(docdir)/html + $(RM) $(DESTDIR)$(mandir)/man3/opus_*.3 $(DESTDIR)$(mandir)/man3/opus.h.3 + +endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/build_draft.sh b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/build_draft.sh new file mode 100755 index 000000000..14ae51dd5 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/build_draft.sh @@ -0,0 +1,113 @@ +#!/bin/sh + +# Copyright (c) 2011-2012 Xiph.Org Foundation and Mozilla Corporation +# +# This file is extracted from RFC6716. Please see that RFC for additional +# information. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - 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. +# +# - Neither the name of Internet Society, IETF or IETF Trust, nor the +# names of specific 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 OWNER +# 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. + +#Stop on errors +set -e +#Set the CWD to the location of this script +[ -n "${0%/*}" ] && cd "${0%/*}" + +toplevel=".." +destdir="opus_source" + +echo packaging source code +rm -rf "${destdir}" +mkdir "${destdir}" +mkdir "${destdir}/src" +mkdir "${destdir}/silk" +mkdir "${destdir}/silk/float" +mkdir "${destdir}/silk/fixed" +mkdir "${destdir}/silk/fixed/x86" +mkdir "${destdir}/silk/fixed/arm" +mkdir "${destdir}/silk/fixed/mips" +mkdir "${destdir}/silk/x86" +mkdir "${destdir}/silk/arm" +mkdir "${destdir}/silk/mips" +mkdir "${destdir}/celt" +mkdir "${destdir}/celt/x86" +mkdir "${destdir}/celt/arm" +mkdir "${destdir}/celt/mips" +mkdir "${destdir}/include" +for f in `cat "${toplevel}"/opus_sources.mk "${toplevel}"/celt_sources.mk \ + "${toplevel}"/silk_sources.mk "${toplevel}"/opus_headers.mk \ + "${toplevel}"/celt_headers.mk "${toplevel}"/silk_headers.mk \ + | grep '\.[ch]' | sed -e 's/^.*=//' -e 's/\\\\//'` ; do + cp -a "${toplevel}/${f}" "${destdir}/${f}" +done +cp -a "${toplevel}"/src/opus_demo.c "${destdir}"/src/ +cp -a "${toplevel}"/src/opus_compare.c "${destdir}"/src/ +cp -a "${toplevel}"/celt/opus_custom_demo.c "${destdir}"/celt/ +cp -a "${toplevel}"/Makefile.unix "${destdir}"/Makefile +cp -a "${toplevel}"/opus_sources.mk "${destdir}"/ +cp -a "${toplevel}"/celt_sources.mk "${destdir}"/ +cp -a "${toplevel}"/silk_sources.mk "${destdir}"/ +cp -a "${toplevel}"/README.draft "${destdir}"/README +cp -a "${toplevel}"/COPYING "${destdir}"/COPYING +cp -a "${toplevel}"/tests/run_vectors.sh "${destdir}"/ + +GZIP=-9 tar --owner=root --group=root --format=v7 -czf opus_source.tar.gz "${destdir}" +echo building base64 version +cat opus_source.tar.gz| base64 | tr -d '\n' | fold -w 64 | \ + sed -e 's/^/\###/' -e 's/$/\<\/spanx\>\/' > \ + opus_source.base64 + + +#echo '
' > opus_compare_escaped.c +#echo '' >> opus_compare_escaped.c +#echo '> opus_compare_escaped.c +#cat opus_compare.c >> opus_compare_escaped.c +#echo ']]>' >> opus_compare_escaped.c +#echo '' >> opus_compare_escaped.c +#echo '
' >> opus_compare_escaped.c + +if [ ! -d ../opus_testvectors ] ; then + echo "Downloading test vectors..." + wget 'http://opus-codec.org/testvectors/opus_testvectors.tar.gz' + tar -C .. -xvzf opus_testvectors.tar.gz +fi +echo '
' > testvectors_sha1 +echo '' >> testvectors_sha1 +echo '> testvectors_sha1 +(cd ../opus_testvectors; sha1sum *.bit *.dec) >> testvectors_sha1 +#cd opus_testvectors +#sha1sum *.bit *.dec >> ../testvectors_sha1 +#cd .. +echo ']]>' >> testvectors_sha1 +echo '' >> testvectors_sha1 +echo '
' >> testvectors_sha1 + +echo running xml2rfc +xml2rfc draft-ietf-codec-opus.xml draft-ietf-codec-opus.html & +xml2rfc draft-ietf-codec-opus.xml +wait diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/build_isobmff.sh b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/build_isobmff.sh new file mode 100755 index 000000000..95ea202e4 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/build_isobmff.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +# Copyright (c) 2014 Xiph.Org Foundation and Mozilla Foundation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - 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. +# +# 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 OWNER +# 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. + +#Stop on errors +set -e +#Set the CWD to the location of this script +[ -n "${0%/*}" ] && cd "${0%/*}" + +HTML=opus_in_isobmff.html + +echo downloading updates... +CSS=${HTML%%.html}.css +wget -q http://vfrmaniac.fushizen.eu/contents/${HTML} -O ${HTML} +wget -q http://vfrmaniac.fushizen.eu/style.css -O ${CSS} + +echo updating links... +cat ${HTML} | sed -e "s/\\.\\.\\/style.css/${CSS}/" > ${HTML}+ && mv ${HTML}+ ${HTML} + +echo stripping... +cat ${HTML} | sed -e 's///g' > ${HTML}+ && mv ${HTML}+ ${HTML} +cat ${HTML} | sed -e 's/ *$//g' > ${HTML}+ && mv ${HTML}+ ${HTML} +cat ${CSS} | sed -e 's/ *$//g' > ${CSS}+ && mv ${CSS}+ ${CSS} + + +VERSION=$(fgrep Version ${HTML} | sed 's/.*Version \([0-9]\.[0-9]\.[0-9]\).*/\1/') +echo Now at version ${VERSION} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/build_oggdraft.sh b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/build_oggdraft.sh new file mode 100755 index 000000000..30ee534b0 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/build_oggdraft.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +# Copyright (c) 2012 Xiph.Org Foundation and Mozilla Corporation +# +# This file is extracted from RFC6716. Please see that RFC for additional +# information. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - 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. +# +# - Neither the name of Internet Society, IETF or IETF Trust, nor the +# names of specific 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 OWNER +# 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. + +#Stop on errors +set -e +#Set the CWD to the location of this script +[ -n "${0%/*}" ] && cd "${0%/*}" + +if test -z `which xml2rfc 2> /dev/null`; then + echo "Error: couldn't find xml2rfc." + echo + echo "Please install xml2rfc version 2 or later." + echo "E.g. 'pip install xml2rfc' or follow the instructions" + echo "on http://pypi.python.org/pypi/xml2rfc/ or tools.ietf.org." + exit 1 +fi + +echo running xml2rfc +# version 2 syntax +xml2rfc draft-ietf-codec-oggopus.xml --text --html diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/customdoxygen.css b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/customdoxygen.css new file mode 100644 index 000000000..70047787c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/customdoxygen.css @@ -0,0 +1,1011 @@ +/* The standard CSS for doxygen */ + +body, table, div, p, dl { + font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; + font-size: 13px; + line-height: 1.3; +} + +/* @group Heading Levels */ + +h1 { + font-size: 150%; +} + +.title { + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2 { + font-size: 120%; +} + +h3 { + font-size: 100%; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd, p.starttd { + margin-top: 2px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #F1F1F1; + border: 1px solid #BDBDBD; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #646464; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #747474; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #B8B8B8; + color: #ffffff; + border: 1px double #A8A8A8; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +.fragment { + font-family: monospace, fixed; + font-size: 105%; +} + +pre.fragment { + border: 1px solid #D5D5D5; + background-color: #FCFCFC; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; +} + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 8px; + margin-right: 8px; +} + +td.indexkey { + background-color: #F1F1F1; + font-weight: bold; + border: 1px solid #D5D5D5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #F1F1F1; + border: 1px solid #D5D5D5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #F2F2F2; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F9F9F9; + border-left: 2px solid #B8B8B8; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #BDBDBD; +} + +th.dirtab { + background: #F1F1F1; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #7A7A7A; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #FAFAFA; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memItemLeft, .memItemRight, .memTemplParams { + border-top: 1px solid #D5D5D5; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #747474; + white-space: nowrap; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #747474; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #F1F1F1; + border: 1px solid #BDBDBD; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; +} + +.memname { + white-space: nowrap; + font-weight: bold; + margin-left: 6px; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #C0C0C0; + border-left: 1px solid #C0C0C0; + border-right: 1px solid #C0C0C0; + padding: 6px 0px 6px 0px; + color: #3D3D3D; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 8px; + border-top-left-radius: 8px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 8px; + -moz-border-radius-topleft: 8px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 8px; + -webkit-border-top-left-radius: 8px; + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #EAEAEA; + +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #C0C0C0; + border-left: 1px solid #C0C0C0; + border-right: 1px solid #C0C0C0; + padding: 2px 5px; + background-color: #FCFCFC; + border-top-width: 0; + /* opera specific markup */ + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 8px; + -moz-border-radius-bottomright: 8px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F9F9F9 95%, #F2F2F2); + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F9F9F9), to(#F2F2F2)); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} + +.params, .retval, .exception, .tparams { + border-spacing: 6px 2px; +} + +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + + + + +/* @end */ + +/* @group Directory (tree) */ + +/* for the tree view */ + +.ftvtree { + font-family: sans-serif; + margin: 0px; +} + +/* these are for tree view when used as main index */ + +.directory { + font-size: 9pt; + font-weight: bold; + margin: 5px; +} + +.directory h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +/* +The following two styles can be used to replace the root node title +with an image of your choice. Simply uncomment the next two styles, +specify the name of your image and be sure to set 'height' to the +proper pixel height of your image. +*/ + +/* +.directory h3.swap { + height: 61px; + background-repeat: no-repeat; + background-image: url("yourimage.gif"); +} +.directory h3.swap span { + display: none; +} +*/ + +.directory > h3 { + margin-top: 0; +} + +.directory p { + margin: 0px; + white-space: nowrap; +} + +.directory div { + display: none; + margin: 0px; +} + +.directory img { + vertical-align: -30%; +} + +/* these are for tree view when not used as main index */ + +.directory-alt { + font-size: 100%; + font-weight: bold; +} + +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +.directory-alt > h3 { + margin-top: 0; +} + +.directory-alt p { + margin: 0px; + white-space: nowrap; +} + +.directory-alt div { + display: none; + margin: 0px; +} + +.directory-alt img { + vertical-align: -30%; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; +} + +address { + font-style: normal; + color: #464646; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #4A4A4A; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #5B5B5B; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + width: 100%; + margin-bottom: 10px; + border: 1px solid #C0C0C0; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #C0C0C0; + border-bottom: 1px solid #C0C0C0; + vertical-align: top; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #C0C0C0; + width: 100%; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #EAEAEA; + font-size: 90%; + color: #3D3D3D; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #C0C0C0; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + height:30px; + line-height:30px; + color:#ABABAB; + border:solid 1px #D3D3D3; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#595959; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; +} + +.navpath li.navelem a:hover +{ + color:#929292; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#595959; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +div.ingroups +{ + margin-left: 5px; + font-size: 8pt; + padding-left: 5px; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #FAFAFA; + margin: 0px; + border-bottom: 1px solid #D5D5D5; +} + +div.headertitle +{ + padding: 5px 5px 5px 7px; +} + +dl +{ + padding: 0 0 0 10px; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */ +dl.section +{ + border-left:4px solid; + padding: 0 0 0 6px; +} + +dl.note +{ + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + border-color: #00D000; +} + +dl.deprecated +{ + border-color: #505050; +} + +dl.todo +{ + border-color: #00C0E0; +} + +dl.test +{ + border-color: #3030E0; +} + +dl.bug +{ + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 100% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #848484; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #AFAFAF; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#545454; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F7F7F7; + border: 1px solid #E3E3E3; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 20px 10px 10px; + width: 200px; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #747474; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } + pre.fragment + { + overflow: visible; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/draft-ietf-codec-oggopus.xml b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/draft-ietf-codec-oggopus.xml new file mode 100644 index 000000000..128816e93 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/draft-ietf-codec-oggopus.xml @@ -0,0 +1,1873 @@ + + + + + + + + + + + + +]> + + + + + +Ogg Encapsulation for the Opus Audio Codec + +Mozilla Corporation +
+ +650 Castro Street +Mountain View +CA +94041 +USA + ++1 650 903-0800 +tterribe@xiph.org +
+
+ + +Voicetronix +
+ +246 Pulteney Street, Level 1 +Adelaide +SA +5000 +Australia + ++61 8 8232 9112 +ron@debian.org +
+
+ + +Mozilla Corporation +
+ +163 West Hastings Street +Vancouver +BC +V6B 1H5 +Canada + ++1 778 785 1540 +giles@xiph.org +
+
+ + +RAI +codec + + + +This document defines the Ogg encapsulation for the Opus interactive speech and + audio codec. +This allows data encoded in the Opus format to be stored in an Ogg logical + bitstream. + + +
+ + +
+ +The IETF Opus codec is a low-latency audio codec optimized for both voice and + general-purpose audio. +See for technical details. +This document defines the encapsulation of Opus in a continuous, logical Ogg + bitstream . +Ogg encapsulation provides Opus with a long-term storage format supporting + all of the essential features, including metadata, fast and accurate seeking, + corruption detection, recapture after errors, low overhead, and the ability to + multiplex Opus with other codecs (including video) with minimal buffering. +It also provides a live streamable format, capable of delivery over a reliable + stream-oriented transport, without requiring all the data, or even the total + length of the data, up-front, in a form that is identical to the on-disk + storage format. + + +Ogg bitstreams are made up of a series of 'pages', each of which contains data + from one or more 'packets'. +Pages are the fundamental unit of multiplexing in an Ogg stream. +Each page is associated with a particular logical stream and contains a capture + pattern and checksum, flags to mark the beginning and end of the logical + stream, and a 'granule position' that represents an absolute position in the + stream, to aid seeking. +A single page can contain up to 65,025 octets of packet data from up to 255 + different packets. +Packets can be split arbitrarily across pages, and continued from one page to + the next (allowing packets much larger than would fit on a single page). +Each page contains 'lacing values' that indicate how the data is partitioned + into packets, allowing a demultiplexer (demuxer) to recover the packet + boundaries without examining the encoded data. +A packet is said to 'complete' on a page when the page contains the final + lacing value corresponding to that packet. + + +This encapsulation defines the contents of the packet data, including + the necessary headers, the organization of those packets into a logical + stream, and the interpretation of the codec-specific granule position field. +It does not attempt to describe or specify the existing Ogg container format. +Readers unfamiliar with the basic concepts mentioned above are encouraged to + review the details in . + + +
+ +
+ +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", + "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in . + + +
+ +
+ +An Ogg Opus stream is organized as follows (see + for an example). + + +
+ +
+ + +There are two mandatory header packets. +The first packet in the logical Ogg bitstream MUST contain the identification + (ID) header, which uniquely identifies a stream as Opus audio. +The format of this header is defined in . +It is placed alone (without any other packet data) on the first page of + the logical Ogg bitstream, and completes on that page. +This page has its 'beginning of stream' flag set. + + +The second packet in the logical Ogg bitstream MUST contain the comment header, + which contains user-supplied metadata. +The format of this header is defined in . +It MAY span multiple pages, beginning on the second page of the logical + stream. +However many pages it spans, the comment header packet MUST finish the page on + which it completes. + + +All subsequent pages are audio data pages, and the Ogg packets they contain are + audio data packets. +Each audio data packet contains one Opus packet for each of N different + streams, where N is typically one for mono or stereo, but MAY be greater than + one for multichannel audio. +The value N is specified in the ID header (see + ), and is fixed over the entire length of the + logical Ogg bitstream. + + +The first (N - 1) Opus packets, if any, are packed one after another + into the Ogg packet, using the self-delimiting framing from Appendix B of + . +The remaining Opus packet is packed at the end of the Ogg packet using the + regular, undelimited framing from Section 3 of . +All of the Opus packets in a single Ogg packet MUST be constrained to have the + same duration. +An implementation of this specification SHOULD treat any Opus packet whose + duration is different from that of the first Opus packet in an Ogg packet as + if it were a malformed Opus packet with an invalid Table Of Contents (TOC) + sequence. + + +The TOC sequence at the beginning of each Opus packet indicates the coding + mode, audio bandwidth, channel count, duration (frame size), and number of + frames per packet, as described in Section 3.1 + of . +The coding mode is one of SILK, Hybrid, or Constrained Energy Lapped Transform + (CELT). +The combination of coding mode, audio bandwidth, and frame size is referred to + as the configuration of an Opus packet. + + +Packets are placed into Ogg pages in order until the end of stream. +Audio data packets might span page boundaries. +The first audio data page could have the 'continued packet' flag set + (indicating the first audio data packet is continued from a previous page) if, + for example, it was a live stream joined mid-broadcast, with the headers + pasted on the front. +If a page has the 'continued packet' flag set and one of the following + conditions is also true: + +the previous page with packet data does not end in a continued packet (does + not end with a lacing value of 255) OR +the page sequence numbers are not consecutive, + + then a demuxer MUST NOT attempt to decode the data for the first packet on the + page unless the demuxer has some special knowledge that would allow it to + interpret this data despite the missing pieces. +An implementation MUST treat a zero-octet audio data packet as if it were a + malformed Opus packet as described in + Section 3.4 of . + + +A logical stream ends with a page with the 'end of stream' flag set, but + implementations need to be prepared to deal with truncated streams that do not + have a page marked 'end of stream'. +There is no reason for the final packet on the last page to be a continued + packet, i.e., for the final lacing value to be 255. +However, demuxers might encounter such streams, possibly as the result of a + transfer that did not complete or of corruption. +If a packet continues onto a subsequent page (i.e., when the page ends with a + lacing value of 255) and one of the following conditions is also true: + +the next page with packet data does not have the 'continued packet' flag + set OR +there is no next page with packet data OR +the page sequence numbers are not consecutive, + + then a demuxer MUST NOT attempt to decode the data from that packet unless the + demuxer has some special knowledge that would allow it to interpret this data + despite the missing pieces. +There MUST NOT be any more pages in an Opus logical bitstream after a page + marked 'end of stream'. + +
+ +
+ +The granule position MUST be zero for the ID header page and the + page where the comment header completes. +That is, the first page in the logical stream, and the last header + page before the first audio data page both have a granule position of zero. + + +The granule position of an audio data page encodes the total number of PCM + samples in the stream up to and including the last fully-decodable sample from + the last packet completed on that page. +The granule position of the first audio data page will usually be larger than + zero, as described in . + + + +A page that is entirely spanned by a single packet (that completes on a + subsequent page) has no granule position, and the granule position field is + set to the special value '-1' in two's complement. + + + +The granule position of an audio data page is in units of PCM audio samples at + a fixed rate of 48 kHz (per channel; a stereo stream's granule position + does not increment at twice the speed of a mono stream). +It is possible to run an Opus decoder at other sampling rates, + but all Opus packets encode samples at a sampling rate that evenly divides + 48 kHz. +Therefore, the value in the granule position field always counts samples + assuming a 48 kHz decoding rate, and the rest of this specification makes + the same assumption. + + + +The duration of an Opus packet as defined in can be + any multiple of 2.5 ms, up to a maximum of 120 ms. +This duration is encoded in the TOC sequence at the beginning of each packet. +The number of samples returned by a decoder corresponds to this duration + exactly, even for the first few packets. +For example, a 20 ms packet fed to a decoder running at 48 kHz will + always return 960 samples. +A demuxer can parse the TOC sequence at the beginning of each Ogg packet to + work backwards or forwards from a packet with a known granule position (i.e., + the last packet completed on some page) in order to assign granule positions + to every packet, or even every individual sample. +The one exception is the last page in the stream, as described below. + + + +All other pages with completed packets after the first MUST have a granule + position equal to the number of samples contained in packets that complete on + that page plus the granule position of the most recent page with completed + packets. +This guarantees that a demuxer can assign individual packets the same granule + position when working forwards as when working backwards. +For this to work, there cannot be any gaps. + + +
+ +In order to support capturing a real-time stream that has lost or not + transmitted packets, a multiplexer (muxer) SHOULD emit packets that explicitly + request the use of Packet Loss Concealment (PLC) in place of the missing + packets. +Implementations that fail to do so still MUST NOT increment the granule + position for a page by anything other than the number of samples contained in + packets that actually complete on that page. + + +Only gaps that are a multiple of 2.5 ms are repairable, as these are the + only durations that can be created by packet loss or discontinuous + transmission. +Muxers need not handle other gap sizes. +Creating the necessary packets involves synthesizing a TOC byte (defined in +Section 3.1 of )—and whatever + additional internal framing is needed—to indicate the packet duration + for each stream. +The actual length of each missing Opus frame inside the packet is zero bytes, + as defined in Section 3.2.1 of . + + + +Zero-byte frames MAY be packed into packets using any of codes 0, 1, + 2, or 3. +When successive frames have the same configuration, the higher code packings + reduce overhead. +Likewise, if the TOC configuration matches, the muxer MAY further combine the + empty frames with previous or subsequent non-zero-length frames (using + code 2 or VBR code 3). + + + + does not impose any requirements on the PLC, but this + section outlines choices that are expected to have a positive influence on + most PLC implementations, including the reference implementation. +Synthesized TOC sequences SHOULD maintain the same mode, audio bandwidth, + channel count, and frame size as the previous packet (if any). +This is the simplest and usually the most well-tested case for the PLC to + handle and it covers all losses that do not include a configuration switch, + as defined in Section 4.5 of . + + + +When a previous packet is available, keeping the audio bandwidth and channel + count the same allows the PLC to provide maximum continuity in the concealment + data it generates. +However, if the size of the gap is not a multiple of the most recent frame + size, then the frame size will have to change for at least some frames. +Such changes SHOULD be delayed as long as possible to simplify + things for PLC implementations. + + + +As an example, a 95 ms gap could be encoded as nineteen 5 ms frames + in two bytes with a single CBR code 3 packet. +If the previous frame size was 20 ms, using four 20 ms frames + followed by three 5 ms frames requires 4 bytes (plus an extra byte + of Ogg lacing overhead), but allows the PLC to use its well-tested steady + state behavior for as long as possible. +The total bitrate of the latter approach, including Ogg overhead, is about + 0.4 kbps, so the impact on file size is minimal. + + + +Changing modes is discouraged, since this causes some decoder implementations + to reset their PLC state. +However, SILK and Hybrid mode frames cannot fill gaps that are not a multiple + of 10 ms. +If switching to CELT mode is needed to match the gap size, a muxer SHOULD do + so at the end of the gap to allow the PLC to function for as long as possible. + + + +In the example above, if the previous frame was a 20 ms SILK mode frame, + the better solution is to synthesize a packet describing four 20 ms SILK + frames, followed by a packet with a single 10 ms SILK + frame, and finally a packet with a 5 ms CELT frame, to fill the 95 ms + gap. +This also requires four bytes to describe the synthesized packet data (two + bytes for a CBR code 3 and one byte each for two code 0 packets) but three + bytes of Ogg lacing overhead are needed to mark the packet boundaries. +At 0.6 kbps, this is still a minimal bitrate impact over a naive, low quality + solution. + + + +Since medium-band audio is an option only in the SILK mode, wideband frames + SHOULD be generated if switching from that configuration to CELT mode, to + ensure that any PLC implementation which does try to migrate state between + the modes will be able to preserve all of the available audio bandwidth. + + +
+ +
+ +There is some amount of latency introduced during the decoding process, to + allow for overlap in the CELT mode, stereo mixing in the SILK mode, and + resampling. +The encoder might have introduced additional latency through its own resampling + and analysis (though the exact amount is not specified). +Therefore, the first few samples produced by the decoder do not correspond to + real input audio, but are instead composed of padding inserted by the encoder + to compensate for this latency. +These samples need to be stored and decoded, as Opus is an asymptotically + convergent predictive codec, meaning the decoded contents of each frame depend + on the recent history of decoder inputs. +However, a player will want to skip these samples after decoding them. + + + +A 'pre-skip' field in the ID header (see ) signals + the number of samples that SHOULD be skipped (decoded but discarded) at the + beginning of the stream, though some specific applications might have a reason + for looking at that data. +This amount need not be a multiple of 2.5 ms, MAY be smaller than a single + packet, or MAY span the contents of several packets. +These samples are not valid audio. + + + +For example, if the first Opus frame uses the CELT mode, it will always + produce 120 samples of windowed overlap-add data. +However, the overlap data is initially all zeros (since there is no prior + frame), meaning this cannot, in general, accurately represent the original + audio. +The SILK mode requires additional delay to account for its analysis and + resampling latency. +The encoder delays the original audio to avoid this problem. + + + +The pre-skip field MAY also be used to perform sample-accurate cropping of + already encoded streams. +In this case, a value of at least 3840 samples (80 ms) provides + sufficient history to the decoder that it will have converged + before the stream's output begins. + + +
+ +
+ +The PCM sample position is determined from the granule position using the + formula + +
+ +
+ + +For example, if the granule position of the first audio data page is 59,971, + and the pre-skip is 11,971, then the PCM sample position of the last decoded + sample from that page is 48,000. + + +This can be converted into a playback time using the formula + +
+ +
+ + +The initial PCM sample position before any samples are played is normally '0'. +In this case, the PCM sample position of the first audio sample to be played + starts at '1', because it marks the time on the clock + after that sample has been played, and a stream + that is exactly one second long has a final PCM sample position of '48000', + as in the example here. + + + +Vorbis streams use a granule position smaller than the number of audio samples + contained in the first audio data page to indicate that some of those samples + are trimmed from the output (see ). +However, to do so, Vorbis requires that the first audio data page contains + exactly two packets, in order to allow the decoder to perform PCM position + adjustments before needing to return any PCM data. +Opus uses the pre-skip mechanism for this purpose instead, since the encoder + might introduce more than a single packet's worth of latency, and since very + large packets in streams with a very large number of channels might not fit + on a single page. + +
+ +
+ +The page with the 'end of stream' flag set MAY have a granule position that + indicates the page contains less audio data than would normally be returned by + decoding up through the final packet. +This is used to end the stream somewhere other than an even frame boundary. +The granule position of the most recent audio data page with completed packets + is used to make this determination, or '0' is used if there were no previous + audio data pages with a completed packet. +The difference between these granule positions indicates how many samples to + keep after decoding the packets that completed on the final page. +The remaining samples are discarded. +The number of discarded samples SHOULD be no larger than the number decoded + from the last packet. + +
+ +
+ +The granule position of the first audio data page with a completed packet MAY + be larger than the number of samples contained in packets that complete on + that page, however it MUST NOT be smaller, unless that page has the 'end of + stream' flag set. +Allowing a granule position larger than the number of samples allows the + beginning of a stream to be cropped or a live stream to be joined without + rewriting the granule position of all the remaining pages. +This means that the PCM sample position just before the first sample to be + played MAY be larger than '0'. +Synchronization when multiplexing with other logical streams still uses the PCM + sample position relative to '0' to compute sample times. +This does not affect the behavior of pre-skip: exactly 'pre-skip' samples + SHOULD be skipped from the beginning of the decoded output, even if the + initial PCM sample position is greater than zero. + + + +On the other hand, a granule position that is smaller than the number of + decoded samples prevents a demuxer from working backwards to assign each + packet or each individual sample a valid granule position, since granule + positions are non-negative. +An implementation MUST treat any stream as invalid if the granule position + is smaller than the number of samples contained in packets that complete on + the first audio data page with a completed packet, unless that page has the + 'end of stream' flag set. +It MAY defer this action until it decodes the last packet completed on that + page. + + + +If that page has the 'end of stream' flag set, a demuxer MUST treat any stream + as invalid if its granule position is smaller than the 'pre-skip' amount. +This would indicate that there are more samples to be skipped from the initial + decoded output than exist in the stream. +If the granule position is smaller than the number of decoded samples produced + by the packets that complete on that page, then a demuxer MUST use an initial + granule position of '0', and can work forwards from '0' to timestamp + individual packets. +If the granule position is larger than the number of decoded samples available, + then the demuxer MUST still work backwards as described above, even if the + 'end of stream' flag is set, to determine the initial granule position, and + thus the initial PCM sample position. +Both of these will be greater than '0' in this case. + +
+ +
+ +Seeking in Ogg files is best performed using a bisection search for a page + whose granule position corresponds to a PCM position at or before the seek + target. +With appropriately weighted bisection, accurate seeking can be performed in + just one or two bisections on average, even in multi-gigabyte files. +See for an example of general implementation guidance. + + + +When seeking within an Ogg Opus stream, an implementation SHOULD start decoding + (and discarding the output) at least 3840 samples (80 ms) prior to + the seek target in order to ensure that the output audio is correct by the + time it reaches the seek target. +This 'pre-roll' is separate from, and unrelated to, the 'pre-skip' used at the + beginning of the stream. +If the point 80 ms prior to the seek target comes before the initial PCM + sample position, an implementation SHOULD start decoding from the beginning of + the stream, applying pre-skip as normal, regardless of whether the pre-skip is + larger or smaller than 80 ms, and then continue to discard samples + to reach the seek target (if any). + +
+ +
+ +
+ +An Ogg Opus logical stream contains exactly two mandatory header packets: + an identification header and a comment header. + + +
+ +
+ +
+ + +The fields in the identification (ID) header have the following meaning: + +Magic Signature: + +This is an 8-octet (64-bit) field that allows codec identification and is + human-readable. +It contains, in order, the magic numbers: + +0x4F 'O' +0x70 'p' +0x75 'u' +0x73 's' +0x48 'H' +0x65 'e' +0x61 'a' +0x64 'd' + +Starting with "Op" helps distinguish it from audio data packets, as this is an + invalid TOC sequence. + + +Version (8 bits, unsigned): + +The version number MUST always be '1' for this version of the encapsulation + specification. +Implementations SHOULD treat streams where the upper four bits of the version + number match that of a recognized specification as backwards-compatible with + that specification. +That is, the version number can be split into "major" and "minor" version + sub-fields, with changes to the "minor" sub-field (in the lower four bits) + signaling compatible changes. +For example, an implementation of this specification SHOULD accept any stream + with a version number of '15' or less, and SHOULD assume any stream with a + version number '16' or greater is incompatible. +The initial version '1' was chosen to keep implementations from relying on this + octet as a null terminator for the "OpusHead" string. + + +Output Channel Count 'C' (8 bits, unsigned): + +This is the number of output channels. +This might be different than the number of encoded channels, which can change + on a packet-by-packet basis. +This value MUST NOT be zero. +The maximum allowable value depends on the channel mapping family, and might be + as large as 255. +See for details. + + +Pre-skip (16 bits, unsigned, little + endian): + +This is the number of samples (at 48 kHz) to discard from the decoder + output when starting playback, and also the number to subtract from a page's + granule position to calculate its PCM sample position. +When cropping the beginning of existing Ogg Opus streams, a pre-skip of at + least 3,840 samples (80 ms) is RECOMMENDED to ensure complete + convergence in the decoder. + + +Input Sample Rate (32 bits, unsigned, little + endian): + +This is the sample rate of the original input (before encoding), in Hz. +This field is not the sample rate to use for + playback of the encoded data. + +Opus can switch between internal audio bandwidths of 4, 6, 8, 12, and + 20 kHz. +Each packet in the stream can have a different audio bandwidth. +Regardless of the audio bandwidth, the reference decoder supports decoding any + stream at a sample rate of 8, 12, 16, 24, or 48 kHz. +The original sample rate of the audio passed to the encoder is not preserved + by the lossy compression. + +An Ogg Opus player SHOULD select the playback sample rate according to the + following procedure: + +If the hardware supports 48 kHz playback, decode at 48 kHz. +Otherwise, if the hardware's highest available sample rate is a supported + rate, decode at this sample rate. +Otherwise, if the hardware's highest available sample rate is less than + 48 kHz, decode at the next higher Opus supported rate above the highest + available hardware rate and resample. +Otherwise, decode at 48 kHz and resample. + +However, the 'Input Sample Rate' field allows the muxer to pass the sample + rate of the original input stream as metadata. +This is useful when the user requires the output sample rate to match the + input sample rate. +For example, when not playing the output, an implementation writing PCM format + samples to disk might choose to resample the audio back to the original input + sample rate to reduce surprise to the user, who might reasonably expect to get + back a file with the same sample rate. + +A value of zero indicates 'unspecified'. +Muxers SHOULD write the actual input sample rate or zero, but implementations + which do something with this field SHOULD take care to behave sanely if given + crazy values (e.g., do not actually upsample the output to 10 MHz if + requested). +Implementations SHOULD support input sample rates between 8 kHz and + 192 kHz (inclusive). +Rates outside this range MAY be ignored by falling back to the default rate of + 48 kHz instead. + + +Output Gain (16 bits, signed, little endian): + +This is a gain to be applied when decoding. +It is 20*log10 of the factor by which to scale the decoder output to achieve + the desired playback volume, stored in a 16-bit, signed, two's complement + fixed-point value with 8 fractional bits (i.e., + Q7.8 ). + +To apply the gain, an implementation could use +
+ +
+ where output_gain is the raw 16-bit value from the header. + +Players and media frameworks SHOULD apply it by default. +If a player chooses to apply any volume adjustment or gain modification, such + as the R128_TRACK_GAIN (see ), the adjustment + MUST be applied in addition to this output gain in order to achieve playback + at the normalized volume. + +A muxer SHOULD set this field to zero, and instead apply any gain prior to + encoding, when this is possible and does not conflict with the user's wishes. +A nonzero output gain indicates the gain was adjusted after encoding, or that + a user wished to adjust the gain for playback while preserving the ability + to recover the original signal amplitude. + +Although the output gain has enormous range (+/- 128 dB, enough to amplify + inaudible sounds to the threshold of physical pain), most applications can + only reasonably use a small portion of this range around zero. +The large range serves in part to ensure that gain can always be losslessly + transferred between OpusHead and R128 gain tags (see below) without + saturating. + +
+Channel Mapping Family (8 bits, unsigned): + +This octet indicates the order and semantic meaning of the output channels. + +Each currently specified value of this octet indicates a mapping family, which + defines a set of allowed channel counts, and the ordered set of channel names + for each allowed channel count. +The details are described in . + +Channel Mapping Table: +This table defines the mapping from encoded streams to output channels. +Its contents are specified in . + +
+
+ + +All fields in the ID headers are REQUIRED, except for the channel mapping + table, which MUST be omitted when the channel mapping family is 0, but + is REQUIRED otherwise. +Implementations SHOULD treat a stream as invalid if it contains an ID header + that does not have enough data for these fields, even if it contain a valid + Magic Signature. +Future versions of this specification, even backwards-compatible versions, + might include additional fields in the ID header. +If an ID header has a compatible major version, but a larger minor version, + an implementation MUST NOT treat it as invalid for containing additional data + not specified here, provided it still completes on the first page. + + +
+ +An Ogg Opus stream allows mapping one number of Opus streams (N) to a possibly + larger number of decoded channels (M + N) to yet another number of + output channels (C), which might be larger or smaller than the number of + decoded channels. +The order and meaning of these channels are defined by a channel mapping, + which consists of the 'channel mapping family' octet and, for channel mapping + families other than family 0, a channel mapping table, as illustrated in + . + + +
+ +
+ + +The fields in the channel mapping table have the following meaning: + +Stream Count 'N' (8 bits, unsigned): + +This is the total number of streams encoded in each Ogg packet. +This value is necessary to correctly parse the packed Opus packets inside an + Ogg packet, as described in . +This value MUST NOT be zero, as without at least one Opus packet with a valid + TOC sequence, a demuxer cannot recover the duration of an Ogg packet. + +For channel mapping family 0, this value defaults to 1, and is not coded. + + +Coupled Stream Count 'M' (8 bits, unsigned): +This is the number of streams whose decoders are to be configured to produce + two channels (stereo). +This MUST be no larger than the total number of streams, N. + +Each packet in an Opus stream has an internal channel count of 1 or 2, which + can change from packet to packet. +This is selected by the encoder depending on the bitrate and the audio being + encoded. +The original channel count of the audio passed to the encoder is not + necessarily preserved by the lossy compression. + +Regardless of the internal channel count, any Opus stream can be decoded as + mono (a single channel) or stereo (two channels) by appropriate initialization + of the decoder. +The 'coupled stream count' field indicates that the decoders for the first M + Opus streams are to be initialized for stereo (two-channel) output, and the + remaining (N - M) decoders are to be initialized for mono (a single + channel) only. +The total number of decoded channels, (M + N), MUST be no larger than + 255, as there is no way to index more channels than that in the channel + mapping. + +For channel mapping family 0, this value defaults to (C - 1) + (i.e., 0 for mono and 1 for stereo), and is not coded. + + +Channel Mapping (8*C bits): +This contains one octet per output channel, indicating which decoded channel + is to be used for each one. +Let 'index' be the value of this octet for a particular output channel. +This value MUST either be smaller than (M + N), or be the special + value 255. +If 'index' is less than 2*M, the output MUST be taken from decoding stream + ('index'/2) as stereo and selecting the left channel if 'index' is even, and + the right channel if 'index' is odd. +If 'index' is 2*M or larger, but less than 255, the output MUST be taken from + decoding stream ('index' - M) as mono. +If 'index' is 255, the corresponding output channel MUST contain pure silence. + +The number of output channels, C, is not constrained to match the number of + decoded channels (M + N). +A single index value MAY appear multiple times, i.e., the same decoded channel + might be mapped to multiple output channels. +Some decoded channels might not be assigned to any output channel, as well. + +For channel mapping family 0, the first index defaults to 0, and if + C == 2, the second index defaults to 1. +Neither index is coded. + + + + + +After producing the output channels, the channel mapping family determines the + semantic meaning of each one. +There are three defined mapping families in this specification. + + +
+ +Allowed numbers of channels: 1 or 2. +RTP mapping. +This is the same channel interpretation as . + + + +1 channel: monophonic (mono). +2 channels: stereo (left, right). + +Special mapping: This channel mapping value also + indicates that the contents consists of a single Opus stream that is stereo if + and only if C == 2, with stream index 0 mapped to output + channel 0 (mono, or left channel) and stream index 1 mapped to + output channel 1 (right channel) if stereo. +When the 'channel mapping family' octet has this value, the channel mapping + table MUST be omitted from the ID header packet. + +
+ +
+ +Allowed numbers of channels: 1...8. +Vorbis channel order (see below). + + +Each channel is assigned to a speaker location in a conventional surround + arrangement. +Specific locations depend on the number of channels, and are given below + in order of the corresponding channel indices. + + 1 channel: monophonic (mono). + 2 channels: stereo (left, right). + 3 channels: linear surround (left, center, right) + 4 channels: quadraphonic (front left, front right, rear left, rear right). + 5 channels: 5.0 surround (front left, front center, front right, rear left, rear right). + 6 channels: 5.1 surround (front left, front center, front right, rear left, rear right, LFE). + 7 channels: 6.1 surround (front left, front center, front right, side left, side right, rear center, LFE). + 8 channels: 7.1 surround (front left, front center, front right, side left, side right, rear left, rear right, LFE) + + + +This set of surround options and speaker location orderings is the same + as those used by the Vorbis codec . +The ordering is different from the one used by the + WAVE and + Free Lossless Audio Codec (FLAC) formats, + so correct ordering requires permutation of the output channels when decoding + to or encoding from those formats. +'LFE' here refers to a Low Frequency Effects channel, often mapped to a + subwoofer with no particular spatial position. +Implementations SHOULD identify 'side' or 'rear' speaker locations with + 'surround' and 'back' as appropriate when interfacing with audio formats + or systems which prefer that terminology. + +
+ +
+ +Allowed numbers of channels: 1...255. +No defined channel meaning. + + +Channels are unidentified. +General-purpose players SHOULD NOT attempt to play these streams. +Offline implementations MAY deinterleave the output into separate PCM files, + one per channel. +Implementations SHOULD NOT produce output for channels mapped to stream index + 255 (pure silence) unless they have no other way to indicate the index of + non-silent channels. + +
+ +
+ +The remaining channel mapping families (2...254) are reserved. +A demuxer implementation encountering a reserved channel mapping family value + SHOULD act as though the value is 255. + +
+ +
+ +An Ogg Opus player MUST support any valid channel mapping with a channel + mapping family of 0 or 1, even if the number of channels does not match the + physically connected audio hardware. +Players SHOULD perform channel mixing to increase or reduce the number of + channels as needed. + + + +Implementations MAY use the matrices in + Figures  + through  to implement + downmixing from multichannel files using + Channel Mapping Family 1, which are + known to give acceptable results for stereo. +Matrices for 3 and 4 channels are normalized so each coefficient row sums + to 1 to avoid clipping. +For 5 or more channels they are normalized to 2 as a compromise between + clipping and dynamic range reduction. + + +In these matrices the front left and front right channels are generally +passed through directly. +When a surround channel is split between both the left and right stereo + channels, coefficients are chosen so their squares sum to 1, which + helps preserve the perceived intensity. +Rear channels are mixed more diffusely or attenuated to maintain focus + on the front channels. + + +
+ + +Exact coefficient values are 1 and 1/sqrt(2), multiplied by + 1/(1 + 1/sqrt(2)) for normalization. + +
+ +
+ + +Exact coefficient values are 1, sqrt(3)/2 and 1/2, multiplied by + 1/(1 + sqrt(3)/2 + 1/2) for normalization. + +
+ +
+ + +Exact coefficient values are 1, 1/sqrt(2), sqrt(3)/2 and 1/2, multiplied by + 2/(1 + 1/sqrt(2) + sqrt(3)/2 + 1/2) + for normalization. + +
+ +
+ + +Exact coefficient values are 1, 1/sqrt(2), sqrt(3)/2 and 1/2, multiplied by +2/(1 + 1/sqrt(2) + sqrt(3)/2 + 1/2 + 1/sqrt(2)) + for normalization. + +
+ +
+ + +Exact coefficient values are 1, 1/sqrt(2), sqrt(3)/2, 1/2 and + sqrt(3)/2/sqrt(2), multiplied by + 2/(1 + 1/sqrt(2) + sqrt(3)/2 + 1/2 + + sqrt(3)/2/sqrt(2) + 1/sqrt(2)) for normalization. +The coefficients are in the same order as in , + and the matrices above. + +
+ +
+ + +Exact coefficient values are 1, 1/sqrt(2), sqrt(3)/2 and 1/2, multiplied by + 2/(2 + 2/sqrt(2) + sqrt(3)) for normalization. +The coefficients are in the same order as in , + and the matrices above. + +
+ +
+ +
+ +
+ +
+ +
+ +
+ + +The comment header consists of a 64-bit magic signature, followed by data in + the same format as the header used in Ogg + Vorbis, except (like Ogg Theora and Speex) the final "framing bit" specified + in the Vorbis spec is not present. + +Magic Signature: + +This is an 8-octet (64-bit) field that allows codec identification and is + human-readable. +It contains, in order, the magic numbers: + +0x4F 'O' +0x70 'p' +0x75 'u' +0x73 's' +0x54 'T' +0x61 'a' +0x67 'g' +0x73 's' + +Starting with "Op" helps distinguish it from audio data packets, as this is an + invalid TOC sequence. + + +Vendor String Length (32 bits, unsigned, little endian): + +This field gives the length of the following vendor string, in octets. +It MUST NOT indicate that the vendor string is longer than the rest of the + packet. + + +Vendor String (variable length, UTF-8 vector): + +This is a simple human-readable tag for vendor information, encoded as a UTF-8 + string . +No terminating null octet is necessary. + +This tag is intended to identify the codec encoder and encapsulation + implementations, for tracing differences in technical behavior. +User-facing applications can use the 'ENCODER' user comment tag to identify + themselves. + + +User Comment List Length (32 bits, unsigned, little endian): + +This field indicates the number of user-supplied comments. +It MAY indicate there are zero user-supplied comments, in which case there are + no additional fields in the packet. +It MUST NOT indicate that there are so many comments that the comment string + lengths would require more data than is available in the rest of the packet. + + +User Comment #i String Length (32 bits, unsigned, little endian): + +This field gives the length of the following user comment string, in octets. +There is one for each user comment indicated by the 'user comment list length' + field. +It MUST NOT indicate that the string is longer than the rest of the packet. + + +User Comment #i String (variable length, UTF-8 vector): + +This field contains a single user comment encoded as a UTF-8 + string . +There is one for each user comment indicated by the 'user comment list length' + field. + + + + + +The vendor string length and user comment list length are REQUIRED, and + implementations SHOULD treat a stream as invalid if it contains a comment + header that does not have enough data for these fields, or that does not + contain enough data for the corresponding vendor string or user comments they + describe. +Making this check before allocating the associated memory to contain the data + helps prevent a possible Denial-of-Service (DoS) attack from small comment + headers that claim to contain strings longer than the entire packet or more + user comments than than could possibly fit in the packet. + + + +Immediately following the user comment list, the comment header MAY + contain zero-padding or other binary data which is not specified here. +If the least-significant bit of the first byte of this data is 1, then editors + SHOULD preserve the contents of this data when updating the tags, but if this + bit is 0, all such data MAY be treated as padding, and truncated or discarded + as desired. +This allows informal experimentation with the format of this binary data until + it can be specified later. + + + +The comment header can be arbitrarily large and might be spread over a large + number of Ogg pages. +Implementations MUST avoid attempting to allocate excessive amounts of memory + when presented with a very large comment header. +To accomplish this, implementations MAY treat a stream as invalid if it has a + comment header larger than 125,829,120 octets (120 MB), and MAY + ignore individual comments that are not fully contained within the first + 61,440 octets of the comment header. + + +
+ +The user comment strings follow the NAME=value format described by + with the same recommended tag names: + ARTIST, TITLE, DATE, ALBUM, and so on. + + +Two new comment tags are introduced here: + + +First, an optional gain for track normalization: +
+ +
+ + representing the volume shift needed to normalize the track's volume + during isolated playback, in random shuffle, and so on. +The gain is a Q7.8 fixed point number in dB, as in the ID header's 'output + gain' field. +This tag is similar to the REPLAYGAIN_TRACK_GAIN tag in + Vorbis , except that the normal volume + reference is the standard. + +Second, an optional gain for album normalization: +
+ +
+ + representing the volume shift needed to normalize the overall volume when + played as part of a particular collection of tracks. +The gain is also a Q7.8 fixed point number in dB, as in the ID header's + 'output gain' field. +The values '-573' and '111' given here are just examples. + + +An Ogg Opus stream MUST NOT have more than one of each of these tags, and if + present their values MUST be an integer from -32768 to 32767, inclusive, + represented in ASCII as a base 10 number with no whitespace. +A leading '+' or '-' character is valid. +Leading zeros are also permitted, but the value MUST be represented by + no more than 6 characters. +Other non-digit characters MUST NOT be present. + + +If present, R128_TRACK_GAIN and R128_ALBUM_GAIN MUST correctly represent + the R128 normalization gain relative to the 'output gain' field specified + in the ID header. +If a player chooses to make use of the R128_TRACK_GAIN tag or the + R128_ALBUM_GAIN tag, it MUST apply those gains + in addition to the 'output gain' value. +If a tool modifies the ID header's 'output gain' field, it MUST also update or + remove the R128_TRACK_GAIN and R128_ALBUM_GAIN comment tags if present. +A muxer SHOULD place the gain it wants other tools to use by default into the + 'output gain' field, and not the comment tag. + + +To avoid confusion with multiple normalization schemes, an Opus comment header + SHOULD NOT contain any of the REPLAYGAIN_TRACK_GAIN, REPLAYGAIN_TRACK_PEAK, + REPLAYGAIN_ALBUM_GAIN, or REPLAYGAIN_ALBUM_PEAK tags, unless they are only + to be used in some context where there is guaranteed to be no such confusion. + normalization is preferred to the earlier + REPLAYGAIN schemes because of its clear definition and adoption by industry. +Peak normalizations are difficult to calculate reliably for lossy codecs + because of variation in excursion heights due to decoder differences. +In the authors' investigations they were not applied consistently or broadly + enough to merit inclusion here. + +
+
+ +
+ +
+ +Technically, valid Opus packets can be arbitrarily large due to the padding + format, although the amount of non-padding data they can contain is bounded. +These packets might be spread over a similarly enormous number of Ogg pages. +When encoding, implementations SHOULD limit the use of padding in audio data + packets to no more than is necessary to make a variable bitrate (VBR) stream + constant bitrate (CBR), unless they have no reasonable way to determine what + is necessary. +Demuxers SHOULD treat audio data packets as invalid (treat them as if they were + malformed Opus packets with an invalid TOC sequence) if they are larger than + 61,440 octets per Opus stream, unless they have a specific reason for + allowing extra padding. +Such packets necessarily contain more padding than needed to make a stream CBR. +Demuxers MUST avoid attempting to allocate excessive amounts of memory when + presented with a very large packet. +Demuxers MAY treat audio data packets as invalid or partially process them if + they are larger than 61,440 octets in an Ogg Opus stream with channel + mapping families 0 or 1. +Demuxers MAY treat audio data packets as invalid or partially process them in + any Ogg Opus stream if the packet is larger than 61,440 octets and also + larger than 7,680 octets per Opus stream. +The presence of an extremely large packet in the stream could indicate a + memory exhaustion attack or stream corruption. + + +In an Ogg Opus stream, the largest possible valid packet that does not use + padding has a size of (61,298*N - 2) octets. +With 255 streams, this is 15,630,988 octets and can + span up to 61,298 Ogg pages, all but one of which will have a granule + position of -1. +This is of course a very extreme packet, consisting of 255 streams, each + containing 120 ms of audio encoded as 2.5 ms frames, each frame + using the maximum possible number of octets (1275) and stored in the least + efficient manner allowed (a VBR code 3 Opus packet). +Even in such a packet, most of the data will be zeros as 2.5 ms frames + cannot actually use all 1275 octets. + + +The largest packet consisting of entirely useful data is + (15,326*N - 2) octets. +This corresponds to 120 ms of audio encoded as 10 ms frames in either + SILK or Hybrid mode, but at a data rate of over 1 Mbps, which makes little + sense for the quality achieved. + + +A more reasonable limit is (7,664*N - 2) octets. +This corresponds to 120 ms of audio encoded as 20 ms stereo CELT mode + frames, with a total bitrate just under 511 kbps (not counting the Ogg + encapsulation overhead). +For channel mapping family 1, N=8 provides a reasonable upper bound, as it + allows for each of the 8 possible output channels to be decoded from a + separate stereo Opus stream. +This gives a size of 61,310 octets, which is rounded up to a multiple of + 1,024 octets to yield the audio data packet size of 61,440 octets + that any implementation is expected to be able to process successfully. + +
+ +
+ +When encoding Opus streams, Ogg muxers SHOULD take into account the + algorithmic delay of the Opus encoder. + + +In encoders derived from the reference + implementation , the number of samples can be + queried with: + +
+ +
+ +To achieve good quality in the very first samples of a stream, implementations + MAY use linear predictive coding (LPC) extrapolation to generate at least 120 + extra samples at the beginning to avoid the Opus encoder having to encode a + discontinuous signal. +For more information on linear prediction, see + . +For an input file containing 'length' samples, the implementation SHOULD set + the pre-skip header value to (delay_samples + extra_samples), encode + at least (length + delay_samples + extra_samples) + samples, and set the granule position of the last page to + (length + delay_samples + extra_samples). +This ensures that the encoded file has the same duration as the original, with + no time offset. The best way to pad the end of the stream is to also use LPC + extrapolation, but zero-padding is also acceptable. + + +
+ +The first step in LPC extrapolation is to compute linear prediction + coefficients. +When extending the end of the signal, order-N (typically with N ranging from 8 + to 40) LPC analysis is performed on a window near the end of the signal. +The last N samples are used as memory to an infinite impulse response (IIR) + filter. + + +The filter is then applied on a zero input to extrapolate the end of the signal. +Let a(k) be the kth LPC coefficient and x(n) be the nth sample of the signal, + each new sample past the end of the signal is computed as: + +
+ +
+ +The process is repeated independently for each channel. +It is possible to extend the beginning of the signal by applying the same + process backward in time. +When extending the beginning of the signal, it is best to apply a "fade in" to + the extrapolated signal, e.g. by multiplying it by a half-Hanning window + . + + +
+ +
+ +In some applications, such as Internet radio, it is desirable to cut a long + stream into smaller chains, e.g. so the comment header can be updated. +This can be done simply by separating the input streams into segments and + encoding each segment independently. +The drawback of this approach is that it creates a small discontinuity + at the boundary due to the lossy nature of Opus. +A muxer MAY avoid this discontinuity by using the following procedure: + +Encode the last frame of the first segment as an independent frame by + turning off all forms of inter-frame prediction. +De-emphasis is allowed. +Set the granule position of the last page to a point near the end of the + last frame. +Begin the second segment with a copy of the last frame of the first + segment. +Set the pre-skip value of the second stream in such a way as to properly + join the two streams. +Continue the encoding process normally from there, without any reset to + the encoder. + + + +In encoders derived from the reference implementation, inter-frame prediction + can be turned off by calling: + +
+ +
+ +For best results, this implementation requires that prediction be explicitly + enabled again before resuming normal encoding, even after a reset. + + +
+ +
+ +
+ +A brief summary of major implementations of this draft is available + at , + along with their status. + + +[Note to RFC Editor: please remove this entire section before + final publication per , along with + its references.] + +
+ +
+ +Implementations of the Opus codec need to take appropriate security + considerations into account, as outlined in . +This is just as much a problem for the container as it is for the codec itself. +Malicious payloads and/or input streams can be used to attack codec + implementations. +Implementations MUST NOT overrun their allocated memory nor consume excessive + resources when decoding payloads or processing input streams. +Although problems in encoding applications are typically rarer, this still + applies to a muxer, as vulnerabilities would allow an attacker to attack + transcoding gateways. + + + +Header parsing code contains the most likely area for potential overruns. +It is important for implementations to ensure their buffers contain enough + data for all of the required fields before attempting to read it (for example, + for all of the channel map data in the ID header). +Implementations would do well to validate the indices of the channel map, also, + to ensure they meet all of the restrictions outlined in + , in order to avoid attempting to read data + from channels that do not exist. + + + +To avoid excessive resource usage, we advise implementations to be especially + wary of streams that might cause them to process far more data than was + actually transmitted. +For example, a relatively small comment header may contain values for the + string lengths or user comment list length that imply that it is many + gigabytes in size. +Even computing the size of the required buffer could overflow a 32-bit integer, + and actually attempting to allocate such a buffer before verifying it would be + a reasonable size is a bad idea. +After reading the user comment list length, implementations might wish to + verify that the header contains at least the minimum amount of data for that + many comments (4 additional octets per comment, to indicate each has a + length of zero) before proceeding any further, again taking care to avoid + overflow in these calculations. +If allocating an array of pointers to point at these strings, the size of the + pointers may be larger than 4 octets, potentially requiring a separate + overflow check. + + + +Another bug in this class we have observed more than once involves the handling + of invalid data at the end of a stream. +Often, implementations will seek to the end of a stream to locate the last + timestamp in order to compute its total duration. +If they do not find a valid capture pattern and Ogg page from the desired + logical stream, they will back up and try again. +If care is not taken to avoid re-scanning data that was already scanned, this + search can quickly devolve into something with a complexity that is quadratic + in the amount of invalid data. + + + +In general when seeking, implementations will wish to be cautious about the + effects of invalid granule position values, and ensure all algorithms will + continue to make progress and eventually terminate, even if these are missing + or out-of-order. + + + +Like most other container formats, Ogg Opus streams SHOULD NOT be used with + insecure ciphers or cipher modes that are vulnerable to known-plaintext + attacks. +Elements such as the Ogg page capture pattern and the magic signatures in the + ID header and the comment header all have easily predictable values, in + addition to various elements of the codec data itself. + +
+ +
+ +An "Ogg Opus file" consists of one or more sequentially multiplexed segments, + each containing exactly one Ogg Opus stream. +The RECOMMENDED mime-type for Ogg Opus files is "audio/ogg". + + + +If more specificity is desired, one MAY indicate the presence of Opus streams + using the codecs parameter defined in and + , e.g., + +
+ +
+ + for an Ogg Opus file. + + + +The RECOMMENDED filename extension for Ogg Opus files is '.opus'. + + + +When Opus is concurrently multiplexed with other streams in an Ogg container, + one SHOULD use one of the "audio/ogg", "video/ogg", or "application/ogg" + mime-types, as defined in . +Such streams are not strictly "Ogg Opus files" as described above, + since they contain more than a single Opus stream per sequentially + multiplexed segment, e.g. video or multiple audio tracks. +In such cases the the '.opus' filename extension is NOT RECOMMENDED. + + + +In either case, this document updates + to add 'opus' as a codecs parameter value with char[8]: 'OpusHead' + as Codec Identifier. + +
+ +
+ +This document updates the IANA Media Types registry to add .opus + as a file extension for "audio/ogg", and to add itself as a reference + alongside for "audio/ogg", "video/ogg", and + "application/ogg" Media Types. + + +This document defines a new registry "Opus Channel Mapping Families" to + indicate how the semantic meanings of the channels in a multi-channel Opus + stream are described. +IANA is requested to create a new name space of "Opus Channel Mapping + Families". +This will be a new registry on the IANA Matrix, and not a subregistry of an + existing registry. +Modifications to this registry follow the "Specification Required" registration + policy as defined in . +Each registry entry consists of a Channel Mapping Family Number, which is + specified in decimal in the range 0 to 255, inclusive, and a Reference (or + list of references) +Each Reference must point to sufficient documentation to describe what + information is coded in the Opus identification header for this channel + mapping family, how a demuxer determines the Stream Count ('N') and Coupled + Stream Count ('M') from this information, and how it determines the proper + interpretation of each of the decoded channels. + + +This document defines three initial assignments for this registry. + + +ValueReference +0[RFCXXXX] +1[RFCXXXX] +255[RFCXXXX] + + +The designated expert will determine if the Reference points to a specification + that meets the requirements for permanence and ready availability laid out + in  and that it specifies the information + described above with sufficient clarity to allow interoperable + implementations. + +
+ +
+ +Thanks to Ben Campbell, Joel M. Halpern, Mark Harris, Greg Maxwell, + Christopher "Monty" Montgomery, Jean-Marc Valin, Stephan Wenger, and Mo Zanaty + for their valuable contributions to this document. +Additional thanks to Andrew D'Addesio, Greg Maxwell, and Vincent Penquerc'h for + their feedback based on early implementations. + +
+ +
+ +In , "RFCXXXX" is to be replaced with the RFC number + assigned to this draft. + +
+ +
+ + + &rfc2119; + &rfc3533; + &rfc3629; + &rfc5226; + &rfc5334; + &rfc6381; + &rfc6716; + + + + Loudness Recommendation EBU R128 + + EBU Technical Committee + + + + + + + +Ogg Vorbis I Format Specification: Comment Field and Header + Specification + + + + + + + + + + + &rfc4732; + &rfc6982; + &rfc7587; + + + + FLAC - Free Lossless Audio Codec Format Description + + + + + + + + Hann window + + Wikipedia + + + + + + + + Linear Predictive Coding + + Wikipedia + + + + + + + + Autocorrelation LPC coeff generation algorithm + (Vorbis source code) + + + + + + + + +Q (number format) +Wikipedia + + + + + + +VorbisComment: Replay Gain + + + + + + + + +Granulepos Encoding and How Seeking Really Works + + + + + + + + + +The Vorbis I Specification, Section 4.3.9 Output Channel Order + + + + + + + + The Vorbis I Specification, Appendix A: Embedding Vorbis + into an Ogg stream + + + + + + + + Multiple Channel Audio Data and WAVE Files + + Microsoft Corporation + + + + + + + + +
diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/draft-ietf-codec-opus-update.xml b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/draft-ietf-codec-opus-update.xml new file mode 100644 index 000000000..3124e22c0 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/draft-ietf-codec-opus-update.xml @@ -0,0 +1,513 @@ + + + + + + + + + + + + + + + Updates to the Opus Audio Codec + + +Mozilla Corporation +
+ +331 E. Evelyn Avenue +Mountain View +CA +94041 +USA + ++1 650 903-0800 +jmvalin@jmvalin.ca +
+
+ + +vocTone +
+ + + + + + + + +koenvos74@gmail.com +
+
+ + + + + + + This document addresses minor issues that were found in the specification + of the Opus audio codec in RFC 6716. It updates the normative decoder implementation + included in the appendix of RFC 6716. The changes fixes real and potential security-related + issues, as well minor quality-related issues. + +
+ + +
+ This document addresses minor issues that were discovered in the reference + implementation of the Opus codec. Unlike most IETF specifications, Opus is defined + in RFC 6716 in terms of a normative reference + decoder implementation rather than from the associated text description. + That RFC includes the reference decoder implementation as Appendix A. + That's why only issues affecting the decoder are + listed here. An up-to-date implementation of the Opus encoder can be found at + . + + Some of the changes in this document update normative behaviour in a way that requires + new test vectors. The English text of the specification is unaffected, only + the C implementation is. The updated specification remains fully compatible with + the original specification. + + + + Note: due to RFC formatting conventions, lines exceeding the column width + in the patch are split using a backslash character. The backslashes + at the end of a line and the white space at the beginning + of the following line are not part of the patch. A properly formatted patch + including all changes is available at + + and has a SHA-1 hash of 029e3aa88fc342c91e67a21e7bfbc9458661cd5f. + + +
+ +
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119. +
+ +
+ The reference implementation does not reinitialize the stereo state + during a mode switch. The old stereo memory can produce a brief impulse + (i.e. single sample) in the decoded audio. This can be fixed by changing + silk/dec_API.c at line 72: + +
+ + for( n = 0; n < DECODER_NUM_CHANNELS; n++ ) { + ret = silk_init_decoder( &channel_state[ n ] ); + } ++ silk_memset(&((silk_decoder *)decState)->sStereo, 0, ++ sizeof(((silk_decoder *)decState)->sStereo)); ++ /* Not strictly needed, but it's cleaner that way */ ++ ((silk_decoder *)decState)->prev_decode_only_middle = 0; + + return ret; + } + +]]> +
+ + This change affects the normative output of the decoder, but the + amount of change is within the tolerance and too small to make the testvector check fail. + +
+ +
+ It was discovered that some invalid packets of very large size could trigger + an out-of-bounds read in the Opus packet parsing code responsible for padding. + This is due to an integer overflow if the signaled padding exceeds 2^31-1 bytes + (the actual packet may be smaller). The code can be fixed by decrementing the + (signed) len value, instead of incrementing a separate padding counter. + This is done by applying the following changes at line 596 of src/opus_decoder.c: + +
+ + /* Padding flag is bit 6 */ + if (ch&0x40) + { +- int padding=0; + int p; + do { + if (len<=0) + return OPUS_INVALID_PACKET; + p = *data++; + len--; +- padding += p==255 ? 254: p; ++ len -= p==255 ? 254: p; + } while (p==255); +- len -= padding; + } + +]]> +
+ This packet parsing issue is limited to reading memory up + to about 60 kB beyond the compressed buffer. This can only be triggered + by a compressed packet more than about 16 MB long, so it's not a problem + for RTP. In theory, it could crash a file + decoder (e.g. Opus in Ogg) if the memory just after the incoming packet + is out-of-range, but our attempts to trigger such a crash in a production + application built using an affected version of the Opus decoder failed. +
+ +
+ The SILK resampler had the following issues: + + The calls to memcpy() were using sizeof(opus_int32), but the type of the + local buffer was opus_int16. + Because the size was wrong, this potentially allowed the source + and destination regions of the memcpy() to overlap on the copy from "buf" to "buf". + We believe that nSamplesIn (number of input samples) is at least fs_in_khZ (sampling rate in kHz), + which is at least 8. + Since RESAMPLER_ORDER_FIR_12 is only 8, that should not be a problem once + the type size is fixed. + The size of the buffer used RESAMPLER_MAX_BATCH_SIZE_IN, but the + data stored in it was actually twice the input batch size + (nSamplesIn<<1). + + The code can be fixed by applying the following changes to line 78 of silk/resampler_private_IIR_FIR.c: + +
+ + ) + { + silk_resampler_state_struct *S = \ +(silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; +- opus_int16 buf[ RESAMPLER_MAX_BATCH_SIZE_IN + \ +RESAMPLER_ORDER_FIR_12 ]; ++ opus_int16 buf[ 2*RESAMPLER_MAX_BATCH_SIZE_IN + \ +RESAMPLER_ORDER_FIR_12 ]; + + /* Copy buffered samples to start of buffer */ +- silk_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_12 \ +* sizeof( opus_int32 ) ); ++ silk_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_12 \ +* sizeof( opus_int16 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = silk_min( inLen, S->batchSize ); + + /* Upsample 2x */ + silk_resampler_private_up2_HQ( S->sIIR, &buf[ \ +RESAMPLER_ORDER_FIR_12 ], in, nSamplesIn ); + + max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 + 1 \ +); /* + 1 because 2x upsampling */ + out = silk_resampler_private_IIR_FIR_INTERPOL( out, \ +buf, max_index_Q16, index_increment_Q16 ); + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of \ +filtered signal to beginning of buffer */ +- silk_memcpy( buf, &buf[ nSamplesIn << 1 ], \ +RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); ++ silk_memmove( buf, &buf[ nSamplesIn << 1 ], \ +RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for \ +the next call */ +- silk_memcpy( S->sFIR, &buf[ nSamplesIn << 1 ], \ +RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); ++ silk_memcpy( S->sFIR, &buf[ nSamplesIn << 1 ], \ +RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + } + +]]> +
+
+ +
+ + It was discovered through decoder fuzzing that some bitstreams could produce + integer values exceeding 32-bits in LPC_inverse_pred_gain_QA(), causing + a wrap-around. The C standard considers + this behavior as undefined. The following patch to line 87 of silk/LPC_inv_pred_gain.c + detects values that do not fit in a 32-bit integer and considers the corresponding filters unstable: + +
+ + /* Update AR coefficient */ + for( n = 0; n < k; n++ ) { +- tmp_QA = Aold_QA[ n ] - MUL32_FRAC_Q( \ +Aold_QA[ k - n - 1 ], rc_Q31, 31 ); +- Anew_QA[ n ] = MUL32_FRAC_Q( tmp_QA, rc_mult2 , mult2Q ); ++ opus_int64 tmp64; ++ tmp_QA = silk_SUB_SAT32( Aold_QA[ n ], MUL32_FRAC_Q( \ +Aold_QA[ k - n - 1 ], rc_Q31, 31 ) ); ++ tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( tmp_QA, \ +rc_mult2 ), mult2Q); ++ if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { ++ return 0; ++ } ++ Anew_QA[ n ] = ( opus_int32 )tmp64; + } + +]]> +
+
+ +
+ + It was discovered -- also from decoder fuzzing -- that an integer wrap-around could + occur when decoding bitstreams with extremely large values for the high LSF parameters. + The end result of the wrap-around is an illegal read access on the stack, which + the authors do not believe is exploitable but should nonetheless be fixed. The following + patch to line 137 of silk/NLSF_stabilize.c prevents the problem: + +
+ + /* Keep delta_min distance between the NLSFs */ + for( i = 1; i < L; i++ ) +- NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], \ +NLSF_Q15[i-1] + NDeltaMin_Q15[i] ); ++ NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], \ +silk_ADD_SAT16( NLSF_Q15[i-1], NDeltaMin_Q15[i] ) ); + + /* Last NLSF should be no higher than 1 - NDeltaMin[L] */ + +]]> +
+ +
+ +
+ On extreme bit-streams, it is possible for log-domain band energy levels + to exceed the maximum single-precision floating point value once converted + to a linear scale. This would later cause the decoded values to be NaN (not a number), + possibly causing problems in the software using the PCM values. This can be + avoided with the following patch to line 552 of celt/quant_bands.c: + +
+ + { + opus_val16 lg = ADD16(oldEBands[i+c*m->nbEBands], + SHL16((opus_val16)eMeans[i],6)); ++ lg = MIN32(QCONST32(32.f, 16), lg); + eBands[i+c*m->nbEBands] = PSHR32(celt_exp2(lg),4); + } + for (;inbEBands;i++) + +]]> +
+
+ +
+ When encoding in hybrid mode at low bitrate, we sometimes only have + enough bits to code a single CELT band (8 - 9.6 kHz). When that happens, + the second band (CELT band 18, from 9.6 to 12 kHz) cannot use folding + because it is wider than the amount already coded, and falls back to + white noise. Because it can also happen on transients (e.g. stops), it + can cause audible pre-echo. + + + To address the issue, we change the folding behavior so that it is + never forced to fall back to LCG due to the first band not containing + enough coefficients to fold onto the second band. This + is achieved by simply repeating part of the first band in the folding + of the second band. This changes the code in celt/bands.c around line 1237: + +
+ + b = 0; + } + +- if (resynth && M*eBands[i]-N >= M*eBands[start] && \ +(update_lowband || lowband_offset==0)) ++ if (resynth && (M*eBands[i]-N >= M*eBands[start] || \ +i==start+1) && (update_lowband || lowband_offset==0)) + lowband_offset = i; + ++ if (i == start+1) ++ { ++ int n1, n2; ++ int offset; ++ n1 = M*(eBands[start+1]-eBands[start]); ++ n2 = M*(eBands[start+2]-eBands[start+1]); ++ offset = M*eBands[start]; ++ /* Duplicate enough of the first band folding data to \ +be able to fold the second band. ++ Copies no data for CELT-only mode. */ ++ OPUS_COPY(&norm[offset+n1], &norm[offset+2*n1 - n2], n2-n1); ++ if (C==2) ++ OPUS_COPY(&norm2[offset+n1], &norm2[offset+2*n1 - n2], \ +n2-n1); ++ } ++ + tf_change = tf_res[i]; + if (i>=m->effEBands) + { + +]]> +
+ + + as well as line 1260: + + +
+ + fold_start = lowband_offset; + while(M*eBands[--fold_start] > effective_lowband); + fold_end = lowband_offset-1; +- while(M*eBands[++fold_end] < effective_lowband+N); ++ while(++fold_end < i && M*eBands[fold_end] < \ +effective_lowband+N); + x_cm = y_cm = 0; + fold_i = fold_start; do { + x_cm |= collapse_masks[fold_i*C+0]; + + +]]> +
+ + The fix does not impact compatibility, because the improvement does + not depend on the encoder doing anything special. There is also no + reasonable way for an encoder to use the original behavior to + improve quality over the proposed change. + +
+ +
+ The last issue is not strictly a bug, but it is an issue that has been reported + when downmixing an Opus decoded stream to mono, whether this is done inside the decoder + or as a post-processing step on the stereo decoder output. Opus intensity stereo allows + optionally coding the two channels 180-degrees out of phase on a per-band basis. + This provides better stereo quality than forcing the two channels to be in phase, + but when the output is downmixed to mono, the energy in the affected bands is cancelled + sometimes resulting in audible artifacts. + + As a work-around for this issue, the decoder MAY choose not to apply the 180-degree + phase shift. This can be useful when downmixing to mono inside or + outside of the decoder (e.g. user-controllable). + +
+ + +
+ Changes in and have + sufficient impact on the testvectors to make them fail. For this reason, + this document also updates the Opus test vectors. The new test vectors now + include two decoded outputs for the same bitstream. The outputs with + suffix 'm' do not apply the CELT 180-degree phase shift as allowed in + , while the outputs without the suffix do. An + implementation is compliant as long as it passes either set of vectors. + + + Any Opus implementation + that passes either the original test vectors from RFC 6716 + or one of the new sets of test vectors is compliant with the Opus specification. However, newer implementations + SHOULD be based on the new test vectors rather than the old ones. + + The new test vectors are located at + . + The SHA-1 hashes of the test vectors are: +
+ + + +
+ Note that the decoder input bitstream files (.bit) are unchanged. +
+
+ +
+ This document fixes two security issues reported on Opus and that affect the + reference implementation in RFC 6716: CVE-2013-0899 + + and CVE-2017-0381 . + CVE- 2013-0899 theoretically could have caused an information leak. The leaked + information would have gone through the decoder process before being accessible + to the attacker. It is fixed by . + CVE-2017-0381 could have resulted in a 16-bit out-of-bounds read from a fixed + location. It is fixed in . + Beyond the two fixed CVEs, this document adds no new security considerations on top of + RFC 6716. + +
+ +
+ This document makes no request of IANA. + + Note to RFC Editor: this section may be removed on publication as an + RFC. +
+ +
+ We would like to thank Juri Aedla for reporting the issue with the parsing of + the Opus padding. Thanks to Felicia Lim for reporting the LSF integer overflow issue. + Also, thanks to Tina le Grand, Jonathan Lennox, and Mark Harris for their + feedback on this document. +
+
+ + + + + + + + + +
diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/draft-ietf-codec-opus.xml b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/draft-ietf-codec-opus.xml new file mode 100644 index 000000000..334cad97a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/draft-ietf-codec-opus.xml @@ -0,0 +1,8276 @@ + + + + + + + +Definition of the Opus Audio Codec + + + +Mozilla Corporation +
+ +650 Castro Street +Mountain View +CA +94041 +USA + ++1 650 903-0800 +jmvalin@jmvalin.ca +
+
+ + +Skype Technologies S.A. +
+ +Soder Malarstrand 43 +Stockholm + +11825 +SE + ++46 73 085 7619 +koen.vos@skype.net +
+
+ + +Mozilla Corporation +
+ +650 Castro Street +Mountain View +CA +94041 +USA + ++1 650 903-0800 +tterriberry@mozilla.com +
+
+ + + +General + + + + + +This document defines the Opus interactive speech and audio codec. +Opus is designed to handle a wide range of interactive audio applications, + including Voice over IP, videoconferencing, in-game chat, and even live, + distributed music performances. +It scales from low bitrate narrowband speech at 6 kb/s to very high quality + stereo music at 510 kb/s. +Opus uses both linear prediction (LP) and the Modified Discrete Cosine + Transform (MDCT) to achieve good compression of both speech and music. + + +
+ + + +
+ +The Opus codec is a real-time interactive audio codec designed to meet the requirements +described in . +It is composed of a linear + prediction (LP)-based layer and a Modified Discrete Cosine Transform + (MDCT)-based layer. +The main idea behind using two layers is that in speech, linear prediction + techniques (such as Code-Excited Linear Prediction, or CELP) code low frequencies more efficiently than transform + (e.g., MDCT) domain techniques, while the situation is reversed for music and + higher speech frequencies. +Thus a codec with both layers available can operate over a wider range than + either one alone and, by combining them, achieve better quality than either + one individually. + + + +The primary normative part of this specification is provided by the source code + in . +Only the decoder portion of this software is normative, though a + significant amount of code is shared by both the encoder and decoder. + provides a decoder conformance test. +The decoder contains a great deal of integer and fixed-point arithmetic which + needs to be performed exactly, including all rounding considerations, so any + useful specification requires domain-specific symbolic language to adequately + define these operations. +Additionally, any +conflict between the symbolic representation and the included reference +implementation must be resolved. For the practical reasons of compatibility and +testability it would be advantageous to give the reference implementation +priority in any disagreement. The C language is also one of the most +widely understood human-readable symbolic representations for machine +behavior. +For these reasons this RFC uses the reference implementation as the sole + symbolic representation of the codec. + + +While the symbolic representation is unambiguous and complete it is not +always the easiest way to understand the codec's operation. For this reason +this document also describes significant parts of the codec in English and +takes the opportunity to explain the rationale behind many of the more +surprising elements of the design. These descriptions are intended to be +accurate and informative, but the limitations of common English sometimes +result in ambiguity, so it is expected that the reader will always read +them alongside the symbolic representation. Numerous references to the +implementation are provided for this purpose. The descriptions sometimes +differ from the reference in ordering or through mathematical simplification +wherever such deviation makes an explanation easier to understand. +For example, the right shift and left shift operations in the reference +implementation are often described using division and multiplication in the text. +In general, the text is focused on the "what" and "why" while the symbolic +representation most clearly provides the "how". + + +
+ +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", + "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be + interpreted as described in RFC 2119 . + + +Various operations in the codec require bit-exact fixed-point behavior, even + when writing a floating point implementation. +The notation "Q<n>", where n is an integer, denotes the number of binary + digits to the right of the decimal point in a fixed-point number. +For example, a signed Q14 value in a 16-bit word can represent values from + -2.0 to 1.99993896484375, inclusive. +This notation is for informational purposes only. +Arithmetic, when described, always operates on the underlying integer. +E.g., the text will explicitly indicate any shifts required after a + multiplication. + + +Expressions, where included in the text, follow C operator rules and + precedence, with the exception that the syntax "x**y" indicates x raised to + the power y. +The text also makes use of the following functions: + + +
+ +The smallest of two values x and y. + +
+ +
+ +The largest of two values x and y. + +
+ +
+
+ +
+ +With this definition, if lo > hi, the lower bound is the one that + is enforced. + +
+ +
+ +The sign of x, i.e., +
+ 0 . +]]> +
+
+
+ +
+ +The absolute value of x, i.e., +
+ +
+
+
+ +
+ +The largest integer z such that z <= f. + +
+ +
+ +The smallest integer z such that z >= f. + +
+ +
+ +The integer z nearest to f, with ties rounded towards negative infinity, + i.e., +
+ +
+
+
+ +
+ +The base-two logarithm of f. + +
+ +
+ +The minimum number of bits required to store a positive integer n in two's + complement notation, or 0 for a non-positive integer n. +
+ 0 +]]> +
+Examples: + +ilog(-1) = 0 +ilog(0) = 0 +ilog(1) = 1 +ilog(2) = 2 +ilog(3) = 2 +ilog(4) = 3 +ilog(7) = 3 + +
+
+ +
+ +
+ +
+ + +The Opus codec scales from 6 kb/s narrowband mono speech to 510 kb/s + fullband stereo music, with algorithmic delays ranging from 5 ms to + 65.2 ms. +At any given time, either the LP layer, the MDCT layer, or both, may be active. +It can seamlessly switch between all of its various operating modes, giving it + a great deal of flexibility to adapt to varying content and network + conditions without renegotiating the current session. +The codec allows input and output of various audio bandwidths, defined as + follows: + + +Abbreviation +Audio Bandwidth +Sample Rate (Effective) +NB (narrowband) 4 kHz 8 kHz +MB (medium-band) 6 kHz 12 kHz +WB (wideband) 8 kHz 16 kHz +SWB (super-wideband) 12 kHz 24 kHz +FB (fullband) 20 kHz (*) 48 kHz + + +(*) Although the sampling theorem allows a bandwidth as large as half the + sampling rate, Opus never codes audio above 20 kHz, as that is the + generally accepted upper limit of human hearing. + + + +Opus defines super-wideband (SWB) with an effective sample rate of 24 kHz, + unlike some other audio coding standards that use 32 kHz. +This was chosen for a number of reasons. +The band layout in the MDCT layer naturally allows skipping coefficients for + frequencies over 12 kHz, but does not allow cleanly dropping just those + frequencies over 16 kHz. +A sample rate of 24 kHz also makes resampling in the MDCT layer easier, + as 24 evenly divides 48, and when 24 kHz is sufficient, it can save + computation in other processing, such as Acoustic Echo Cancellation (AEC). +Experimental changes to the band layout to allow a 16 kHz cutoff + (32 kHz effective sample rate) showed potential quality degradations at + other sample rates, and at typical bitrates the number of bits saved by using + such a cutoff instead of coding in fullband (FB) mode is very small. +Therefore, if an application wishes to process a signal sampled at 32 kHz, + it should just use FB. + + + +The LP layer is based on the SILK codec + . +It supports NB, MB, or WB audio and frame sizes from 10 ms to 60 ms, + and requires an additional 5 ms look-ahead for noise shaping estimation. +A small additional delay (up to 1.5 ms) may be required for sampling rate + conversion. +Like Vorbis and many other modern codecs, SILK is inherently designed for + variable-bitrate (VBR) coding, though the encoder can also produce + constant-bitrate (CBR) streams. +The version of SILK used in Opus is substantially modified from, and not + compatible with, the stand-alone SILK codec previously deployed by Skype. +This document does not serve to define that format, but those interested in the + original SILK codec should see instead. + + + +The MDCT layer is based on the CELT codec . +It supports NB, WB, SWB, or FB audio and frame sizes from 2.5 ms to + 20 ms, and requires an additional 2.5 ms look-ahead due to the + overlapping MDCT windows. +The CELT codec is inherently designed for CBR coding, but unlike many CBR + codecs it is not limited to a set of predetermined rates. +It internally allocates bits to exactly fill any given target budget, and an + encoder can produce a VBR stream by varying the target on a per-frame basis. +The MDCT layer is not used for speech when the audio bandwidth is WB or less, + as it is not useful there. +On the other hand, non-speech signals are not always adequately coded using + linear prediction, so for music only the MDCT layer should be used. + + + +A "Hybrid" mode allows the use of both layers simultaneously with a frame size + of 10 or 20 ms and a SWB or FB audio bandwidth. +The LP layer codes the low frequencies by resampling the signal down to WB. +The MDCT layer follows, coding the high frequency portion of the signal. +The cutoff between the two lies at 8 kHz, the maximum WB audio bandwidth. +In the MDCT layer, all bands below 8 kHz are discarded, so there is no + coding redundancy between the two layers. + + + +The sample rate (in contrast to the actual audio bandwidth) can be chosen + independently on the encoder and decoder side, e.g., a fullband signal can be + decoded as wideband, or vice versa. +This approach ensures a sender and receiver can always interoperate, regardless + of the capabilities of their actual audio hardware. +Internally, the LP layer always operates at a sample rate of twice the audio + bandwidth, up to a maximum of 16 kHz, which it continues to use for SWB + and FB. +The decoder simply resamples its output to support different sample rates. +The MDCT layer always operates internally at a sample rate of 48 kHz. +Since all the supported sample rates evenly divide this rate, and since the + the decoder may easily zero out the high frequency portion of the spectrum in + the frequency domain, it can simply decimate the MDCT layer output to achieve + the other supported sample rates very cheaply. + + + +After conversion to the common, desired output sample rate, the decoder simply + adds the output from the two layers together. +To compensate for the different look-ahead required by each layer, the CELT + encoder input is delayed by an additional 2.7 ms. +This ensures that low frequencies and high frequencies arrive at the same time. +This extra delay may be reduced by an encoder by using less look-ahead for noise + shaping or using a simpler resampler in the LP layer, but this will reduce + quality. +However, the base 2.5 ms look-ahead in the CELT layer cannot be reduced in + the encoder because it is needed for the MDCT overlap, whose size is fixed by + the decoder. + + + +Both layers use the same entropy coder, avoiding any waste from "padding bits" + between them. +The hybrid approach makes it easy to support both CBR and VBR coding. +Although the LP layer is VBR, the bit allocation of the MDCT layer can produce + a final stream that is CBR by using all the bits left unused by the LP layer. + + +
+ +The Opus codec includes a number of control parameters which can be changed dynamically during +regular operation of the codec, without interrupting the audio stream from the encoder to the decoder. +These parameters only affect the encoder since any impact they have on the bit-stream is signaled +in-band such that a decoder can decode any Opus stream without any out-of-band signaling. Any Opus +implementation can add or modify these control parameters without affecting interoperability. The most +important encoder control parameters in the reference encoder are listed below. + + +
+ +Opus supports all bitrates from 6 kb/s to 510 kb/s. All other parameters being +equal, higher bitrate results in higher quality. For a frame size of 20 ms, these +are the bitrate "sweet spots" for Opus in various configurations: + +8-12 kb/s for NB speech, +16-20 kb/s for WB speech, +28-40 kb/s for FB speech, +48-64 kb/s for FB mono music, and +64-128 kb/s for FB stereo music. + + +
+ +
+ +Opus can transmit either mono or stereo frames within a single stream. +When decoding a mono frame in a stereo decoder, the left and right channels are + identical, and when decoding a stereo frame in a mono decoder, the mono output + is the average of the left and right channels. +In some cases, it is desirable to encode a stereo input stream in mono (e.g., + because the bitrate is too low to encode stereo with sufficient quality). +The number of channels encoded can be selected in real-time, but by default the + reference encoder attempts to make the best decision possible given the + current bitrate. + +
+ +
+ +The audio bandwidths supported by Opus are listed in + . +Just like for the number of channels, any decoder can decode audio encoded at + any bandwidth. +For example, any Opus decoder operating at 8 kHz can decode a FB Opus + frame, and any Opus decoder operating at 48 kHz can decode a NB frame. +Similarly, the reference encoder can take a 48 kHz input signal and + encode it as NB. +The higher the audio bandwidth, the higher the required bitrate to achieve + acceptable quality. +The audio bandwidth can be explicitly specified in real-time, but by default + the reference encoder attempts to make the best bandwidth decision possible + given the current bitrate. + +
+ + +
+ +Opus can encode frames of 2.5, 5, 10, 20, 40 or 60 ms. +It can also combine multiple frames into packets of up to 120 ms. +For real-time applications, sending fewer packets per second reduces the + bitrate, since it reduces the overhead from IP, UDP, and RTP headers. +However, it increases latency and sensitivity to packet losses, as losing one + packet constitutes a loss of a bigger chunk of audio. +Increasing the frame duration also slightly improves coding efficiency, but the + gain becomes small for frame sizes above 20 ms. +For this reason, 20 ms frames are a good choice for most applications. + +
+ +
+ +There are various aspects of the Opus encoding process where trade-offs +can be made between CPU complexity and quality/bitrate. In the reference +encoder, the complexity is selected using an integer from 0 to 10, where +0 is the lowest complexity and 10 is the highest. Examples of +computations for which such trade-offs may occur are: + +The order of the pitch analysis whitening filter , +The order of the short-term noise shaping filter, +The number of states in delayed decision quantization of the +residual signal, and +The use of certain bit-stream features such as variable time-frequency +resolution and the pitch post-filter. + + +
+ +
+ +Audio codecs often exploit inter-frame correlations to reduce the +bitrate at a cost in error propagation: after losing one packet +several packets need to be received before the decoder is able to +accurately reconstruct the speech signal. The extent to which Opus +exploits inter-frame dependencies can be adjusted on the fly to +choose a trade-off between bitrate and amount of error propagation. + +
+ +
+ + Another mechanism providing robustness against packet loss is the in-band + Forward Error Correction (FEC). Packets that are determined to + contain perceptually important speech information, such as onsets or + transients, are encoded again at a lower bitrate and this re-encoded + information is added to a subsequent packet. + +
+ +
+ +Opus is more efficient when operating with variable bitrate (VBR), which is +the default. However, in some (rare) applications, constant bitrate (CBR) +is required. There are two main reasons to operate in CBR mode: + +When the transport only supports a fixed size for each compressed frame +When encryption is used for an audio stream that is either highly constrained + (e.g. yes/no, recorded prompts) or highly sensitive + + +When low-latency transmission is required over a relatively slow connection, then +constrained VBR can also be used. This uses VBR in a way that simulates a +"bit reservoir" and is equivalent to what MP3 (MPEG 1, Layer 3) and +AAC (Advanced Audio Coding) call CBR (i.e., not true +CBR due to the bit reservoir). + +
+ +
+ + Discontinuous Transmission (DTX) reduces the bitrate during silence + or background noise. When DTX is enabled, only one frame is encoded + every 400 milliseconds. + +
+ +
+ +
+ +
+ + +The Opus encoder produces "packets", which are each a contiguous set of bytes + meant to be transmitted as a single unit. +The packets described here do not include such things as IP, UDP, or RTP + headers which are normally found in a transport-layer packet. +A single packet may contain multiple audio frames, so long as they share a + common set of parameters, including the operating mode, audio bandwidth, frame + size, and channel count (mono vs. stereo). +This section describes the possible combinations of these parameters and the + internal framing used to pack multiple frames into a single packet. +This framing is not self-delimiting. +Instead, it assumes that a higher layer (such as UDP or RTP +or Ogg or Matroska ) + will communicate the length, in bytes, of the packet, and it uses this + information to reduce the framing overhead in the packet itself. +A decoder implementation MUST support the framing described in this section. +An alternative, self-delimiting variant of the framing is described in + . +Support for that variant is OPTIONAL. + + + +All bit diagrams in this document number the bits so that bit 0 is the most + significant bit of the first byte, and bit 7 is the least significant. +Bit 8 is thus the most significant bit of the second byte, etc. +Well-formed Opus packets obey certain requirements, marked [R1] through [R7] + below. +These are summarized in along with + appropriate means of handling malformed packets. + + +
+ +A well-formed Opus packet MUST contain at least one byte [R1]. +This byte forms a table-of-contents (TOC) header that signals which of the + various modes and configurations a given packet uses. +It is composed of a configuration number, "config", a stereo flag, "s", and a + frame count code, "c", arranged as illustrated in + . +A description of each of these fields follows. + + +
+ +
+ + +The top five bits of the TOC byte, labeled "config", encode one of 32 possible + configurations of operating mode, audio bandwidth, and frame size. +As described, the LP (SILK) layer and MDCT (CELT) layer can be combined in three possible + operating modes: + +A SILK-only mode for use in low bitrate connections with an audio bandwidth + of WB or less, +A Hybrid (SILK+CELT) mode for SWB or FB speech at medium bitrates, and +A CELT-only mode for very low delay speech transmission as well as music + transmission (NB to FB). + +The 32 possible configurations each identify which one of these operating modes + the packet uses, as well as the audio bandwidth and the frame size. + lists the parameters for each configuration. + + +Configuration Number(s) +Mode +Bandwidth +Frame Sizes +0...3 SILK-only NB 10, 20, 40, 60 ms +4...7 SILK-only MB 10, 20, 40, 60 ms +8...11 SILK-only WB 10, 20, 40, 60 ms +12...13 Hybrid SWB 10, 20 ms +14...15 Hybrid FB 10, 20 ms +16...19 CELT-only NB 2.5, 5, 10, 20 ms +20...23 CELT-only WB 2.5, 5, 10, 20 ms +24...27 CELT-only SWB 2.5, 5, 10, 20 ms +28...31 CELT-only FB 2.5, 5, 10, 20 ms + + +The configuration numbers in each range (e.g., 0...3 for NB SILK-only) + correspond to the various choices of frame size, in the same order. +For example, configuration 0 has a 10 ms frame size and configuration 3 + has a 60 ms frame size. + + + +One additional bit, labeled "s", signals mono vs. stereo, with 0 indicating + mono and 1 indicating stereo. + + + +The remaining two bits of the TOC byte, labeled "c", code the number of frames + per packet (codes 0 to 3) as follows: + +0: 1 frame in the packet +1: 2 frames in the packet, each with equal compressed size +2: 2 frames in the packet, with different compressed sizes +3: an arbitrary number of frames in the packet + +This draft refers to a packet as a code 0 packet, code 1 packet, etc., based on + the value of "c". + + +
+ +
+ + +This section describes how frames are packed according to each possible value + of "c" in the TOC byte. + + +
+ +When a packet contains multiple VBR frames (i.e., code 2 or 3), the compressed + length of one or more of these frames is indicated with a one- or two-byte + sequence, with the meaning of the first byte as follows: + +0: No frame (discontinuous transmission (DTX) or lost packet) +1...251: Length of the frame in bytes +252...255: A second byte is needed. The total length is (second_byte*4)+first_byte + + + + +The special length 0 indicates that no frame is available, either because it + was dropped during transmission by some intermediary or because the encoder + chose not to transmit it. +Any Opus frame in any mode MAY have a length of 0. + + + +The maximum representable length is 255*4+255=1275 bytes. +For 20 ms frames, this represents a bitrate of 510 kb/s, which is + approximately the highest useful rate for lossily compressed fullband stereo + music. +Beyond this point, lossless codecs are more appropriate. +It is also roughly the maximum useful rate of the MDCT layer, as shortly + thereafter quality no longer improves with additional bits due to limitations + on the codebook sizes. + + + +No length is transmitted for the last frame in a VBR packet, or for any of the + frames in a CBR packet, as it can be inferred from the total size of the + packet and the size of all other data in the packet. +However, the length of any individual frame MUST NOT exceed + 1275 bytes [R2], to allow for repacketization by gateways, + conference bridges, or other software. + +
+ +
+ + +For code 0 packets, the TOC byte is immediately followed by N-1 bytes + of compressed data for a single frame (where N is the size of the packet), + as illustrated in . + +
+ +
+
+ +
+ +For code 1 packets, the TOC byte is immediately followed by the + (N-1)/2 bytes of compressed data for the first frame, followed by + (N-1)/2 bytes of compressed data for the second frame, as illustrated in + . +The number of payload bytes available for compressed data, N-1, MUST be even + for all code 1 packets [R3]. + +
+ +
+
+ +
+ +For code 2 packets, the TOC byte is followed by a one- or two-byte sequence + indicating the length of the first frame (marked N1 in ), + followed by N1 bytes of compressed data for the first frame. +The remaining N-N1-2 or N-N1-3 bytes are the compressed data for the + second frame. +This is illustrated in . +A code 2 packet MUST contain enough bytes to represent a valid length. +For example, a 1-byte code 2 packet is always invalid, and a 2-byte code 2 + packet whose second byte is in the range 252...255 is also invalid. +The length of the first frame, N1, MUST also be no larger than the size of the + payload remaining after decoding that length for all code 2 packets [R4]. +This makes, for example, a 2-byte code 2 packet with a second byte in the range + 1...251 invalid as well (the only valid 2-byte code 2 packet is one where the + length of both frames is zero). + +
+ +
+
+ +
+ +Code 3 packets signal the number of frames, as well as additional + padding, called "Opus padding" to indicate that this padding is added at the + Opus layer, rather than at the transport layer. +Code 3 packets MUST have at least 2 bytes [R6,R7]. +The TOC byte is followed by a byte encoding the number of frames in the packet + in bits 2 to 7 (marked "M" in ), with bit 1 indicating whether + or not Opus padding is inserted (marked "p" in ), and bit 0 + indicating VBR (marked "v" in ). +M MUST NOT be zero, and the audio duration contained within a packet MUST NOT + exceed 120 ms [R5]. +This limits the maximum frame count for any frame size to 48 (for 2.5 ms + frames), with lower limits for longer frame sizes. + illustrates the layout of the frame count + byte. + +
+ +
+ +When Opus padding is used, the number of bytes of padding is encoded in the + bytes following the frame count byte. +Values from 0...254 indicate that 0...254 bytes of padding are included, + in addition to the byte(s) used to indicate the size of the padding. +If the value is 255, then the size of the additional padding is 254 bytes, + plus the padding value encoded in the next byte. +There MUST be at least one more byte in the packet in this case [R6,R7]. +The additional padding bytes appear at the end of the packet, and MUST be set + to zero by the encoder to avoid creating a covert channel. +The decoder MUST accept any value for the padding bytes, however. + + +Although this encoding provides multiple ways to indicate a given number of + padding bytes, each uses a different number of bytes to indicate the padding + size, and thus will increase the total packet size by a different amount. +For example, to add 255 bytes to a packet, set the padding bit, p, to 1, insert + a single byte after the frame count byte with a value of 254, and append 254 + padding bytes with the value zero to the end of the packet. +To add 256 bytes to a packet, set the padding bit to 1, insert two bytes after + the frame count byte with the values 255 and 0, respectively, and append 254 + padding bytes with the value zero to the end of the packet. +By using the value 255 multiple times, it is possible to create a packet of any + specific, desired size. +Let P be the number of header bytes used to indicate the padding size plus the + number of padding bytes themselves (i.e., P is the total number of bytes added + to the packet). +Then P MUST be no more than N-2 [R6,R7]. + + +In the CBR case, let R=N-2-P be the number of bytes remaining in the packet + after subtracting the (optional) padding. +Then the compressed length of each frame in bytes is equal to R/M. +The value R MUST be a non-negative integer multiple of M [R6]. +The compressed data for all M frames follows, each of size + R/M bytes, as illustrated in . + + +
+ +
+ + +In the VBR case, the (optional) padding length is followed by M-1 frame + lengths (indicated by "N1" to "N[M-1]" in ), each encoded in a + one- or two-byte sequence as described above. +The packet MUST contain enough data for the M-1 lengths after removing the + (optional) padding, and the sum of these lengths MUST be no larger than the + number of bytes remaining in the packet after decoding them [R7]. +The compressed data for all M frames follows, each frame consisting of the + indicated number of bytes, with the final frame consuming any remaining bytes + before the final padding, as illustrated in . +The number of header bytes (TOC byte, frame count byte, padding length bytes, + and frame length bytes), plus the signaled length of the first M-1 frames themselves, + plus the signaled length of the padding MUST be no larger than N, the total size of the + packet. + + +
+ +
+
+
+ +
+ +Simplest case, one NB mono 20 ms SILK frame: + + +
+ +
+ + +Two FB mono 5 ms CELT frames of the same compressed size: + + +
+ +
+ + +Two FB mono 20 ms Hybrid frames of different compressed size: + + +
+ +
+ + +Four FB stereo 20 ms CELT frames of the same compressed size: + + +
+ +
+
+ +
+ +A receiver MUST NOT process packets which violate any of the rules above as + normal Opus packets. +They are reserved for future applications, such as in-band headers (containing + metadata, etc.). +Packets which violate these constraints may cause implementations of + this specification to treat them as malformed, and + discard them. + + +These constraints are summarized here for reference: + +Packets are at least one byte. +No implicit frame length is larger than 1275 bytes. +Code 1 packets have an odd total length, N, so that (N-1)/2 is an + integer. +Code 2 packets have enough bytes after the TOC for a valid frame + length, and that length is no larger than the number of bytes remaining in the + packet. +Code 3 packets contain at least one frame, but no more than 120 ms + of audio total. +The length of a CBR code 3 packet, N, is at least two bytes, the number of + bytes added to indicate the padding size plus the trailing padding bytes + themselves, P, is no more than N-2, and the frame count, M, satisfies + the constraint that (N-2-P) is a non-negative integer multiple of M. +VBR code 3 packets are large enough to contain all the header bytes (TOC + byte, frame count byte, any padding length bytes, and any frame length bytes), + plus the length of the first M-1 frames, plus any trailing padding bytes. + + +
+ +
+ +
+ +The Opus decoder consists of two main blocks: the SILK decoder and the CELT + decoder. +At any given time, one or both of the SILK and CELT decoders may be active. +The output of the Opus decode is the sum of the outputs from the SILK and CELT + decoders with proper sample rate conversion and delay compensation on the SILK + side, and optional decimation (when decoding to sample rates less than + 48 kHz) on the CELT side, as illustrated in the block diagram below. + +
+ +| Decoder |--->| Rate |----+ +Bit- +---------+ | | | | Conversion | v +stream | Range |---+ +---------+ +------------+ /---\ Audio +------->| Decoder | | + |------> + | |---+ +---------+ +------------+ \---/ + +---------+ | | CELT | | Decimation | ^ + +->| Decoder |--->| (Optional) |----+ + | | | | + +---------+ +------------+ +]]> + +
+ +
+ +Opus uses an entropy coder based on range coding +, +which is itself a rediscovery of the FIFO arithmetic code introduced by . +It is very similar to arithmetic encoding, except that encoding is done with +digits in any base instead of with bits, +so it is faster when using larger bases (i.e., a byte). All of the +calculations in the range coder must use bit-exact integer arithmetic. + + +Symbols may also be coded as "raw bits" packed directly into the bitstream, + bypassing the range coder. +These are packed backwards starting at the end of the frame, as illustrated in + . +This reduces complexity and makes the stream more resilient to bit errors, as + corruption in the raw bits will not desynchronize the decoding process, unlike + corruption in the input to the range decoder. +Raw bits are only used in the CELT layer. + + +
+ : ++ + +: : ++ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +: | <- Boundary occurs at an arbitrary bit position : ++-+-+-+ + +: <- Raw bits data (packed LSB to MSB) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +]]> +
+ + +Each symbol coded by the range coder is drawn from a finite alphabet and coded + in a separate "context", which describes the size of the alphabet and the + relative frequency of each symbol in that alphabet. + + +Suppose there is a context with n symbols, identified with an index that ranges + from 0 to n-1. +The parameters needed to encode or decode symbol k in this context are + represented by a three-tuple (fl[k], fh[k], ft), with + 0 <= fl[k] < fh[k] <= ft <= 65535. +The values of this tuple are derived from the probability model for the + symbol, represented by traditional "frequency counts". +Because Opus uses static contexts these are not updated as symbols are decoded. +Let f[i] be the frequency of symbol i. +Then the three-tuple corresponding to symbol k is given by + +
+ +
+ +The range decoder extracts the symbols and integers encoded using the range + encoder in . +The range decoder maintains an internal state vector composed of the two-tuple + (val, rng), representing the difference between the high end of the + current range and the actual coded value, minus one, and the size of the + current range, respectively. +Both val and rng are 32-bit unsigned integer values. + + +
+ +Let b0 be the first input byte (or zero if there are no bytes in this Opus + frame). +The decoder initializes rng to 128 and initializes val to + (127 - (b0>>1)), where (b0>>1) is the top 7 bits of the + first input byte. +It saves the remaining bit, (b0&1), for use in the renormalization + procedure described in , which the + decoder invokes immediately after initialization to read additional bits and + establish the invariant that rng > 2**23. + +
+ +
+ +Decoding a symbol is a two-step process. +The first step determines a 16-bit unsigned value fs, which lies within the + range of some symbol in the current context. +The second step updates the range decoder state with the three-tuple + (fl[k], fh[k], ft) corresponding to that symbol. + + +The first step is implemented by ec_decode() (entdec.c), which computes +
+ +
+The divisions here are integer division. +
+ +The decoder then identifies the symbol in the current context corresponding to + fs; i.e., the value of k whose three-tuple (fl[k], fh[k], ft) + satisfies fl[k] <= fs < fh[k]. +It uses this tuple to update val according to +
+ +
+If fl[k] is greater than zero, then the decoder updates rng using +
+ +
+Otherwise, it updates rng using +
+ +
+
+ +Using a special case for the first symbol (rather than the last symbol, as is + commonly done in other arithmetic coders) ensures that all the truncation + error from the finite precision arithmetic accumulates in symbol 0. +This makes the cost of coding a 0 slightly smaller, on average, than its + estimated probability indicates and makes the cost of coding any other symbol + slightly larger. +When contexts are designed so that 0 is the most probable symbol, which is + often the case, this strategy minimizes the inefficiency introduced by the + finite precision. +It also makes some of the special-case decoding routines in + particularly simple. + + +After the updates, implemented by ec_dec_update() (entdec.c), the decoder + normalizes the range using the procedure in the next section, and returns the + index k. + + +
+ +To normalize the range, the decoder repeats the following process, implemented + by ec_dec_normalize() (entdec.c), until rng > 2**23. +If rng is already greater than 2**23, the entire process is skipped. +First, it sets rng to (rng<<8). +Then it reads the next byte of the Opus frame and forms an 8-bit value sym, + using the left-over bit buffered from the previous byte as the high bit + and the top 7 bits of the byte just read as the other 7 bits of sym. +The remaining bit in the byte just read is buffered for use in the next + iteration. +If no more input bytes remain, it uses zero bits instead. +See for the initialization used to process + the first byte. +Then, it sets +
+ +
+
+ +It is normal and expected that the range decoder will read several bytes + into the raw bits data (if any) at the end of the packet by the time the frame + is completely decoded, as illustrated in . +This same data MUST also be returned as raw bits when requested. +The encoder is expected to terminate the stream in such a way that the decoder + will decode the intended values regardless of the data contained in the raw + bits. + describes a procedure for doing this. +If the range decoder consumes all of the bytes belonging to the current frame, + it MUST continue to use zero when any further input bytes are required, even + if there is additional data in the current packet from padding or other + frames. + + +
+ | : ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ^ ^ + | End of data buffered by the range coder | +...-----------------------------------------------+ + | + | End of data consumed by raw bits + +-------------------------------------------------------... +]]> +
+
+
+ +
+ +The reference implementation uses three additional decoding methods that are + exactly equivalent to the above, but make assumptions and simplifications that + allow for a more efficient implementation. + +
+ +The first is ec_decode_bin() (entdec.c), defined using the parameter ftb + instead of ft. +It is mathematically equivalent to calling ec_decode() with + ft = (1<<ftb), but avoids one of the divisions. + +
+
+ +The next is ec_dec_bit_logp() (entdec.c), which decodes a single binary symbol, + replacing both the ec_decode() and ec_dec_update() steps. +The context is described by a single parameter, logp, which is the absolute + value of the base-2 logarithm of the probability of a "1". +It is mathematically equivalent to calling ec_decode() with + ft = (1<<logp), followed by ec_dec_update() with + the 3-tuple (fl[k] = 0, + fh[k] = (1<<logp) - 1, + ft = (1<<logp)) if the returned value + of fs is less than (1<<logp) - 1 (a "0" was decoded), and with + (fl[k] = (1<<logp) - 1, + fh[k] = ft = (1<<logp)) otherwise (a "1" was + decoded). +The implementation requires no multiplications or divisions. + +
+
+ +The last is ec_dec_icdf() (entdec.c), which decodes a single symbol with a + table-based context of up to 8 bits, also replacing both the ec_decode() and + ec_dec_update() steps, as well as the search for the decoded symbol in between. +The context is described by two parameters, an icdf + ("inverse" cumulative distribution function) table and ftb. +As with ec_decode_bin(), (1<<ftb) is equivalent to ft. +idcf[k], on the other hand, stores (1<<ftb)-fh[k], which is equal to + (1<<ftb) - fl[k+1]. +fl[0] is assumed to be 0, and the table is terminated by a value of 0 (where + fh[k] == ft). + + +The function is mathematically equivalent to calling ec_decode() with + ft = (1<<ftb), using the returned value fs to search the table + for the first entry where fs < (1<<ftb)-icdf[k], and + calling ec_dec_update() with + fl[k] = (1<<ftb) - icdf[k-1] (or 0 + if k == 0), fh[k] = (1<<ftb) - idcf[k], + and ft = (1<<ftb). +Combining the search with the update allows the division to be replaced by a + series of multiplications (which are usually much cheaper), and using an + inverse CDF allows the use of an ftb as large as 8 in an 8-bit table without + any special cases. +This is the primary interface with the range decoder in the SILK layer, though + it is used in a few places in the CELT layer as well. + + +Although icdf[k] is more convenient for the code, the frequency counts, f[k], + are a more natural representation of the probability distribution function + (PDF) for a given symbol. +Therefore this draft lists the latter, not the former, when describing the + context in which a symbol is coded as a list, e.g., {4, 4, 4, 4}/16 for a + uniform context with four possible values and ft = 16. +The value of ft after the slash is always the sum of the entries in the PDF, + but is included for convenience. +Contexts with identical probabilities, f[k]/ft, but different values of ft + (or equivalently, ftb) are not the same, and cannot, in general, be used in + place of one another. +An icdf table is also not capable of representing a PDF where the first symbol + has 0 probability. +In such contexts, ec_dec_icdf() can decode the symbol by using a table that + drops the entries for any initial zero-probability values and adding the + constant offset of the first value with a non-zero probability to its return + value. + +
+
+ +
+ +The raw bits used by the CELT layer are packed at the end of the packet, with + the least significant bit of the first value packed in the least significant + bit of the last byte, filling up to the most significant bit in the last byte, + continuing on to the least significant bit of the penultimate byte, and so on. +The reference implementation reads them using ec_dec_bits() (entdec.c). +Because the range decoder must read several bytes ahead in the stream, as + described in , the input consumed by the + raw bits may overlap with the input consumed by the range coder, and a decoder + MUST allow this. +The format should render it impossible to attempt to read more raw bits than + there are actual bits in the frame, though a decoder may wish to check for + this and report an error. + +
+ +
+ +The function ec_dec_uint() (entdec.c) decodes one of ft equiprobable values in + the range 0 to (ft - 1), inclusive, each with a frequency of 1, + where ft may be as large as (2**32 - 1). +Because ec_decode() is limited to a total frequency of (2**16 - 1), + it splits up the value into a range coded symbol representing up to 8 of the + high bits, and, if necessary, raw bits representing the remainder of the + value. +The limit of 8 bits in the range coded symbol is a trade-off between + implementation complexity, modeling error (since the symbols no longer truly + have equal coding cost), and rounding error introduced by the range coder + itself (which gets larger as more bits are included). +Using raw bits reduces the maximum number of divisions required in the worst + case, but means that it may be possible to decode a value outside the range + 0 to (ft - 1), inclusive. + + + +ec_dec_uint() takes a single, positive parameter, ft, which is not necessarily + a power of two, and returns an integer, t, whose value lies between 0 and + (ft - 1), inclusive. +Let ftb = ilog(ft - 1), i.e., the number of bits required + to store (ft - 1) in two's complement notation. +If ftb is 8 or less, then t is decoded with t = ec_decode(ft), and + the range coder state is updated using the three-tuple (t, t + 1, + ft). + + +If ftb is greater than 8, then the top 8 bits of t are decoded using +
+> (ftb - 8)) + 1) , +]]> +
+ the decoder state is updated using the three-tuple + (t, t + 1, + ((ft - 1) >> (ftb - 8)) + 1), + and the remaining bits are decoded as raw bits, setting +
+ +
+If, at this point, t >= ft, then the current frame is corrupt. +In that case, the decoder should assume there has been an error in the coding, + decoding, or transmission and SHOULD take measures to conceal the + error and/or report to the application that the error has occurred. +
+ +
+ +
+ +The bit allocation routines in the CELT decoder need a conservative upper bound + on the number of bits that have been used from the current frame thus far, + including both range coder bits and raw bits. +This drives allocation decisions that must match those made in the encoder. +The upper bound is computed in the reference implementation to whole-bit + precision by the function ec_tell() (entcode.h) and to fractional 1/8th bit + precision by the function ec_tell_frac() (entcode.c). +Like all operations in the range coder, it must be implemented in a bit-exact + manner, and must produce exactly the same value returned by the same functions + in the encoder after encoding the same symbols. + + +ec_tell() is guaranteed to return ceil(ec_tell_frac()/8.0). +In various places the codec will check to ensure there is enough room to + contain a symbol before attempting to decode it. +In practice, although the number of bits used so far is an upper bound, + decoding a symbol whose probability model suggests it has a worst-case cost of + p 1/8th bits may actually advance the return value of ec_tell_frac() by + p-1, p, or p+1 1/8th bits, due to approximation error in that upper bound, + truncation error in the range coder, and for large values of ft, modeling + error in ec_dec_uint(). + + +However, this error is bounded, and periodic calls to ec_tell() or + ec_tell_frac() at precisely defined points in the decoding process prevent it + from accumulating. +For a range coder symbol that requires a whole number of bits (i.e., + for which ft/(fh[k] - fl[k]) is a power of two), where there are at + least p 1/8th bits available, decoding the symbol will never cause ec_tell() or + ec_tell_frac() to exceed the size of the frame ("bust the budget"). +In this case the return value of ec_tell_frac() will only advance by more than + p 1/8th bits if there was an additional, fractional number of bits remaining, + and it will never advance beyond the next whole-bit boundary, which is safe, + since frames always contain a whole number of bits. +However, when p is not a whole number of bits, an extra 1/8th bit is required + to ensure that decoding the symbol will not bust the budget. + + +The reference implementation keeps track of the total number of whole bits that + have been processed by the decoder so far in the variable nbits_total, + including the (possibly fractional) number of bits that are currently + buffered, but not consumed, inside the range coder. +nbits_total is initialized to 9 just before the initial range renormalization + process completes (or equivalently, it can be initialized to 33 after the + first renormalization). +The extra two bits over the actual amount buffered by the range coder + guarantees that it is an upper bound and that there is enough room for the + encoder to terminate the stream. +Each iteration through the range coder's renormalization loop increases + nbits_total by 8. +Reading raw bits increases nbits_total by the number of raw bits read. + + +
+ +The whole number of bits buffered in rng may be estimated via lg = ilog(rng). +ec_tell() then becomes a simple matter of removing these bits from the total. +It returns (nbits_total - lg). + + +In a newly initialized decoder, before any symbols have been read, this reports + that 1 bit has been used. +This is the bit reserved for termination of the encoder. + +
+ +
+ +ec_tell_frac() estimates the number of bits buffered in rng to fractional + precision. +Since rng must be greater than 2**23 after renormalization, lg must be at least + 24. +Let +
+ +> (lg-16) , +]]> +
+ so that 32768 <= r_Q15 < 65536, an unsigned Q15 value representing the + fractional part of rng. +Then the following procedure can be used to add one bit of precision to lg. +First, update +
+ +> 15 . +]]> +
+Then add the 16th bit of r_Q15 to lg via +
+ +> 16) . +]]> +
+Finally, if this bit was a 1, reduce r_Q15 by a factor of two via +
+ +> 1 , +]]> +
+ so that it once again lies in the range 32768 <= r_Q15 < 65536. +
+ +This procedure is repeated three times to extend lg to 1/8th bit precision. +ec_tell_frac() then returns (nbits_total*8 - lg). + +
+ +
+ +
+ +
+ +The decoder's LP layer uses a modified version of the SILK codec (herein simply + called "SILK"), which runs a decoded excitation signal through adaptive + long-term and short-term prediction synthesis filters. +It runs at NB, MB, and WB sample rates internally. +When used in a SWB or FB Hybrid frame, the LP layer itself still only runs in + WB. + + +
+ +An overview of the decoder is given in . + +
+ +| Range |--->| Decode |---------------------------+ + 1 | Decoder | 2 | Parameters |----------+ 5 | + +---------+ +------------+ 4 | | + 3 | | | + \/ \/ \/ + +------------+ +------------+ +------------+ + | Generate |-->| LTP |-->| LPC | + | Excitation | | Synthesis | | Synthesis | + +------------+ +------------+ +------------+ + ^ | + | | + +-------------------+----------------+ + | 6 + | +------------+ +-------------+ + +-->| Stereo |-->| Sample Rate |--> + | Unmixing | 7 | Conversion | 8 + +------------+ +-------------+ + +1: Range encoded bitstream +2: Coded parameters +3: Pulses, LSBs, and signs +4: Pitch lags, Long-Term Prediction (LTP) coefficients +5: Linear Predictive Coding (LPC) coefficients and gains +6: Decoded signal (mono or mid-side stereo) +7: Unmixed signal (mono or left-right stereo) +8: Resampled signal +]]> + +
+ + +The decoder feeds the bitstream (1) to the range decoder from + , and then decodes the parameters in it (2) + using the procedures detailed in + Sections  + through . +These parameters (3, 4, 5) are used to generate an excitation signal (see + ), which is fed to an optional + long-term prediction (LTP) filter (voiced frames only, see + ) and then a short-term prediction filter + (see ), producing the decoded signal (6). +For stereo streams, the mid-side representation is converted to separate left + and right channels (7). +The result is finally resampled to the desired output sample rate (e.g., + 48 kHz) so that the resampled signal (8) can be mixed with the CELT + layer. + + +
+ +
+ + +Internally, the LP layer of a single Opus frame is composed of either a single + 10 ms regular SILK frame or between one and three 20 ms regular SILK + frames. +A stereo Opus frame may double the number of regular SILK frames (up to a total + of six), since it includes separate frames for a mid channel and, optionally, + a side channel. +Optional Low Bit-Rate Redundancy (LBRR) frames, which are reduced-bitrate + encodings of previous SILK frames, may be included to aid in recovery from + packet loss. +If present, these appear before the regular SILK frames. +They are in most respects identical to regular, active SILK frames, except that + they are usually encoded with a lower bitrate. +This draft uses "SILK frame" to refer to either one and "regular SILK frame" if + it needs to draw a distinction between the two. + + +Logically, each SILK frame is in turn composed of either two or four 5 ms + subframes. +Various parameters, such as the quantization gain of the excitation and the + pitch lag and filter coefficients can vary on a subframe-by-subframe basis. +Physically, the parameters for each subframe are interleaved in the bitstream, + as described in the relevant sections for each parameter. + + +All of these frames and subframes are decoded from the same range coder, with + no padding between them. +Thus packing multiple SILK frames in a single Opus frame saves, on average, + half a byte per SILK frame. +It also allows some parameters to be predicted from prior SILK frames in the + same Opus frame, since this does not degrade packet loss robustness (beyond + any penalty for merely using fewer, larger packets to store multiple frames). + + + +Stereo support in SILK uses a variant of mid-side coding, allowing a mono + decoder to simply decode the mid channel. +However, the data for the two channels is interleaved, so a mono decoder must + still unpack the data for the side channel. +It would be required to do so anyway for Hybrid Opus frames, or to support + decoding individual 20 ms frames. + + + + summarizes the overall grouping of the contents of + the LP layer. +Figures  + and  illustrate + the ordering of the various SILK frames for a 60 ms Opus frame, for both + mono and stereo, respectively. + + + +Symbol(s) +PDF(s) +Condition + +Voice Activity Detection (VAD) flags +{1, 1}/2 + + +LBRR flag +{1, 1}/2 + + +Per-frame LBRR flags + + + +LBRR Frame(s) + + + +Regular SILK Frame(s) + + + + + +
+ +
+ +
+ +
+ +
+ +
+ +The LP layer begins with two to eight header bits, decoded in silk_Decode() + (dec_API.c). +These consist of one Voice Activity Detection (VAD) bit per frame (up to 3), + followed by a single flag indicating the presence of LBRR frames. +For a stereo packet, these first flags correspond to the mid channel, and a + second set of flags is included for the side channel. + + +Because these are the first symbols decoded by the range coder and because they + are coded as binary values with uniform probability, they can be extracted + directly from the most significant bits of the first byte of compressed data. +Thus, a receiver can determine if an Opus frame contains any active SILK frames + without the overhead of using the range decoder. + +
+ +
+ +For Opus frames longer than 20 ms, a set of LBRR flags is + decoded for each channel that has its LBRR flag set. +Each set contains one flag per 20 ms SILK frame. +40 ms Opus frames use the 2-frame LBRR flag PDF from + , and 60 ms Opus frames use the + 3-frame LBRR flag PDF. +For each channel, the resulting 2- or 3-bit integer contains the corresponding + LBRR flag for each frame, packed in order from the LSB to the MSB. + + + +Frame Size +PDF +40 ms {0, 53, 53, 150}/256 +60 ms {0, 41, 20, 29, 41, 15, 28, 82}/256 + + + +A 10 or 20 ms Opus frame does not contain any per-frame LBRR flags, + as there may be at most one LBRR frame per channel. +The global LBRR flag in the header bits (see ) + is already sufficient to indicate the presence of that single LBRR frame. + + +
+ +
+ +The LBRR frames, if present, contain an encoded representation of the signal + immediately prior to the current Opus frame as if it were encoded with the + current mode, frame size, audio bandwidth, and channel count, even if those + differ from the prior Opus frame. +When one of these parameters changes from one Opus frame to the next, this + implies that the LBRR frames of the current Opus frame may not be simple + drop-in replacements for the contents of the previous Opus frame. + + + +For example, when switching from 20 ms to 60 ms, the 60 ms Opus + frame may contain LBRR frames covering up to three prior 20 ms Opus + frames, even if those frames already contained LBRR frames covering some of + the same time periods. +When switching from 20 ms to 10 ms, the 10 ms Opus frame can + contain an LBRR frame covering at most half the prior 20 ms Opus frame, + potentially leaving a hole that needs to be concealed from even a single + packet loss (see ). +When switching from mono to stereo, the LBRR frames in the first stereo Opus + frame MAY contain a non-trivial side channel. + + + +In order to properly produce LBRR frames under all conditions, an encoder might + need to buffer up to 60 ms of audio and re-encode it during these + transitions. +However, the reference implementation opts to disable LBRR frames at the + transition point for simplicity. +Since transitions are relatively infrequent in normal usage, this does not have + a significant impact on packet loss robustness. + + + +The LBRR frames immediately follow the LBRR flags, prior to any regular SILK + frames. + describes their exact contents. +LBRR frames do not include their own separate VAD flags. +LBRR frames are only meant to be transmitted for active speech, thus all LBRR + frames are treated as active. + + + +In a stereo Opus frame longer than 20 ms, although the per-frame LBRR + flags for the mid channel are coded as a unit before the per-frame LBRR flags + for the side channel, the LBRR frames themselves are interleaved. +The decoder parses an LBRR frame for the mid channel of a given 20 ms + interval (if present) and then immediately parses the corresponding LBRR + frame for the side channel (if present), before proceeding to the next + 20 ms interval. + +
+ +
+ +The regular SILK frame(s) follow the LBRR frames (if any). + describes their contents, as well. +Unlike the LBRR frames, a regular SILK frame is coded for each time interval in + an Opus frame, even if the corresponding VAD flags are unset. +For stereo Opus frames longer than 20 ms, the regular mid and side SILK + frames for each 20 ms interval are interleaved, just as with the LBRR + frames. +The side frame may be skipped by coding an appropriate flag, as detailed in + . + +
+ +
+ +Each SILK frame includes a set of side information that encodes + +The frame type and quantization type (), +Quantization gains (), +Short-term prediction filter coefficients (), +A Line Spectral Frequencies (LSF) interpolation weight (), + +Long-term prediction filter lags and gains (), + and + +A linear congruential generator (LCG) seed (). + +The quantized excitation signal (see ) follows + these at the end of the frame. + details the overall organization of a + SILK frame. + + + +Symbol(s) +PDF(s) +Condition + +Stereo Prediction Weights + + + +Mid-only Flag + + + +Frame Type + + + +Subframe Gains + + + +Normalized LSF Stage-1 Index + + + +Normalized LSF Stage-2 Residual + + + +Normalized LSF Interpolation Weight + +20 ms frame + +Primary Pitch Lag + +Voiced frame + +Subframe Pitch Contour + +Voiced frame + +Periodicity Index + +Voiced frame + +LTP Filter + +Voiced frame + +LTP Scaling + + + +LCG Seed + + + +Excitation Rate Level + + + +Excitation Pulse Counts + + + +Excitation Pulse Locations + +Non-zero pulse count + +Excitation LSBs + + + +Excitation Signs + + + + + +
+ +A SILK frame corresponding to the mid channel of a stereo Opus frame begins + with a pair of side channel prediction weights, designed such that zeros + indicate normal mid-side coupling. +Since these weights can change on every frame, the first portion of each frame + linearly interpolates between the previous weights and the current ones, using + zeros for the previous weights if none are available. +These prediction weights are never included in a mono Opus frame, and the + previous weights are reset to zeros on any transition from mono to stereo. +They are also not included in an LBRR frame for the side channel, even if the + LBRR flags indicate the corresponding mid channel was not coded. +In that case, the previous weights are used, again substituting in zeros if no + previous weights are available since the last decoder reset + (see ). + + + +To summarize, these weights are coded if and only if + +This is a stereo Opus frame (), and +The current SILK frame corresponds to the mid channel. + + + + +The prediction weights are coded in three separate pieces, which are decoded + by silk_stereo_decode_pred() (decode_stereo_pred.c). +The first piece jointly codes the high-order part of a table index for both + weights. +The second piece codes the low-order part of each table index. +The third piece codes an offset used to linearly interpolate between table + indices. +The details are as follows. + + + +Let n be an index decoded with the 25-element stage-1 PDF in + . +Then let i0 and i1 be indices decoded with the stage-2 and stage-3 PDFs in + , respectively, and let i2 and i3 + be two more indices decoded with the stage-2 and stage-3 PDFs, all in that + order. + + + +Stage +PDF +Stage 1 +{7, 2, 1, 1, 1, + 10, 24, 8, 1, 1, + 3, 23, 92, 23, 3, + 1, 1, 8, 24, 10, + 1, 1, 1, 2, 7}/256 + +Stage 2 +{85, 86, 85}/256 + +Stage 3 +{51, 51, 52, 51, 51}/256 + + + +Then use n, i0, and i2 to form two table indices, wi0 and wi1, according to +
+ +
+ where the division is integer division. +The range of these indices is 0 to 14, inclusive. +Let w[i] be the i'th weight from . +Then the two prediction weights, w0_Q13 and w1_Q13, are +
+> 16)*(2*i3 + 1) + +w0_Q13 = w_Q13[wi0] + + ((w_Q13[wi0+1] - w_Q13[wi0])*6554) >> 16)*(2*i1 + 1) + - w1_Q13 +]]> +
+N.b., w1_Q13 is computed first here, because w0_Q13 depends on it. +The constant 6554 is approximately 0.1 in Q16. +Although wi0 and wi1 only have 15 possible values, + contains 16 entries to allow + interpolation between entry wi0 and (wi0 + 1) (and likewise for wi1). +
+ + +Index +Weight (Q13) + 0 -13732 + 1 -10050 + 2 -8266 + 3 -7526 + 4 -6500 + 5 -5000 + 6 -2950 + 7 -820 + 8 820 + 9 2950 +10 5000 +11 6500 +12 7526 +13 8266 +14 10050 +15 13732 + + +
+ +
+ +A flag appears after the stereo prediction weights that indicates if only the + mid channel is coded for this time interval. +It appears only when + +This is a stereo Opus frame (see ), +The current SILK frame corresponds to the mid channel, and +Either + +This is a regular SILK frame where the VAD flags + (see ) indicate that the corresponding side + channel is not active. + +This is an LBRR frame where the LBRR flags + (see and ) + indicate that the corresponding side channel is not coded. + + + + +It is omitted when there are no stereo weights, for all of the same reasons. +It is also omitted for a regular SILK frame when the VAD flag of the + corresponding side channel frame is set (indicating it is active). +The side channel must be coded in this case, making the mid-only flag + redundant. +It is also omitted for an LBRR frame when the corresponding LBRR flags + indicate the side channel is coded. + + + +When the flag is present, the decoder reads a single value using the PDF in + , as implemented in + silk_stereo_decode_mid_only() (decode_stereo_pred.c). +If the flag is set, then there is no corresponding SILK frame for the side + channel, the entire decoding process for the side channel is skipped, and + zeros are fed to the stereo unmixing process (see + ) instead. +As stated above, LBRR frames still include this flag when the LBRR flag + indicates that the side channel is not coded. +In that case, if this flag is zero (indicating that there should be a side + channel), then Packet Loss Concealment (PLC, see + ) SHOULD be invoked to recover a + side channel signal. +Otherwise, the stereo image will collapse. + + + +PDF +{192, 64}/256 + + +
+ +
+ +Each SILK frame contains a single "frame type" symbol that jointly codes the + signal type and quantization offset type of the corresponding frame. +If the current frame is a regular SILK frame whose VAD bit was not set (an + "inactive" frame), then the frame type symbol takes on a value of either 0 or + 1 and is decoded using the first PDF in . +If the frame is an LBRR frame or a regular SILK frame whose VAD flag was set + (an "active" frame), then the value of the symbol may range from 2 to 5, + inclusive, and is decoded using the second PDF in + . + translates between the value of the + frame type symbol and the corresponding signal type and quantization offset + type. + + + +VAD Flag +PDF +Inactive {26, 230, 0, 0, 0, 0}/256 +Active {0, 0, 24, 74, 148, 10}/256 + + + +Frame Type +Signal Type +Quantization Offset Type +0 Inactive Low +1 Inactive High +2 Unvoiced Low +3 Unvoiced High +4 Voiced Low +5 Voiced High + + +
+ +
+ +A separate quantization gain is coded for each 5 ms subframe. +These gains control the step size between quantization levels of the excitation + signal and, therefore, the quality of the reconstruction. +They are independent of and unrelated to the pitch contours coded for voiced + frames. +The quantization gains are themselves uniformly quantized to 6 bits on a + log scale, giving them a resolution of approximately 1.369 dB and a range + of approximately 1.94 dB to 88.21 dB. + + +The subframe gains are either coded independently, or relative to the gain from + the most recent coded subframe in the same channel. +Independent coding is used if and only if + + +This is the first subframe in the current SILK frame, and + +Either + + +This is the first SILK frame of its type (LBRR or regular) for this channel in + the current Opus frame, or + + +The previous SILK frame of the same type (LBRR or regular) for this channel in + the same Opus frame was not coded. + + + + + + + +In an independently coded subframe gain, the 3 most significant bits of the + quantization gain are decoded using a PDF selected from + based on the decoded signal + type (see ). + + + +Signal Type +PDF +Inactive {32, 112, 68, 29, 12, 1, 1, 1}/256 +Unvoiced {2, 17, 45, 60, 62, 47, 19, 4}/256 +Voiced {1, 3, 26, 71, 94, 50, 9, 2}/256 + + + +The 3 least significant bits are decoded using a uniform PDF: + + +PDF +{32, 32, 32, 32, 32, 32, 32, 32}/256 + + + +These 6 bits are combined to form a value, gain_index, between 0 and 63. +When the gain for the previous subframe is available, then the current gain is + limited as follows: +
+ +
+This may help some implementations limit the change in precision of their + internal LTP history. +The indices which this clamp applies to cannot simply be removed from the + codebook, because previous_log_gain will not be available after packet loss. +The clamping is skipped after a decoder reset, and in the side channel if the + previous frame in the side channel was not coded, since there is no value for + previous_log_gain available. +It MAY also be skipped after packet loss. +
+ + +For subframes which do not have an independent gain (including the first + subframe of frames not listed as using independent coding above), the + quantization gain is coded relative to the gain from the previous subframe (in + the same channel). +The PDF in yields a delta_gain_index value + between 0 and 40, inclusive. + + +PDF +{6, 5, 11, 31, 132, 21, 8, 4, + 3, 2, 2, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1}/256 + + +The following formula translates this index into a quantization gain for the + current subframe using the gain from the previous subframe: +
+ +
+
+ +silk_gains_dequant() (gain_quant.c) dequantizes log_gain for the k'th subframe + and converts it into a linear Q16 scale factor via +
+>16) + 2090) +]]> +
+
+ +The function silk_log2lin() (log2lin.c) computes an approximation of + 2**(inLog_Q7/128.0), where inLog_Q7 is its Q7 input. +Let i = inLog_Q7>>7 be the integer part of inLogQ7 and + f = inLog_Q7&127 be the fractional part. +Then +
+>16)+f)*((1<>7) +]]> +
+ yields the approximate exponential. +The final Q16 gain values lies between 81920 and 1686110208, inclusive + (representing scale factors of 1.25 to 25728, respectively). +
+
+ +
+ +A set of normalized Line Spectral Frequency (LSF) coefficients follow the + quantization gains in the bitstream, and represent the Linear Predictive + Coding (LPC) coefficients for the current SILK frame. +Once decoded, the normalized LSFs form an increasing list of Q15 values between + 0 and 1. +These represent the interleaved zeros on the upper half of the unit circle + (between 0 and pi, hence "normalized") in the standard decomposition + of the LPC filter into a symmetric part + and an anti-symmetric part (P and Q in ). +Because of non-linear effects in the decoding process, an implementation SHOULD + match the fixed-point arithmetic described in this section exactly. +An encoder SHOULD also use the same process. + + +The normalized LSFs are coded using a two-stage vector quantizer (VQ) + ( and ). +NB and MB frames use an order-10 predictor, while WB frames use an order-16 + predictor, and thus have different sets of tables. +After reconstructing the normalized LSFs + (), the decoder runs them through a + stabilization process (), interpolates + them between frames (), converts them + back into LPC coefficients (), and then runs + them through further processes to limit the range of the coefficients + () and the gain of the filter + (). +All of this is necessary to ensure the reconstruction process is stable. + + +
+ +The first VQ stage uses a 32-element codebook, coded with one of the PDFs in + , depending on the audio bandwidth and + the signal type of the current SILK frame. +This yields a single index, I1, for the entire frame, which + +Indexes an element in a coarse codebook, +Selects the PDFs for the second stage of the VQ, and +Selects the prediction weights used to remove intra-frame redundancy from + the second stage. + +The actual codebook elements are listed in + and + , but they are not needed until the last + stages of reconstructing the LSF coefficients. + + + +Audio Bandwidth +Signal Type +PDF +NB or MB Inactive or unvoiced + +{44, 34, 30, 19, 21, 12, 11, 3, + 3, 2, 16, 2, 2, 1, 5, 2, + 1, 3, 3, 1, 1, 2, 2, 2, + 3, 1, 9, 9, 2, 7, 2, 1}/256 + +NB or MB Voiced + +{1, 10, 1, 8, 3, 8, 8, 14, +13, 14, 1, 14, 12, 13, 11, 11, +12, 11, 10, 10, 11, 8, 9, 8, + 7, 8, 1, 1, 6, 1, 6, 5}/256 + +WB Inactive or unvoiced + +{31, 21, 3, 17, 1, 8, 17, 4, + 1, 18, 16, 4, 2, 3, 1, 10, + 1, 3, 16, 11, 16, 2, 2, 3, + 2, 11, 1, 4, 9, 8, 7, 3}/256 + +WB Voiced + +{1, 4, 16, 5, 18, 11, 5, 14, +15, 1, 3, 12, 13, 14, 14, 6, +14, 12, 2, 6, 1, 12, 12, 11, +10, 3, 10, 5, 1, 1, 1, 3}/256 + + + +
+ +
+ +A total of 16 PDFs are available for the LSF residual in the second stage: the + 8 (a...h) for NB and MB frames given in + , and the 8 (i...p) for WB frames + given in . +Which PDF is used for which coefficient is driven by the index, I1, + decoded in the first stage. + lists the letter of the + corresponding PDF for each normalized LSF coefficient for NB and MB, and + lists the same information for WB. + + + +Codebook +PDF +a {1, 1, 1, 15, 224, 11, 1, 1, 1}/256 +b {1, 1, 2, 34, 183, 32, 1, 1, 1}/256 +c {1, 1, 4, 42, 149, 55, 2, 1, 1}/256 +d {1, 1, 8, 52, 123, 61, 8, 1, 1}/256 +e {1, 3, 16, 53, 101, 74, 6, 1, 1}/256 +f {1, 3, 17, 55, 90, 73, 15, 1, 1}/256 +g {1, 7, 24, 53, 74, 67, 26, 3, 1}/256 +h {1, 1, 18, 63, 78, 58, 30, 6, 1}/256 + + + +Codebook +PDF +i {1, 1, 1, 9, 232, 9, 1, 1, 1}/256 +j {1, 1, 2, 28, 186, 35, 1, 1, 1}/256 +k {1, 1, 3, 42, 152, 53, 2, 1, 1}/256 +l {1, 1, 10, 49, 126, 65, 2, 1, 1}/256 +m {1, 4, 19, 48, 100, 77, 5, 1, 1}/256 +n {1, 1, 14, 54, 100, 72, 12, 1, 1}/256 +o {1, 1, 15, 61, 87, 61, 25, 4, 1}/256 +p {1, 7, 21, 50, 77, 81, 17, 1, 1}/256 + + + +I1 +Coefficient + +0 1 2 3 4 5 6 7 8 9 + 0 +a a a a a a a a a a + 1 +b d b c c b c b b b + 2 +c b b b b b b b b b + 3 +b c c c c b c b b b + 4 +c d d d d c c c c c + 5 +a f d d c c c c b b + g +a c c c c c c c c b + 7 +c d g e e e f e f f + 8 +c e f f e f e g e e + 9 +c e e h e f e f f e +10 +e d d d c d c c c c +11 +b f f g e f e f f f +12 +c h e g f f f f f f +13 +c h f f f f f g f e +14 +d d f e e f e f e e +15 +c d d f f e e e e e +16 +c e e g e f e f f f +17 +c f e g f f f e f e +18 +c h e f e f e f f f +19 +c f e g h g f g f e +20 +d g h e g f f g e f +21 +c h g e e e f e f f +22 +e f f e g g f g f e +23 +c f f g f g e g e e +24 +e f f f d h e f f e +25 +c d e f f g e f f e +26 +c d c d d e c d d d +27 +b b c c c c c d c c +28 +e f f g g g f g e f +29 +d f f e e e e d d c +30 +c f d h f f e e f e +31 +e e f e f g f g f e + + + +I1 +Coefficient + +0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 + 0 +i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i + 1 +k  l  l  l  l  l  k  k  k  k  k  j  j  j  i  l + 2 +k  n  n  l  p  m  m  n  k  n  m  n  n  m  l  l + 3 +i  k  j  k  k  j  j  j  j  j  i  i  i  i  i  j + 4 +i  o  n  m  o  m  p  n  m  m  m  n  n  m  m  l + 5 +i  l  n  n  m  l  l  n  l  l  l  l  l  l  k  m + 6 +i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i + 7 +i  k  o  l  p  k  n  l  m  n  n  m  l  l  k  l + 8 +i  o  k  o  o  m  n  m  o  n  m  m  n  l  l  l + 9 +k  j  i  i  i  i  i  i  i  i  i  i  i  i  i  i +10 +i  j  i  i  i  i  i  i  i  i  i  i  i  i  i  j +11 +k  k  l  m  n  l  l  l  l  l  l  l  k  k  j  l +12 +k  k  l  l  m  l  l  l  l  l  l  l  l  k  j  l +13 +l  m  m  m  o  m  m  n  l  n  m  m  n  m  l  m +14 +i  o  m  n  m  p  n  k  o  n  p  m  m  l  n  l +15 +i  j  i  j  j  j  j  j  j  j  i  i  i  i  j  i +16 +j  o  n  p  n  m  n  l  m  n  m  m  m  l  l  m +17 +j  l  l  m  m  l  l  n  k  l  l  n  n  n  l  m +18 +k  l  l  k  k  k  l  k  j  k  j  k  j  j  j  m +19 +i  k  l  n  l  l  k  k  k  j  j  i  i  i  i  i +20 +l  m  l  n  l  l  k  k  j  j  j  j  j  k  k  m +21 +k  o  l  p  p  m  n  m  n  l  n  l  l  k  l  l +22 +k  l  n  o  o  l  n  l  m  m  l  l  l  l  k  m +23 +j  l  l  m  m  m  m  l  n  n  n  l  j  j  j  j +24 +k  n  l  o  o  m  p  m  m  n  l  m  m  l  l  l +25 +i  o  j  j  i  i  i  i  i  i  i  i  i  i  i  i +26 +i  o  o  l  n  k  n  n  l  m  m  p  p  m  m  m +27 +l  l  p  l  n  m  l  l  l  k  k  l  l  l  k  l +28 +i  i  j  i  i  i  k  j  k  j  j  k  k  k  j  j +29 +i  l  k  n  l  l  k  l  k  j  i  i  j  i  i  j +30 +l  n  n  m  p  n  l  l  k  l  k  k  j  i  j  i +31 +k  l  n  l  m  l  l  l  k  j  k  o  m  i  i  i + + + +Decoding the second stage residual proceeds as follows. +For each coefficient, the decoder reads a symbol using the PDF corresponding to + I1 from either or + , and subtracts 4 from the result + to give an index in the range -4 to 4, inclusive. +If the index is either -4 or 4, it reads a second symbol using the PDF in + , and adds the value of this second symbol + to the index, using the same sign. +This gives the index, I2[k], a total range of -10 to 10, inclusive. + + + +PDF +{156, 60, 24, 9, 4, 2, 1}/256 + + + +The decoded indices from both stages are translated back into normalized LSF + coefficients in silk_NLSF_decode() (NLSF_decode.c). +The stage-2 indices represent residuals after both the first stage of the VQ + and a separate backwards-prediction step. +The backwards prediction process in the encoder subtracts a prediction from + each residual formed by a multiple of the coefficient that follows it. +The decoder must undo this process. + contains lists of prediction weights + for each coefficient. +There are two lists for NB and MB, and another two lists for WB, giving two + possible prediction weights for each coefficient. + + + +Coefficient +A +B +C +D + 0 179 116 175 68 + 1 138 67 148 62 + 2 140 82 160 66 + 3 148 59 176 60 + 4 151 92 178 72 + 5 149 72 173 117 + 6 153 100 174 85 + 7 151 89 164 90 + 8 163 92 177 118 + 9 174 136 +10 196 151 +11 182 142 +12 198 160 +13 192 142 +14 182 155 + + + +The prediction is undone using the procedure implemented in + silk_NLSF_residual_dequant() (NLSF_decode.c), which is as follows. +Each coefficient selects its prediction weight from one of the two lists based + on the stage-1 index, I1. + gives the selections for each + coefficient for NB and MB, and gives + the selections for WB. +Let d_LPC be the order of the codebook, i.e., 10 for NB and MB, and 16 for WB, + and let pred_Q8[k] be the weight for the k'th coefficient selected by this + process for 0 <= k < d_LPC-1. +Then, the stage-2 residual for each coefficient is computed via +
+>8 : 0) + + ((((I2[k]<<10) - sign(I2[k])*102)*qstep)>>16) , +]]> +
+ where qstep is the Q16 quantization step size, which is 11796 for NB and MB + and 9830 for WB (representing step sizes of approximately 0.18 and 0.15, + respectively). +
+ + +I1 +Coefficient + +0 1 2 3 4 5 6 7 8 + 0 +A B A A A A A A A + 1 +B A A A A A A A A + 2 +A A A A A A A A A + 3 +B B B A A A A B A + 4 +A B A A A A A A A + 5 +A B A A A A A A A + 6 +B A B B A A A B A + 7 +A B B A A B B A A + 8 +A A B B A B A B B + 9 +A A B B A A B B B +10 +A A A A A A A A A +11 +A B A B B B B B A +12 +A B A B B B B B A +13 +A B B B B B B B A +14 +B A B B A B B B B +15 +A B B B B B A B A +16 +A A B B A B A B A +17 +A A B B B A B B B +18 +A B B A A B B B A +19 +A A A B B B A B A +20 +A B B A A B A B A +21 +A B B A A A B B A +22 +A A A A A B B B B +23 +A A B B A A A B B +24 +A A A B A B B B B +25 +A B B B B B B B A +26 +A A A A A A A A A +27 +A A A A A A A A A +28 +A A B A B B A B A +29 +B A A B A A A A A +30 +A A A B B A B A B +31 +B A B B A B B B B + + + +I1 +Coefficient + +0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 + 0 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D + 1 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  C + 2 +C  C  D  C  C  D  D  D  C  D  D  D  D  C  C + 3 +C  C  C  C  C  C  C  C  C  C  C  C  D  C  C + 4 +C  D  D  C  D  C  D  D  C  D  D  D  D  D  C + 5 +C  C  D  C  C  C  C  C  C  C  C  C  C  C  C + 6 +D  C  C  C  C  C  C  C  C  C  C  D  C  D  C + 7 +C  D  D  C  C  C  D  C  D  D  D  C  D  C  D + 8 +C  D  C  D  D  C  D  C  D  C  D  D  D  D  D + 9 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D +10 +C  D  C  C  C  C  C  C  C  C  C  C  C  C  C +11 +C  C  D  C  D  D  D  D  D  D  D  C  D  C  C +12 +C  C  D  C  C  D  C  D  C  D  C  C  D  C  C +13 +C  C  C  C  D  D  C  D  C  D  D  D  D  C  C +14 +C  D  C  C  C  D  D  C  D  D  D  C  D  D  D +15 +C  C  D  D  C  C  C  C  C  C  C  C  D  D  C +16 +C  D  D  C  D  C  D  D  D  D  D  C  D  C  C +17 +C  C  D  C  C  C  C  D  C  C  D  D  D  C  C +18 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D +19 +C  C  C  C  C  C  C  C  C  C  C  C  D  C  C +20 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  C +21 +C  D  C  D  C  D  D  C  D  C  D  C  D  D  C +22 +C  C  D  D  D  D  C  D  D  C  C  D  D  C  C +23 +C  D  D  C  D  C  D  C  D  C  C  C  C  D  C +24 +C  C  C  D  D  C  D  C  D  D  D  D  D  D  D +25 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D +26 +C  D  D  C  C  C  D  D  C  C  D  D  D  D  D +27 +C  C  C  C  C  D  C  D  D  D  D  C  D  D  D +28 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D +29 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D +30 +D  C  C  C  C  C  C  C  C  C  C  D  C  C  C +31 +C  C  D  C  C  D  D  D  C  C  D  C  C  D  C + + +
+ +
+ +Once the stage-1 index I1 and the stage-2 residual res_Q10[] have been decoded, + the final normalized LSF coefficients can be reconstructed. + + +The spectral distortion introduced by the quantization of each LSF coefficient + varies, so the stage-2 residual is weighted accordingly, using the + low-complexity Inverse Harmonic Mean Weighting (IHMW) function proposed in + . +The weights are derived directly from the stage-1 codebook vector. +Let cb1_Q8[k] be the k'th entry of the stage-1 codebook vector from + or + . +Then for 0 <= k < d_LPC the following expression + computes the square of the weight as a Q18 value: +
+ + + +
+ where cb1_Q8[-1] = 0 and cb1_Q8[d_LPC] = 256, and the + division is integer division. +This is reduced to an unsquared, Q9 value using the following square-root + approximation: +
+>(i-8)) & 127 +y = ((i&1) ? 32768 : 46214) >> ((32-i)>>1) +w_Q9[k] = y + ((213*f*y)>>16) +]]> +
+The constant 46214 here is approximately the square root of 2 in Q15. +The cb1_Q8[] vector completely determines these weights, and they may be + tabulated and stored as 13-bit unsigned values (with a range of 1819 to 5227, + inclusive) to avoid computing them when decoding. +The reference implementation already requires code to compute these weights on + unquantized coefficients in the encoder, in silk_NLSF_VQ_weights_laroia() + (NLSF_VQ_weights_laroia.c) and its callers, so it reuses that code in the + decoder instead of using a pre-computed table to reduce the amount of ROM + required. +
+ + +I1 +Codebook (Q8) + + 0   1   2   3   4   5   6   7   8   9 +0 +12  35  60  83 108 132 157 180 206 228 +1 +15  32  55  77 101 125 151 175 201 225 +2 +19  42  66  89 114 137 162 184 209 230 +3 +12  25  50  72  97 120 147 172 200 223 +4 +26  44  69  90 114 135 159 180 205 225 +5 +13  22  53  80 106 130 156 180 205 228 +6 +15  25  44  64  90 115 142 168 196 222 +7 +19  24  62  82 100 120 145 168 190 214 +8 +22  31  50  79 103 120 151 170 203 227 +9 +21  29  45  65 106 124 150 171 196 224 +10 +30  49  75  97 121 142 165 186 209 229 +11 +19  25  52  70  93 116 143 166 192 219 +12 +26  34  62  75  97 118 145 167 194 217 +13 +25  33  56  70  91 113 143 165 196 223 +14 +21  34  51  72  97 117 145 171 196 222 +15 +20  29  50  67  90 117 144 168 197 221 +16 +22  31  48  66  95 117 146 168 196 222 +17 +24  33  51  77 116 134 158 180 200 224 +18 +21  28  70  87 106 124 149 170 194 217 +19 +26  33  53  64  83 117 152 173 204 225 +20 +27  34  65  95 108 129 155 174 210 225 +21 +20  26  72  99 113 131 154 176 200 219 +22 +34  43  61  78  93 114 155 177 205 229 +23 +23  29  54  97 124 138 163 179 209 229 +24 +30  38  56  89 118 129 158 178 200 231 +25 +21  29  49  63  85 111 142 163 193 222 +26 +27  48  77 103 133 158 179 196 215 232 +27 +29  47  74  99 124 151 176 198 220 237 +28 +33  42  61  76  93 121 155 174 207 225 +29 +29  53  87 112 136 154 170 188 208 227 +30 +24  30  52  84 131 150 166 186 203 229 +31 +37  48  64  84 104 118 156 177 201 230 + + + +I1 +Codebook (Q8) + + 0  1  2  3  4   5   6   7   8   9  10  11  12  13  14  15 +0 + 7 23 38 54 69  85 100 116 131 147 162 178 193 208 223 239 +1 +13 25 41 55 69  83  98 112 127 142 157 171 187 203 220 236 +2 +15 21 34 51 61  78  92 106 126 136 152 167 185 205 225 240 +3 +10 21 36 50 63  79  95 110 126 141 157 173 189 205 221 237 +4 +17 20 37 51 59  78  89 107 123 134 150 164 184 205 224 240 +5 +10 15 32 51 67  81  96 112 129 142 158 173 189 204 220 236 +6 + 8 21 37 51 65  79  98 113 126 138 155 168 179 192 209 218 +7 +12 15 34 55 63  78  87 108 118 131 148 167 185 203 219 236 +8 +16 19 32 36 56  79  91 108 118 136 154 171 186 204 220 237 +9 +11 28 43 58 74  89 105 120 135 150 165 180 196 211 226 241 +10 + 6 16 33 46 60  75  92 107 123 137 156 169 185 199 214 225 +11 +11 19 30 44 57  74  89 105 121 135 152 169 186 202 218 234 +12 +12 19 29 46 57  71  88 100 120 132 148 165 182 199 216 233 +13 +17 23 35 46 56  77  92 106 123 134 152 167 185 204 222 237 +14 +14 17 45 53 63  75  89 107 115 132 151 171 188 206 221 240 +15 + 9 16 29 40 56  71  88 103 119 137 154 171 189 205 222 237 +16 +16 19 36 48 57  76  87 105 118 132 150 167 185 202 218 236 +17 +12 17 29 54 71  81  94 104 126 136 149 164 182 201 221 237 +18 +15 28 47 62 79  97 115 129 142 155 168 180 194 208 223 238 +19 + 8 14 30 45 62  78  94 111 127 143 159 175 192 207 223 239 +20 +17 30 49 62 79  92 107 119 132 145 160 174 190 204 220 235 +21 +14 19 36 45 61  76  91 108 121 138 154 172 189 205 222 238 +22 +12 18 31 45 60  76  91 107 123 138 154 171 187 204 221 236 +23 +13 17 31 43 53  70  83 103 114 131 149 167 185 203 220 237 +24 +17 22 35 42 58  78  93 110 125 139 155 170 188 206 224 240 +25 + 8 15 34 50 67  83  99 115 131 146 162 178 193 209 224 239 +26 +13 16 41 66 73  86  95 111 128 137 150 163 183 206 225 241 +27 +17 25 37 52 63  75  92 102 119 132 144 160 175 191 212 231 +28 +19 31 49 65 83 100 117 133 147 161 174 187 200 213 227 242 +29 +18 31 52 68 88 103 117 126 138 149 163 177 192 207 223 239 +30 +16 29 47 61 76  90 106 119 133 147 161 176 193 209 224 240 +31 +15 21 35 50 61  73  86  97 110 119 129 141 175 198 218 237 + + + +Given the stage-1 codebook entry cb1_Q8[], the stage-2 residual res_Q10[], and + their corresponding weights, w_Q9[], the reconstructed normalized LSF + coefficients are +
+ +
+ where the division is integer division. +However, nothing in either the reconstruction process or the + quantization process in the encoder thus far guarantees that the coefficients + are monotonically increasing and separated well enough to ensure a stable + filter . +When using the reference encoder, roughly 2% of frames violate this constraint. +The next section describes a stabilization procedure used to make these + guarantees. +
+ +
+ +
+ +The normalized LSF stabilization procedure is implemented in + silk_NLSF_stabilize() (NLSF_stabilize.c). +This process ensures that consecutive values of the normalized LSF + coefficients, NLSF_Q15[], are spaced some minimum distance apart + (predetermined to be the 0.01 percentile of a large training set). + gives the minimum spacings for NB and MB + and those for WB, where row k is the minimum allowed value of + NLSF_Q[k]-NLSF_Q[k-1]. +For the purposes of computing this spacing for the first and last coefficient, + NLSF_Q15[-1] is taken to be 0, and NLSF_Q15[d_LPC] is taken to be 32768. + + + +Coefficient +NB and MB +WB + 0 250 100 + 1 3 3 + 2 6 40 + 3 3 3 + 4 3 3 + 5 3 3 + 6 4 5 + 7 3 14 + 8 3 14 + 9 3 10 +10 461 11 +11 3 +12 8 +13 9 +14 7 +15 3 +16 347 + + + +The procedure starts off by trying to make small adjustments which attempt to + minimize the amount of distortion introduced. +After 20 such adjustments, it falls back to a more direct method which + guarantees the constraints are enforced but may require large adjustments. + + +Let NDeltaMin_Q15[k] be the minimum required spacing for the current audio + bandwidth from . +First, the procedure finds the index i where + NLSF_Q15[i] - NLSF_Q15[i-1] - NDeltaMin_Q15[i] is the + smallest, breaking ties by using the lower value of i. +If this value is non-negative, then the stabilization stops; the coefficients + satisfy all the constraints. +Otherwise, if i == 0, it sets NLSF_Q15[0] to NDeltaMin_Q15[0], and if + i == d_LPC, it sets NLSF_Q15[d_LPC-1] to + (32768 - NDeltaMin_Q15[d_LPC]). +For all other values of i, both NLSF_Q15[i-1] and NLSF_Q15[i] are updated as + follows: +
+>1) + \ NDeltaMin_Q15[k] + /_ + k=0 + d_LPC + __ + max_center_Q15 = 32768 - (NDeltaMin_Q15[i]>>1) - \ NDeltaMin_Q15[k] + /_ + k=i+1 +center_freq_Q15 = clamp(min_center_Q15[i], + (NLSF_Q15[i-1] + NLSF_Q15[i] + 1)>>1, + max_center_Q15[i]) + + NLSF_Q15[i-1] = center_freq_Q15 - (NDeltaMin_Q15[i]>>1) + + NLSF_Q15[i] = NLSF_Q15[i-1] + NDeltaMin_Q15[i] . +]]> +
+Then the procedure repeats again, until it has either executed 20 times or + has stopped because the coefficients satisfy all the constraints. +
+ +After the 20th repetition of the above procedure, the following fallback + procedure executes once. +First, the values of NLSF_Q15[k] for 0 <= k < d_LPC + are sorted in ascending order. +Then for each value of k from 0 to d_LPC-1, NLSF_Q15[k] is set to +
+ +
+Next, for each value of k from d_LPC-1 down to 0, NLSF_Q15[k] is set to +
+ +
+
+ +
+ +
+ +For 20 ms SILK frames, the first half of the frame (i.e., the first two + subframes) may use normalized LSF coefficients that are interpolated between + the decoded LSFs for the most recent coded frame (in the same channel) and the + current frame. +A Q2 interpolation factor follows the LSF coefficient indices in the bitstream, + which is decoded using the PDF in . +This happens in silk_decode_indices() (decode_indices.c). +After either + +An uncoded regular SILK frame in the side channel, or +A decoder reset (see ), + + the decoder still decodes this factor, but ignores its value and always uses + 4 instead. +For 10 ms SILK frames, this factor is not stored at all. + + + +PDF +{13, 22, 29, 11, 181}/256 + + + +Let n2_Q15[k] be the normalized LSF coefficients decoded by the procedure in + , n0_Q15[k] be the LSF coefficients + decoded for the prior frame, and w_Q2 be the interpolation factor. +Then the normalized LSF coefficients used for the first half of a 20 ms + frame, n1_Q15[k], are +
+> 2) . +]]> +
+This interpolation is performed in silk_decode_parameters() + (decode_parameters.c). +
+
+ +
+ +Any LPC filter A(z) can be split into a symmetric part P(z) and an + anti-symmetric part Q(z) such that +
+ +
+with +
+ +
+The even normalized LSF coefficients correspond to a pair of conjugate roots of + P(z), while the odd coefficients correspond to a pair of conjugate roots of + Q(z), all of which lie on the unit circle. +In addition, P(z) has a root at pi and Q(z) has a root at 0. +Thus, they may be reconstructed mathematically from a set of normalized LSF + coefficients, n[k], as +
+ +
+
+ +However, SILK performs this reconstruction using a fixed-point approximation so + that all decoders can reproduce it in a bit-exact manner to avoid prediction + drift. +The function silk_NLSF2A() (NLSF2A.c) implements this procedure. + + +To start, it approximates cos(pi*n[k]) using a table lookup with linear + interpolation. +The encoder SHOULD use the inverse of this piecewise linear approximation, + rather than the true inverse of the cosine function, when deriving the + normalized LSF coefficients. +These values are also re-ordered to improve numerical accuracy when + constructing the LPC polynomials. + + + +Coefficient +NB and MB +WB + 0 0 0 + 1 9 15 + 2 6 8 + 3 3 7 + 4 4 4 + 5 5 11 + 6 8 12 + 7 1 3 + 8 2 2 + 9 7 13 +10 10 +11 5 +12 6 +13 9 +14 14 +15 1 + + + +The top 7 bits of each normalized LSF coefficient index a value in the table, + and the next 8 bits interpolate between it and the next value. +Let i = (n[k] >> 8) be the integer index and + f = (n[k] & 255) be the fractional part of a given + coefficient. +Then the re-ordered, approximated cosine, c_Q17[ordering[k]], is +
+> 3 , +]]> +
+ where ordering[k] is the k'th entry of the column of + corresponding to the current audio + bandwidth and cos_Q12[i] is the i'th entry of . +
+ + +i ++0 ++1 ++2 ++3 +0 + 4096 4095 4091 4085 +4 + 4076 4065 4052 4036 +8 + 4017 3997 3973 3948 +12 + 3920 3889 3857 3822 +16 + 3784 3745 3703 3659 +20 + 3613 3564 3513 3461 +24 + 3406 3349 3290 3229 +28 + 3166 3102 3035 2967 +32 + 2896 2824 2751 2676 +36 + 2599 2520 2440 2359 +40 + 2276 2191 2106 2019 +44 + 1931 1842 1751 1660 +48 + 1568 1474 1380 1285 +52 + 1189 1093 995 897 +56 + 799 700 601 501 +60 + 401 301 201 101 +64 + 0 -101 -201 -301 +68 + -401 -501 -601 -700 +72 + -799 -897 -995 -1093 +76 +-1189-1285-1380-1474 +80 +-1568-1660-1751-1842 +84 +-1931-2019-2106-2191 +88 +-2276-2359-2440-2520 +92 +-2599-2676-2751-2824 +96 +-2896-2967-3035-3102 +100 +-3166-3229-3290-3349 +104 +-3406-3461-3513-3564 +108 +-3613-3659-3703-3745 +112 +-3784-3822-3857-3889 +116 +-3920-3948-3973-3997 +120 +-4017-4036-4052-4065 +124 +-4076-4085-4091-4095 +128 +-4096 + + + +Given the list of cosine values, silk_NLSF2A_find_poly() (NLSF2A.c) + computes the coefficients of P and Q, described here via a simple recurrence. +Let p_Q16[k][j] and q_Q16[k][j] be the coefficients of the products of the + first (k+1) root pairs for P and Q, with j indexing the coefficient number. +Only the first (k+2) coefficients are needed, as the products are symmetric. +Let p_Q16[0][0] = q_Q16[0][0] = 1<<16, + p_Q16[0][1] = -c_Q17[0], q_Q16[0][1] = -c_Q17[1], and + d2 = d_LPC/2. +As boundary conditions, assume + p_Q16[k][j] = q_Q16[k][j] = 0 for all + j < 0. +Also, assume p_Q16[k][k+2] = p_Q16[k][k] and + q_Q16[k][k+2] = q_Q16[k][k] (because of the symmetry). +Then, for 0 < k < d2 and 0 <= j <= k+1, +
+>16) , + +q_Q16[k][j] = q_Q16[k-1][j] + q_Q16[k-1][j-2] + - ((c_Q17[2*k+1]*q_Q16[k-1][j-1] + 32768)>>16) . +]]> +
+The use of Q17 values for the cosine terms in an otherwise Q16 expression + implicitly scales them by a factor of 2. +The multiplications in this recurrence may require up to 48 bits of precision + in the result to avoid overflow. +In practice, each row of the recurrence only depends on the previous row, so an + implementation does not need to store all of them. +
+ +silk_NLSF2A() uses the values from the last row of this recurrence to + reconstruct a 32-bit version of the LPC filter (without the leading 1.0 + coefficient), a32_Q17[k], 0 <= k < d2: +
+ +
+The sum and difference of two terms from each of the p_Q16 and q_Q16 + coefficient lists reflect the (1 + z**-1) and + (1 - z**-1) factors of P and Q, respectively. +The promotion of the expression from Q16 to Q17 implicitly scales the result + by 1/2. +
+
+ +
+ +The a32_Q17[] coefficients are too large to fit in a 16-bit value, which + significantly increases the cost of applying this filter in fixed-point + decoders. +Reducing them to Q12 precision doesn't incur any significant quality loss, + but still does not guarantee they will fit. +silk_NLSF2A() applies up to 10 rounds of bandwidth expansion to limit + the dynamic range of these coefficients. +Even floating-point decoders SHOULD perform these steps, to avoid mismatch. + + +For each round, the process first finds the index k such that abs(a32_Q17[k]) + is largest, breaking ties by choosing the lowest value of k. +Then, it computes the corresponding Q12 precision value, maxabs_Q12, subject to + an upper bound to avoid overflow in subsequent computations: +
+> 5, 163838) . +]]> +
+If this is larger than 32767, the procedure derives the chirp factor, + sc_Q16[0], to use in the bandwidth expansion as +
+> 2 +]]> +
+ where the division here is integer division. +This is an approximation of the chirp factor needed to reduce the target + coefficient to 32767, though it is both less than 0.999 and, for + k > 0 when maxabs_Q12 is much greater than 32767, still slightly + too large. +The upper bound on maxabs_Q12, 163838, was chosen because it is equal to + ((2**31 - 1) >> 14) + 32767, i.e., the + largest value of maxabs_Q12 that would not overflow the numerator in the + equation above when stored in a signed 32-bit integer. +
+ +silk_bwexpander_32() (bwexpander_32.c) performs the bandwidth expansion (again, + only when maxabs_Q12 is greater than 32767) using the following recurrence: +
+> 16 + +sc_Q16[k+1] = (sc_Q16[0]*sc_Q16[k] + 32768) >> 16 +]]> +
+The first multiply may require up to 48 bits of precision in the result to + avoid overflow. +The second multiply must be unsigned to avoid overflow with only 32 bits of + precision. +The reference implementation uses a slightly more complex formulation that + avoids the 32-bit overflow using signed multiplication, but is otherwise + equivalent. +
+ +After 10 rounds of bandwidth expansion are performed, they are simply saturated + to 16 bits: +
+> 5, 32767) << 5 . +]]> +
+Because this performs the actual saturation in the Q12 domain, but converts the + coefficients back to the Q17 domain for the purposes of prediction gain + limiting, this step must be performed after the 10th round of bandwidth + expansion, regardless of whether or not the Q12 version of any coefficient + still overflows a 16-bit integer. +This saturation is not performed if maxabs_Q12 drops to 32767 or less prior to + the 10th round. +
+
+ +
+ +The prediction gain of an LPC synthesis filter is the square-root of the output + energy when the filter is excited by a unit-energy impulse. +Even if the Q12 coefficients would fit, the resulting filter may still have a + significant gain (especially for voiced sounds), making the filter unstable. +silk_NLSF2A() applies up to 18 additional rounds of bandwidth expansion to + limit the prediction gain. +Instead of controlling the amount of bandwidth expansion using the prediction + gain itself (which may diverge to infinity for an unstable filter), + silk_NLSF2A() uses silk_LPC_inverse_pred_gain_QA() (LPC_inv_pred_gain.c) to + compute the reflection coefficients associated with the filter. +The filter is stable if and only if the magnitude of these coefficients is + sufficiently less than one. +The reflection coefficients, rc[k], can be computed using a simple Levinson + recurrence, initialized with the LPC coefficients + a[d_LPC-1][n] = a[n], and then updated via +
+ +
+
+ +However, silk_LPC_inverse_pred_gain_QA() approximates this using fixed-point + arithmetic to guarantee reproducible results across platforms and + implementations. +Since small changes in the coefficients can make a stable filter unstable, it + takes the real Q12 coefficients that will be used during reconstruction as + input. +Thus, let +
+> 5 +]]> +
+ be the Q12 version of the LPC coefficients that will eventually be used. +As a simple initial check, the decoder computes the DC response as +
+ +
+ and if DC_resp > 4096, the filter is unstable. +
+ +Increasing the precision of these Q12 coefficients to Q24 for intermediate + computations allows more accurate computation of the reflection coefficients, + so the decoder initializes the recurrence via +
+ +
+Then for each k from d_LPC-1 down to 0, if + abs(a32_Q24[k][k]) > 16773022, the filter is unstable and the + recurrence stops. +The constant 16773022 here is approximately 0.99975 in Q24. +Otherwise, row k-1 of a32_Q24 is computed from row k as +
+> 32) , + + b1[k] = ilog(div_Q30[k]) , + + b2[k] = b1[k] - 16 , + + (1<<29) - 1 + inv_Qb2[k] = ----------------------- , + div_Q30[k] >> (b2[k]+1) + + err_Q29[k] = (1<<29) + - ((div_Q30[k]<<(15-b2[k]))*inv_Qb2[k] >> 16) , + + gain_Qb1[k] = ((inv_Qb2[k] << 16) + + (err_Q29[k]*inv_Qb2[k] >> 13)) , + +num_Q24[k-1][n] = a32_Q24[k][n] + - ((a32_Q24[k][k-n-1]*rc_Q31[k] + (1<<30)) >> 31) , + +a32_Q24[k-1][n] = (num_Q24[k-1][n]*gain_Qb1[k] + + (1<<(b1[k]-1))) >> b1[k] , +]]> +
+ where 0 <= n < k. +Here, rc_Q30[k] are the reflection coefficients. +div_Q30[k] is the denominator for each iteration, and gain_Qb1[k] is its + multiplicative inverse (with b1[k] fractional bits, where b1[k] ranges from + 20 to 31). +inv_Qb2[k], which ranges from 16384 to 32767, is a low-precision version of + that inverse (with b2[k] fractional bits). +err_Q29[k] is the residual error, ranging from -32763 to 32392, which is used + to improve the accuracy. +The values t_Q24[k-1][n] for each n are the numerators for the next row of + coefficients in the recursion, and a32_Q24[k-1][n] is the final version of + that row. +Every multiply in this procedure except the one used to compute gain_Qb1[k] + requires more than 32 bits of precision, but otherwise all intermediate + results fit in 32 bits or less. +In practice, because each row only depends on the next one, an implementation + does not need to store them all. +
+ +If abs(a32_Q24[k][k]) <= 16773022 for + 0 <= k < d_LPC, then the filter is considered stable. +However, the problem of determining stability is ill-conditioned when the + filter contains several reflection coefficients whose magnitude is very close + to one. +This fixed-point algorithm is not mathematically guaranteed to correctly + classify filters as stable or unstable in this case, though it does very well + in practice. + + +On round i, 1 <= i <= 18, if the filter passes these + stability checks, then this procedure stops, and the final LPC coefficients to + use for reconstruction in are +
+> 5 . +]]> +
+Otherwise, a round of bandwidth expansion is applied using the same procedure + as in , with +
+ +
+During the 15th round, sc_Q16[0] becomes 0 in the above equation, so a_Q12[k] + is set to 0 for all k, guaranteeing a stable filter. +
+
+ +
+ +
+ +After the normalized LSF indices and, for 20 ms frames, the LSF + interpolation index, voiced frames (see ) + include additional LTP parameters. +There is one primary lag index for each SILK frame, but this is refined to + produce a separate lag index per subframe using a vector quantizer. +Each subframe also gets its own prediction gain coefficient. + + +
+ +The primary lag index is coded either relative to the primary lag of the prior + frame in the same channel, or as an absolute index. +Absolute coding is used if and only if + + +This is the first SILK frame of its type (LBRR or regular) for this channel in + the current Opus frame, + + +The previous SILK frame of the same type (LBRR or regular) for this channel in + the same Opus frame was not coded, or + + +That previous SILK frame was coded, but was not voiced (see + ). + + + + + +With absolute coding, the primary pitch lag may range from 2 ms + (inclusive) up to 18 ms (exclusive), corresponding to pitches from + 500 Hz down to 55.6 Hz, respectively. +It is comprised of a high part and a low part, where the decoder reads the high + part using the 32-entry codebook in + and the low part using the codebook corresponding to the current audio + bandwidth from . +The final primary pitch lag is then +
+ +
+ where lag_high is the high part, lag_low is the low part, and lag_scale + and lag_min are the values from the "Scale" and "Minimum Lag" columns of + , respectively. +
+ + +PDF +{3, 3, 6, 11, 21, 30, 32, 19, + 11, 10, 12, 13, 13, 12, 11, 9, + 8, 7, 6, 4, 2, 2, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 1}/256 + + + +Audio Bandwidth +PDF +Scale +Minimum Lag +Maximum Lag +NB {64, 64, 64, 64}/256 4 16 144 +MB {43, 42, 43, 43, 42, 43}/256 6 24 216 +WB {32, 32, 32, 32, 32, 32, 32, 32}/256 8 32 288 + + + +All frames that do not use absolute coding for the primary lag index use + relative coding instead. +The decoder reads a single delta value using the 21-entry PDF in + . +If the resulting value is zero, it falls back to the absolute coding procedure + from the prior paragraph. +Otherwise, the final primary pitch lag is then +
+ +
+ where previous_lag is the primary pitch lag from the most recent frame in the + same channel and delta_lag_index is the value just decoded. +This allows a per-frame change in the pitch lag of -8 to +11 samples. +The decoder does no clamping at this point, so this value can fall outside the + range of 2 ms to 18 ms, and the decoder must use this unclamped + value when using relative coding in the next SILK frame (if any). +However, because an Opus frame can use relative coding for at most two + consecutive SILK frames, integer overflow should not be an issue. +
+ + +PDF +{46, 2, 2, 3, 4, 6, 10, 15, + 26, 38, 30, 22, 15, 10, 7, 6, + 4, 4, 2, 2, 2}/256 + + + +After the primary pitch lag, a "pitch contour", stored as a single entry from + one of four small VQ codebooks, gives lag offsets for each subframe in the + current SILK frame. +The codebook index is decoded using one of the PDFs in + depending on the current frame size + and audio bandwidth. +Tables  + through  + give the corresponding offsets to apply to the primary pitch lag for each + subframe given the decoded codebook index. + + + +Audio Bandwidth +SILK Frame Size +Codebook Size +PDF +NB 10 ms 3 +{143, 50, 63}/256 +NB 20 ms 11 +{68, 12, 21, 17, 19, 22, 30, 24, + 17, 16, 10}/256 +MB or WB 10 ms 12 +{91, 46, 39, 19, 14, 12, 8, 7, + 6, 5, 5, 4}/256 +MB or WB 20 ms 34 +{33, 22, 18, 16, 15, 14, 14, 13, + 13, 10, 9, 9, 8, 6, 6, 6, + 5, 4, 4, 4, 3, 3, 3, 2, + 2, 2, 2, 2, 2, 2, 1, 1, + 1, 1}/256 + + + +Index +Subframe Offsets +0  0  0 +1  1  0 +2  0  1 + + + +Index +Subframe Offsets + 0  0  0  0  0 + 1  2  1  0 -1 + 2 -1  0  1  2 + 3 -1  0  0  1 + 4 -1  0  0  0 + 5  0  0  0  1 + 6  0  0  1  1 + 7  1  1  0  0 + 8  1  0  0  0 + 9  0  0  0 -1 +10  1  0  0 -1 + + + +Index +Subframe Offsets + 0  0  0 + 1  0  1 + 2  1  0 + 3 -1  1 + 4  1 -1 + 5 -1  2 + 6  2 -1 + 7 -2  2 + 8  2 -2 + 9 -2  3 +10  3 -2 +11 -3  3 + + + +Index +Subframe Offsets + 0  0  0  0  0 + 1  0  0  1  1 + 2  1  1  0  0 + 3 -1  0  0  0 + 4  0  0  0  1 + 5  1  0  0  0 + 6 -1  0  0  1 + 7  0  0  0 -1 + 8 -1  0  1  2 + 9  1  0  0 -1 +10 -2 -1  1  2 +11  2  1  0 -1 +12 -2  0  0  2 +13 -2  0  1  3 +14  2  1 -1 -2 +15 -3 -1  1  3 +16  2  0  0 -2 +17  3  1  0 -2 +18 -3 -1  2  4 +19 -4 -1  1  4 +20  3  1 -1 -3 +21 -4 -1  2  5 +22  4  2 -1 -3 +23  4  1 -1 -4 +24 -5 -1  2  6 +25  5  2 -1 -4 +26 -6 -2  2  6 +27 -5 -2  2  5 +28  6  2 -1 -5 +29 -7 -2  3  8 +30  6  2 -2 -6 +31  5  2 -2 -5 +32  8  3 -2 -7 +33 -9 -3  3  9 + + + +The final pitch lag for each subframe is assembled in silk_decode_pitch() + (decode_pitch.c). +Let lag be the primary pitch lag for the current SILK frame, contour_index be + index of the VQ codebook, and lag_cb[contour_index][k] be the corresponding + entry of the codebook from the appropriate table given above for the k'th + subframe. +Then the final pitch lag for that subframe is +
+ +
+ where lag_min and lag_max are the values from the "Minimum Lag" and + "Maximum Lag" columns of , + respectively. +
+ +
+ +
+ +SILK uses a separate 5-tap pitch filter for each subframe, selected from one + of three codebooks. +The three codebooks each represent different rate-distortion trade-offs, with + average rates of 1.61 bits/subframe, 3.68 bits/subframe, and + 4.85 bits/subframe, respectively. + + + +The importance of the filter coefficients generally depends on two factors: the + periodicity of the signal and relative energy between the current subframe and + the signal from one period earlier. +Greater periodicity and decaying energy both lead to more important filter + coefficients, and thus should be coded with lower distortion and higher rate. +These properties are relatively stable over the duration of a single SILK + frame, hence all of the subframes in a SILK frame choose their filter from the + same codebook. +This is signaled with an explicitly-coded "periodicity index". +This immediately follows the subframe pitch lags, and is coded using the + 3-entry PDF from . + + + +PDF +{77, 80, 99}/256 + + + +The indices of the filters for each subframe follow. +They are all coded using the PDF from + corresponding to the periodicity index. +Tables  + through  + contain the corresponding filter taps as signed Q7 integers. + + + +Periodicity Index +Codebook Size +PDF +0 8 {185, 15, 13, 13, 9, 9, 6, 6}/256 +1 16 {57, 34, 21, 20, 15, 13, 12, 13, + 10, 10, 9, 10, 9, 8, 7, 8}/256 +2 32 {15, 16, 14, 12, 12, 12, 11, 11, + 11, 10, 9, 9, 9, 9, 8, 8, + 8, 8, 7, 7, 6, 6, 5, 4, + 5, 4, 4, 4, 3, 4, 3, 2}/256 + + + +Index +Filter Taps (Q7) + 0 +  4   6  24   7   5 + 1 +  0   0   2   0   0 + 2 + 12  28  41  13  -4 + 3 + -9  15  42  25  14 + 4 +  1  -2  62  41  -9 + 5 +-10  37  65  -4   3 + 6 + -6   4  66   7  -8 + 7 + 16  14  38  -3  33 + + + +Index +Filter Taps (Q7) + + 0 + 13  22  39  23  12 + 1 + -1  36  64  27  -6 + 2 + -7  10  55  43  17 + 3 +  1   1   8   1   1 + 4 +  6 -11  74  53  -9 + 5 +-12  55  76 -12   8 + 6 + -3   3  93  27  -4 + 7 + 26  39  59   3  -8 + 8 +  2   0  77  11   9 + 9 + -8  22  44  -6   7 +10 + 40   9  26   3   9 +11 + -7  20 101  -7   4 +12 +  3  -8  42  26   0 +13 +-15  33  68   2  23 +14 + -2  55  46  -2  15 +15 +  3  -1  21  16  41 + + + +Index +Filter Taps (Q7) + 0 + -6  27  61  39   5 + 1 +-11  42  88   4   1 + 2 + -2  60  65   6  -4 + 3 + -1  -5  73  56   1 + 4 + -9  19  94  29  -9 + 5 +  0  12  99   6   4 + 6 +  8 -19 102  46 -13 + 7 +  3   2  13   3   2 + 8 +  9 -21  84  72 -18 + 9 +-11  46 104 -22   8 +10 + 18  38  48  23   0 +11 +-16  70  83 -21  11 +12 +  5 -11 117  22  -8 +13 + -6  23 117 -12   3 +14 +  3  -8  95  28   4 +15 +-10  15  77  60 -15 +16 + -1   4 124   2  -4 +17 +  3  38  84  24 -25 +18 +  2  13  42  13  31 +19 + 21  -4  56  46  -1 +20 + -1  35  79 -13  19 +21 + -7  65  88  -9 -14 +22 + 20   4  81  49 -29 +23 + 20   0  75   3 -17 +24 +  5  -9  44  92  -8 +25 +  1  -3  22  69  31 +26 + -6  95  41 -12   5 +27 + 39  67  16  -4   1 +28 +  0  -6 120  55 -36 +29 +-13  44 122   4 -24 +30 + 81   5  11   3   7 +31 +  2   0   9  10  88 + + +
+ +
+ +An LTP scaling parameter appears after the LTP filter coefficients if and only + if + +This is a voiced frame (see ), and +Either + + +This SILK frame corresponds to the first time interval of the + current Opus frame for its type (LBRR or regular), or + + +This is an LBRR frame where the LBRR flags (see + ) indicate the previous LBRR frame in the same + channel is not coded. + + + + +This allows the encoder to trade off the prediction gain between + packets against the recovery time after packet loss. +Unlike absolute-coding for pitch lags, regular SILK frames that are not at the + start of an Opus frame (i.e., that do not correspond to the first 20 ms + time interval in Opus frames of 40 or 60 ms) do not include this + field, even if the prior frame was not voiced, or (in the case of the side + channel) not even coded. +After an uncoded frame in the side channel, the LTP buffer (see + ) is cleared to zero, and is thus in a + known state. +In contrast, LBRR frames do include this field when the prior frame was not + coded, since the LTP buffer contains the output of the PLC, which is + non-normative. + + +If present, the decoder reads a value using the 3-entry PDF in + . +The three possible values represent Q14 scale factors of 15565, 12288, and + 8192, respectively (corresponding to approximately 0.95, 0.75, and 0.5). +Frames that do not code the scaling parameter use the default factor of 15565 + (approximately 0.95). + + + +PDF +{128, 64, 64}/256 + + +
+ +
+ +
+ +As described in , SILK uses a + linear congruential generator (LCG) to inject pseudorandom noise into the + quantized excitation. +To ensure synchronization of this process between the encoder and decoder, each + SILK frame stores a 2-bit seed after the LTP parameters (if any). +The encoder may consider the choice of seed during quantization, and the + flexibility of this choice lets it reduce distortion, helping to pay for the + bit cost required to signal it. +The decoder reads the seed using the uniform 4-entry PDF in + , yielding a value between 0 and 3, inclusive. + + + +PDF +{64, 64, 64, 64}/256 + + +
+ +
+ +SILK codes the excitation using a modified version of the Pyramid Vector + Quantization (PVQ) codebook . +The PVQ codebook is designed for Laplace-distributed values and consists of all + sums of K signed, unit pulses in a vector of dimension N, where two pulses at + the same position are required to have the same sign. +Thus the codebook includes all integer codevectors y of dimension N that + satisfy +
+ +
+Unlike regular PVQ, SILK uses a variable-length, rather than fixed-length, + encoding. +This encoding is better suited to the more Gaussian-like distribution of the + coefficient magnitudes and the non-uniform distribution of their signs (caused + by the quantization offset described below). +SILK also handles large codebooks by coding the least significant bits (LSBs) + of each coefficient directly. +This adds a small coding efficiency loss, but greatly reduces the computation + time and ROM size required for decoding, as implemented in + silk_decode_pulses() (decode_pulses.c). +
+ + +SILK fixes the dimension of the codebook to N = 16. +The excitation is made up of a number of "shell blocks", each 16 samples in + size. + lists the number of shell blocks + required for a SILK frame for each possible audio bandwidth and frame size. +10 ms MB frames nominally contain 120 samples (10 ms at + 12 kHz), which is not a multiple of 16. +This is handled by coding 8 shell blocks (128 samples) and discarding the final + 8 samples of the last block. +The decoder contains no special case that prevents an encoder from placing + pulses in these samples, and they must be correctly parsed from the bitstream + if present, but they are otherwise ignored. + + + +Audio Bandwidth +Frame Size +Number of Shell Blocks +NB 10 ms 5 +MB 10 ms 8 +WB 10 ms 10 +NB 20 ms 10 +MB 20 ms 15 +WB 20 ms 20 + + +
+ +The first symbol in the excitation is a "rate level", which is an index from 0 + to 8, inclusive, coded using the PDF in + corresponding to the signal type of the current frame (from + ). +The rate level selects the PDF used to decode the number of pulses in + the individual shell blocks. +It does not directly convey any information about the bitrate or the number of + pulses itself, but merely changes the probability of the symbols in + . +Level 0 provides a more efficient encoding at low rates generally, and + level 8 provides a more efficient encoding at high rates generally, + though the most efficient level for a particular SILK frame may depend on the + exact distribution of the coded symbols. +An encoder should, but is not required to, use the most efficient rate level. + + + +Signal Type +PDF +Inactive or Unvoiced +{15, 51, 12, 46, 45, 13, 33, 27, 14}/256 +Voiced +{33, 30, 36, 17, 34, 49, 18, 21, 18}/256 + + +
+ +
+ +The total number of pulses in each of the shell blocks follows the rate level. +The pulse counts for all of the shell blocks are coded consecutively, before + the content of any of the blocks. +Each block may have anywhere from 0 to 16 pulses, inclusive, coded using the + 18-entry PDF in corresponding to the + rate level from . +The special value 17 indicates that this block has one or more additional + LSBs to decode for each coefficient. +If the decoder encounters this value, it decodes another value for the actual + pulse count of the block, but uses the PDF corresponding to the special rate + level 9 instead of the normal rate level. +This process repeats until the decoder reads a value less than 17, and it then + sets the number of extra LSBs used to the number of 17's decoded for that + block. +If it reads the value 17 ten times, then the next iteration uses the special + rate level 10 instead of 9. +The probability of decoding a 17 when using the PDF for rate level 10 is + zero, ensuring that the number of LSBs for a block will not exceed 10. +The cumulative distribution for rate level 10 is just a shifted version of + that for 9 and thus does not require any additional storage. + + + +Rate Level +PDF +0 +{131, 74, 25, 8, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}/256 +1 +{58, 93, 60, 23, 7, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}/256 +2 +{43, 51, 46, 33, 24, 16, 11, 8, 6, 3, 3, 3, 2, 1, 1, 2, 1, 2}/256 +3 +{17, 52, 71, 57, 31, 12, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}/256 +4 +{6, 21, 41, 53, 49, 35, 21, 11, 6, 3, 2, 2, 1, 1, 1, 1, 1, 1}/256 +5 +{7, 14, 22, 28, 29, 28, 25, 20, 17, 13, 11, 9, 7, 5, 4, 4, 3, 10}/256 +6 +{2, 5, 14, 29, 42, 46, 41, 31, 19, 11, 6, 3, 2, 1, 1, 1, 1, 1}/256 +7 +{1, 2, 4, 10, 19, 29, 35, 37, 34, 28, 20, 14, 8, 5, 4, 2, 2, 2}/256 +8 +{1, 2, 2, 5, 9, 14, 20, 24, 27, 28, 26, 23, 20, 15, 11, 8, 6, 15}/256 +9 +{1, 1, 1, 6, 27, 58, 56, 39, 25, 14, 10, 6, 3, 3, 2, 1, 1, 2}/256 +10 +{2, 1, 6, 27, 58, 56, 39, 25, 14, 10, 6, 3, 3, 2, 1, 1, 2, 0}/256 + + +
+ +
+ +The locations of the pulses in each shell block follow the pulse counts, + as decoded by silk_shell_decoder() (shell_coder.c). +As with the pulse counts, these locations are coded for all the shell blocks + before any of the remaining information for each block. +Unlike many other codecs, SILK places no restriction on the distribution of + pulses within a shell block. +All of the pulses may be placed in a single location, or each one in a unique + location, or anything in between. + + + +The location of pulses is coded by recursively partitioning each block into + halves, and coding how many pulses fall on the left side of the split. +All remaining pulses must fall on the right side of the split. +The process then recurses into the left half, and after that returns, the + right half (preorder traversal). +The PDF to use is chosen by the size of the current partition (16, 8, 4, or 2) + and the number of pulses in the partition (1 to 16, inclusive). +Tables  + through  list the + PDFs used for each partition size and pulse count. +This process skips partitions without any pulses, i.e., where the initial pulse + count from was zero, or where the split in + the prior level indicated that all of the pulses fell on the other side. +These partitions have nothing to code, so they require no PDF. + + + +Pulse Count +PDF + 1 {126, 130}/256 + 2 {56, 142, 58}/256 + 3 {25, 101, 104, 26}/256 + 4 {12, 60, 108, 64, 12}/256 + 5 {7, 35, 84, 87, 37, 6}/256 + 6 {4, 20, 59, 86, 63, 21, 3}/256 + 7 {3, 12, 38, 72, 75, 42, 12, 2}/256 + 8 {2, 8, 25, 54, 73, 59, 27, 7, 1}/256 + 9 {2, 5, 17, 39, 63, 65, 42, 18, 4, 1}/256 +10 {1, 4, 12, 28, 49, 63, 54, 30, 11, 3, 1}/256 +11 {1, 4, 8, 20, 37, 55, 57, 41, 22, 8, 2, 1}/256 +12 {1, 3, 7, 15, 28, 44, 53, 48, 33, 16, 6, 1, 1}/256 +13 {1, 2, 6, 12, 21, 35, 47, 48, 40, 25, 12, 5, 1, 1}/256 +14 {1, 1, 4, 10, 17, 27, 37, 47, 43, 33, 21, 9, 4, 1, 1}/256 +15 {1, 1, 1, 8, 14, 22, 33, 40, 43, 38, 28, 16, 8, 1, 1, 1}/256 +16 {1, 1, 1, 1, 13, 18, 27, 36, 41, 41, 34, 24, 14, 1, 1, 1, 1}/256 + + + +Pulse Count +PDF + 1 {127, 129}/256 + 2 {53, 149, 54}/256 + 3 {22, 105, 106, 23}/256 + 4 {11, 61, 111, 63, 10}/256 + 5 {6, 35, 86, 88, 36, 5}/256 + 6 {4, 20, 59, 87, 62, 21, 3}/256 + 7 {3, 13, 40, 71, 73, 41, 13, 2}/256 + 8 {3, 9, 27, 53, 70, 56, 28, 9, 1}/256 + 9 {3, 8, 19, 37, 57, 61, 44, 20, 6, 1}/256 +10 {3, 7, 15, 28, 44, 54, 49, 33, 17, 5, 1}/256 +11 {1, 7, 13, 22, 34, 46, 48, 38, 28, 14, 4, 1}/256 +12 {1, 1, 11, 22, 27, 35, 42, 47, 33, 25, 10, 1, 1}/256 +13 {1, 1, 6, 14, 26, 37, 43, 43, 37, 26, 14, 6, 1, 1}/256 +14 {1, 1, 4, 10, 20, 31, 40, 42, 40, 31, 20, 10, 4, 1, 1}/256 +15 {1, 1, 3, 8, 16, 26, 35, 38, 38, 35, 26, 16, 8, 3, 1, 1}/256 +16 {1, 1, 2, 6, 12, 21, 30, 36, 38, 36, 30, 21, 12, 6, 2, 1, 1}/256 + + + +Pulse Count +PDF + 1 {127, 129}/256 + 2 {49, 157, 50}/256 + 3 {20, 107, 109, 20}/256 + 4 {11, 60, 113, 62, 10}/256 + 5 {7, 36, 84, 87, 36, 6}/256 + 6 {6, 24, 57, 82, 60, 23, 4}/256 + 7 {5, 18, 39, 64, 68, 42, 16, 4}/256 + 8 {6, 14, 29, 47, 61, 52, 30, 14, 3}/256 + 9 {1, 15, 23, 35, 51, 50, 40, 30, 10, 1}/256 +10 {1, 1, 21, 32, 42, 52, 46, 41, 18, 1, 1}/256 +11 {1, 6, 16, 27, 36, 42, 42, 36, 27, 16, 6, 1}/256 +12 {1, 5, 12, 21, 31, 38, 40, 38, 31, 21, 12, 5, 1}/256 +13 {1, 3, 9, 17, 26, 34, 38, 38, 34, 26, 17, 9, 3, 1}/256 +14 {1, 3, 7, 14, 22, 29, 34, 36, 34, 29, 22, 14, 7, 3, 1}/256 +15 {1, 2, 5, 11, 18, 25, 31, 35, 35, 31, 25, 18, 11, 5, 2, 1}/256 +16 {1, 1, 4, 9, 15, 21, 28, 32, 34, 32, 28, 21, 15, 9, 4, 1, 1}/256 + + + +Pulse Count +PDF + 1 {128, 128}/256 + 2 {42, 172, 42}/256 + 3 {21, 107, 107, 21}/256 + 4 {12, 60, 112, 61, 11}/256 + 5 {8, 34, 86, 86, 35, 7}/256 + 6 {8, 23, 55, 90, 55, 20, 5}/256 + 7 {5, 15, 38, 72, 72, 36, 15, 3}/256 + 8 {6, 12, 27, 52, 77, 47, 20, 10, 5}/256 + 9 {6, 19, 28, 35, 40, 40, 35, 28, 19, 6}/256 +10 {4, 14, 22, 31, 37, 40, 37, 31, 22, 14, 4}/256 +11 {3, 10, 18, 26, 33, 38, 38, 33, 26, 18, 10, 3}/256 +12 {2, 8, 13, 21, 29, 36, 38, 36, 29, 21, 13, 8, 2}/256 +13 {1, 5, 10, 17, 25, 32, 38, 38, 32, 25, 17, 10, 5, 1}/256 +14 {1, 4, 7, 13, 21, 29, 35, 36, 35, 29, 21, 13, 7, 4, 1}/256 +15 {1, 2, 5, 10, 17, 25, 32, 36, 36, 32, 25, 17, 10, 5, 2, 1}/256 +16 {1, 2, 4, 7, 13, 21, 28, 34, 36, 34, 28, 21, 13, 7, 4, 2, 1}/256 + + +
+ +
+ +After the decoder reads the pulse locations for all blocks, it reads the LSBs + (if any) for each block in turn. +Inside each block, it reads all the LSBs for each coefficient in turn, even + those where no pulses were allocated, before proceeding to the next one. +For 10 ms MB frames, it reads LSBs even for the extra 8 samples in + the last block. +The LSBs are coded from most significant to least significant, and they all use + the PDF in . + + + +PDF +{136, 120}/256 + + + +The number of LSBs read for each coefficient in a block is determined in + . +The magnitude of the coefficient is initially equal to the number of pulses + placed at that location in . +As each LSB is decoded, the magnitude is doubled, and then the value of the LSB + added to it, to obtain an updated magnitude. + +
+ +
+ +After decoding the pulse locations and the LSBs, the decoder knows the + magnitude of each coefficient in the excitation. +It then decodes a sign for all coefficients with a non-zero magnitude, using + one of the PDFs from . +If the value decoded is 0, then the coefficient magnitude is negated. +Otherwise, it remains positive. + + + +The decoder chooses the PDF for the sign based on the signal type and + quantization offset type (from ) and the + number of pulses in the block (from ). +The number of pulses in the block does not take into account any LSBs. +Most PDFs are skewed towards negative signs because of the quantization offset, + but the PDFs for zero pulses are highly skewed towards positive signs. +If a block contains many positive coefficients, it is sometimes beneficial to + code it solely using LSBs (i.e., with zero pulses), since the encoder may be + able to save enough bits on the signs to justify the less efficient + coefficient magnitude encoding. + + + +Signal Type +Quantization Offset Type +Pulse Count +PDF +Inactive Low 0 {2, 254}/256 +Inactive Low 1 {207, 49}/256 +Inactive Low 2 {189, 67}/256 +Inactive Low 3 {179, 77}/256 +Inactive Low 4 {174, 82}/256 +Inactive Low 5 {163, 93}/256 +Inactive Low 6 or more {157, 99}/256 +Inactive High 0 {58, 198}/256 +Inactive High 1 {245, 11}/256 +Inactive High 2 {238, 18}/256 +Inactive High 3 {232, 24}/256 +Inactive High 4 {225, 31}/256 +Inactive High 5 {220, 36}/256 +Inactive High 6 or more {211, 45}/256 +Unvoiced Low 0 {1, 255}/256 +Unvoiced Low 1 {210, 46}/256 +Unvoiced Low 2 {190, 66}/256 +Unvoiced Low 3 {178, 78}/256 +Unvoiced Low 4 {169, 87}/256 +Unvoiced Low 5 {162, 94}/256 +Unvoiced Low 6 or more {152, 104}/256 +Unvoiced High 0 {48, 208}/256 +Unvoiced High 1 {242, 14}/256 +Unvoiced High 2 {235, 21}/256 +Unvoiced High 3 {224, 32}/256 +Unvoiced High 4 {214, 42}/256 +Unvoiced High 5 {205, 51}/256 +Unvoiced High 6 or more {190, 66}/256 +Voiced Low 0 {1, 255}/256 +Voiced Low 1 {162, 94}/256 +Voiced Low 2 {152, 104}/256 +Voiced Low 3 {147, 109}/256 +Voiced Low 4 {144, 112}/256 +Voiced Low 5 {141, 115}/256 +Voiced Low 6 or more {138, 118}/256 +Voiced High 0 {8, 248}/256 +Voiced High 1 {203, 53}/256 +Voiced High 2 {187, 69}/256 +Voiced High 3 {176, 80}/256 +Voiced High 4 {168, 88}/256 +Voiced High 5 {161, 95}/256 +Voiced High 6 or more {154, 102}/256 + + +
+ +
+ + +After the signs have been read, there is enough information to reconstruct the + complete excitation signal. +This requires adding a constant quantization offset to each non-zero sample, + and then pseudorandomly inverting and offsetting every sample. +The constant quantization offset varies depending on the signal type and + quantization offset type (see ). + + + +Signal Type +Quantization Offset Type +Quantization Offset (Q23) +Inactive Low 25 +Inactive High 60 +Unvoiced Low 25 +Unvoiced High 60 +Voiced Low 8 +Voiced High 25 + + + +Let e_raw[i] be the raw excitation value at position i, with a magnitude + composed of the pulses at that location (see + ) combined with any additional LSBs (see + ), and with the corresponding sign decoded in + . +Additionally, let seed be the current pseudorandom seed, which is initialized + to the value decoded from for the first sample in + the current SILK frame, and updated for each subsequent sample according to + the procedure below. +Finally, let offset_Q23 be the quantization offset from + . +Then the following procedure produces the final reconstructed excitation value, + e_Q23[i]: +
+ +
+When e_raw[i] is zero, sign() returns 0 by the definition in + , so the factor of 20 does not get added. +The final e_Q23[i] value may require more than 16 bits per sample, but will not + require more than 23, including the sign. +
+ +
+ +
+ +
+ + +The remainder of the reconstruction process for the frame does not need to be + bit-exact, as small errors should only introduce proportionally small + distortions. +Although the reference implementation only includes a fixed-point version of + the remaining steps, this section describes them in terms of a floating-point + version for simplicity. +This produces a signal with a nominal range of -1.0 to 1.0. + + + +silk_decode_core() (decode_core.c) contains the code for the main + reconstruction process. +It proceeds subframe-by-subframe, since quantization gains, LTP parameters, and + (in 20 ms SILK frames) LPC coefficients can vary from one to the + next. + + + +Let a_Q12[k] be the LPC coefficients for the current subframe. +If this is the first or second subframe of a 20 ms SILK frame and the LSF + interpolation factor, w_Q2 (see ), is + less than 4, then these correspond to the final LPC coefficients produced by + from the interpolated LSF coefficients, + n1_Q15[k] (computed in ). +Otherwise, they correspond to the final LPC coefficients produced from the + uninterpolated LSF coefficients for the current frame, n2_Q15[k]. + + + +Also, let n be the number of samples in a subframe (40 for NB, 60 for MB, and + 80 for WB), s be the index of the current subframe in this SILK frame (0 or 1 + for 10 ms frames, or 0 to 3 for 20 ms frames), and j be the index of + the first sample in the residual corresponding to the current subframe. + + +
+ +Voiced SILK frames (see ) pass the excitation + through an LTP filter using the parameters decoded in + to produce an LPC residual. +The LTP filter requires LPC residual values from before the current subframe as + input. +However, since the LPC coefficients may have changed, it obtains this residual + by "rewhitening" the corresponding output signal using the LPC coefficients + from the current subframe. +Let out[i] for + (j - pitch_lags[s] - d_LPC - 2) <= i < j + be the fully reconstructed output signal from the last + (pitch_lags[s] + d_LPC + 2) samples of previous subframes + (see ), where pitch_lags[s] is the pitch + lag for the current subframe from . +During reconstruction of the first subframe for this channel after either + +An uncoded regular SILK frame (if this is the side channel), or +A decoder reset (see ), + + out[] is rewhitened into an LPC residual, + res[i], via +
+ +
+This requires storage to buffer up to 306 values of out[i] from previous + subframes. +This corresponds to WB with a maximum pitch lag of + 18 ms * 16 kHz samples, plus 16 samples for d_LPC, plus 2 + samples for the width of the LTP filter. +
+ + +Let e_Q23[i] for j <= i < (j + n) be the + excitation for the current subframe, and b_Q7[k] for + 0 <= k < 5 be the coefficients of the LTP filter + taken from the codebook entry in one of + Tables  + through  + corresponding to the index decoded for the current subframe in + . +Then for i such that j <= i < (j + n), + the LPC residual is +
+ +
+
+ + +For unvoiced frames, the LPC residual for + j <= i < (j + n) is simply a normalized + copy of the excitation signal, i.e., +
+ +
+
+
+ +
+ +LPC synthesis uses the short-term LPC filter to predict the next output + coefficient. +For i such that (j - d_LPC) <= i < j, let + lpc[i] be the result of LPC synthesis from the last d_LPC samples of the + previous subframe, or zeros in the first subframe for this channel after + either + +An uncoded regular SILK frame (if this is the side channel), or +A decoder reset (see ). + +Then for i such that j <= i < (j + n), the + result of LPC synthesis for the current subframe is +
+ +
+The decoder saves the final d_LPC values, i.e., lpc[i] such that + (j + n - d_LPC) <= i < (j + n), + to feed into the LPC synthesis of the next subframe. +This requires storage for up to 16 values of lpc[i] (for WB frames). +
+ + +Then, the signal is clamped into the final nominal range: +
+ +
+This clamping occurs entirely after the LPC synthesis filter has run. +The decoder saves the unclamped values, lpc[i], to feed into the LPC filter for + the next subframe, but saves the clamped values, out[i], for rewhitening in + voiced frames. +
+
+ +
+ +
+ +
+ +For stereo streams, after decoding a frame from each channel, the decoder must + convert the mid-side (MS) representation into a left-right (LR) + representation. +The function silk_stereo_MS_to_LR (stereo_MS_to_LR.c) implements this process. +In it, the decoder predicts the side channel using a) a simple low-passed + version of the mid channel, and b) the unfiltered mid channel, using the + prediction weights decoded in . +This simple low-pass filter imposes a one-sample delay, and the unfiltered +mid channel is also delayed by one sample. +In order to allow seamless switching between stereo and mono, mono streams must + also impose the same one-sample delay. +The encoder requires an additional one-sample delay for both mono and stereo + streams, though an encoder may omit the delay for mono if it knows it will + never switch to stereo. + + + +The unmixing process operates in two phases. +The first phase lasts for 8 ms, during which it interpolates the + prediction weights from the previous frame, prev_w0_Q13 and prev_w1_Q13, to + the values for the current frame, w0_Q13 and w1_Q13. +The second phase simply uses these weights for the remainder of the frame. + + + +Let mid[i] and side[i] be the contents of out[i] (from + ) for the current mid and side channels, + respectively, and let left[i] and right[i] be the corresponding stereo output + channels. +If the side channel is not coded (see ), + then side[i] is set to zero. +Also let j be defined as in , n1 be + the number of samples in phase 1 (64 for NB, 96 for MB, and 128 for WB), + and n2 be the total number of samples in the frame. +Then for i such that j <= i < (j + n2), + the left and right channel output is +
+ +
+These formulas require two samples prior to index j, the start of the + frame, for the mid channel, and one prior sample for the side channel. +For the first frame after a decoder reset, zeros are used instead. +
+ +
+ +
+ +After stereo unmixing (if any), the decoder applies resampling to convert the + decoded SILK output to the sample rate desired by the application. +This is necessary when decoding a Hybrid frame at SWB or FB sample rates, or + whenever the decoder wants the output at a different sample rate than the + internal SILK sampling rate (e.g., to allow a constant sample rate when the + audio bandwidth changes, or to allow mixing with audio from other + applications). +The resampler itself is non-normative, and a decoder can use any method it + wants to perform the resampling. + + + +However, a minimum amount of delay is imposed to allow the resampler to + operate, and this delay is normative, so that the corresponding delay can be + applied to the MDCT layer in the encoder. +A decoder is always free to use a resampler which requires more delay than + allowed for here (e.g., to improve quality), but it must then delay the output + of the MDCT layer by this extra amount. +Keeping as much delay as possible on the encoder side allows an encoder which + knows it will never use any of the SILK or Hybrid modes to skip this delay. +By contrast, if it were all applied by the decoder, then a decoder which + processes audio in fixed-size blocks would be forced to delay the output of + CELT frames just in case of a later switch to a SILK or Hybrid mode. + + + + gives the maximum resampler delay + in samples at 48 kHz for each SILK audio bandwidth. +Because the actual output rate may not be 48 kHz, it may not be possible + to achieve exactly these delays while using a whole number of input or output + samples. +The reference implementation is able to resample to any of the supported + output sampling rates (8, 12, 16, 24, or 48 kHz) within or near this + delay constraint. +Some resampling filters (including those used by the reference implementation) + may add a delay that is not an exact integer, or is not linear-phase, and so + cannot be represented by a single delay at all frequencies. +However, such deviations are unlikely to be perceptible, and the comparison + tool described in is designed to be relatively + insensitive to them. +The delays listed here are the ones that should be targeted by the encoder. + + + +Audio Bandwidth +Delay in millisecond +NB 0.538 +MB 0.692 +WB 0.706 + + + +NB is given a smaller decoder delay allocation than MB and WB to allow a + higher-order filter when resampling to 8 kHz in both the encoder and + decoder. +This implies that the audio content of two SILK frames operating at different + bandwidths are not perfectly aligned in time. +This is not an issue for any transitions described in + , because they all involve a SILK decoder reset. +When the decoder is reset, any samples remaining in the resampling buffer + are discarded, and the resampler is re-initialized with silence. + + +
+ +
+ + +
+ + +The CELT layer of Opus is based on the Modified Discrete Cosine Transform + with partially overlapping windows of 5 to 22.5 ms. +The main principle behind CELT is that the MDCT spectrum is divided into +bands that (roughly) follow the Bark scale, i.e., the scale of the ear's +critical bands . The normal CELT layer uses 21 of those bands, though Opus + Custom (see ) may use a different number of bands. +In Hybrid mode, the first 17 bands (up to 8 kHz) are not coded. +A band can contain as little as one MDCT bin per channel, and as many as 176 +bins per channel, as detailed in . +In each band, the gain (energy) is coded separately from +the shape of the spectrum. Coding the gain explicitly makes it easy to +preserve the spectral envelope of the signal. The remaining unit-norm shape +vector is encoded using a Pyramid Vector Quantizer (PVQ) . + + + +Frame Size: +2.5 ms +5 ms +10 ms +20 ms +Start Frequency +Stop Frequency +Band Bins: + 0 1 2 4 8 0 Hz 200 Hz + 1 1 2 4 8 200 Hz 400 Hz + 2 1 2 4 8 400 Hz 600 Hz + 3 1 2 4 8 600 Hz 800 Hz + 4 1 2 4 8 800 Hz 1000 Hz + 5 1 2 4 8 1000 Hz 1200 Hz + 6 1 2 4 8 1200 Hz 1400 Hz + 7 1 2 4 8 1400 Hz 1600 Hz + 8 2 4 8 16 1600 Hz 2000 Hz + 9 2 4 8 16 2000 Hz 2400 Hz +10 2 4 8 16 2400 Hz 2800 Hz +11 2 4 8 16 2800 Hz 3200 Hz +12 4 8 16 32 3200 Hz 4000 Hz +13 4 8 16 32 4000 Hz 4800 Hz +14 4 8 16 32 4800 Hz 5600 Hz +15 6 12 24 48 5600 Hz 6800 Hz +16 6 12 24 48 6800 Hz 8000 Hz +17 8 16 32 64 8000 Hz 9600 Hz +18 12 24 48 96 9600 Hz 12000 Hz +19 18 36 72 144 12000 Hz 15600 Hz +20 22 44 88 176 15600 Hz 20000 Hz + + + +Transients are notoriously difficult for transform codecs to code. +CELT uses two different strategies for them: + +Using multiple smaller MDCTs instead of a single large MDCT, and +Dynamic time-frequency resolution changes (See ). + +To improve quality on highly tonal and periodic signals, CELT includes +a prefilter/postfilter combination. The prefilter on the encoder side +attenuates the signal's harmonics. The postfilter on the decoder side +restores the original gain of the harmonics, while shaping the coding noise +to roughly follow the harmonics. Such noise shaping reduces the perception +of the noise. + + + +When coding a stereo signal, three coding methods are available: + +mid-side stereo: encodes the mean and the difference of the left and right channels, +intensity stereo: only encodes the mean of the left and right channels (discards the difference), +dual stereo: encodes the left and right channels separately. + + + + +An overview of the decoder is given in . + + +
+| decoder |----+ + | +---------+ | + | | + | +---------+ v + | | Fine | +---+ + +->| decoder |->| + | + | +---------+ +---+ + | ^ | ++---------+ | | | +| Range | | +----------+ v +| Decoder |-+ | Bit | +------+ ++---------+ | |Allocation| | 2**x | + | +----------+ +------+ + | | | + | v v +--------+ + | +---------+ +---+ +-------+ | pitch | + +->| PVQ |->| * |->| IMDCT |->| post- |---> + | | decoder | +---+ +-------+ | filter | + | +---------+ +--------+ + | ^ + +--------------------------------------+ +]]> +
+ + +The decoder is based on the following symbols and sets of symbols: + + + +Symbol(s) +PDF +Condition +silence {32767, 1}/32768 +post-filter {1, 1}/2 +octave uniform (6)post-filter +period raw bits (4+octave)post-filter +gain raw bits (3)post-filter +tapset {2, 1, 1}/4post-filter +transient {7, 1}/8 +intra {7, 1}/8 +coarse energy +tf_change +tf_select {1, 1}/2 +spread {7, 2, 21, 2}/32 +dyn. alloc. +alloc. trim {2, 2, 5, 10, 22, 46, 22, 10, 5, 2, 2}/128 +skip {1, 1}/2 +intensity uniform +dual {1, 1}/2 +fine energy +residual +anti-collapse{1, 1}/2 +finalize + + + +The decoder extracts information from the range-coded bitstream in the order +described in . In some circumstances, it is +possible for a decoded value to be out of range due to a very small amount of redundancy +in the encoding of large integers by the range coder. +In that case, the decoder should assume there has been an error in the coding, +decoding, or transmission and SHOULD take measures to conceal the error and/or report +to the application that a problem has occurred. Such out of range errors cannot occur +in the SILK layer. + + +
+ +The "transient" flag indicates whether the frame uses a single long MDCT or several short MDCTs. +When it is set, then the MDCT coefficients represent multiple +short MDCTs in the frame. When not set, the coefficients represent a single +long MDCT for the frame. The flag is encoded in the bitstream with a probability of 1/8. +In addition to the global transient flag is a per-band +binary flag to change the time-frequency (tf) resolution independently in each band. The +change in tf resolution is defined in tf_select_table[][] in celt.c and depends +on the frame size, whether the transient flag is set, and the value of tf_select. +The tf_select flag uses a 1/2 probability, but is only decoded +if it can have an impact on the result knowing the value of all per-band +tf_change flags. + +
+ +
+ + +It is important to quantize the energy with sufficient resolution because +any energy quantization error cannot be compensated for at a later +stage. Regardless of the resolution used for encoding the spectral shape of a band, +it is perceptually important to preserve the energy in each band. CELT uses a +three-step coarse-fine-fine strategy for encoding the energy in the base-2 log +domain, as implemented in quant_bands.c + +
+ +Coarse quantization of the energy uses a fixed resolution of 6 dB +(integer part of base-2 log). To minimize the bitrate, prediction is applied +both in time (using the previous frame) and in frequency (using the previous +bands). The part of the prediction that is based on the +previous frame can be disabled, creating an "intra" frame where the energy +is coded without reference to prior frames. The decoder first reads the intra flag +to determine what prediction is used. +The 2-D z-transform of +the prediction filter is: +
+ +
+where b is the band index and l is the frame index. The prediction coefficients +applied depend on the frame size in use when not using intra energy and are alpha=0, beta=4915/32768 +when using intra energy. +The time-domain prediction is based on the final fine quantization of the previous +frame, while the frequency domain (within the current frame) prediction is based +on coarse quantization only (because the fine quantization has not been computed +yet). The prediction is clamped internally so that fixed point implementations with +limited dynamic range always remain in the same state as floating point implementations. +We approximate the ideal +probability distribution of the prediction error using a Laplace distribution +with separate parameters for each frame size in intra- and inter-frame modes. These +parameters are held in the e_prob_model table in quant_bands.c. +The +coarse energy quantization is performed by unquant_coarse_energy() and +unquant_coarse_energy_impl() (quant_bands.c). The encoding of the Laplace-distributed values is +implemented in ec_laplace_decode() (laplace.c). +
+ +
+ +
+ +The number of bits assigned to fine energy quantization in each band is determined +by the bit allocation computation described in . +Let B_i be the number of fine energy bits +for band i; the refinement is an integer f in the range [0,2**B_i-1]. The mapping between f +and the correction applied to the coarse energy is equal to (f+1/2)/2**B_i - 1/2. Fine +energy quantization is implemented in quant_fine_energy() (quant_bands.c). + + +When some bits are left "unused" after all other flags have been decoded, these bits +are assigned to a "final" step of fine allocation. In effect, these bits are used +to add one extra fine energy bit per band per channel. The allocation process +determines two "priorities" for the final fine bits. +Any remaining bits are first assigned only to bands of priority 0, starting +from band 0 and going up. If all bands of priority 0 have received one bit per +channel, then bands of priority 1 are assigned an extra bit per channel, +starting from band 0. If any bits are left after this, they are left unused. +This is implemented in unquant_energy_finalise() (quant_bands.c). + + +
+ +
+ +
+ +Because the bit allocation drives the decoding of the range-coder +stream, it MUST be recovered exactly so that identical coding decisions are +made in the encoder and decoder. Any deviation from the reference's resulting +bit allocation will result in corrupted output, though implementers are +free to implement the procedure in any way which produces identical results. + +The per-band gain-shape structure of the CELT layer ensures that using + the same number of bits for the spectral shape of a band in every frame will + result in a roughly constant signal-to-noise ratio in that band. +This results in coding noise that has the same spectral envelope as the signal. +The masking curve produced by a standard psychoacoustic model also closely + follows the spectral envelope of the signal. +This structure means that the ideal allocation is more consistent from frame to + frame than it is for other codecs without an equivalent structure, and that a + fixed allocation provides fairly consistent perceptual + performance . + +Many codecs transmit significant amounts of side information to control the + bit allocation within a frame. +Often this control is only indirect, and must be exercised carefully to + achieve the desired rate constraints. +The CELT layer, however, can adapt over a very wide range of rates, and thus + has a large number of codebook sizes to choose from for each band. +Explicitly signaling the size of each of these codebooks would impose + considerable overhead, even though the allocation is relatively static from + frame to frame. +This is because all of the information required to compute these codebook sizes + must be derived from a single frame by itself, in order to retain robustness + to packet loss, so the signaling cannot take advantage of knowledge of the + allocation in neighboring frames. +This problem is exacerbated in low-latency (small frame size) applications, + which would include this overhead in every frame. + +For this reason, in the MDCT mode Opus uses a primarily implicit bit +allocation. The available bitstream capacity is known in advance to both +the encoder and decoder without additional signaling, ultimately from the +packet sizes expressed by a higher-level protocol. Using this information, +the codec interpolates an allocation from a hard-coded table. + +While the band-energy structure effectively models intra-band masking, +it ignores the weaker inter-band masking, band-temporal masking, and +other less significant perceptual effects. While these effects can +often be ignored, they can become significant for particular samples. One +mechanism available to encoders would be to simply increase the overall +rate for these frames, but this is not possible in a constant rate mode +and can be fairly inefficient. As a result three explicitly signaled +mechanisms are provided to alter the implicit allocation: + + + +Band boost +Allocation trim +Band skipping + + + +The first of these mechanisms, band boost, allows an encoder to boost +the allocation in specific bands. The second, allocation trim, works by +biasing the overall allocation towards higher or lower frequency bands. The third, band +skipping, selects which low-precision high frequency bands +will be allocated no shape bits at all. + +In stereo mode there are two additional parameters +potentially coded as part of the allocation procedure: a parameter to allow the +selective elimination of allocation for the 'side' (i.e., intensity stereo) in jointly coded bands, +and a flag to deactivate joint coding (i.e., dual stereo). These values are not signaled if +they would be meaningless in the overall context of the allocation. + +Because every signaled adjustment increases overhead and implementation +complexity, none were included speculatively: the reference encoder makes use +of all of these mechanisms. While the decision logic in the reference was +found to be effective enough to justify the overhead and complexity, further +analysis techniques may be discovered which increase the effectiveness of these +parameters. As with other signaled parameters, an encoder is free to choose the +values in any manner, but unless a technique is known to deliver superior +perceptual results the methods used by the reference implementation should be +used. + +The allocation process consists of the following steps: determining the per-band +maximum allocation vector, decoding the boosts, decoding the tilt, determining +the remaining capacity of the frame, searching the mode table for the +entry nearest but not exceeding the available space (subject to the tilt, boosts, band +maximums, and band minimums), linear interpolation, reallocation of +unused bits with concurrent skip decoding, determination of the +fine-energy vs. shape split, and final reallocation. This process results +in a per-band shape allocation (in 1/8th bit units), a per-band fine-energy +allocation (in 1 bit per channel units), a set of band priorities for +controlling the use of remaining bits at the end of the frame, and a +remaining balance of unallocated space, which is usually zero except +at very high rates. + + +The "static" bit allocation (in 1/8 bits) for a quality q, excluding the minimums, maximums, +tilt and boosts, is equal to channels*N*alloc[band][q]<<LM>>2, where +alloc[][] is given in and LM=log2(frame_size/120). The allocation +is obtained by linearly interpolating between two values of q (in steps of 1/64) to find the +highest allocation that does not exceed the number of bits remaining. + + + + Rows indicate the MDCT bands, columns are the different quality (q) parameters. The units are 1/32 bit per MDCT bin. +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +090110118126134144152162172200 +080100110119127137145155165200 +07590103112120130138148158200 +0698493104114124132142152200 +063788695103113123133143200 +05671808997107117127137200 +04965758391101111121131200 +0405870788595105115125200 +034516572788898108118198 +029455966728292102112193 +02039536066768696106188 +01832475460708090100183 +0102640475464748494178 +002031394757677787173 +001223324151617181168 +00015253545556575163 +0004172939495969158 +0000122333435363153 +000011626364656148 +000001015203045129 +00000111120104 + + +The maximum allocation vector is an approximation of the maximum space +that can be used by each band for a given mode. The value is +approximate because the shape encoding is variable rate (due +to entropy coding of splitting parameters). Setting the maximum too low reduces the +maximum achievable quality in a band while setting it too high +may result in waste: bitstream capacity available at the end +of the frame which can not be put to any use. The maximums +specified by the codec reflect the average maximum. In the reference +implementation, the maximums in bits/sample are precomputed in a static table +(see cache_caps50[] in static_modes_float.h) for each band, +for each value of LM, and for both mono and stereo. + +Implementations are expected +to simply use the same table data, but the procedure for generating +this table is included in rate.c as part of compute_pulse_cache(). + +To convert the values in cache.caps into the actual maximums: first +set nbBands to the maximum number of bands for this mode, and stereo to +zero if stereo is not in use and one otherwise. For each band set N +to the number of MDCT bins covered by the band (for one channel), set LM +to the shift value for the frame size, +then set i to nbBands*(2*LM+stereo). Then set the maximum for the band to +the i-th index of cache.caps + 64 and multiply by the number of channels +in the current frame (one or two) and by N, then divide the result by 4 +using integer division. The resulting vector will be called +cap[]. The elements fit in signed 16-bit integers but do not fit in 8 bits. +This procedure is implemented in the reference in the function init_caps() in celt.c. + + +The band boosts are represented by a series of binary symbols which +are entropy coded with very low probability. Each band can potentially be boosted +multiple times, subject to the frame actually having enough room to obey +the boost and having enough room to code the boost symbol. The default +coding cost for a boost starts out at six bits (probability p=1/64), but subsequent boosts +in a band cost only a single bit and every time a band is boosted the +initial cost is reduced (down to a minimum of two bits, or p=1/4). Since the initial +cost of coding a boost is 6 bits, the coding cost of the boost symbols when +completely unused is 0.48 bits/frame for a 21 band mode (21*-log2(1-1/2**6)). + +To decode the band boosts: First set 'dynalloc_logp' to 6, the initial +amount of storage required to signal a boost in bits, 'total_bits' to the +size of the frame in 8th bits, 'total_boost' to zero, and 'tell' to the total number +of 8th bits decoded +so far. For each band from the coding start (0 normally, but 17 in Hybrid mode) +to the coding end (which changes depending on the signaled bandwidth), the boost quanta +in units of 1/8 bit is calculated as quanta = min(8*N, max(48, N)). +This represents a boost step size of six bits, subject to a lower limit of +1/8th bit/sample and an upper limit of 1 bit/sample. +Set 'boost' to zero and 'dynalloc_loop_logp' +to dynalloc_logp. While dynalloc_loop_log (the current worst case symbol cost) in +8th bits plus tell is less than total_bits plus total_boost and boost is less than cap[] for this +band: Decode a bit from the bitstream with a with dynalloc_loop_logp as the cost +of a one, update tell to reflect the current used capacity, if the decoded value +is zero break the loop otherwise add quanta to boost and total_boost, subtract quanta from +total_bits, and set dynalloc_loop_log to 1. When the while loop finishes +boost contains the boost for this band. If boost is non-zero and dynalloc_logp +is greater than 2, decrease dynalloc_logp. Once this process has been +executed on all bands, the band boosts have been decoded. This procedure +is implemented around line 2474 of celt.c. + +At very low rates it is possible that there won't be enough available +space to execute the inner loop even once. In these cases band boost +is not possible but its overhead is completely eliminated. Because of the +high cost of band boost when activated, a reasonable encoder should not be +using it at very low rates. The reference implements its dynalloc decision +logic around line 1304 of celt.c. + +The allocation trim is a integer value from 0-10. The default value of +5 indicates no trim. The trim parameter is entropy coded in order to +lower the coding cost of less extreme adjustments. Values lower than +5 bias the allocation towards lower frequencies and values above 5 +bias it towards higher frequencies. Like other signaled parameters, signaling +of the trim is gated so that it is not included if there is insufficient space +available in the bitstream. To decode the trim, first set +the trim value to 5, then if and only if the count of decoded 8th bits so far (ec_tell_frac) +plus 48 (6 bits) is less than or equal to the total frame size in 8th +bits minus total_boost (a product of the above band boost procedure), +decode the trim value using the PDF in . + + +PDF +{1, 1, 2, 5, 10, 22, 46, 22, 10, 5, 2, 2}/128 + + +For 10 ms and 20 ms frames using short blocks and that have at least LM+2 bits left prior to +the allocation process, then one anti-collapse bit is reserved in the allocation process so it can +be decoded later. Following the the anti-collapse reservation, one bit is reserved for skip if available. + +For stereo frames, bits are reserved for intensity stereo and for dual stereo. Intensity stereo +requires ilog2(end-start) bits. Those bits are reserved if there is enough bits left. Following this, one +bit is reserved for dual stereo if available. + + +The allocation computation begins by setting up some initial conditions. +'total' is set to the remaining available 8th bits, computed by taking the +size of the coded frame times 8 and subtracting ec_tell_frac(). From this value, one (8th bit) +is subtracted to ensure that the resulting allocation will be conservative. 'anti_collapse_rsv' +is set to 8 (8th bits) if and only if the frame is a transient, LM is greater than 1, and total is +greater than or equal to (LM+2) * 8. Total is then decremented by anti_collapse_rsv and clamped +to be equal to or greater than zero. 'skip_rsv' is set to 8 (8th bits) if total is greater than +8, otherwise it is zero. Total is then decremented by skip_rsv. This reserves space for the +final skipping flag. + +If the current frame is stereo, intensity_rsv is set to the conservative log2 in 8th bits +of the number of coded bands for this frame (given by the table LOG2_FRAC_TABLE in rate.c). If +intensity_rsv is greater than total then intensity_rsv is set to zero. Otherwise total is +decremented by intensity_rsv, and if total is still greater than 8, dual_stereo_rsv is +set to 8 and total is decremented by dual_stereo_rsv. + +The allocation process then computes a vector representing the hard minimum amounts allocation +any band will receive for shape. This minimum is higher than the technical limit of the PVQ +process, but very low rate allocations produce an excessively sparse spectrum and these bands +are better served by having no allocation at all. For each coded band, set thresh[band] to +twenty-four times the number of MDCT bins in the band and divide by 16. If 8 times the number +of channels is greater, use that instead. This sets the minimum allocation to one bit per channel +or 48 128th bits per MDCT bin, whichever is greater. The band-size dependent part of this +value is not scaled by the channel count, because at the very low rates where this limit is +applicable there will usually be no bits allocated to the side. + +The previously decoded allocation trim is used to derive a vector of per-band adjustments, +'trim_offsets[]'. For each coded band take the alloc_trim and subtract 5 and LM. Then multiply +the result by the number of channels, the number of MDCT bins in the shortest frame size for this mode, +the number of remaining bands, 2**LM, and 8. Then divide this value by 64. Finally, if the +number of MDCT bins in the band per channel is only one, 8 times the number of channels is subtracted +in order to diminish the allocation by one bit, because width 1 bands receive greater benefit +from the coarse energy coding. + + +
+ +
+ +In each band, the normalized "shape" is encoded +using a vector quantization scheme called a "pyramid vector quantizer". + + +In +the simplest case, the number of bits allocated in + is converted to a number of pulses as described +by . Knowing the number of pulses and the +number of samples in the band, the decoder calculates the size of the codebook +as detailed in . The size is used to decode +an unsigned integer (uniform probability model), which is the codeword index. +This index is converted into the corresponding vector as explained in +. This vector is then scaled to unit norm. + + +
+ +Although the allocation is performed in 1/8th bit units, the quantization requires +an integer number of pulses K. To do this, the encoder searches for the value +of K that produces the number of bits nearest to the allocated value +(rounding down if exactly halfway between two values), not to exceed +the total number of bits available. For efficiency reasons, the search is performed against a +precomputed allocation table which only permits some K values for each N. The number of +codebook entries can be computed as explained in . The difference +between the number of bits allocated and the number of bits used is accumulated to a +"balance" (initialized to zero) that helps adjust the +allocation for the next bands. One third of the balance is applied to the +bit allocation of each band to help achieve the target allocation. The only +exceptions are the band before the last and the last band, for which half the balance +and the whole balance are applied, respectively. + +
+ +
+ + +Decoding of PVQ vectors is implemented in decode_pulses() (cwrs.c). +The unique codeword index is decoded as a uniformly-distributed integer value between 0 and +V(N,K)-1, where V(N,K) is the number of possible combinations of K pulses in +N samples. The index is then converted to a vector in the same way specified in +. The indexing is based on the calculation of V(N,K) +(denoted N(L,K) in ). + + + + The number of combinations can be computed recursively as +V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1), with V(N,0) = 1 and V(0,K) = 0, K != 0. +There are many different ways to compute V(N,K), including precomputed tables and direct +use of the recursive formulation. The reference implementation applies the recursive +formulation one line (or column) at a time to save on memory use, +along with an alternate, +univariate recurrence to initialize an arbitrary line, and direct +polynomial solutions for small N. All of these methods are +equivalent, and have different trade-offs in speed, memory usage, and +code size. Implementations MAY use any methods they like, as long as +they are equivalent to the mathematical definition. + + + +The decoded vector X is recovered as follows. +Let i be the index decoded with the procedure in + with ft = V(N,K), so that 0 <= i < V(N,K). +Let k = K. +Then for j = 0 to (N - 1), inclusive, do: + +Let p = (V(N-j-1,k) + V(N-j,k))/2. + +If i < p, then let sgn = 1, else let sgn = -1 + and set i = i - p. + +Let k0 = k and set p = p - V(N-j-1,k). + +While p > i, set k = k - 1 and + p = p - V(N-j-1,k). + + +Set X[j] = sgn*(k0 - k) and i = i - p. + + + + + +The decoded vector X is then normalized such that its +L2-norm equals one. + +
+ +
+ +The normalized vector decoded in is then rotated +for the purpose of avoiding tonal artifacts. The rotation gain is equal to +
+ +
+ +where N is the number of dimensions, K is the number of pulses, and f_r depends on +the value of the "spread" parameter in the bit-stream. +
+ + +Spread value +f_r + 0 infinite (no rotation) + 1 15 + 2 10 + 3 5 + + + +The rotation angle is then calculated as +
+ +
+A 2-D rotation R(i,j) between points x_i and x_j is defined as: +
+ +
+ +An N-D rotation is then achieved by applying a series of 2-D rotations back and forth, in the +following order: R(x_1, x_2), R(x_2, x_3), ..., R(x_N-2, X_N-1), R(x_N-1, X_N), +R(x_N-2, X_N-1), ..., R(x_1, x_2). +
+ + +If the decoded vector represents more +than one time block, then this spreading process is applied separately on each time block. +Also, if each block represents 8 samples or more, then another N-D rotation, by +(pi/2-theta), is applied before the rotation described above. This +extra rotation is applied in an interleaved manner with a stride equal to round(sqrt(N/nb_blocks)), +i.e., it is applied independently for each set of sample S_k = {stride*n + k}, n=0..N/stride-1. + +
+ +
+ +To avoid the need for multi-precision calculations when decoding PVQ codevectors, +the maximum size allowed for codebooks is 32 bits. When larger codebooks are +needed, the vector is instead split in two sub-vectors of size N/2. +A quantized gain parameter with precision +derived from the current allocation is entropy coded to represent the relative +gains of each side of the split, and the entire decoding process is recursively +applied. Multiple levels of splitting may be applied up to a limit of LM+1 splits. +The same recursive mechanism is applied for the joint coding +of stereo audio. + + +
+ +
+ +The time-frequency (TF) parameters are used to control the time-frequency resolution tradeoff +in each coded band. For each band, there are two possible TF choices. For the first +band coded, the PDF is {3, 1}/4 for frames marked as transient and {15, 1}/16 for +the other frames. For subsequent bands, the TF choice is coded relative to the +previous TF choice with probability {15, 1}/15 for transient frames and {31, 1}/32 +otherwise. The mapping between the decoded TF choices and the adjustment in TF +resolution is shown in the tables below. + + + +Frame size (ms) +0 +1 +2.5 0 -1 +5 0 -1 +10 0 -2 +20 0 -2 + + + +Frame size (ms) +0 +1 +2.5 0 -1 +5 0 -2 +10 0 -3 +20 0 -3 + + + + +Frame size (ms) +0 +1 +2.5 0 -1 +5 1 0 +10 2 0 +20 3 0 + + + +Frame size (ms) +0 +1 +2.5 0 -1 +5 1 -1 +10 1 -1 +20 1 -1 + + + +A negative TF adjustment means that the temporal resolution is increased, +while a positive TF adjustment means that the frequency resolution is increased. +Changes in TF resolution are implemented using the Hadamard transform . To increase +the time resolution by N, N "levels" of the Hadamard transform are applied to the +decoded vector for each interleaved MDCT vector. To increase the frequency resolution +(assumes a transient frame), then N levels of the Hadamard transform are applied +across the interleaved MDCT vector. In the case of increased +time resolution the decoder uses the "sequency order" because the input vector +is sorted in time. + +
+ + +
+ +
+ +The anti-collapse feature is designed to avoid the situation where the use of multiple +short MDCTs causes the energy in one or more of the MDCTs to be zero for +some bands, causing unpleasant artifacts. +When the frame has the transient bit set, an anti-collapse bit is decoded. +When anti-collapse is set, the energy in each small MDCT is prevented +from collapsing to zero. For each band of each MDCT where a collapse is +detected, a pseudo-random signal is inserted with an energy corresponding +to the minimum energy over the two previous frames. A renormalization step is +then required to ensure that the anti-collapse step did not alter the +energy preservation property. + +
+ +
+ +Just as each band was normalized in the encoder, the last step of the decoder before +the inverse MDCT is to denormalize the bands. Each decoded normalized band is +multiplied by the square root of the decoded energy. This is done by denormalise_bands() +(bands.c). + +
+ +
+ + +The inverse MDCT implementation has no special characteristics. The +input is N frequency-domain samples and the output is 2*N time-domain +samples, while scaling by 1/2. A "low-overlap" window reduces the algorithmic delay. +It is derived from a basic (full overlap) 240-sample version of the window used by the Vorbis codec: +
+ +
+The low-overlap window is created by zero-padding the basic window and inserting ones in the +middle, such that the resulting window still satisfies power complementarity . +The IMDCT and +windowing are performed by mdct_backward (mdct.c). +
+ +
+ +The output of the inverse MDCT (after weighted overlap-add) is sent to the +post-filter. Although the post-filter is applied at the end, the post-filter +parameters are encoded at the beginning, just after the silence flag. +The post-filter can be switched on or off using one bit (logp=1). +If the post-filter is enabled, then the octave is decoded as an integer value +between 0 and 6 of uniform probability. Once the octave is known, the fine pitch +within the octave is decoded using 4+octave raw bits. The final pitch period +is equal to (16<<octave)+fine_pitch-1 so it is bounded between 15 and 1022, +inclusively. Next, the gain is decoded as three raw bits and is equal to +G=3*(int_gain+1)/32. The set of post-filter taps is decoded last, using +a pdf equal to {2, 1, 1}/4. Tapset zero corresponds to the filter coefficients +g0 = 0.3066406250, g1 = 0.2170410156, g2 = 0.1296386719. Tapset one +corresponds to the filter coefficients g0 = 0.4638671875, g1 = 0.2680664062, +g2 = 0, and tapset two uses filter coefficients g0 = 0.7998046875, +g1 = 0.1000976562, g2 = 0. + + + +The post-filter response is thus computed as: +
+ + + +
+ +During a transition between different gains, a smooth transition is calculated +using the square of the MDCT window. It is important that values of y(n) be +interpolated one at a time such that the past value of y(n) used is interpolated. +
+
+ +
+ +After the post-filter, +the signal is de-emphasized using the inverse of the pre-emphasis filter +used in the encoder: +
+ +
+where alpha_p=0.8500061035. +
+
+ +
+ +
+ +
+ +Packet loss concealment (PLC) is an optional decoder-side feature that +SHOULD be included when receiving from an unreliable channel. Because +PLC is not part of the bitstream, there are many acceptable ways to +implement PLC with different complexity/quality trade-offs. + + + +The PLC in +the reference implementation depends on the mode of last packet received. +In CELT mode, the PLC finds a periodicity in the decoded +signal and repeats the windowed waveform using the pitch offset. The windowed +waveform is overlapped in such a way as to preserve the time-domain aliasing +cancellation with the previous frame and the next frame. This is implemented +in celt_decode_lost() (mdct.c). In SILK mode, the PLC uses LPC extrapolation +from the previous frame, implemented in silk_PLC() (PLC.c). + + +
+ +Clock drift refers to the gradual desynchronization of two endpoints +whose sample clocks run at different frequencies while they are streaming +live audio. Differences in clock frequencies are generally attributable to +manufacturing variation in the endpoints' clock hardware. For long-lived +streams, the time difference between sender and receiver can grow without +bound. + + + +When the sender's clock runs slower than the receiver's, the effect is similar +to packet loss: too few packets are received. The receiver can distinguish +between drift and loss if the transport provides packet timestamps. A receiver +for live streams SHOULD conceal the effects of drift, and MAY do so by invoking +the PLC. + + + +When the sender's clock runs faster than the receiver's, too many packets will +be received. The receiver MAY respond by skipping any packet (i.e., not +submitting the packet for decoding). This is likely to produce a less severe +artifact than if the frame were dropped after decoding. + + + +A decoder MAY employ a more sophisticated drift compensation method. For +example, the +NetEQ component +of the +Google WebRTC codebase +compensates for drift by adding or removing +one period when the signal is highly periodic. The reference implementation of +Opus allows a caller to learn whether the current frame's signal is highly +periodic, and if so what the period is, using the OPUS_GET_PITCH() request. + +
+ +
+ +
+ + +Switching between the Opus coding modes, audio bandwidths, and channel counts + requires careful consideration to avoid audible glitches. +Switching between any two configurations of the CELT-only mode, any two + configurations of the Hybrid mode, or from WB SILK to Hybrid mode does not + require any special treatment in the decoder, as the MDCT overlap will smooth + the transition. +Switching from Hybrid mode to WB SILK requires adding in the final contents + of the CELT overlap buffer to the first SILK-only packet. +This can be done by decoding a 2.5 ms silence frame with the CELT decoder + using the channel count of the SILK-only packet (and any choice of audio + bandwidth), which will correctly handle the cases when the channel count + changes as well. + + + +When changing the channel count for SILK-only or Hybrid packets, the encoder + can avoid glitches by smoothly varying the stereo width of the input signal + before or after the transition, and SHOULD do so. +However, other transitions between SILK-only packets or between NB or MB SILK + and Hybrid packets may cause glitches, because neither the LSF coefficients + nor the LTP, LPC, stereo unmixing, and resampler buffers are available at the + new sample rate. +These switches SHOULD be delayed by the encoder until quiet periods or + transients, where the inevitable glitches will be less audible. Additionally, + the bit-stream MAY include redundant side information ("redundancy"), in the + form of additional CELT frames embedded in each of the Opus frames around the + transition. + + + +The other transitions that cannot be easily handled are those where the lower + frequencies switch between the SILK LP-based model and the CELT MDCT model. +However, an encoder may not have an opportunity to delay such a switch to a + convenient point. +For example, if the content switches from speech to music, and the encoder does + not have enough latency in its analysis to detect this in advance, there may + be no convenient silence period during which to make the transition for quite + some time. +To avoid or reduce glitches during these problematic mode transitions, and + also between audio bandwidth changes in the SILK-only modes, transitions MAY + include redundant side information ("redundancy"), in the form of an + additional CELT frame embedded in the Opus frame. + + + +A transition between coding the lower frequencies with the LP model and the + MDCT model or a transition that involves changing the SILK bandwidth + is only normatively specified when it includes redundancy. +For those without redundancy, it is RECOMMENDED that the decoder use a + concealment technique (e.g., make use of a PLC algorithm) to "fill in" the + gap or discontinuity caused by the mode transition. +Therefore, PLC MUST NOT be applied during any normative transition, i.e., when + +A packet includes redundancy for this transition (as described below), +The transition is between any WB SILK packet and any Hybrid packet, or vice + versa, +The transition is between any two Hybrid mode packets, or +The transition is between any two CELT mode packets, + + unless there is actual packet loss. + + +
+ +Transitions with side information include an extra 5 ms "redundant" CELT + frame within the Opus frame. +This frame is designed to fill in the gap or discontinuity in the different + layers without requiring the decoder to conceal it. +For transitions from CELT-only to SILK-only or Hybrid, the redundant frame is + inserted in the first Opus frame after the transition (i.e., the first + SILK-only or Hybrid frame). +For transitions from SILK-only or Hybrid to CELT-only, the redundant frame is + inserted in the last Opus frame before the transition (i.e., the last + SILK-only or Hybrid frame). + + +
+ +The presence of redundancy is signaled in all SILK-only and Hybrid frames, not + just those involved in a mode transition. +This allows the frames to be decoded correctly even if an adjacent frame is + lost. +For SILK-only frames, this signaling is implicit, based on the size of the + of the Opus frame and the number of bits consumed decoding the SILK portion of + it. +After decoding the SILK portion of the Opus frame, the decoder uses ec_tell() + (see ) to check if there are at least 17 bits + remaining. +If so, then the frame contains redundancy. + + + +For Hybrid frames, this signaling is explicit. +After decoding the SILK portion of the Opus frame, the decoder uses ec_tell() + (see ) to ensure there are at least 37 bits remaining. +If so, it reads a symbol with the PDF in + , and if the value is 1, then the + frame contains redundancy. +Otherwise (if there were fewer than 37 bits left or the value was 0), the frame + does not contain redundancy. + + + +PDF +{4095, 1}/4096 + +
+ +
+ +Since the current frame is a SILK-only or a Hybrid frame, it must be at least + 10 ms. +Therefore, it needs an additional flag to indicate whether the redundant + 5 ms CELT frame should be mixed into the beginning of the current frame, + or the end. +After determining that a frame contains redundancy, the decoder reads a + 1 bit symbol with a uniform PDF + (). + + + +PDF +{1, 1}/2 + + + +If the value is zero, this is the first frame in the transition, and the + redundancy belongs at the end. +If the value is one, this is the second frame in the transition, and the + redundancy belongs at the beginning. +There is no way to specify that an Opus frame contains separate redundant CELT + frames at both the beginning and the end. + +
+ +
+ +Unlike the CELT portion of a Hybrid frame, the redundant CELT frame does not + use the same entropy coder state as the rest of the Opus frame, because this + would break the CELT bit allocation mechanism in Hybrid frames. +Thus, a redundant CELT frame always starts and ends on a byte boundary, even in + SILK-only frames, where this is not strictly necessary. + + + +For SILK-only frames, the number of bytes in the redundant CELT frame is simply + the number of whole bytes remaining, which must be at least 2, due to the + space check in . +For Hybrid frames, the number of bytes is equal to 2, plus a decoded unsigned + integer less than 256 (see ). +This may be more than the number of whole bytes remaining in the Opus frame, + in which case the frame is invalid. +However, a decoder is not required to ignore the entire frame, as this may be + the result of a bit error that desynchronized the range coder. +There may still be useful data before the error, and a decoder MAY keep any + audio decoded so far instead of invoking the PLC, but it is RECOMMENDED that + the decoder stop decoding and discard the rest of the current Opus frame. + + + +It would have been possible to avoid these invalid states in the design of Opus + by limiting the range of the explicit length decoded from Hybrid frames by the + actual number of whole bytes remaining. +However, this would require an encoder to determine the rate allocation for the + MDCT layer up front, before it began encoding that layer. +By allowing some invalid sizes, the encoder is able to defer that decision + until much later. +When encoding Hybrid frames which do not include redundancy, the encoder must + still decide up-front if it wishes to use the minimum 37 bits required to + trigger encoding of the redundancy flag, but this is a much looser + restriction. + + + +After determining the size of the redundant CELT frame, the decoder reduces + the size of the buffer currently in use by the range coder by that amount. +The CELT layer read any raw bits from the end of this reduced buffer, and all + calculations of the number of bits remaining in the buffer must be done using + this new, reduced size, rather than the original size of the Opus frame. + +
+ +
+ +The redundant frame is decoded like any other CELT-only frame, with the + exception that it does not contain a TOC byte. +The frame size is fixed at 5 ms, the channel count is set to that of the + current frame, and the audio bandwidth is also set to that of the current + frame, with the exception that for MB SILK frames, it is set to WB. + + + +If the redundancy belongs at the beginning (in a CELT-only to SILK-only or + Hybrid transition), the final reconstructed output uses the first 2.5 ms + of audio output by the decoder for the redundant frame as-is, discarding + the corresponding output from the SILK-only or Hybrid portion of the frame. +The remaining 2.5 ms is cross-lapped with the decoded SILK/Hybrid signal + using the CELT's power-complementary MDCT window to ensure a smooth + transition. + + + +If the redundancy belongs at the end (in a SILK-only or Hybrid to CELT-only + transition), only the second half (2.5 ms) of the audio output by the + decoder for the redundant frame is used. +In that case, the second half of the redundant frame is cross-lapped with the + end of the SILK/Hybrid signal, again using CELT's power-complementary MDCT + window to ensure a smooth transition. + +
+ +
+ +
+ +When a transition occurs, the state of the SILK or the CELT decoder (or both) + may need to be reset before decoding a frame in the new mode. +This avoids reusing "out of date" memory, which may not have been updated in + some time or may not be in a well-defined state due to, e.g., PLC. +The SILK state is reset before every SILK-only or Hybrid frame where the + previous frame was CELT-only. +The CELT state is reset every time the operating mode changes and the new mode + is either Hybrid or CELT-only, except when the transition uses redundancy as + described above. +When switching from SILK-only or Hybrid to CELT-only with redundancy, the CELT + state is reset before decoding the redundant CELT frame embedded in the + SILK-only or Hybrid frame, but it is not reset before decoding the following + CELT-only frame. +When switching from CELT-only mode to SILK-only or Hybrid mode with redundancy, + the CELT decoder is not reset for decoding the redundant CELT frame. + +
+ +
+ + + illustrates all of the normative + transitions involving a mode change, an audio bandwidth change, or both. +Each one uses an S, H, or C to represent an Opus frame in the corresponding + mode. +In addition, an R indicates the presence of redundancy in the Opus frame it is + cross-lapped with. +Its location in the first or last 5 ms is assumed to correspond to whether + it is the frame before or after the transition. +Other uses of redundancy are non-normative. +Finally, a c indicates the contents of the CELT overlap buffer after the + previously decoded frame (i.e., as extracted by decoding a silence frame). +
+ S -> S + & + !R -> R + & + ;S -> S -> S + +NB or MB SILK to Hybrid with Redundancy: S -> S -> S + & + !R ->;H -> H -> H + +WB SILK to Hybrid: S -> S -> S ->!H -> H -> H + +SILK to CELT with Redundancy: S -> S -> S + & + !R -> C -> C -> C + +Hybrid to NB or MB SILK with Redundancy: H -> H -> H + & + !R -> R + & + ;S -> S -> S + +Hybrid to WB SILK: H -> H -> H -> c + \ + + > S -> S -> S + +Hybrid to CELT with Redundancy: H -> H -> H + & + !R -> C -> C -> C + +CELT to SILK with Redundancy: C -> C -> C -> R + & + ;S -> S -> S + +CELT to Hybrid with Redundancy: C -> C -> C -> R + & + |H -> H -> H + +Key: +S SILK-only frame ; SILK decoder reset +H Hybrid frame | CELT and SILK decoder resets +C CELT-only frame ! CELT decoder reset +c CELT overlap + Direct mixing +R Redundant CELT frame & Windowed cross-lap +]]> +
+The first two and the last two Opus frames in each example are illustrative, + i.e., there is no requirement that a stream remain in the same configuration + for three consecutive frames before or after a switch. +
+ + +The behavior of transitions without redundancy where PLC is allowed is non-normative. +An encoder might still wish to use these transitions if, for example, it + doesn't want to add the extra bitrate required for redundancy or if it makes + a decision to switch after it has already transmitted the frame that would + have had to contain the redundancy. + illustrates the recommended + cross-lapping and decoder resets for these transitions. +
+ S -> S ;S -> S -> S + +NB or MB SILK to Hybrid: S -> S -> S |H -> H -> H + +SILK to CELT without Redundancy: S -> S -> S -> P + & + !C -> C -> C + +Hybrid to NB or MB SILK: H -> H -> H -> c + + + ;S -> S -> S + +Hybrid to CELT without Redundancy: H -> H -> H -> P + & + !C -> C -> C + +CELT to SILK without Redundancy: C -> C -> C -> P + & + ;S -> S -> S + +CELT to Hybrid without Redundancy: C -> C -> C -> P + & + |H -> H -> H + +Key: +S SILK-only frame ; SILK decoder reset +H Hybrid frame | CELT and SILK decoder resets +C CELT-only frame ! CELT decoder reset +c CELT overlap + Direct mixing +P Packet Loss Concealment & Windowed cross-lap +]]> +
+Encoders SHOULD NOT use other transitions, e.g., those that involve redundancy + in ways not illustrated in . +
+ +
+ +
+ +
+ + + + + + +
+ +Just like the decoder, the Opus encoder also normally consists of two main blocks: the +SILK encoder and the CELT encoder. However, unlike the case of the decoder, a valid +(though potentially suboptimal) Opus encoder is not required to support all modes and +may thus only include a SILK encoder module or a CELT encoder module. +The output bit-stream of the Opus encoding contains bits from the SILK and CELT + encoders, though these are not separable due to the use of a range coder. +A block diagram of the encoder is illustrated below. + +
+ +| Rate |--->| Encoder | V + +-----------+ | | Conversion | | | +---------+ + | Optional | | +------------+ +---------+ | Range | +->| High-pass |--+ | Encoder |----> + | Filter | | +--------------+ +---------+ | | Bit- + +-----------+ | | Delay | | CELT | +---------+ stream + +->| Compensation |->| Encoder | ^ + | | | |------+ + +--------------+ +---------+ +]]> + +
+
+ + +For a normal encoder where both the SILK and the CELT modules are included, an optimal +encoder should select which coding mode to use at run-time depending on the conditions. +In the reference implementation, the frame size is selected by the application, but the +other configuration parameters (number of channels, bandwidth, mode) are automatically +selected (unless explicitly overridden by the application) depend on the following: + +Requested bitrate +Input sampling rate +Type of signal (speech vs music) +Frame size in use + + +The type of signal currently needs to be provided by the application (though it can be +changed in real-time). An Opus encoder implementation could also do automatic detection, +but since Opus is an interactive codec, such an implementation would likely have to either +delay the signal (for non-interactive applications) or delay the mode switching decisions (for +interactive applications). + + + +When the encoder is configured for voice over IP applications, the input signal is +filtered by a high-pass filter to remove the lowest part of the spectrum +that contains little speech energy and may contain background noise. This is a second order +Auto Regressive Moving Average (i.e., with poles and zeros) filter with a cut-off frequency around 50 Hz. +In the future, a music detector may also be used to lower the cut-off frequency when the +input signal is detected to be music rather than speech. + + +
+ +The range coder acts as the bit-packer for Opus. +It is used in three different ways: to encode + + +Entropy-coded symbols with a fixed probability model using ec_encode() + (entenc.c), + + +Integers from 0 to (2**M - 1) using ec_enc_uint() or ec_enc_bits() + (entenc.c), + +Integers from 0 to (ft - 1) (where ft is not a power of two) using + ec_enc_uint() (entenc.c). + + + + + +The range encoder maintains an internal state vector composed of the four-tuple + (val, rng, rem, ext) representing the low end of the current + range, the size of the current range, a single buffered output byte, and a + count of additional carry-propagating output bytes. +Both val and rng are 32-bit unsigned integer values, rem is a byte value or + less than 255 or the special value -1, and ext is an unsigned integer with at + least 11 bits. +This state vector is initialized at the start of each each frame to the value + (0, 2**31, -1, 0). +After encoding a sequence of symbols, the value of rng in the encoder should + exactly match the value of rng in the decoder after decoding the same sequence + of symbols. +This is a powerful tool for detecting errors in either an encoder or decoder + implementation. +The value of val, on the other hand, represents different things in the encoder + and decoder, and is not expected to match. + + + +The decoder has no analog for rem and ext. +These are used to perform carry propagation in the renormalization loop below. +Each iteration of this loop produces 9 bits of output, consisting of 8 data + bits and a carry flag. +The encoder cannot determine the final value of the output bytes until it + propagates these carry flags. +Therefore the reference implementation buffers a single non-propagating output + byte (i.e., one less than 255) in rem and keeps a count of additional + propagating (i.e., 255) output bytes in ext. +An implementation may choose to use any mathematically equivalent scheme to + perform carry propagation. + + +
+ +The main encoding function is ec_encode() (entenc.c), which encodes symbol k in + the current context using the same three-tuple (fl[k], fh[k], ft) + as the decoder to describe the range of the symbol (see + ). + + +ec_encode() updates the state of the encoder as follows. +If fl[k] is greater than zero, then +
+ +
+Otherwise, val is unchanged and +
+ +
+The divisions here are integer division. +
+ +
+ +After this update, the range is normalized using a procedure very similar to + that of , implemented by + ec_enc_normalize() (entenc.c). +The following process is repeated until rng > 2**23. +First, the top 9 bits of val, (val>>23), are sent to the carry buffer, + described in . +Then, the encoder sets +
+ +
+
+
+ +
+ +The function ec_enc_carry_out() (entenc.c) implements carry propagation and + output buffering. +It takes as input a 9-bit value, c, consisting of 8 data bits and an additional + carry bit. +If c is equal to the value 255, then ext is simply incremented, and no other + state updates are performed. +Otherwise, let b = (c>>8) be the carry bit. +Then, + + +If the buffered byte rem contains a value other than -1, the encoder outputs + the byte (rem + b). +Otherwise, if rem is -1, no byte is output. + + +If ext is non-zero, then the encoder outputs ext bytes---all with a value of 0 + if b is set, or 255 if b is unset---and sets ext to 0. + + +rem is set to the 8 data bits: +
+ +
+
+
+
+
+ +
+ +
+ +The reference implementation uses three additional encoding methods that are + exactly equivalent to the above, but make assumptions and simplifications that + allow for a more efficient implementation. + + +
+ +The first is ec_encode_bin() (entenc.c), defined using the parameter ftb + instead of ft. +It is mathematically equivalent to calling ec_encode() with + ft = (1<<ftb), but avoids using division. + +
+ +
+ +The next is ec_enc_bit_logp() (entenc.c), which encodes a single binary symbol. +The context is described by a single parameter, logp, which is the absolute + value of the base-2 logarithm of the probability of a "1". +It is mathematically equivalent to calling ec_encode() with the 3-tuple + (fl[k] = 0, fh[k] = (1<<logp) - 1, + ft = (1<<logp)) if k is 0 and with + (fl[k] = (1<<logp) - 1, + fh[k] = ft = (1<<logp)) if k is 1. +The implementation requires no multiplications or divisions. + +
+ +
+ +The last is ec_enc_icdf() (entenc.c), which encodes a single binary symbol with + a table-based context of up to 8 bits. +This uses the same icdf table as ec_dec_icdf() from + . +The function is mathematically equivalent to calling ec_encode() with + fl[k] = (1<<ftb) - icdf[k-1] (or 0 if + k == 0), fh[k] = (1<<ftb) - icdf[k], and + ft = (1<<ftb). +This only saves a few arithmetic operations over ec_encode_bin(), but allows + the encoder to use the same icdf tables as the decoder. + +
+ +
+ +
+ +The raw bits used by the CELT layer are packed at the end of the buffer using + ec_enc_bits() (entenc.c). +Because the raw bits may continue into the last byte output by the range coder + if there is room in the low-order bits, the encoder must be prepared to merge + these values into a single byte. +The procedure in does this in a way that + ensures both the range coded data and the raw bits can be decoded + successfully. + +
+ +
+ +The function ec_enc_uint() (entenc.c) encodes one of ft equiprobable symbols in + the range 0 to (ft - 1), inclusive, each with a frequency of 1, + where ft may be as large as (2**32 - 1). +Like the decoder (see ), it splits up the + value into a range coded symbol representing up to 8 of the high bits, and, if + necessary, raw bits representing the remainder of the value. + + +ec_enc_uint() takes a two-tuple (t, ft), where t is the value to be + encoded, 0 <= t < ft, and ft is not necessarily a + power of two. +Let ftb = ilog(ft - 1), i.e., the number of bits required + to store (ft - 1) in two's complement notation. +If ftb is 8 or less, then t is encoded directly using ec_encode() with the + three-tuple (t, t + 1, ft). + + +If ftb is greater than 8, then the top 8 bits of t are encoded using the + three-tuple (t>>(ftb - 8), + (t>>(ftb - 8)) + 1, + ((ft - 1)>>(ftb - 8)) + 1), and the + remaining bits, + (t & ((1<<(ftb - 8)) - 1), + are encoded as raw bits with ec_enc_bits(). + +
+ +
+ +After all symbols are encoded, the stream must be finalized by outputting a + value inside the current range. +Let end be the integer in the interval [val, val + rng) with the + largest number of trailing zero bits, b, such that + (end + (1<<b) - 1) is also in the interval + [val, val + rng). +This choice of end allows the maximum number of trailing bits to be set to + arbitrary values while still ensuring the range coded part of the buffer can + be decoded correctly. +Then, while end is not zero, the top 9 bits of end, i.e., (end>>23), are + passed to the carry buffer in accordance with the procedure in + , and end is updated via +
+ +
+Finally, if the buffered output byte, rem, is neither zero nor the special + value -1, or the carry count, ext, is greater than zero, then 9 zero bits are + sent to the carry buffer to flush it to the output buffer. +When outputting the final byte from the range coder, if it would overlap any + raw bits already packed into the end of the output buffer, they should be ORed + into the same byte. +The bit allocation routines in the CELT layer should ensure that this can be + done without corrupting the range coder data so long as end is chosen as + described above. +If there is any space between the end of the range coder data and the end of + the raw bits, it is padded with zero bits. +This entire process is implemented by ec_enc_done() (entenc.c). +
+
+ +
+ + The bit allocation routines in Opus need to be able to determine a + conservative upper bound on the number of bits that have been used + to encode the current frame thus far. This drives allocation + decisions and ensures that the range coder and raw bits will not + overflow the output buffer. This is computed in the + reference implementation to whole-bit precision by + the function ec_tell() (entcode.h) and to fractional 1/8th bit + precision by the function ec_tell_frac() (entcode.c). + Like all operations in the range coder, it must be implemented in a + bit-exact manner, and must produce exactly the same value returned by + the same functions in the decoder after decoding the same symbols. + +
+ +
+ +
+ + In many respects the SILK encoder mirrors the SILK decoder described + in . + Details such as the quantization and range coder tables can be found + there, while this section describes the high-level design choices that + were made. + The diagram below shows the basic modules of the SILK encoder. +
+ +| Rate |--->| Mixing |--->| Core |----------> +Input |Conversion| | | | Encoder | Bitstream + +----------+ +--------+ +---------+ +]]> + +
+
+ +
+ +The input signal's sampling rate is adjusted by a sample rate conversion +module so that it matches the SILK internal sampling rate. +The input to the sample rate converter is delayed by a number of samples +depending on the sample rate ratio, such that the overall delay is constant +for all input and output sample rates. + +
+ +
+ +The stereo mixer is only used for stereo input signals. +It converts a stereo left/right signal into an adaptive +mid/side representation. +The first step is to compute non-adaptive mid/side signals +as half the sum and difference between left and right signals. +The side signal is then minimized in energy by subtracting a +prediction of it based on the mid signal. +This prediction works well when the left and right signals +exhibit linear dependency, for instance for an amplitude-panned +input signal. +Like in the decoder, the prediction coefficients are linearly +interpolated during the first 8 ms of the frame. + The mid signal is always encoded, whereas the residual + side signal is only encoded if it has sufficient + energy compared to the mid signal's energy. + If it has not, + the "mid_only_flag" is set without encoding the side signal. + + +The predictor coefficients are coded regardless of whether +the side signal is encoded. +For each frame, two predictor coefficients are computed, one +that predicts between low-passed mid and side channels, and +one that predicts between high-passed mid and side channels. +The low-pass filter is a simple three-tap filter +and creates a delay of one sample. +The high-pass filtered signal is the difference between +the mid signal delayed by one sample and the low-passed +signal. Instead of explicitly computing the high-passed +signal, it is computationally more efficient to transform +the prediction coefficients before applying them to the +filtered mid signal, as follows +
+ + + +
+where w0 and w1 are the low-pass and high-pass prediction +coefficients, mid(n-1) is the mid signal delayed by one sample, +LP(n) and HP(n) are the low-passed and high-passed +signals and pred(n) is the prediction signal that is subtracted +from the side signal. +
+
+ +
+ +What follows is a description of the core encoder and its components. +For simplicity, the core encoder is referred to simply as the encoder in +the remainder of this section. An overview of the encoder is given in +. + +
+ +| | + +---------+ | +---------+ | | + |Voice | | |LTP |12 | | + +-->|Activity |--+ +----->|Scaling |-----------+---->| | + | |Detector |3 | | |Control |<--+ | | | + | +---------+ | | +---------+ | | | | + | | | +---------+ | | | | + | | | |Gains | | | | | + | | | +-->|Processor|---|---+---|---->| R | + | | | | | |11 | | | | a | + | \/ | | +---------+ | | | | n | + | +---------+ | | +---------+ | | | | g | + | |Pitch | | | |LSF | | | | | e | + | +->|Analysis |---+ | |Quantizer|---|---|---|---->| | + | | | |4 | | | |8 | | | | E |--> + | | +---------+ | | +---------+ | | | | n | 2 + | | | | 9/\ 10| | | | | c | + | | | | | \/ | | | | o | + | | +---------+ | | +----------+ | | | | d | + | | |Noise | +--|-->|Prediction|--+---|---|---->| e | + | +->|Shaping |---|--+ |Analysis |7 | | | | r | + | | |Analysis |5 | | | | | | | | | + | | +---------+ | | +----------+ | | | | | + | | | | /\ | | | | | + | | +----------|--|--------+ | | | | | + | | | \/ \/ \/ \/ \/ | | + | | | +---------+ +------------+ | | + | | | | | |Noise | | | +-+-------+-----+------>|Prefilter|--------->|Shaping |-->| | +1 | | 6 |Quantization|13 | | + +---------+ +------------+ +---+ + +1: Input speech signal +2: Range encoded bitstream +3: Voice activity estimate +4: Pitch lags (per 5 ms) and voicing decision (per 20 ms) +5: Noise shaping quantization coefficients + - Short term synthesis and analysis + noise shaping coefficients (per 5 ms) + - Long term synthesis and analysis noise + shaping coefficients (per 5 ms and for voiced speech only) + - Noise shaping tilt (per 5 ms) + - Quantizer gain/step size (per 5 ms) +6: Input signal filtered with analysis noise shaping filters +7: Short and long term prediction coefficients + LTP (per 5 ms) and LPC (per 20 ms) +8: LSF quantization indices +9: LSF coefficients +10: Quantized LSF coefficients +11: Processed gains, and synthesis noise shape coefficients +12: LTP state scaling coefficient. Controlling error propagation + / prediction gain trade-off +13: Quantized signal +]]> + +
+ +
+ +The input signal is processed by a Voice Activity Detector (VAD) to produce +a measure of voice activity, spectral tilt, and signal-to-noise estimates for +each frame. The VAD uses a sequence of half-band filterbanks to split the +signal into four subbands: 0...Fs/16, Fs/16...Fs/8, Fs/8...Fs/4, and +Fs/4...Fs/2, where Fs is the sampling frequency (8, 12, 16, or 24 kHz). +The lowest subband, from 0 - Fs/16, is high-pass filtered with a first-order +moving average (MA) filter (with transfer function H(z) = 1-z**(-1)) to +reduce the energy at the lowest frequencies. For each frame, the signal +energy per subband is computed. +In each subband, a noise level estimator tracks the background noise level +and a Signal-to-Noise Ratio (SNR) value is computed as the logarithm of the +ratio of energy to noise level. +Using these intermediate variables, the following parameters are calculated +for use in other SILK modules: + + +Average SNR. The average of the subband SNR values. + + + +Smoothed subband SNRs. Temporally smoothed subband SNR values. + + + +Speech activity level. Based on the average SNR and a weighted average of the +subband energies. + + + +Spectral tilt. A weighted average of the subband SNRs, with positive weights +for the low subbands and negative weights for the high subbands. + + + +
+ +
+ +The input signal is processed by the open loop pitch estimator shown in +. +
+ +|sampling|->|Correlator| | + | | | | | |4 + | +--------+ +----------+ \/ + | | 2 +-------+ + | | +-->|Speech |5 + +---------+ +--------+ | \/ | |Type |-> + |LPC | |Down | | +----------+ | | + +->|Analysis | +->|sample |-+------------->|Time- | +-------+ + | | | | |to 8 kHz| |Correlator|-----------> + | +---------+ | +--------+ |__________| 6 + | | | |3 + | \/ | \/ + | +---------+ | +----------+ + | |Whitening| | |Time- | +-+->|Filter |-+--------------------------->|Correlator|-----------> +1 | | | | 7 + +---------+ +----------+ + +1: Input signal +2: Lag candidates from stage 1 +3: Lag candidates from stage 2 +4: Correlation threshold +5: Voiced/unvoiced flag +6: Pitch correlation +7: Pitch lags +]]> + +
+The pitch analysis finds a binary voiced/unvoiced classification, and, for +frames classified as voiced, four pitch lags per frame - one for each +5 ms subframe - and a pitch correlation indicating the periodicity of +the signal. +The input is first whitened using a Linear Prediction (LP) whitening filter, +where the coefficients are computed through standard Linear Prediction Coding +(LPC) analysis. The order of the whitening filter is 16 for best results, but +is reduced to 12 for medium complexity and 8 for low complexity modes. +The whitened signal is analyzed to find pitch lags for which the time +correlation is high. +The analysis consists of three stages for reducing the complexity: + +In the first stage, the whitened signal is downsampled to 4 kHz +(from 8 kHz) and the current frame is correlated to a signal delayed +by a range of lags, starting from a shortest lag corresponding to +500 Hz, to a longest lag corresponding to 56 Hz. + + +The second stage operates on an 8 kHz signal (downsampled from 12, 16, +or 24 kHz) and measures time correlations only near the lags +corresponding to those that had sufficiently high correlations in the first +stage. The resulting correlations are adjusted for a small bias towards +short lags to avoid ending up with a multiple of the true pitch lag. +The highest adjusted correlation is compared to a threshold depending on: + + +Whether the previous frame was classified as voiced + + +The speech activity level + + +The spectral tilt. + + +If the threshold is exceeded, the current frame is classified as voiced and +the lag with the highest adjusted correlation is stored for a final pitch +analysis of the highest precision in the third stage. + + +The last stage operates directly on the whitened input signal to compute time +correlations for each of the four subframes independently in a narrow range +around the lag with highest correlation from the second stage. + + +
+
+ +
+ +The noise shaping analysis finds gains and filter coefficients used in the +prefilter and noise shaping quantizer. These parameters are chosen such that +they will fulfill several requirements: + + +Balancing quantization noise and bitrate. +The quantization gains determine the step size between reconstruction levels +of the excitation signal. Therefore, increasing the quantization gain +amplifies quantization noise, but also reduces the bitrate by lowering +the entropy of the quantization indices. + + +Spectral shaping of the quantization noise; the noise shaping quantizer is +capable of reducing quantization noise in some parts of the spectrum at the +cost of increased noise in other parts without substantially changing the +bitrate. +By shaping the noise such that it follows the signal spectrum, it becomes +less audible. In practice, best results are obtained by making the shape +of the noise spectrum slightly flatter than the signal spectrum. + + +De-emphasizing spectral valleys; by using different coefficients in the +analysis and synthesis part of the prefilter and noise shaping quantizer, +the levels of the spectral valleys can be decreased relative to the levels +of the spectral peaks such as speech formants and harmonics. +This reduces the entropy of the signal, which is the difference between the +coded signal and the quantization noise, thus lowering the bitrate. + + +Matching the levels of the decoded speech formants to the levels of the +original speech formants; an adjustment gain and a first order tilt +coefficient are computed to compensate for the effect of the noise +shaping quantization on the level and spectral tilt. + + + + +
+ + + Frequency + +1: Input signal spectrum +2: De-emphasized and level matched spectrum +3: Quantization noise spectrum +]]> + +
+ shows an example of an +input signal spectrum (1). +After de-emphasis and level matching, the spectrum has deeper valleys (2). +The quantization noise spectrum (3) more or less follows the input signal +spectrum, while having slightly less pronounced peaks. +The entropy, which provides a lower bound on the bitrate for encoding the +excitation signal, is proportional to the area between the de-emphasized +spectrum (2) and the quantization noise spectrum (3). Without de-emphasis, +the entropy is proportional to the area between input spectrum (1) and +quantization noise (3) - clearly higher. +
+ + +The transformation from input signal to de-emphasized signal can be +described as a filtering operation with a filter +
+ + + +
+having an adjustment gain G, a first order tilt adjustment filter with +tilt coefficient c_tilt, and where +
+ + + +
+is the analysis part of the de-emphasis filter, consisting of the short-term +shaping filter with coefficients a_ana(k), and the long-term shaping filter +with coefficients b_ana(k) and pitch lag L. +The parameter d determines the number of long-term shaping filter taps. +
+ + +Similarly, but without the tilt adjustment, the synthesis part can be written as +
+ + + +
+
+ +All noise shaping parameters are computed and applied per subframe of 5 ms. +First, an LPC analysis is performed on a windowed signal block of 15 ms. +The signal block has a look-ahead of 5 ms relative to the current subframe, +and the window is an asymmetric sine window. The LPC analysis is done with the +autocorrelation method, with an order of between 8, in lowest-complexity mode, +and 16, for best quality. + + +Optionally the LPC analysis and noise shaping filters are warped by replacing +the delay elements by first-order allpass filters. +This increases the frequency resolution at low frequencies and reduces it at +high ones, which better matches the human auditory system and improves +quality. +The warped analysis and filtering comes at a cost in complexity +and is therefore only done in higher complexity modes. + + +The quantization gain is found by taking the square root of the residual energy +from the LPC analysis and multiplying it by a value inversely proportional +to the coding quality control parameter and the pitch correlation. + + +Next the two sets of short-term noise shaping coefficients a_ana(k) and +a_syn(k) are obtained by applying different amounts of bandwidth expansion to the +coefficients found in the LPC analysis. +This bandwidth expansion moves the roots of the LPC polynomial towards the +origin, using the formulas +
+ + + +
+where a(k) is the k'th LPC coefficient, and the bandwidth expansion factors +g_ana and g_syn are calculated as +
+ + + +
+where C is the coding quality control parameter between 0 and 1. +Applying more bandwidth expansion to the analysis part than to the synthesis +part gives the desired de-emphasis of spectral valleys in between formants. +
+ + +The long-term shaping is applied only during voiced frames. +It uses three filter taps, described by +
+ + + +
+For unvoiced frames these coefficients are set to 0. The multiplication factors +F_ana and F_syn are chosen between 0 and 1, depending on the coding quality +control parameter, as well as the calculated pitch correlation and smoothed +subband SNR of the lowest subband. By having F_ana less than F_syn, +the pitch harmonics are emphasized relative to the valleys in between the +harmonics. +
+ + +The tilt coefficient c_tilt is for unvoiced frames chosen as +
+ + + +
+and as +
+ + + +
+for voiced frames, where V is the voice activity level between 0 and 1. +
+ +The adjustment gain G serves to correct any level mismatch between the original +and decoded signals that might arise from the noise shaping and de-emphasis. +This gain is computed as the ratio of the prediction gain of the short-term +analysis and synthesis filter coefficients. The prediction gain of an LPC +synthesis filter is the square root of the output energy when the filter is +excited by a unit-energy impulse on the input. +An efficient way to compute the prediction gain is by first computing the +reflection coefficients from the LPC coefficients through the step-down +algorithm, and extracting the prediction gain from the reflection coefficients +as +
+ + + +
+where r_k is the k'th reflection coefficient. +
+ + +Initial values for the quantization gains are computed as the square-root of +the residual energy of the LPC analysis, adjusted by the coding quality control +parameter. +These quantization gains are later adjusted based on the results of the +prediction analysis. + +
+ +
+ +The prediction analysis is performed in one of two ways depending on how +the pitch estimator classified the frame. +The processing for voiced and unvoiced speech is described in + and + , respectively. + Inputs to this function include the pre-whitened signal from the + pitch estimator (see ). + + +
+ + For a frame of voiced speech the pitch pulses will remain dominant in the + pre-whitened input signal. + Further whitening is desirable as it leads to higher quality at the same + available bitrate. + To achieve this, a Long-Term Prediction (LTP) analysis is carried out to + estimate the coefficients of a fifth-order LTP filter for each of four + subframes. + The LTP coefficients are quantized using the method described in + , and the quantized LTP + coefficients are used to compute the LTP residual signal. + This LTP residual signal is the input to an LPC analysis where the LPC coefficients are + estimated using Burg's method , such that the residual energy is minimized. + The estimated LPC coefficients are converted to a Line Spectral Frequency (LSF) vector + and quantized as described in . +After quantization, the quantized LSF vector is converted back to LPC +coefficients using the full procedure in . +By using quantized LTP coefficients and LPC coefficients derived from the +quantized LSF coefficients, the encoder remains fully synchronized with the +decoder. +The quantized LPC and LTP coefficients are also used to filter the input +signal and measure residual energy for each of the four subframes. + +
+
+ +For a speech signal that has been classified as unvoiced, there is no need +for LTP filtering, as it has already been determined that the pre-whitened +input signal is not periodic enough within the allowed pitch period range +for LTP analysis to be worth the cost in terms of complexity and bitrate. +The pre-whitened input signal is therefore discarded, and instead the input +signal is used for LPC analysis using Burg's method. +The resulting LPC coefficients are converted to an LSF vector and quantized +as described in the following section. +They are then transformed back to obtain quantized LPC coefficients, which +are then used to filter the input signal and measure residual energy for +each of the four subframes. + +
+ +The main purpose of linear prediction in SILK is to reduce the bitrate by +minimizing the residual energy. +At least at high bitrates, perceptual aspects are handled +independently by the noise shaping filter. +Burg's method is used because it provides higher prediction gain +than the autocorrelation method and, unlike the covariance method, +produces stable filters (assuming numerical errors don't spoil +that). SILK's implementation of Burg's method is also computationally +faster than the autocovariance method. +The implementation of Burg's method differs from traditional +implementations in two aspects. +The first difference is that it +operates on autocorrelations, similar to the Schur algorithm , but +with a simple update to the autocorrelations after finding each +reflection coefficient to make the result identical to Burg's method. +This brings down the complexity of Burg's method to near that of +the autocorrelation method. +The second difference is that the signal in each subframe is scaled +by the inverse of the residual quantization step size. Subframes with +a small quantization step size will on average spend more bits for a +given amount of residual energy than subframes with a large step size. +Without scaling, Burg's method minimizes the total residual energy in +all subframes, which doesn't necessarily minimize the total number of +bits needed for coding the quantized residual. The residual energy +of the scaled subframes is a better measure for that number of +bits. + +
+
+
+ +
+ +Unlike many other speech codecs, SILK uses variable bitrate coding +for the LSFs. +This improves the average rate-distortion (R-D) tradeoff and reduces outliers. +The variable bitrate coding minimizes a linear combination of the weighted +quantization errors and the bitrate. +The weights for the quantization errors are the Inverse +Harmonic Mean Weighting (IHMW) function proposed by Laroia et al. +(see ). +These weights are referred to here as Laroia weights. + + +The LSF quantizer consists of two stages. +The first stage is an (unweighted) vector quantizer (VQ), with a +codebook size of 32 vectors. +The quantization errors for the codebook vector are sorted, and +for the N best vectors a second stage quantizer is run. +By varying the number N a tradeoff is made between R-D performance +and computational efficiency. +For each of the N codebook vectors the Laroia weights corresponding +to that vector (and not to the input vector) are calculated. +Then the residual between the input LSF vector and the codebook +vector is scaled by the square roots of these Laroia weights. +This scaling partially normalizes error sensitivity for the +residual vector, so that a uniform quantizer with fixed +step sizes can be used in the second stage without too much +performance loss. +And by scaling with Laroia weights determined from the first-stage +codebook vector, the process can be reversed in the decoder. + + +The second stage uses predictive delayed decision scalar +quantization. +The quantization error is weighted by Laroia weights determined +from the LSF input vector. +The predictor multiplies the previous quantized residual value +by a prediction coefficient that depends on the vector index from the +first stage VQ and on the location in the LSF vector. +The prediction is subtracted from the LSF residual value before +quantizing the result, and added back afterwards. +This subtraction can be interpreted as shifting the quantization levels +of the scalar quantizer, and as a result the quantization error of +each value depends on the quantization decision of the previous value. +This dependency is exploited by the delayed decision mechanism to +search for a quantization sequency with best R-D performance +with a Viterbi-like algorithm . +The quantizer processes the residual LSF vector in reverse order +(i.e., it starts with the highest residual LSF value). +This is done because the prediction works slightly +better in the reverse direction. + + +The quantization index of the first stage is entropy coded. +The quantization sequence from the second stage is also entropy +coded, where for each element the probability table is chosen +depending on the vector index from the first stage and the location +of that element in the LSF vector. + + +
+ +If the input is stable, finding the best candidate usually results in a +quantized vector that is also stable. Because of the two-stage approach, +however, it is possible that the best quantization candidate is unstable. +The encoder applies the same stabilization procedure applied by the decoder + (see to ensure the LSF parameters + are within their valid range, increasingly sorted, and have minimum + distances between each other and the border values. + +
+
+ +
+ +For voiced frames, the prediction analysis described in + resulted in four sets +(one set per subframe) of five LTP coefficients, plus four weighting matrices. +The LTP coefficients for each subframe are quantized using entropy constrained +vector quantization. +A total of three vector codebooks are available for quantization, with +different rate-distortion trade-offs. The three codebooks have 10, 20, and +40 vectors and average rates of about 3, 4, and 5 bits per vector, respectively. +Consequently, the first codebook has larger average quantization distortion at +a lower rate, whereas the last codebook has smaller average quantization +distortion at a higher rate. +Given the weighting matrix W_ltp and LTP vector b, the weighted rate-distortion +measure for a codebook vector cb_i with rate r_i is give by +
+ + + +
+where u is a fixed, heuristically-determined parameter balancing the distortion +and rate. +Which codebook gives the best performance for a given LTP vector depends on the +weighting matrix for that LTP vector. +For example, for a low valued W_ltp, it is advantageous to use the codebook +with 10 vectors as it has a lower average rate. +For a large W_ltp, on the other hand, it is often better to use the codebook +with 40 vectors, as it is more likely to contain the best codebook vector. +The weighting matrix W_ltp depends mostly on two aspects of the input signal. +The first is the periodicity of the signal; the more periodic, the larger W_ltp. +The second is the change in signal energy in the current subframe, relative to +the signal one pitch lag earlier. +A decaying energy leads to a larger W_ltp than an increasing energy. +Both aspects fluctuate relatively slowly, which causes the W_ltp matrices for +different subframes of one frame often to be similar. +Because of this, one of the three codebooks typically gives good performance +for all subframes, and therefore the codebook search for the subframe LTP +vectors is constrained to only allow codebook vectors to be chosen from the +same codebook, resulting in a rate reduction. +
+ + +To find the best codebook, each of the three vector codebooks is +used to quantize all subframe LTP vectors and produce a combined +weighted rate-distortion measure for each vector codebook. +The vector codebook with the lowest combined rate-distortion +over all subframes is chosen. The quantized LTP vectors are used +in the noise shaping quantizer, and the index of the codebook +plus the four indices for the four subframe codebook vectors +are passed on to the range encoder. + +
+ +
+ +In the prefilter the input signal is filtered using the spectral valley +de-emphasis filter coefficients from the noise shaping analysis +(see ). +By applying only the noise shaping analysis filter to the input signal, +it provides the input to the noise shaping quantizer. + +
+ +
+ +The noise shaping quantizer independently shapes the signal and coding noise +spectra to obtain a perceptually higher quality at the same bitrate. + + +The prefilter output signal is multiplied with a compensation gain G computed +in the noise shaping analysis. Then the output of a synthesis shaping filter +is added, and the output of a prediction filter is subtracted to create a +residual signal. +The residual signal is multiplied by the inverse quantized quantization gain +from the noise shaping analysis, and input to a scalar quantizer. +The quantization indices of the scalar quantizer represent a signal of pulses +that is input to the pyramid range encoder. +The scalar quantizer also outputs a quantization signal, which is multiplied +by the quantized quantization gain from the noise shaping analysis to create +an excitation signal. +The output of the prediction filter is added to the excitation signal to form +the quantized output signal y(n). +The quantized output signal y(n) is input to the synthesis shaping and +prediction filters. + + +Optionally the noise shaping quantizer operates in a delayed decision +mode. +In this mode it uses a Viterbi algorithm to keep track of +multiple rounding choices in the quantizer and select the best +one after a delay of 32 samples. This improves the rate/distortion +performance of the quantizer. + +
+ +
+ + SILK was designed to run in Variable Bitrate (VBR) mode. However + the reference implementation also has a Constant Bitrate (CBR) mode + for SILK. In CBR mode SILK will attempt to encode each packet with + no more than the allowed number of bits. The Opus wrapper code + then pads the bitstream if any unused bits are left in SILK mode, or + encodes the high band with the remaining number of bits in Hybrid mode. + The number of payload bits is adjusted by changing + the quantization gains and the rate/distortion tradeoff in the noise + shaping quantizer, in an iterative loop + around the noise shaping quantizer and entropy coding. + Compared to the SILK VBR mode, the CBR mode has lower + audio quality at a given average bitrate, and also has higher + computational complexity. + +
+ +
+ +
+ + +
+ +Most of the aspects of the CELT encoder can be directly derived from the description +of the decoder. For example, the filters and rotations in the encoder are simply the +inverse of the operation performed by the decoder. Similarly, the quantizers generally +optimize for the mean square error (because noise shaping is part of the bit-stream itself), +so no special search is required. For this reason, only the less straightforward aspects of the +encoder are described here. + + +
+The pitch prefilter is applied after the pre-emphasis. It is applied +in such a way as to be the inverse of the decoder's post-filter. The main non-obvious aspect of the +prefilter is the selection of the pitch period. The pitch search should be optimized for the +following criteria: + +continuity: it is important that the pitch period +does not change abruptly between frames; and +avoidance of pitch multiples: when the period used is a multiple of the real period +(lower frequency fundamental), the post-filter loses most of its ability to reduce noise + + +
+ +
+ +The MDCT output is divided into bands that are designed to match the ear's critical +bands for the smallest (2.5 ms) frame size. The larger frame sizes use integer +multiples of the 2.5 ms layout. For each band, the encoder +computes the energy that will later be encoded. Each band is then normalized by the +square root of the unquantized energy, such that each band now forms a unit vector X. +The energy and the normalization are computed by compute_band_energies() +and normalise_bands() (bands.c), respectively. + +
+ +
+ + +Energy quantization (both coarse and fine) can be easily understood from the decoding process. +For all useful bitrates, the coarse quantizer always chooses the quantized log energy value that +minimizes the error for each band. Only at very low rate does the encoder allow larger errors to +minimize the rate and avoid using more bits than are available. When the +available CPU requirements allow it, it is best to try encoding the coarse energy both with and without +inter-frame prediction such that the best prediction mode can be selected. The optimal mode depends on +the coding rate, the available bitrate, and the current rate of packet loss. + + +The fine energy quantizer always chooses the quantized log energy value that +minimizes the error for each band because the rate of the fine quantization depends only +on the bit allocation and not on the values that are coded. + +
+ +
+The encoder must use exactly the same bit allocation process as used by the decoder +and described in . The three mechanisms that can be used by the +encoder to adjust the bitrate on a frame-by-frame basis are band boost, allocation trim, +and band skipping. + + +
+The reference encoder makes a decision to boost a band when the energy of that band is significantly +higher than that of the neighboring bands. Let E_j be the log-energy of band j, we define + +D_j = 2*E_j - E_j-1 - E_j+1 + + +The allocation of band j is boosted once if D_j > t1 and twice if D_j > t2. For LM>=1, t1=2 and t2=4, +while for LM<1, t1=3 and t2=5. + + +
+ +
+The allocation trim is a value between 0 and 10 (inclusively) that controls the allocation +balance between the low and high frequencies. The encoder starts with a safe "default" of 5 +and deviates from that default in two different ways. First the trim can deviate by +/- 2 +depending on the spectral tilt of the input signal. For signals with more low frequencies, the +trim is increased by up to 2, while for signals with more high frequencies, the trim is +decreased by up to 2. +For stereo inputs, the trim value can +be decreased by up to 4 when the inter-channel correlation at low frequency (first 8 bands) +is high. +
+ +
+The encoder uses band skipping to ensure that the shape of the bands is only coded +if there is at least 1/2 bit per sample available for the PVQ. If not, then no bit is allocated +and folding is used instead. To ensure continuity in the allocation, some amount of hysteresis is +added to the process, such that a band that received PVQ bits in the previous frame only needs 7/16 +bit/sample to be coded for the current frame, while a band that did not receive PVQ bits in the +previous frames needs at least 9/16 bit/sample to be coded. +
+ +
+ +
+Because CELT applies mid-side stereo coupling in the normalized domain, it does not suffer from +important stereo image problems even when the two channels are completely uncorrelated. For this reason +it is always safe to use stereo coupling on any audio frame. That being said, there are some frames +for which dual (independent) stereo is still more efficient. This decision is made by comparing the estimated +entropy with and without coupling over the first 13 bands, taking into account the fact that all bands with +more than two MDCT bins require one extra degree of freedom when coded in mid-side. Let L1_ms and L1_lr +be the L1-norm of the mid-side vector and the L1-norm of the left-right vector, respectively. The decision +to use mid-side is made if and only if +
+ +
+where bins is the number of MDCT bins in the first 13 bands and E is the number of extra degrees of +freedom for mid-side coding. For LM>1, E=13, otherwise E=5. +
+ +The reference encoder decides on the intensity stereo threshold based on the bitrate alone. After +taking into account the frame size by subtracting 80 bits per frame for coarse energy, the first +band using intensity coding is as follows: + + + +bitrate (kb/s) +start band +<35 8 +35-50 12 +50-68 16 +84-84 18 +84-102 19 +102-130 20 +>130 disabled + + + +
+ +
+ +The choice of time-frequency resolution used in is based on +R-D optimization. The distortion is the L1-norm (sum of absolute values) of each band +after each TF resolution under consideration. The L1 norm is used because it represents the entropy +for a Laplacian source. The number of bits required to code a change in TF resolution between +two bands is higher than the cost of having those two bands use the same resolution, which is +what requires the R-D optimization. The optimal decision is computed using the Viterbi algorithm. +See tf_analysis() in celt/celt.c. + +
+ +
+ +The choice of the spreading value in has an +impact on the nature of the coding noise introduced by CELT. The larger the f_r value, the +lower the impact of the rotation, and the more tonal the coding noise. The +more tonal the signal, the more tonal the noise should be, so the CELT encoder determines +the optimal value for f_r by estimating how tonal the signal is. The tonality estimate +is based on discrete pdf (4-bin histogram) of each band. Bands that have a large number of small +values are considered more tonal and a decision is made by combining all bands with more than +8 samples. See spreading_decision() in celt/bands.c. + +
+ +
+CELT uses a Pyramid Vector Quantization (PVQ) +codebook for quantizing the details of the spectrum in each band that have not +been predicted by the pitch predictor. The PVQ codebook consists of all sums +of K signed pulses in a vector of N samples, where two pulses at the same position +are required to have the same sign. Thus the codebook includes +all integer codevectors y of N dimensions that satisfy sum(abs(y(j))) = K. + + + +In bands where there are sufficient bits allocated PVQ is used to encode +the unit vector that results from the normalization in + directly. Given a PVQ codevector y, +the unit vector X is obtained as X = y/||y||, where ||.|| denotes the +L2 norm. + + + +
+ + +The search for the best codevector y is performed by alg_quant() +(vq.c). There are several possible approaches to the +search, with a trade-off between quality and complexity. The method used in the reference +implementation computes an initial codeword y1 by projecting the normalized spectrum +X onto the codebook pyramid of K-1 pulses: + + +y0 = truncate_towards_zero( (K-1) * X / sum(abs(X))) + + + +Depending on N, K and the input data, the initial codeword y0 may contain from +0 to K-1 non-zero values. All the remaining pulses, with the exception of the last one, +are found iteratively with a greedy search that minimizes the normalized correlation +between y and X: +
+ +
+
+ + +The search described above is considered to be a good trade-off between quality +and computational cost. However, there are other possible ways to search the PVQ +codebook and the implementers MAY use any other search methods. See alg_quant() in celt/vq.c. + +
+ +
+ + +The vector to encode, X, is converted into an index i such that + 0 <= i < V(N,K) as follows. +Let i = 0 and k = 0. +Then for j = (N - 1) down to 0, inclusive, do: + + +If k > 0, set + i = i + (V(N-j-1,k-1) + V(N-j,k-1))/2. + +Set k = k + abs(X[j]). + +If X[j] < 0, set + i = i + (V(N-j-1,k) + V(N-j,k))/2. + + + + + +The index i is then encoded using the procedure in + with ft = V(N,K). + + +
+ +
+ + + + + +
+ +
+ + +
+ + +It is our intention to allow the greatest possible choice of freedom in +implementing the specification. For this reason, outside of the exceptions +noted in this section, conformance is defined through the reference +implementation of the decoder provided in . +Although this document includes an English description of the codec, should +the description contradict the source code of the reference implementation, +the latter shall take precedence. + + + +Compliance with this specification means that in addition to following the normative keywords in this document, + a decoder's output MUST also be + within the thresholds specified by the opus_compare.c tool (included + with the code) when compared to the reference implementation for each of the + test vectors provided (see ) and for each output + sampling rate and channel count supported. In addition, a compliant + decoder implementation MUST have the same final range decoder state as that of the + reference decoder. It is therefore RECOMMENDED that the + decoder implement the same functional behavior as the reference. + + A decoder implementation is not required to support all output sampling + rates or all output channel counts. + + +
+ +Using the reference code provided in , +a test vector can be decoded with + +opus_demo -d <rate> <channels> testvectorX.bit testX.out + +where <rate> is the sampling rate and can be 8000, 12000, 16000, 24000, or 48000, and +<channels> is 1 for mono or 2 for stereo. + + + +If the range decoder state is incorrect for one of the frames, the decoder will exit with +"Error: Range coder state mismatch between encoder and decoder". If the decoder succeeds, then +the output can be compared with the "reference" output with + +opus_compare -s -r <rate> testvectorX.dec testX.out + +for stereo or + +opus_compare -r <rate> testvectorX.dec testX.out + +for mono. + + +In addition to indicating whether the test vector comparison passes, the opus_compare tool +outputs an "Opus quality metric" that indicates how well the tested decoder matches the +reference implementation. A quality of 0 corresponds to the passing threshold, while +a quality of 100 is the highest possible value and means that the output of the tested decoder is identical to the reference +implementation. The passing threshold (quality 0) was calibrated in such a way that it corresponds to +additive white noise with a 48 dB SNR (similar to what can be obtained on a cassette deck). +It is still possible for an implementation to sound very good with such a low quality measure +(e.g. if the deviation is due to inaudible phase distortion), but unless this is verified by +listening tests, it is RECOMMENDED that implementations achieve a quality above 90 for 48 kHz +decoding. For other sampling rates, it is normal for the quality metric to be lower +(typically as low as 50 even for a good implementation) because of harmless mismatch with +the delay and phase of the internal sampling rate conversion. + + + +On POSIX environments, the run_vectors.sh script can be used to verify all test +vectors. This can be done with + +run_vectors.sh <exec path> <vector path> <rate> + +where <exec path> is the directory where the opus_demo and opus_compare executables +are built and <vector path> is the directory containing the test vectors. + +
+ +
+ +Opus Custom is an OPTIONAL part of the specification that is defined to +handle special sample rates and frame rates that are not supported by the +main Opus specification. Use of Opus Custom is discouraged for all but very +special applications for which a frame size different from 2.5, 5, 10, or 20 ms is +needed (for either complexity or latency reasons). Because Opus Custom is +optional, streams encoded using Opus Custom cannot be expected to be decodable by all Opus +implementations. Also, because no in-band mechanism exists for specifying the sampling +rate and frame size of Opus Custom streams, out-of-band signaling is required. +In Opus Custom operation, only the CELT layer is available, using the opus_custom_* function +calls in opus_custom.h. + +
+ +
+ +
+ + +Implementations of the Opus codec need to take appropriate security considerations +into account, as outlined in . +It is extremely important for the decoder to be robust against malicious +payloads. +Malicious payloads must not cause the decoder to overrun its allocated memory + or to take an excessive amount of resources to decode. +Although problems +in encoders are typically rarer, the same applies to the encoder. Malicious +audio streams must not cause the encoder to misbehave because this would +allow an attacker to attack transcoding gateways. + + +The reference implementation contains no known buffer overflow or cases where + a specially crafted packet or audio segment could cause a significant increase + in CPU load. +However, on certain CPU architectures where denormalized floating-point + operations are much slower than normal floating-point operations, it is + possible for some audio content (e.g., silence or near-silence) to cause an + increase in CPU load. +Denormals can be introduced by reordering operations in the compiler and depend + on the target architecture, so it is difficult to guarantee that an implementation + avoids them. +For architectures on which denormals are problematic, adding very small + floating-point offsets to the affected signals to prevent significant numbers + of denormalized operations is RECOMMENDED. +Alternatively, it is often possible to configure the hardware to treat + denormals as zero (DAZ). +No such issue exists for the fixed-point reference implementation. + +The reference implementation was validated in the following conditions: + + +Sending the decoder valid packets generated by the reference encoder and + verifying that the decoder's final range coder state matches that of the + encoder. + + +Sending the decoder packets generated by the reference encoder and then + subjected to random corruption. + +Sending the decoder random packets. + +Sending the decoder packets generated by a version of the reference encoder + modified to make random coding decisions (internal fuzzing), including mode + switching, and verifying that the range coder final states match. + + +In all of the conditions above, both the encoder and the decoder were run + inside the Valgrind memory + debugger, which tracks reads and writes to invalid memory regions as well as + the use of uninitialized memory. +There were no errors reported on any of the tested conditions. + +
+ + +
+ +This document has no actions for IANA. + +
+ +
+ +Thanks to all other developers, including Raymond Chen, Soeren Skak Jensen, Gregory Maxwell, +Christopher Montgomery, and Karsten Vandborg Soerensen. We would also +like to thank Igor Dyakonov, Jan Skoglund, and Christian Hoene for their help with subjective testing of the +Opus codec. Thanks to Ralph Giles, John Ridges, Ben Schwartz, Keith Yan, Christian Hoene, Kat Walsh, and many others on the Opus and CELT mailing lists +for their bug reports and feedback. + +
+ +
+The authors agree to grant third parties the irrevocable right to copy, use and distribute +the work (excluding Code Components available under the simplified BSD license), with or +without modification, in any medium, without royalty, provided that, unless separate +permission is granted, redistributed modified works do not contain misleading author, version, +name of work, or endorsement information. +
+ +
+ + + + + + + +Key words for use in RFCs to Indicate Requirement Levels + + + + + + + + + + + +Requirements for an Internet Audio Codec + + + + + +IETF + + +This document provides specific requirements for an Internet audio + codec. These requirements address quality, sample rate, bitrate, + and packet-loss robustness, as well as other desirable properties. + + + + + + + + + + +SILK Speech Codec + + + + + + + + + + + + + + + + + +Robust and Efficient Quantization of Speech LSP Parameters Using Structured Vector Quantization + + + + + + + + + + + + + + + + +Constrained-Energy Lapped Transform (CELT) Codec + + + + + + + + + + + + + + + + + + +Guidelines for the use of Variable Bit Rate Audio with Secure RTP + + + + + + + + + + + + + + +Internet Denial-of-Service Considerations + + + + + +IAB + + +This document provides an overview of possible avenues for denial-of-service (DoS) attack on Internet systems. The aim is to encourage protocol designers and network engineers towards designs that are more robust. We discuss partial solutions that reduce the effectiveness of attacks, and how some solutions might inadvertently open up alternative vulnerabilities. This memo provides information for the Internet community. + + + + + + +Range encoding: An algorithm for removing redundancy from a digitised message + + + + + + + + +Source coding algorithms for fast data compression + + + + + + + + +A Pyramid Vector Quantizer + + + + + + + + +The Computation of Line Spectral Frequencies Using Chebyshev Polynomials + + + + + + + + + + +Valgrind website + + + + + + +Google NetEQ code + + + + + + +Google WebRTC code + + + + + + + +Opus Git Repository + + + + + + +Opus website + + + + + + +Vorbis website + + + + + + +Matroska website + + + + + + +Opus Testvectors (webside) + + + + + + +Opus Testvectors (proceedings) + + + + + + +Line Spectral Pairs +Wikipedia + + + + + +Range Coding +Wikipedia + + + + + +Hadamard Transform +Wikipedia + + + + + +Viterbi Algorithm +Wikipedia + + + + + +White Noise +Wikipedia + + + + + +Linear Prediction +Wikipedia + + + + + +Modified Discrete Cosine Transform +Wikipedia + + + + + +Fast Fourier Transform +Wikipedia + + + + + +Z-transform +Wikipedia + + + + + + +Maximum Entropy Spectral Analysis + + + + + + +A fixed point computation of partial correlation coefficients + + + + + + + + +Analysis/synthesis filter bank design based on time domain aliasing cancellation + + + + + + + + +A High-Quality Speech and Audio Codec With Less Than 10 ms delay + + + + + + + + + + + + +Subdivision of the audible frequency range into critical bands + + + + + + + + + +
+ +This appendix contains the complete source code for the +reference implementation of the Opus codec written in C. By default, +this implementation relies on floating-point arithmetic, but it can be +compiled to use only fixed-point arithmetic by defining the FIXED_POINT +macro. Information on building and using the reference implementation is +available in the README file. + + +The implementation can be compiled with either a C89 or a C99 +compiler. It is reasonably optimized for most platforms such that +only architecture-specific optimizations are likely to be useful. +The FFT used is a slightly modified version of the KISS-FFT library, +but it is easy to substitute any other FFT library. + + + +While the reference implementation does not rely on any +undefined behavior as defined by C89 or C99, +it relies on common implementation-defined behavior +for two's complement architectures: + +Right shifts of negative values are consistent with two's complement arithmetic, so that a>>b is equivalent to floor(a/(2**b)), +For conversion to a signed integer of N bits, the value is reduced modulo 2**N to be within range of the type, +The result of integer division of a negative value is truncated towards zero, and +The compiler provides a 64-bit integer type (a C99 requirement which is supported by most C89 compilers). + + + + +In its current form, the reference implementation also requires the following +architectural characteristics to obtain acceptable performance: + +Two's complement arithmetic, +At least a 16 bit by 16 bit integer multiplier (32-bit result), and +At least a 32-bit adder/accumulator. + + + + +
+ +The complete source code can be extracted from this draft, by running the +following command line: + + + opus_source.tar.gz +]]> + +tar xzvf opus_source.tar.gz + +cd opus_source +make + +On systems where the provided Makefile does not work, the following command line may be used to compile +the source code: + + + + + +On systems where the base64 utility is not present, the following commands can be used instead: + + opus.b64 +]]> +openssl base64 -d -in opus.b64 > opus_source.tar.gz + + + +
+ +
+ +As of the time of publication of this memo, an up-to-date implementation conforming to +this standard is available in a + Git repository. +Releases and other resources are available at + . However, although that implementation is expected to + remain conformant with the standard, it is the code in this document that shall + remain normative. + +
+ +
+ + + +
+ +
+ +Because of size constraints, the Opus test vectors are not distributed in this +draft. They are available in the proceedings of the 83th IETF meeting (Paris) and from the Opus codec website at +. These test vectors were created specifically to exercise +all aspects of the decoder and therefore the audio quality of the decoded output is +significantly lower than what Opus can achieve in normal operation. + + + +The SHA1 hash of the files in the test vector package are + + + +
+ +
+ +
+ +To use the internal framing described in , the decoder + must know the total length of the Opus packet, in bytes. +This section describes a simple variation of that framing which can be used + when the total length of the packet is not known. +Nothing in the encoding of the packet itself allows a decoder to distinguish + between the regular, undelimited framing and the self-delimiting framing + described in this appendix. +Which one is used and where must be established by context at the transport + layer. +It is RECOMMENDED that a transport layer choose exactly one framing scheme, + rather than allowing an encoder to signal which one it wants to use. + + + +For example, although a regular Opus stream does not support more than two + channels, a multi-channel Opus stream may be formed from several one- and + two-channel streams. +To pack an Opus packet from each of these streams together in a single packet + at the transport layer, one could use the self-delimiting framing for all but + the last stream, and then the regular, undelimited framing for the last one. +Reverting to the undelimited framing for the last stream saves overhead + (because the total size of the transport-layer packet will still be known), + and ensures that a "multi-channel" stream which only has a single Opus stream + uses the same framing as a regular Opus stream does. +This avoids the need for signaling to distinguish these two cases. + + + +The self-delimiting framing is identical to the regular, undelimited framing + from , except that each Opus packet contains one extra + length field, encoded using the same one- or two-byte scheme from + . +This extra length immediately precedes the compressed data of the first Opus + frame in the packet, and is interpreted in the various modes as follows: + + +Code 0 packets: It is the length of the single Opus frame (see + ). + + +Code 1 packets: It is the length used for both of the Opus frames (see + ). + + +Code 2 packets: It is the length of the second Opus frame (see + ). + +CBR Code 3 packets: It is the length used for all of the Opus frames (see + ). + +VBR Code 3 packets: It is the length of the last Opus frame (see + ). + + + + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/draft-ietf-payload-rtp-opus.xml b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/draft-ietf-payload-rtp-opus.xml new file mode 100644 index 000000000..c4eb21077 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/draft-ietf-payload-rtp-opus.xml @@ -0,0 +1,960 @@ + + + + + + + + + + + + + + + + + + + + + + ]> + + + + + + + + + + + + + + + + + + RTP Payload Format for the Opus Speech and Audio Codec + + + +
+ jspittka@gmail.com +
+
+ + + vocTone +
+ + + + + + + + koenvos74@gmail.com +
+
+ + + Mozilla +
+ + 331 E. Evelyn Avenue + Mountain View + CA + 94041 + USA + + jmvalin@jmvalin.ca +
+
+ + + + + + This document defines the Real-time Transport Protocol (RTP) payload + format for packetization of Opus encoded + speech and audio data necessary to integrate the codec in the + most compatible way. It also provides an applicability statement + for the use of Opus over RTP. Further, it describes media type registrations + for the RTP payload format. + + +
+ + +
+ + Opus is a speech and audio codec developed within the + IETF Internet Wideband Audio Codec working group. The codec + has a very low algorithmic delay and it + is highly scalable in terms of audio bandwidth, bitrate, and + complexity. Further, it provides different modes to efficiently encode speech signals + as well as music signals, thus making it the codec of choice for + various applications using the Internet or similar networks. + + + This document defines the Real-time Transport Protocol (RTP) + payload format for packetization + of Opus encoded speech and audio data necessary to + integrate Opus in the + most compatible way. It also provides an applicability statement + for the use of Opus over RTP. + Further, it describes media type registrations for + the RTP payload format. + +
+ +
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in . + + + The range of audio frequecies being coded + Constant bitrate + Central Processing Unit + Discontinuous transmission + Forward error correction + Internet Protocol + Speech or audio samples (per channel) + Session Description Protocol + Variable bitrate + + + + Throughout this document, we refer to the following definitions: + + + Abbreviation + Name + Audio Bandwidth (Hz) + Sampling Rate (Hz) + NB + Narrowband + 0 - 4000 + 8000 + + MB + Mediumband + 0 - 6000 + 12000 + + WB + Wideband + 0 - 8000 + 16000 + + SWB + Super-wideband + 0 - 12000 + 24000 + + FB + Fullband + 0 - 20000 + 48000 + + + Audio bandwidth naming + + +
+ +
+ + Opus encodes speech + signals as well as general audio signals. Two different modes can be + chosen, a voice mode or an audio mode, to allow the most efficient coding + depending on the type of the input signal, the sampling frequency of the + input signal, and the intended application. + + + + The voice mode allows efficient encoding of voice signals at lower bit + rates while the audio mode is optimized for general audio signals at medium and + higher bitrates. + + + + Opus is highly scalable in terms of audio + bandwidth, bitrate, and complexity. Further, Opus allows + transmitting stereo signals with in-band signaling in the bit-stream. + + +
+ + Opus supports bitrates from 6 kb/s to 510 kb/s. + The bitrate can be changed dynamically within that range. + All + other parameters being + equal, higher bitrates result in higher audio quality. + +
+ + For a frame size of + 20 ms, these + are the bitrate "sweet spots" for Opus in various configurations: + + + 8-12 kb/s for NB speech, + 16-20 kb/s for WB speech, + 28-40 kb/s for FB speech, + 48-64 kb/s for FB mono music, and + 64-128 kb/s for FB stereo music. + + +
+
+ + For the same average bitrate, variable bitrate (VBR) can achieve higher audio quality + than constant bitrate (CBR). For the majority of voice transmission applications, VBR + is the best choice. One reason for choosing CBR is the potential + information leak that might occur when encrypting the + compressed stream. See for guidelines on when VBR is + appropriate for encrypted audio communications. In the case where an existing + VBR stream needs to be converted to CBR for security reasons, then the Opus padding + mechanism described in is the RECOMMENDED way to achieve padding + because the RTP padding bit is unencrypted. + + + The bitrate can be adjusted at any point in time. To avoid congestion, + the average bitrate SHOULD NOT exceed the available + network bandwidth. If no target bitrate is specified, the bitrates specified in + are RECOMMENDED. + + +
+ +
+ + + Opus can, as described in , + be operated with a variable bitrate. In that case, the encoder will + automatically reduce the bitrate for certain input signals, like periods + of silence. When using continuous transmission, it will reduce the + bitrate when the characteristics of the input signal permit, but + will never interrupt the transmission to the receiver. Therefore, the + received signal will maintain the same high level of audio quality over the + full duration of a transmission while minimizing the average bit + rate over time. + + + + In cases where the bitrate of Opus needs to be reduced even + further or in cases where only constant bitrate is available, + the Opus encoder can use discontinuous + transmission (DTX), where parts of the encoded signal that + correspond to periods of silence in the input speech or audio signal + are not transmitted to the receiver. A receiver can distinguish + between DTX and packet loss by looking for gaps in the sequence + number, as described by Section 4.1 + of . + + + + On the receiving side, the non-transmitted parts will be handled by a + frame loss concealment unit in the Opus decoder which generates a + comfort noise signal to replace the non transmitted parts of the + speech or audio signal. Use of Comfort + Noise (CN) with Opus is discouraged. + The transmitter MUST drop whole frames only, + based on the size of the last transmitted frame, + to ensure successive RTP timestamps differ by a multiple of 120 and + to allow the receiver to use whole frames for concealment. + + + + DTX can be used with both variable and constant bitrate. + It will have a slightly lower speech or audio + quality than continuous transmission. Therefore, using continuous + transmission is RECOMMENDED unless constraints on available network bandwidth + are severe. + + +
+ +
+ +
+ + + Complexity of the encoder can be scaled to optimize for CPU resources in real-time, mostly as + a trade-off between audio quality and bitrate. Also, different modes of Opus have different complexity. + + +
+ +
+ + + The voice mode of Opus allows for embedding "in-band" forward error correction (FEC) + data into the Opus bit stream. This FEC scheme adds + redundant information about the previous packet (N-1) to the current + output packet N. For + each frame, the encoder decides whether to use FEC based on (1) an + externally-provided estimate of the channel's packet loss rate; (2) an + externally-provided estimate of the channel's capacity; (3) the + sensitivity of the audio or speech signal to packet loss; (4) whether + the receiving decoder has indicated it can take advantage of "in-band" + FEC information. The decision to send "in-band" FEC information is + entirely controlled by the encoder and therefore no special precautions + for the payload have to be taken. + + + + On the receiving side, the decoder can take advantage of this + additional information when it loses a packet and the next packet + is available. In order to use the FEC data, the jitter buffer needs + to provide access to payloads with the FEC data. + Instead of performing loss concealment for a missing packet, the + receiver can then configure its decoder to decode the FEC data from the next packet. + + + + Any compliant Opus decoder is capable of ignoring + FEC information when it is not needed, so encoding with FEC cannot cause + interoperability problems. + However, if FEC cannot be used on the receiving side, then FEC + SHOULD NOT be used, as it leads to an inefficient usage of network + resources. Decoder support for FEC SHOULD be indicated at the time a + session is set up. + + +
+ +
+ + + Opus allows for transmission of stereo audio signals. This operation + is signaled in-band in the Opus bit-stream and no special arrangement + is needed in the payload format. An + Opus decoder is capable of handling a stereo encoding, but an + application might only be capable of consuming a single audio + channel. + + + If a decoder cannot take advantage of the benefits of a stereo signal + this SHOULD be indicated at the time a session is set up. In that case + the sending side SHOULD NOT send stereo signals as it leads to an + inefficient usage of network resources. + + +
+ +
+ +
+ The payload format for Opus consists of the RTP header and Opus payload + data. +
+ The format of the RTP header is specified in . + The use of the fields of the RTP header by the Opus payload format is + consistent with that specification. + + The payload length of Opus is an integer number of octets and + therefore no padding is necessary. The payload MAY be padded by an + integer number of octets according to , + although the Opus internal padding is preferred. + + The timestamp, sequence number, and marker bit (M) of the RTP header + are used in accordance with Section 4.1 + of . + + The RTP payload type for Opus is to be assigned dynamically. + + The receiving side MUST be prepared to receive duplicate RTP + packets. The receiver MUST provide at most one of those payloads to the + Opus decoder for decoding, and MUST discard the others. + + Opus supports 5 different audio bandwidths, which can be adjusted during + a stream. + The RTP timestamp is incremented with a 48000 Hz clock rate + for all modes of Opus and all sampling rates. + The unit + for the timestamp is samples per single (mono) channel. The RTP timestamp corresponds to the + sample time of the first encoded sample in the encoded frame. + For data encoded with sampling rates other than 48000 Hz, + the sampling rate has to be adjusted to 48000 Hz. + +
+ +
+ + The Opus encoder can output encoded frames representing 2.5, 5, 10, 20, + 40, or 60 ms of speech or audio data. Further, an arbitrary number of frames can be + combined into a packet, up to a maximum packet duration representing + 120 ms of speech or audio data. The grouping of one or more Opus + frames into a single Opus packet is defined in Section 3 of + . An RTP payload MUST contain exactly one + Opus packet as defined by that document. + + + shows the structure combined with the RTP header. + +
+ + + +
+ + + shows supported frame sizes in + milliseconds of encoded speech or audio data for the speech and audio modes + (Mode) and sampling rates (fs) of Opus and shows how the timestamp is + incremented for packetization (ts incr). If the Opus encoder + outputs multiple encoded frames into a single packet, the timestamp + increment is the sum of the increments for the individual frames. + + + + Mode + fs + 2.5 + 5 + 10 + 20 + 40 + 60 + ts incr + all + 120 + 240 + 480 + 960 + 1920 + 2880 + voice + NB/MB/WB/SWB/FB + x + x + o + o + o + o + audio + NB/WB/SWB/FB + o + o + o + o + x + x + + +
+ +
+ +
+ + The target bitrate of Opus can be adjusted at any point in time, thus + allowing efficient congestion control. Furthermore, the amount + of encoded speech or audio data encoded in a + single packet can be used for congestion control, since the transmission + rate is inversely proportional to the packet duration. A lower packet + transmission rate reduces the amount of header overhead, but at the same + time increases latency and loss sensitivity, so it ought to be used with + care. + + Since UDP does not provide congestion control, applications that use + RTP over UDP SHOULD implement their own congestion control above the + UDP layer . Work in the rmcat working group + describes the + interactions and conceptual interfaces necessary between the application + components that relate to congestion control, including the RTP layer, + the higher-level media codec control layer, and the lower-level + transport interface, as well as components dedicated to congestion + control functions. +
+ +
+ One media subtype (audio/opus) has been defined and registered as + described in the following section. + +
+ Media type registration is done according to and . + + Type name: audio + Subtype name: opus + + Required parameters: + + the RTP timestamp is incremented with a + 48000 Hz clock rate for all modes of Opus and all sampling + rates. For data encoded with sampling rates other than 48000 Hz, + the sampling rate has to be adjusted to 48000 Hz. + + + + Optional parameters: + + + + a hint about the maximum output sampling rate that the receiver is + capable of rendering in Hz. + The decoder MUST be capable of decoding + any audio bandwidth but due to hardware limitations only signals + up to the specified sampling rate can be played back. Sending signals + with higher audio bandwidth results in higher than necessary network + usage and encoding complexity, so an encoder SHOULD NOT encode + frequencies above the audio bandwidth specified by maxplaybackrate. + This parameter can take any value between 8000 and 48000, although + commonly the value will match one of the Opus bandwidths + (). + By default, the receiver is assumed to have no limitations, i.e. 48000. + + + + + a hint about the maximum input sampling rate that the sender is likely to produce. + This is not a guarantee that the sender will never send any higher bandwidth + (e.g. it could send a pre-recorded prompt that uses a higher bandwidth), but it + indicates to the receiver that frequencies above this maximum can safely be discarded. + This parameter is useful to avoid wasting receiver resources by operating the audio + processing pipeline (e.g. echo cancellation) at a higher rate than necessary. + This parameter can take any value between 8000 and 48000, although + commonly the value will match one of the Opus bandwidths + (). + By default, the sender is assumed to have no limitations, i.e. 48000. + + + + the maximum duration of media represented + by a packet (according to Section 6 of + ) that a decoder wants to receive, in + milliseconds rounded up to the next full integer value. + Possible values are 3, 5, 10, 20, 40, 60, or an arbitrary + multiple of an Opus frame size rounded up to the next full integer + value, up to a maximum value of 120, as + defined in . If no value is + specified, the default is 120. + + + the preferred duration of media represented + by a packet (according to Section 6 of + ) that a decoder wants to receive, in + milliseconds rounded up to the next full integer value. + Possible values are 3, 5, 10, 20, 40, 60, or an arbitrary + multiple of an Opus frame size rounded up to the next full integer + value, up to a maximum value of 120, as defined in . If no value is + specified, the default is 20. + + + specifies the maximum average + receive bitrate of a session in bits per second (b/s). The actual + value of the bitrate can vary, as it is dependent on the + characteristics of the media in a packet. Note that the maximum + average bitrate MAY be modified dynamically during a session. Any + positive integer is allowed, but values outside the range + 6000 to 510000 SHOULD be ignored. If no value is specified, the + maximum value specified in + for the corresponding mode of Opus and corresponding maxplaybackrate + is the default. + + + specifies whether the decoder prefers receiving stereo or mono signals. + Possible values are 1 and 0 where 1 specifies that stereo signals are preferred, + and 0 specifies that only mono signals are preferred. + Independent of the stereo parameter every receiver MUST be able to receive and + decode stereo signals but sending stereo signals to a receiver that signaled a + preference for mono signals may result in higher than necessary network + utilization and encoding complexity. If no value is specified, + the default is 0 (mono). + + + + specifies whether the sender is likely to produce stereo audio. + Possible values are 1 and 0, where 1 specifies that stereo signals are likely to + be sent, and 0 specifies that the sender will likely only send mono. + This is not a guarantee that the sender will never send stereo audio + (e.g. it could send a pre-recorded prompt that uses stereo), but it + indicates to the receiver that the received signal can be safely downmixed to mono. + This parameter is useful to avoid wasting receiver resources by operating the audio + processing pipeline (e.g. echo cancellation) in stereo when not necessary. + If no value is specified, the default is 0 + (mono). + + + + specifies if the decoder prefers the use of a constant bitrate versus + variable bitrate. Possible values are 1 and 0, where 1 specifies constant + bitrate and 0 specifies variable bitrate. If no value is specified, + the default is 0 (vbr). When cbr is 1, the maximum average bitrate can still + change, e.g. to adapt to changing network conditions. + + + specifies that the decoder has the capability to + take advantage of the Opus in-band FEC. Possible values are 1 and 0. + Providing 0 when FEC cannot be used on the receiving side is + RECOMMENDED. If no + value is specified, useinbandfec is assumed to be 0. + This parameter is only a preference and the receiver MUST be able to process + packets that include FEC information, even if it means the FEC part is discarded. + + + specifies if the decoder prefers the use of + DTX. Possible values are 1 and 0. If no value is specified, the + default is 0. + + + Encoding considerations: + + The Opus media type is framed and consists of binary data according + to Section 4.8 in . + + + Security considerations: + + See of this document. + + + Interoperability considerations: none + Published specification: RFC [XXXX] + Note to the RFC Editor: Replace [XXXX] with the number of the published + RFC. + + Applications that use this media type: + + Any application that requires the transport of + speech or audio data can use this media type. Some examples are, + but not limited to, audio and video conferencing, Voice over IP, + media streaming. + + + Fragment identifier considerations: N/A + + Person & email address to contact for further information: + + SILK Support silksupport@skype.net + Jean-Marc Valin jmvalin@jmvalin.ca + + + Intended usage: COMMON + + Restrictions on usage: + + + For transfer over RTP, the RTP payload format ( of this document) SHALL be + used. + + + Author: + + Julian Spittka jspittka@gmail.com + Koen Vos koenvos74@gmail.com + Jean-Marc Valin jmvalin@jmvalin.ca + + + Change controller: IETF Payload Working Group delegated from the IESG +
+
+ +
+ The information described in the media type specification has a + specific mapping to fields in the Session Description Protocol (SDP) + , which is commonly used to describe RTP + sessions. When SDP is used to specify sessions employing Opus, + the mapping is as follows: + + + + The media type ("audio") goes in SDP "m=" as the media name. + + The media subtype ("opus") goes in SDP "a=rtpmap" as the encoding + name. The RTP clock rate in "a=rtpmap" MUST be 48000 and the number of + channels MUST be 2. + + The OPTIONAL media type parameters "ptime" and "maxptime" are + mapped to "a=ptime" and "a=maxptime" attributes, respectively, in the + SDP. + + The OPTIONAL media type parameters "maxaveragebitrate", + "maxplaybackrate", "stereo", "cbr", "useinbandfec", and + "usedtx", when present, MUST be included in the "a=fmtp" attribute + in the SDP, expressed as a media type string in the form of a + semicolon-separated list of parameter=value pairs (e.g., + maxplaybackrate=48000). They MUST NOT be specified in an + SSRC-specific "fmtp" source-level attribute (as defined in + Section 6.3 of ). + + The OPTIONAL media type parameters "sprop-maxcapturerate", + and "sprop-stereo" MAY be mapped to the "a=fmtp" SDP attribute by + copying them directly from the media type parameter string as part + of the semicolon-separated list of parameter=value pairs (e.g., + sprop-stereo=1). These same OPTIONAL media type parameters MAY also + be specified using an SSRC-specific "fmtp" source-level attribute + as described in Section 6.3 of . + They MAY be specified in both places, in which case the parameter + in the source-level attribute overrides the one found on the + "a=fmtp" line. The value of any parameter which is not specified in + a source-level source attribute MUST be taken from the "a=fmtp" + line, if it is present there. + + + + + Below are some examples of SDP session descriptions for Opus: + + Example 1: Standard mono session with 48000 Hz clock rate +
+ + + +
+ + + Example 2: 16000 Hz clock rate, maximum packet size of 40 ms, + recommended packet size of 40 ms, maximum average bitrate of 20000 bps, + prefers to receive stereo but only plans to send mono, FEC is desired, + DTX is not desired + +
+ + + +
+ + Example 3: Two-way full-band stereo preferred + +
+ + + +
+ + +
+ + When using the offer-answer procedure described in to negotiate the use of Opus, the following + considerations apply: + + + + Opus supports several clock rates. For signaling purposes only + the highest, i.e. 48000, is used. The actual clock rate of the + corresponding media is signaled inside the payload and is not + restricted by this payload format description. The decoder MUST be + capable of decoding every received clock rate. An example + is shown below: + +
+ + + +
+
+ + The "ptime" and "maxptime" parameters are unidirectional + receive-only parameters and typically will not compromise + interoperability; however, some values might cause application + performance to suffer. defines the SDP offer-answer handling of the + "ptime" parameter. The "maxptime" parameter MUST be handled in the + same way. + + + The "maxplaybackrate" parameter is a unidirectional receive-only + parameter that reflects limitations of the local receiver. When + sending to a single destination, a sender MUST NOT use an audio + bandwidth higher than necessary to make full use of audio sampled at + a sampling rate of "maxplaybackrate". Gateways or senders that + are sending the same encoded audio to multiple destinations + SHOULD NOT use an audio bandwidth higher than necessary to + represent audio sampled at "maxplaybackrate", as this would lead + to inefficient use of network resources. + The "maxplaybackrate" parameter does not + affect interoperability. Also, this parameter SHOULD NOT be used + to adjust the audio bandwidth as a function of the bitrate, as this + is the responsibility of the Opus encoder implementation. + + + The "maxaveragebitrate" parameter is a unidirectional receive-only + parameter that reflects limitations of the local receiver. The sender + of the other side MUST NOT send with an average bitrate higher than + "maxaveragebitrate" as it might overload the network and/or + receiver. The "maxaveragebitrate" parameter typically will not + compromise interoperability; however, some values might cause + application performance to suffer, and ought to be set with + care. + + The "sprop-maxcapturerate" and "sprop-stereo" parameters are + unidirectional sender-only parameters that reflect limitations of + the sender side. + They allow the receiver to set up a reduced-complexity audio + processing pipeline if the sender is not planning to use the full + range of Opus's capabilities. + Neither "sprop-maxcapturerate" nor "sprop-stereo" affect + interoperability and the receiver MUST be capable of receiving any signal. + + + + The "stereo" parameter is a unidirectional receive-only + parameter. When sending to a single destination, a sender MUST + NOT use stereo when "stereo" is 0. Gateways or senders that are + sending the same encoded audio to multiple destinations SHOULD + NOT use stereo when "stereo" is 0, as this would lead to + inefficient use of network resources. The "stereo" parameter does + not affect interoperability. + + + + The "cbr" parameter is a unidirectional receive-only + parameter. + + + The "useinbandfec" parameter is a unidirectional receive-only + parameter. + + The "usedtx" parameter is a unidirectional receive-only + parameter. + + Any unknown parameter in an offer MUST be ignored by the receiver + and MUST be removed from the answer. + +
+ + + The Opus parameters in an SDP Offer/Answer exchange are completely + orthogonal, and there is no relationship between the SDP Offer and + the Answer. + +
+ +
+ + For declarative use of SDP such as in Session Announcement Protocol + (SAP), , and RTSP, , for + Opus, the following needs to be considered: + + + + The values for "maxptime", "ptime", "maxplaybackrate", and + "maxaveragebitrate" ought to be selected carefully to ensure that a + reasonable performance can be achieved for the participants of a session. + + + The values for "maxptime", "ptime", and of the payload + format configuration are recommendations by the decoding side to ensure + the best performance for the decoder. + + + All other parameters of the payload format configuration are declarative + and a participant MUST use the configurations that are provided for + the session. More than one configuration can be provided if necessary + by declaring multiple RTP payload types; however, the number of types + ought to be kept small. + +
+
+ +
+ + Use of variable bitrate (VBR) is subject to the security considerations in + . + + RTP packets using the payload format defined in this specification + are subject to the security considerations discussed in the RTP + specification , and in any applicable RTP profile such as + RTP/AVP , RTP/AVPF , + RTP/SAVP or RTP/SAVPF . + However, as "Securing the RTP Protocol Framework: + Why RTP Does Not Mandate a Single Media Security Solution" + discusses, it is not an RTP payload + format's responsibility to discuss or mandate what solutions are used + to meet the basic security goals like confidentiality, integrity and + source authenticity for RTP in general. This responsibility lays on + anyone using RTP in an application. They can find guidance on + available security mechanisms and important considerations in Options + for Securing RTP Sessions [I-D.ietf-avtcore-rtp-security-options]. + Applications SHOULD use one or more appropriate strong security + mechanisms. + + This payload format and the Opus encoding do not exhibit any + significant non-uniformity in the receiver-end computational load and thus + are unlikely to pose a denial-of-service threat due to the receipt of + pathological datagrams. +
+ +
+ Many people have made useful comments and suggestions contributing to this document. + In particular, we would like to thank + Tina le Grand, Cullen Jennings, Jonathan Lennox, Gregory Maxwell, Colin Perkins, Jan Skoglund, + Timothy B. Terriberry, Martin Thompson, Justin Uberti, Magnus Westerlund, and Mo Zanaty. +
+
+ + + + &rfc2119; + &rfc3389; + &rfc3550; + &rfc3711; + &rfc3551; + &rfc6838; + &rfc4855; + &rfc4566; + &rfc3264; + &rfc2326; + &rfc5576; + &rfc6562; + &rfc6716; + + + + &rfc2974; + &rfc4585; + &rfc5124; + &rfc5405; + &rfc7202; + + + + rmcat documents + + + + + + + + + + + +
diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/footer.html b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/footer.html new file mode 100644 index 000000000..346c40aba --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/footer.html @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + +
+For more information visit the Opus Website. + + +
+ + + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/header.html b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/header.html new file mode 100644 index 000000000..babdcf6d7 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/header.html @@ -0,0 +1,61 @@ + + + + + + + + +$projectname: $title +$title + + + +$treeview +$search +$mathjax + +$extrastylesheet + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + +
+
Opus
+
+ + +
+
$projectbrief
+
$projectnumber +
+
+
$projectbrief
+
$searchbox
+
+ + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/meson.build b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/meson.build new file mode 100644 index 000000000..ee42a2b02 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/meson.build @@ -0,0 +1,33 @@ +have_dot = find_program('dot', required: false).found() + +doxyfile_conf = configuration_data() +doxyfile_conf.set('VERSION', opus_version) +doxyfile_conf.set('HAVE_DOT', have_dot) +doxyfile_conf.set('top_srcdir', top_srcdir) +doxyfile_conf.set('top_builddir', top_builddir) + +doxyfile = configure_file(input: 'Doxyfile.in', + output: 'Doxyfile', + configuration: doxyfile_conf, + install: false) + +docdir = join_paths(get_option('datadir'), get_option('docdir')) + +doc_inputs = [ + 'customdoxygen.css', + 'footer.html', + 'header.html', + 'opus_logo.svg', + top_srcdir + '/include/opus.h', + top_srcdir + '/include/opus_multistream.h', + top_srcdir + '/include/opus_defines.h', + top_srcdir + '/include/opus_types.h', + top_srcdir + '/include/opus_custom.h', +] + +custom_target('doc', + input: [ doxyfile ] + doc_inputs, + output: [ 'html' ], + command: [ doxygen, doxyfile ], + install_dir: docdir, + install: true) diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/opus_in_isobmff.css b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/opus_in_isobmff.css new file mode 100644 index 000000000..bffe8f45a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/opus_in_isobmff.css @@ -0,0 +1,60 @@ +/* Normal links */ +.normal_link a:link +{ + color : yellow; +} +.normal_link a:visited +{ + color : green; +} + +/* Boxes */ +.pre +{ + white-space: pre; /* CSS 2.0 */ + white-space: pre-wrap; /* CSS 2.1 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: -moz-pre-wrap; /* Mozilla */ + white-space: -hp-pre-wrap; /* HP Printers */ + word-wrap : break-word; /* IE 5+ */ +} + +.title_box +{ + width : 470px; + height : 70px; + margin : 2px 50px 2px 2px; + padding : 10px; + border : 1px solid black; + background-color : #666666; + white-space : pre; + float : left; + text-align : center; + color : #C0C0C0; + font-size : 50pt; + font-style : italic; +} + +.subindex_box +{ + margin : 5px; + padding : 14px 22px; + border : 1px solid black; + background-color : #778877; + float : left; + text-align : center; + color : #115555; + font-size : 32pt; +} + +.frame_box +{ + margin : 10px; + padding : 10px; + border : 0px; + background-color : #084040; + text-align : left; + color : #C0C0C0; + font-family : monospace; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/opus_in_isobmff.html b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/opus_in_isobmff.html new file mode 100644 index 000000000..38aefbf2a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/opus_in_isobmff.html @@ -0,0 +1,692 @@ + + + + + + Encapsulation of Opus in ISO Base Media File Format + + + Encapsulation of Opus in ISO Base Media File Format
+ last updated: August 28, 2018
+
+ + + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/opus_logo.svg b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/opus_logo.svg new file mode 100644 index 000000000..db2879efc --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/opus_logo.svg @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/opus_update.patch b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/opus_update.patch new file mode 100644 index 000000000..11f066c70 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/opus_update.patch @@ -0,0 +1,244 @@ +diff --git a/celt/bands.c b/celt/bands.c +index 6962587..32e1de6 100644 +--- a/celt/bands.c ++++ b/celt/bands.c +@@ -1234,9 +1234,23 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end, + b = 0; + } + +- if (resynth && M*eBands[i]-N >= M*eBands[start] && (update_lowband || lowband_offset==0)) ++ if (resynth && (M*eBands[i]-N >= M*eBands[start] || i==start+1) && (update_lowband || lowband_offset==0)) + lowband_offset = i; + ++ if (i == start+1) ++ { ++ int n1, n2; ++ int offset; ++ n1 = M*(eBands[start+1]-eBands[start]); ++ n2 = M*(eBands[start+2]-eBands[start+1]); ++ offset = M*eBands[start]; ++ /* Duplicate enough of the first band folding data to be able to fold the second band. ++ Copies no data for CELT-only mode. */ ++ OPUS_COPY(&norm[offset+n1], &norm[offset+2*n1 - n2], n2-n1); ++ if (C==2) ++ OPUS_COPY(&norm2[offset+n1], &norm2[offset+2*n1 - n2], n2-n1); ++ } ++ + tf_change = tf_res[i]; + if (i>=m->effEBands) + { +@@ -1257,7 +1271,7 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end, + fold_start = lowband_offset; + while(M*eBands[--fold_start] > effective_lowband); + fold_end = lowband_offset-1; +- while(M*eBands[++fold_end] < effective_lowband+N); ++ while(++fold_end < i && M*eBands[fold_end] < effective_lowband+N); + x_cm = y_cm = 0; + fold_i = fold_start; do { + x_cm |= collapse_masks[fold_i*C+0]; +diff --git a/celt/quant_bands.c b/celt/quant_bands.c +index e5ed9ef..82fb823 100644 +--- a/celt/quant_bands.c ++++ b/celt/quant_bands.c +@@ -552,6 +552,7 @@ void log2Amp(const CELTMode *m, int start, int end, + { + opus_val16 lg = ADD16(oldEBands[i+c*m->nbEBands], + SHL16((opus_val16)eMeans[i],6)); ++ lg = MIN32(QCONST32(32.f, 16), lg); + eBands[i+c*m->nbEBands] = PSHR32(celt_exp2(lg),4); + } + for (;inbEBands;i++) +diff --git a/silk/LPC_inv_pred_gain.c b/silk/LPC_inv_pred_gain.c +index 60c439b..6c301da 100644 +--- a/silk/LPC_inv_pred_gain.c ++++ b/silk/LPC_inv_pred_gain.c +@@ -84,8 +84,13 @@ static opus_int32 LPC_inverse_pred_gain_QA( /* O Returns inver + + /* Update AR coefficient */ + for( n = 0; n < k; n++ ) { +- tmp_QA = Aold_QA[ n ] - MUL32_FRAC_Q( Aold_QA[ k - n - 1 ], rc_Q31, 31 ); +- Anew_QA[ n ] = MUL32_FRAC_Q( tmp_QA, rc_mult2 , mult2Q ); ++ opus_int64 tmp64; ++ tmp_QA = silk_SUB_SAT32( Aold_QA[ n ], MUL32_FRAC_Q( Aold_QA[ k - n - 1 ], rc_Q31, 31 ) ); ++ tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( tmp_QA, rc_mult2 ), mult2Q); ++ if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { ++ return 0; ++ } ++ Anew_QA[ n ] = ( opus_int32 )tmp64; + } + } + +diff --git a/silk/NLSF_stabilize.c b/silk/NLSF_stabilize.c +index 979aaba..2ef2398 100644 +--- a/silk/NLSF_stabilize.c ++++ b/silk/NLSF_stabilize.c +@@ -134,7 +134,7 @@ void silk_NLSF_stabilize( + + /* Keep delta_min distance between the NLSFs */ + for( i = 1; i < L; i++ ) +- NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], NLSF_Q15[i-1] + NDeltaMin_Q15[i] ); ++ NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], silk_ADD_SAT16( NLSF_Q15[i-1], NDeltaMin_Q15[i] ) ); + + /* Last NLSF should be no higher than 1 - NDeltaMin[L] */ + NLSF_Q15[L-1] = silk_min_int( NLSF_Q15[L-1], (1<<15) - NDeltaMin_Q15[L] ); +diff --git a/silk/dec_API.c b/silk/dec_API.c +index efd7918..21bb7e0 100644 +--- a/silk/dec_API.c ++++ b/silk/dec_API.c +@@ -72,6 +72,9 @@ opus_int silk_InitDecoder( /* O Returns error co + for( n = 0; n < DECODER_NUM_CHANNELS; n++ ) { + ret = silk_init_decoder( &channel_state[ n ] ); + } ++ silk_memset(&((silk_decoder *)decState)->sStereo, 0, sizeof(((silk_decoder *)decState)->sStereo)); ++ /* Not strictly needed, but it's cleaner that way */ ++ ((silk_decoder *)decState)->prev_decode_only_middle = 0; + + return ret; + } +diff --git a/silk/resampler_private_IIR_FIR.c b/silk/resampler_private_IIR_FIR.c +index dbd6d9a..91a43aa 100644 +--- a/silk/resampler_private_IIR_FIR.c ++++ b/silk/resampler_private_IIR_FIR.c +@@ -75,10 +75,10 @@ void silk_resampler_private_IIR_FIR( + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; +- opus_int16 buf[ RESAMPLER_MAX_BATCH_SIZE_IN + RESAMPLER_ORDER_FIR_12 ]; ++ opus_int16 buf[ 2*RESAMPLER_MAX_BATCH_SIZE_IN + RESAMPLER_ORDER_FIR_12 ]; + + /* Copy buffered samples to start of buffer */ +- silk_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); ++ silk_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; +@@ -95,13 +95,13 @@ void silk_resampler_private_IIR_FIR( + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ +- silk_memcpy( buf, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); ++ silk_memmove( buf, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ +- silk_memcpy( S->sFIR, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); ++ silk_memcpy( S->sFIR, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + } + +diff --git a/src/opus_decoder.c b/src/opus_decoder.c +index 0cc56f8..8a30fbc 100644 +--- a/src/opus_decoder.c ++++ b/src/opus_decoder.c +@@ -595,16 +595,14 @@ static int opus_packet_parse_impl(const unsigned char *data, int len, + /* Padding flag is bit 6 */ + if (ch&0x40) + { +- int padding=0; + int p; + do { + if (len<=0) + return OPUS_INVALID_PACKET; + p = *data++; + len--; +- padding += p==255 ? 254: p; ++ len -= p==255 ? 254: p; + } while (p==255); +- len -= padding; + } + if (len<0) + return OPUS_INVALID_PACKET; +diff --git a/run_vectors.sh b/run_vectors.sh +index 7cd23ed..4841b0a 100755 +--- a/run_vectors.sh ++++ b/run_vectors.sh +@@ -1,3 +1,5 @@ ++#!/bin/sh ++# + # Copyright (c) 2011-2012 IETF Trust, Jean-Marc Valin. All rights reserved. + # + # This file is extracted from RFC6716. Please see that RFC for additional +@@ -31,10 +33,8 @@ + # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-#!/bin/sh +- +-rm logs_mono.txt +-rm logs_stereo.txt ++rm -f logs_mono.txt logs_mono2.txt ++rm -f logs_stereo.txt logs_stereo2.txt + + if [ "$#" -ne "3" ]; then + echo "usage: run_vectors.sh " +@@ -45,18 +45,23 @@ CMD_PATH=$1 + VECTOR_PATH=$2 + RATE=$3 + +-OPUS_DEMO=$CMD_PATH/opus_demo +-OPUS_COMPARE=$CMD_PATH/opus_compare ++: ${OPUS_DEMO:=$CMD_PATH/opus_demo} ++: ${OPUS_COMPARE:=$CMD_PATH/opus_compare} + + if [ -d $VECTOR_PATH ]; then + echo Test vectors found in $VECTOR_PATH + else + echo No test vectors found +- #Don't make the test fail here because the test vectors will be +- #distributed separately ++ #Don't make the test fail here because the test vectors ++ #will be distributed separately + exit 0 + fi + ++if [ ! -x $OPUS_COMPARE ]; then ++ echo ERROR: Compare program not found: $OPUS_COMPARE ++ exit 1 ++fi ++ + if [ -x $OPUS_DEMO ]; then + echo Decoding with $OPUS_DEMO + else +@@ -82,9 +87,11 @@ do + echo ERROR: decoding failed + exit 1 + fi +- $OPUS_COMPARE -r $RATE $VECTOR_PATH/testvector$file.dec tmp.out >> logs_mono.txt 2>&1 ++ $OPUS_COMPARE -r $RATE $VECTOR_PATH/testvector${file}.dec tmp.out >> logs_mono.txt 2>&1 + float_ret=$? +- if [ "$float_ret" -eq "0" ]; then ++ $OPUS_COMPARE -r $RATE $VECTOR_PATH/testvector${file}m.dec tmp.out >> logs_mono2.txt 2>&1 ++ float_ret2=$? ++ if [ "$float_ret" -eq "0" ] || [ "$float_ret2" -eq "0" ]; then + echo output matches reference + else + echo ERROR: output does not match reference +@@ -111,9 +118,11 @@ do + echo ERROR: decoding failed + exit 1 + fi +- $OPUS_COMPARE -s -r $RATE $VECTOR_PATH/testvector$file.dec tmp.out >> logs_stereo.txt 2>&1 ++ $OPUS_COMPARE -s -r $RATE $VECTOR_PATH/testvector${file}.dec tmp.out >> logs_stereo.txt 2>&1 + float_ret=$? +- if [ "$float_ret" -eq "0" ]; then ++ $OPUS_COMPARE -s -r $RATE $VECTOR_PATH/testvector${file}m.dec tmp.out >> logs_stereo2.txt 2>&1 ++ float_ret2=$? ++ if [ "$float_ret" -eq "0" ] || [ "$float_ret2" -eq "0" ]; then + echo output matches reference + else + echo ERROR: output does not match reference +@@ -125,5 +134,10 @@ done + + + echo All tests have passed successfully +-grep quality logs_mono.txt | awk '{sum+=$4}END{print "Average mono quality is", sum/NR, "%"}' +-grep quality logs_stereo.txt | awk '{sum+=$4}END{print "Average stereo quality is", sum/NR, "%"}' ++mono1=`grep quality logs_mono.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` ++mono2=`grep quality logs_mono2.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` ++echo $mono1 $mono2 | awk '{if ($2 > $1) $1 = $2; print "Average mono quality is", $1, "%"}' ++ ++stereo1=`grep quality logs_stereo.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` ++stereo2=`grep quality logs_stereo2.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` ++echo $stereo1 $stereo2 | awk '{if ($2 > $1) $1 = $2; print "Average stereo quality is", $1, "%"}' diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/release.txt b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/release.txt new file mode 100644 index 000000000..411ab7f4b --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/release.txt @@ -0,0 +1,43 @@ += Release checklist = + +== Source release == + +- Check for uncommitted changes to master. +- Update OPUS_LT_* API versioning in configure.ac. +- Tag the release commit with 'git tag -s vN.M'. + - Include release notes in the tag annotation. +- Verify 'make distcheck' produces a tarball with + the desired name. +- Push tag to public repo. +- Upload source package 'opus-${version}.tar.gz' + - Add to https://svn.xiph.org/releases/opus/ + - Update checksum files + - svn commit + - Copy to archive.mozilla.org/pub/opus/ + - Update checksum files there as well. +- Add release notes to https://gitlab.xiph.org/xiph/opus-website.git +- Update links and checksums on the downloads page. +- Add a copy of the documentation to + and update the links. +- Update /topic in #opus IRC channel. + +Releases are commited to https://svn.xiph.org/releases/opus/ +which propagates to downloads.xiph.org, and copied manually +to https://archive.mozilla.org/pub/opus/ + +Website updates are committed to https://gitlab.xiph.org/xiph/opus-website.git +which propagates to https://opus-codec.org/ + +== Binary release == + +We usually build opus-tools binaries for MacOS and Windows. + +Binary releases are copied manually to +https://archive.mozilla.org/pub/opus/win32/ + +For Mac, submit a pull request to homebrew. + +== Website updates == + +For major releases, recreate the files on https://opus-codec.org/examples/ +with the next encoder. diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/doc/trivial_example.c b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/trivial_example.c new file mode 100644 index 000000000..9cf435b4a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/doc/trivial_example.c @@ -0,0 +1,171 @@ +/* Copyright (c) 2013 Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +/* This is meant to be a simple example of encoding and decoding audio + using Opus. It should make it easy to understand how the Opus API + works. For more information, see the full API documentation at: + https://www.opus-codec.org/docs/ */ + +#include +#include +#include +#include +#include + +/*The frame size is hardcoded for this sample code but it doesn't have to be*/ +#define FRAME_SIZE 960 +#define SAMPLE_RATE 48000 +#define CHANNELS 2 +#define APPLICATION OPUS_APPLICATION_AUDIO +#define BITRATE 64000 + +#define MAX_FRAME_SIZE 6*960 +#define MAX_PACKET_SIZE (3*1276) + +int main(int argc, char **argv) +{ + char *inFile; + FILE *fin; + char *outFile; + FILE *fout; + opus_int16 in[FRAME_SIZE*CHANNELS]; + opus_int16 out[MAX_FRAME_SIZE*CHANNELS]; + unsigned char cbits[MAX_PACKET_SIZE]; + int nbBytes; + /*Holds the state of the encoder and decoder */ + OpusEncoder *encoder; + OpusDecoder *decoder; + int err; + + if (argc != 3) + { + fprintf(stderr, "usage: trivial_example input.pcm output.pcm\n"); + fprintf(stderr, "input and output are 16-bit little-endian raw files\n"); + return EXIT_FAILURE; + } + + /*Create a new encoder state */ + encoder = opus_encoder_create(SAMPLE_RATE, CHANNELS, APPLICATION, &err); + if (err<0) + { + fprintf(stderr, "failed to create an encoder: %s\n", opus_strerror(err)); + return EXIT_FAILURE; + } + /* Set the desired bit-rate. You can also set other parameters if needed. + The Opus library is designed to have good defaults, so only set + parameters you know you need. Doing otherwise is likely to result + in worse quality, but better. */ + err = opus_encoder_ctl(encoder, OPUS_SET_BITRATE(BITRATE)); + if (err<0) + { + fprintf(stderr, "failed to set bitrate: %s\n", opus_strerror(err)); + return EXIT_FAILURE; + } + inFile = argv[1]; + fin = fopen(inFile, "rb"); + if (fin==NULL) + { + fprintf(stderr, "failed to open input file: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + + /* Create a new decoder state. */ + decoder = opus_decoder_create(SAMPLE_RATE, CHANNELS, &err); + if (err<0) + { + fprintf(stderr, "failed to create decoder: %s\n", opus_strerror(err)); + return EXIT_FAILURE; + } + outFile = argv[2]; + fout = fopen(outFile, "wb"); + if (fout==NULL) + { + fprintf(stderr, "failed to open output file: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + while (1) + { + int i; + unsigned char pcm_bytes[MAX_FRAME_SIZE*CHANNELS*2]; + int frame_size; + size_t samples; + + /* Read a 16 bits/sample audio frame. */ + samples = fread(pcm_bytes, sizeof(short)*CHANNELS, FRAME_SIZE, fin); + + /* For simplicity, only read whole frames. In a real application, + * we'd pad the final partial frame with zeroes, record the exact + * duration, and trim the decoded audio to match. + */ + if (samples != FRAME_SIZE) + { + break; + } + + /* Convert from little-endian ordering. */ + for (i=0;i>8)&0xFF; + } + /* Write the decoded audio to file. */ + fwrite(pcm_bytes, sizeof(short), frame_size*CHANNELS, fout); + } + /*Destroy the encoder state*/ + opus_encoder_destroy(encoder); + opus_decoder_destroy(decoder); + fclose(fin); + fclose(fout); + return EXIT_SUCCESS; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/include/meson.build b/native/opennow-streamer/vendor/audiopus-sys/opus/include/meson.build new file mode 100644 index 000000000..c1fb0b76f --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/include/meson.build @@ -0,0 +1,13 @@ +opus_headers = [ + 'opus.h', + 'opus_multistream.h', + 'opus_projection.h', + 'opus_types.h', + 'opus_defines.h', +] + +if opt_custom_modes + opus_headers += ['opus_custom.h'] +endif + +install_headers(opus_headers, subdir: 'opus') diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus.h b/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus.h new file mode 100644 index 000000000..d282f21d2 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus.h @@ -0,0 +1,981 @@ +/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +/** + * @file opus.h + * @brief Opus reference implementation API + */ + +#ifndef OPUS_H +#define OPUS_H + +#include "opus_types.h" +#include "opus_defines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @mainpage Opus + * + * The Opus codec is designed for interactive speech and audio transmission over the Internet. + * It is designed by the IETF Codec Working Group and incorporates technology from + * Skype's SILK codec and Xiph.Org's CELT codec. + * + * The Opus codec is designed to handle a wide range of interactive audio applications, + * including Voice over IP, videoconferencing, in-game chat, and even remote live music + * performances. It can scale from low bit-rate narrowband speech to very high quality + * stereo music. Its main features are: + + * @li Sampling rates from 8 to 48 kHz + * @li Bit-rates from 6 kb/s to 510 kb/s + * @li Support for both constant bit-rate (CBR) and variable bit-rate (VBR) + * @li Audio bandwidth from narrowband to full-band + * @li Support for speech and music + * @li Support for mono and stereo + * @li Support for multichannel (up to 255 channels) + * @li Frame sizes from 2.5 ms to 60 ms + * @li Good loss robustness and packet loss concealment (PLC) + * @li Floating point and fixed-point implementation + * + * Documentation sections: + * @li @ref opus_encoder + * @li @ref opus_decoder + * @li @ref opus_repacketizer + * @li @ref opus_multistream + * @li @ref opus_libinfo + * @li @ref opus_custom + */ + +/** @defgroup opus_encoder Opus Encoder + * @{ + * + * @brief This page describes the process and functions used to encode Opus. + * + * Since Opus is a stateful codec, the encoding process starts with creating an encoder + * state. This can be done with: + * + * @code + * int error; + * OpusEncoder *enc; + * enc = opus_encoder_create(Fs, channels, application, &error); + * @endcode + * + * From this point, @c enc can be used for encoding an audio stream. An encoder state + * @b must @b not be used for more than one stream at the same time. Similarly, the encoder + * state @b must @b not be re-initialized for each frame. + * + * While opus_encoder_create() allocates memory for the state, it's also possible + * to initialize pre-allocated memory: + * + * @code + * int size; + * int error; + * OpusEncoder *enc; + * size = opus_encoder_get_size(channels); + * enc = malloc(size); + * error = opus_encoder_init(enc, Fs, channels, application); + * @endcode + * + * where opus_encoder_get_size() returns the required size for the encoder state. Note that + * future versions of this code may change the size, so no assuptions should be made about it. + * + * The encoder state is always continuous in memory and only a shallow copy is sufficient + * to copy it (e.g. memcpy()) + * + * It is possible to change some of the encoder's settings using the opus_encoder_ctl() + * interface. All these settings already default to the recommended value, so they should + * only be changed when necessary. The most common settings one may want to change are: + * + * @code + * opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate)); + * opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity)); + * opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal_type)); + * @endcode + * + * where + * + * @arg bitrate is in bits per second (b/s) + * @arg complexity is a value from 1 to 10, where 1 is the lowest complexity and 10 is the highest + * @arg signal_type is either OPUS_AUTO (default), OPUS_SIGNAL_VOICE, or OPUS_SIGNAL_MUSIC + * + * See @ref opus_encoderctls and @ref opus_genericctls for a complete list of parameters that can be set or queried. Most parameters can be set or changed at any time during a stream. + * + * To encode a frame, opus_encode() or opus_encode_float() must be called with exactly one frame (2.5, 5, 10, 20, 40 or 60 ms) of audio data: + * @code + * len = opus_encode(enc, audio_frame, frame_size, packet, max_packet); + * @endcode + * + * where + *
    + *
  • audio_frame is the audio data in opus_int16 (or float for opus_encode_float())
  • + *
  • frame_size is the duration of the frame in samples (per channel)
  • + *
  • packet is the byte array to which the compressed data is written
  • + *
  • max_packet is the maximum number of bytes that can be written in the packet (4000 bytes is recommended). + * Do not use max_packet to control VBR target bitrate, instead use the #OPUS_SET_BITRATE CTL.
  • + *
+ * + * opus_encode() and opus_encode_float() return the number of bytes actually written to the packet. + * The return value can be negative, which indicates that an error has occurred. If the return value + * is 2 bytes or less, then the packet does not need to be transmitted (DTX). + * + * Once the encoder state if no longer needed, it can be destroyed with + * + * @code + * opus_encoder_destroy(enc); + * @endcode + * + * If the encoder was created with opus_encoder_init() rather than opus_encoder_create(), + * then no action is required aside from potentially freeing the memory that was manually + * allocated for it (calling free(enc) for the example above) + * + */ + +/** Opus encoder state. + * This contains the complete state of an Opus encoder. + * It is position independent and can be freely copied. + * @see opus_encoder_create,opus_encoder_init + */ +typedef struct OpusEncoder OpusEncoder; + +/** Gets the size of an OpusEncoder structure. + * @param[in] channels int: Number of channels. + * This must be 1 or 2. + * @returns The size in bytes. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels); + +/** + */ + +/** Allocates and initializes an encoder state. + * There are three coding modes: + * + * @ref OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice + * signals. It enhances the input signal by high-pass filtering and + * emphasizing formants and harmonics. Optionally it includes in-band + * forward error correction to protect against packet loss. Use this + * mode for typical VoIP applications. Because of the enhancement, + * even at high bitrates the output may sound different from the input. + * + * @ref OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most + * non-voice signals like music. Use this mode for music and mixed + * (music/voice) content, broadcast, and applications requiring less + * than 15 ms of coding delay. + * + * @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that + * disables the speech-optimized mode in exchange for slightly reduced delay. + * This mode can only be set on an newly initialized or freshly reset encoder + * because it changes the codec delay. + * + * This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution). + * @param [in] Fs opus_int32: Sampling rate of input signal (Hz) + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) in input signal + * @param [in] application int: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY) + * @param [out] error int*: @ref opus_errorcodes + * @note Regardless of the sampling rate and number channels selected, the Opus encoder + * can switch to a lower audio bandwidth or number of channels if the bitrate + * selected is too low. This also means that it is safe to always use 48 kHz stereo input + * and let the encoder optimize the encoding. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create( + opus_int32 Fs, + int channels, + int application, + int *error +); + +/** Initializes a previously allocated encoder state + * The memory pointed to by st must be at least the size returned by opus_encoder_get_size(). + * This is intended for applications which use their own allocator instead of malloc. + * @see opus_encoder_create(),opus_encoder_get_size() + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] Fs opus_int32: Sampling rate of input signal (Hz) + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) in input signal + * @param [in] application int: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY) + * @retval #OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_EXPORT int opus_encoder_init( + OpusEncoder *st, + opus_int32 Fs, + int channels, + int application +) OPUS_ARG_NONNULL(1); + +/** Encodes an Opus frame. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] pcm opus_int16*: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size int: Number of samples per channel in the + * input signal. + * This must be an Opus frame size for + * the encoder's sampling rate. + * For example, at 48 kHz the permitted + * values are 120, 240, 480, 960, 1920, + * and 2880. + * Passing in a duration of less than + * 10 ms (480 samples at 48 kHz) will + * prevent the encoder from using the LPC + * or hybrid modes. + * @param [out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode( + OpusEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Encodes an Opus frame from floating point input. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] pcm float*: Input in float format (interleaved if 2 channels), with a normal range of +/-1.0. + * Samples with a range beyond +/-1.0 are supported but will + * be clipped by decoders using the integer API and should + * only be used if it is known that the far end supports + * extended dynamic range. + * length is frame_size*channels*sizeof(float) + * @param [in] frame_size int: Number of samples per channel in the + * input signal. + * This must be an Opus frame size for + * the encoder's sampling rate. + * For example, at 48 kHz the permitted + * values are 120, 240, 480, 960, 1920, + * and 2880. + * Passing in a duration of less than + * 10 ms (480 samples at 48 kHz) will + * prevent the encoder from using the LPC + * or hybrid modes. + * @param [out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode_float( + OpusEncoder *st, + const float *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Frees an OpusEncoder allocated by opus_encoder_create(). + * @param[in] st OpusEncoder*: State to be freed. + */ +OPUS_EXPORT void opus_encoder_destroy(OpusEncoder *st); + +/** Perform a CTL function on an Opus encoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @param st OpusEncoder*: Encoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls or + * @ref opus_encoderctls. + * @see opus_genericctls + * @see opus_encoderctls + */ +OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); +/**@}*/ + +/** @defgroup opus_decoder Opus Decoder + * @{ + * + * @brief This page describes the process and functions used to decode Opus. + * + * The decoding process also starts with creating a decoder + * state. This can be done with: + * @code + * int error; + * OpusDecoder *dec; + * dec = opus_decoder_create(Fs, channels, &error); + * @endcode + * where + * @li Fs is the sampling rate and must be 8000, 12000, 16000, 24000, or 48000 + * @li channels is the number of channels (1 or 2) + * @li error will hold the error code in case of failure (or #OPUS_OK on success) + * @li the return value is a newly created decoder state to be used for decoding + * + * While opus_decoder_create() allocates memory for the state, it's also possible + * to initialize pre-allocated memory: + * @code + * int size; + * int error; + * OpusDecoder *dec; + * size = opus_decoder_get_size(channels); + * dec = malloc(size); + * error = opus_decoder_init(dec, Fs, channels); + * @endcode + * where opus_decoder_get_size() returns the required size for the decoder state. Note that + * future versions of this code may change the size, so no assuptions should be made about it. + * + * The decoder state is always continuous in memory and only a shallow copy is sufficient + * to copy it (e.g. memcpy()) + * + * To decode a frame, opus_decode() or opus_decode_float() must be called with a packet of compressed audio data: + * @code + * frame_size = opus_decode(dec, packet, len, decoded, max_size, 0); + * @endcode + * where + * + * @li packet is the byte array containing the compressed data + * @li len is the exact number of bytes contained in the packet + * @li decoded is the decoded audio data in opus_int16 (or float for opus_decode_float()) + * @li max_size is the max duration of the frame in samples (per channel) that can fit into the decoded_frame array + * + * opus_decode() and opus_decode_float() return the number of samples (per channel) decoded from the packet. + * If that value is negative, then an error has occurred. This can occur if the packet is corrupted or if the audio + * buffer is too small to hold the decoded audio. + * + * Opus is a stateful codec with overlapping blocks and as a result Opus + * packets are not coded independently of each other. Packets must be + * passed into the decoder serially and in the correct order for a correct + * decode. Lost packets can be replaced with loss concealment by calling + * the decoder with a null pointer and zero length for the missing packet. + * + * A single codec state may only be accessed from a single thread at + * a time and any required locking must be performed by the caller. Separate + * streams must be decoded with separate decoder states and can be decoded + * in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK + * defined. + * + */ + +/** Opus decoder state. + * This contains the complete state of an Opus decoder. + * It is position independent and can be freely copied. + * @see opus_decoder_create,opus_decoder_init + */ +typedef struct OpusDecoder OpusDecoder; + +/** Gets the size of an OpusDecoder structure. + * @param [in] channels int: Number of channels. + * This must be 1 or 2. + * @returns The size in bytes. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_size(int channels); + +/** Allocates and initializes a decoder state. + * @param [in] Fs opus_int32: Sample rate to decode at (Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) to decode + * @param [out] error int*: #OPUS_OK Success or @ref opus_errorcodes + * + * Internally Opus stores data at 48000 Hz, so that should be the default + * value for Fs. However, the decoder can efficiently decode to buffers + * at 8, 12, 16, and 24 kHz so if for some reason the caller cannot use + * data at the full sample rate, or knows the compressed data doesn't + * use the full frequency range, it can request decoding at a reduced + * rate. Likewise, the decoder is capable of filling in either mono or + * interleaved stereo pcm buffers, at the caller's request. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusDecoder *opus_decoder_create( + opus_int32 Fs, + int channels, + int *error +); + +/** Initializes a previously allocated decoder state. + * The state must be at least the size returned by opus_decoder_get_size(). + * This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @param [in] st OpusDecoder*: Decoder state. + * @param [in] Fs opus_int32: Sampling rate to decode to (Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) to decode + * @retval #OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_EXPORT int opus_decoder_init( + OpusDecoder *st, + opus_int32 Fs, + int channels +) OPUS_ARG_NONNULL(1); + +/** Decode an Opus packet. + * @param [in] st OpusDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len opus_int32: Number of bytes in payload* + * @param [out] pcm opus_int16*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size Number of samples per channel of available space in \a pcm. + * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will + * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1), + * then frame_size needs to be exactly the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and + * FEC cases, frame_size must be a multiple of 2.5 ms. + * @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be + * decoded. If no such data is available, the frame is decoded as if it were lost. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode( + OpusDecoder *st, + const unsigned char *data, + opus_int32 len, + opus_int16 *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Decode an Opus packet with floating point output. + * @param [in] st OpusDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len opus_int32: Number of bytes in payload + * @param [out] pcm float*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(float) + * @param [in] frame_size Number of samples per channel of available space in \a pcm. + * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will + * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1), + * then frame_size needs to be exactly the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and + * FEC cases, frame_size must be a multiple of 2.5 ms. + * @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be + * decoded. If no such data is available the frame is decoded as if it were lost. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode_float( + OpusDecoder *st, + const unsigned char *data, + opus_int32 len, + float *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on an Opus decoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @param st OpusDecoder*: Decoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls or + * @ref opus_decoderctls. + * @see opus_genericctls + * @see opus_decoderctls + */ +OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); + +/** Frees an OpusDecoder allocated by opus_decoder_create(). + * @param[in] st OpusDecoder*: State to be freed. + */ +OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st); + +/** Parse an opus packet into one or more frames. + * Opus_decode will perform this operation internally so most applications do + * not need to use this function. + * This function does not copy the frames, the returned pointers are pointers into + * the input packet. + * @param [in] data char*: Opus packet to be parsed + * @param [in] len opus_int32: size of data + * @param [out] out_toc char*: TOC pointer + * @param [out] frames char*[48] encapsulated frames + * @param [out] size opus_int16[48] sizes of the encapsulated frames + * @param [out] payload_offset int*: returns the position of the payload within the packet (in bytes) + * @returns number of frames + */ +OPUS_EXPORT int opus_packet_parse( + const unsigned char *data, + opus_int32 len, + unsigned char *out_toc, + const unsigned char *frames[48], + opus_int16 size[48], + int *payload_offset +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5); + +/** Gets the bandwidth of an Opus packet. + * @param [in] data char*: Opus packet + * @retval OPUS_BANDWIDTH_NARROWBAND Narrowband (4kHz bandpass) + * @retval OPUS_BANDWIDTH_MEDIUMBAND Mediumband (6kHz bandpass) + * @retval OPUS_BANDWIDTH_WIDEBAND Wideband (8kHz bandpass) + * @retval OPUS_BANDWIDTH_SUPERWIDEBAND Superwideband (12kHz bandpass) + * @retval OPUS_BANDWIDTH_FULLBAND Fullband (20kHz bandpass) + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_bandwidth(const unsigned char *data) OPUS_ARG_NONNULL(1); + +/** Gets the number of samples per frame from an Opus packet. + * @param [in] data char*: Opus packet. + * This must contain at least one byte of + * data. + * @param [in] Fs opus_int32: Sampling rate in Hz. + * This must be a multiple of 400, or + * inaccurate results will be returned. + * @returns Number of samples per frame. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs) OPUS_ARG_NONNULL(1); + +/** Gets the number of channels from an Opus packet. + * @param [in] data char*: Opus packet + * @returns Number of channels + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_channels(const unsigned char *data) OPUS_ARG_NONNULL(1); + +/** Gets the number of frames in an Opus packet. + * @param [in] packet char*: Opus packet + * @param [in] len opus_int32: Length of packet + * @returns Number of frames + * @retval OPUS_BAD_ARG Insufficient data was passed to the function + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1); + +/** Gets the number of samples of an Opus packet. + * @param [in] packet char*: Opus packet + * @param [in] len opus_int32: Length of packet + * @param [in] Fs opus_int32: Sampling rate in Hz. + * This must be a multiple of 400, or + * inaccurate results will be returned. + * @returns Number of samples + * @retval OPUS_BAD_ARG Insufficient data was passed to the function + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1); + +/** Gets the number of samples of an Opus packet. + * @param [in] dec OpusDecoder*: Decoder state + * @param [in] packet char*: Opus packet + * @param [in] len opus_int32: Length of packet + * @returns Number of samples + * @retval OPUS_BAD_ARG Insufficient data was passed to the function + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); + +/** Applies soft-clipping to bring a float signal within the [-1,1] range. If + * the signal is already in that range, nothing is done. If there are values + * outside of [-1,1], then the signal is clipped as smoothly as possible to + * both fit in the range and avoid creating excessive distortion in the + * process. + * @param [in,out] pcm float*: Input PCM and modified PCM + * @param [in] frame_size int Number of samples per channel to process + * @param [in] channels int: Number of channels + * @param [in,out] softclip_mem float*: State memory for the soft clipping process (one float per channel, initialized to zero) + */ +OPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, float *softclip_mem); + + +/**@}*/ + +/** @defgroup opus_repacketizer Repacketizer + * @{ + * + * The repacketizer can be used to merge multiple Opus packets into a single + * packet or alternatively to split Opus packets that have previously been + * merged. Splitting valid Opus packets is always guaranteed to succeed, + * whereas merging valid packets only succeeds if all frames have the same + * mode, bandwidth, and frame size, and when the total duration of the merged + * packet is no more than 120 ms. The 120 ms limit comes from the + * specification and limits decoder memory requirements at a point where + * framing overhead becomes negligible. + * + * The repacketizer currently only operates on elementary Opus + * streams. It will not manipualte multistream packets successfully, except in + * the degenerate case where they consist of data from a single stream. + * + * The repacketizing process starts with creating a repacketizer state, either + * by calling opus_repacketizer_create() or by allocating the memory yourself, + * e.g., + * @code + * OpusRepacketizer *rp; + * rp = (OpusRepacketizer*)malloc(opus_repacketizer_get_size()); + * if (rp != NULL) + * opus_repacketizer_init(rp); + * @endcode + * + * Then the application should submit packets with opus_repacketizer_cat(), + * extract new packets with opus_repacketizer_out() or + * opus_repacketizer_out_range(), and then reset the state for the next set of + * input packets via opus_repacketizer_init(). + * + * For example, to split a sequence of packets into individual frames: + * @code + * unsigned char *data; + * int len; + * while (get_next_packet(&data, &len)) + * { + * unsigned char out[1276]; + * opus_int32 out_len; + * int nb_frames; + * int err; + * int i; + * err = opus_repacketizer_cat(rp, data, len); + * if (err != OPUS_OK) + * { + * release_packet(data); + * return err; + * } + * nb_frames = opus_repacketizer_get_nb_frames(rp); + * for (i = 0; i < nb_frames; i++) + * { + * out_len = opus_repacketizer_out_range(rp, i, i+1, out, sizeof(out)); + * if (out_len < 0) + * { + * release_packet(data); + * return (int)out_len; + * } + * output_next_packet(out, out_len); + * } + * opus_repacketizer_init(rp); + * release_packet(data); + * } + * @endcode + * + * Alternatively, to combine a sequence of frames into packets that each + * contain up to TARGET_DURATION_MS milliseconds of data: + * @code + * // The maximum number of packets with duration TARGET_DURATION_MS occurs + * // when the frame size is 2.5 ms, for a total of (TARGET_DURATION_MS*2/5) + * // packets. + * unsigned char *data[(TARGET_DURATION_MS*2/5)+1]; + * opus_int32 len[(TARGET_DURATION_MS*2/5)+1]; + * int nb_packets; + * unsigned char out[1277*(TARGET_DURATION_MS*2/2)]; + * opus_int32 out_len; + * int prev_toc; + * nb_packets = 0; + * while (get_next_packet(data+nb_packets, len+nb_packets)) + * { + * int nb_frames; + * int err; + * nb_frames = opus_packet_get_nb_frames(data[nb_packets], len[nb_packets]); + * if (nb_frames < 1) + * { + * release_packets(data, nb_packets+1); + * return nb_frames; + * } + * nb_frames += opus_repacketizer_get_nb_frames(rp); + * // If adding the next packet would exceed our target, or it has an + * // incompatible TOC sequence, output the packets we already have before + * // submitting it. + * // N.B., The nb_packets > 0 check ensures we've submitted at least one + * // packet since the last call to opus_repacketizer_init(). Otherwise a + * // single packet longer than TARGET_DURATION_MS would cause us to try to + * // output an (invalid) empty packet. It also ensures that prev_toc has + * // been set to a valid value. Additionally, len[nb_packets] > 0 is + * // guaranteed by the call to opus_packet_get_nb_frames() above, so the + * // reference to data[nb_packets][0] should be valid. + * if (nb_packets > 0 && ( + * ((prev_toc & 0xFC) != (data[nb_packets][0] & 0xFC)) || + * opus_packet_get_samples_per_frame(data[nb_packets], 48000)*nb_frames > + * TARGET_DURATION_MS*48)) + * { + * out_len = opus_repacketizer_out(rp, out, sizeof(out)); + * if (out_len < 0) + * { + * release_packets(data, nb_packets+1); + * return (int)out_len; + * } + * output_next_packet(out, out_len); + * opus_repacketizer_init(rp); + * release_packets(data, nb_packets); + * data[0] = data[nb_packets]; + * len[0] = len[nb_packets]; + * nb_packets = 0; + * } + * err = opus_repacketizer_cat(rp, data[nb_packets], len[nb_packets]); + * if (err != OPUS_OK) + * { + * release_packets(data, nb_packets+1); + * return err; + * } + * prev_toc = data[nb_packets][0]; + * nb_packets++; + * } + * // Output the final, partial packet. + * if (nb_packets > 0) + * { + * out_len = opus_repacketizer_out(rp, out, sizeof(out)); + * release_packets(data, nb_packets); + * if (out_len < 0) + * return (int)out_len; + * output_next_packet(out, out_len); + * } + * @endcode + * + * An alternate way of merging packets is to simply call opus_repacketizer_cat() + * unconditionally until it fails. At that point, the merged packet can be + * obtained with opus_repacketizer_out() and the input packet for which + * opus_repacketizer_cat() needs to be re-added to a newly reinitialized + * repacketizer state. + */ + +typedef struct OpusRepacketizer OpusRepacketizer; + +/** Gets the size of an OpusRepacketizer structure. + * @returns The size in bytes. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_size(void); + +/** (Re)initializes a previously allocated repacketizer state. + * The state must be at least the size returned by opus_repacketizer_get_size(). + * This can be used for applications which use their own allocator instead of + * malloc(). + * It must also be called to reset the queue of packets waiting to be + * repacketized, which is necessary if the maximum packet duration of 120 ms + * is reached or if you wish to submit packets with a different Opus + * configuration (coding mode, audio bandwidth, frame size, or channel count). + * Failure to do so will prevent a new packet from being added with + * opus_repacketizer_cat(). + * @see opus_repacketizer_create + * @see opus_repacketizer_get_size + * @see opus_repacketizer_cat + * @param rp OpusRepacketizer*: The repacketizer state to + * (re)initialize. + * @returns A pointer to the same repacketizer state that was passed in. + */ +OPUS_EXPORT OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1); + +/** Allocates memory and initializes the new repacketizer with + * opus_repacketizer_init(). + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusRepacketizer *opus_repacketizer_create(void); + +/** Frees an OpusRepacketizer allocated by + * opus_repacketizer_create(). + * @param[in] rp OpusRepacketizer*: State to be freed. + */ +OPUS_EXPORT void opus_repacketizer_destroy(OpusRepacketizer *rp); + +/** Add a packet to the current repacketizer state. + * This packet must match the configuration of any packets already submitted + * for repacketization since the last call to opus_repacketizer_init(). + * This means that it must have the same coding mode, audio bandwidth, frame + * size, and channel count. + * This can be checked in advance by examining the top 6 bits of the first + * byte of the packet, and ensuring they match the top 6 bits of the first + * byte of any previously submitted packet. + * The total duration of audio in the repacketizer state also must not exceed + * 120 ms, the maximum duration of a single packet, after adding this packet. + * + * The contents of the current repacketizer state can be extracted into new + * packets using opus_repacketizer_out() or opus_repacketizer_out_range(). + * + * In order to add a packet with a different configuration or to add more + * audio beyond 120 ms, you must clear the repacketizer state by calling + * opus_repacketizer_init(). + * If a packet is too large to add to the current repacketizer state, no part + * of it is added, even if it contains multiple frames, some of which might + * fit. + * If you wish to be able to add parts of such packets, you should first use + * another repacketizer to split the packet into pieces and add them + * individually. + * @see opus_repacketizer_out_range + * @see opus_repacketizer_out + * @see opus_repacketizer_init + * @param rp OpusRepacketizer*: The repacketizer state to which to + * add the packet. + * @param[in] data const unsigned char*: The packet data. + * The application must ensure + * this pointer remains valid + * until the next call to + * opus_repacketizer_init() or + * opus_repacketizer_destroy(). + * @param len opus_int32: The number of bytes in the packet data. + * @returns An error code indicating whether or not the operation succeeded. + * @retval #OPUS_OK The packet's contents have been added to the repacketizer + * state. + * @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC sequence, + * the packet's TOC sequence was not compatible + * with previously submitted packets (because + * the coding mode, audio bandwidth, frame size, + * or channel count did not match), or adding + * this packet would increase the total amount of + * audio stored in the repacketizer state to more + * than 120 ms. + */ +OPUS_EXPORT int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); + + +/** Construct a new packet from data previously submitted to the repacketizer + * state via opus_repacketizer_cat(). + * @param rp OpusRepacketizer*: The repacketizer state from which to + * construct the new packet. + * @param begin int: The index of the first frame in the current + * repacketizer state to include in the output. + * @param end int: One past the index of the last frame in the + * current repacketizer state to include in the + * output. + * @param[out] data const unsigned char*: The buffer in which to + * store the output packet. + * @param maxlen opus_int32: The maximum number of bytes to store in + * the output buffer. In order to guarantee + * success, this should be at least + * 1276 for a single frame, + * or for multiple frames, + * 1277*(end-begin). + * However, 1*(end-begin) plus + * the size of all packet data submitted to + * the repacketizer since the last call to + * opus_repacketizer_init() or + * opus_repacketizer_create() is also + * sufficient, and possibly much smaller. + * @returns The total size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BAD_ARG [begin,end) was an invalid range of + * frames (begin < 0, begin >= end, or end > + * opus_repacketizer_get_nb_frames()). + * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the + * complete output packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Return the total number of frames contained in packet data submitted to + * the repacketizer state so far via opus_repacketizer_cat() since the last + * call to opus_repacketizer_init() or opus_repacketizer_create(). + * This defines the valid range of packets that can be extracted with + * opus_repacketizer_out_range() or opus_repacketizer_out(). + * @param rp OpusRepacketizer*: The repacketizer state containing the + * frames. + * @returns The total number of frames contained in the packet data submitted + * to the repacketizer state. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1); + +/** Construct a new packet from data previously submitted to the repacketizer + * state via opus_repacketizer_cat(). + * This is a convenience routine that returns all the data submitted so far + * in a single packet. + * It is equivalent to calling + * @code + * opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp), + * data, maxlen) + * @endcode + * @param rp OpusRepacketizer*: The repacketizer state from which to + * construct the new packet. + * @param[out] data const unsigned char*: The buffer in which to + * store the output packet. + * @param maxlen opus_int32: The maximum number of bytes to store in + * the output buffer. In order to guarantee + * success, this should be at least + * 1277*opus_repacketizer_get_nb_frames(rp). + * However, + * 1*opus_repacketizer_get_nb_frames(rp) + * plus the size of all packet data + * submitted to the repacketizer since the + * last call to opus_repacketizer_init() or + * opus_repacketizer_create() is also + * sufficient, and possibly much smaller. + * @returns The total size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the + * complete output packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1); + +/** Pads a given Opus packet to a larger size (possibly changing the TOC sequence). + * @param[in,out] data const unsigned char*: The buffer containing the + * packet to pad. + * @param len opus_int32: The size of the packet. + * This must be at least 1. + * @param new_len opus_int32: The desired size of the packet after padding. + * This must be at least as large as len. + * @returns an error code + * @retval #OPUS_OK \a on success. + * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len. + * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. + */ +OPUS_EXPORT int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len); + +/** Remove all padding from a given Opus packet and rewrite the TOC sequence to + * minimize space usage. + * @param[in,out] data const unsigned char*: The buffer containing the + * packet to strip. + * @param len opus_int32: The size of the packet. + * This must be at least 1. + * @returns The new size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BAD_ARG \a len was less than 1. + * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len); + +/** Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence). + * @param[in,out] data const unsigned char*: The buffer containing the + * packet to pad. + * @param len opus_int32: The size of the packet. + * This must be at least 1. + * @param new_len opus_int32: The desired size of the packet after padding. + * This must be at least 1. + * @param nb_streams opus_int32: The number of streams (not channels) in the packet. + * This must be at least as large as len. + * @returns an error code + * @retval #OPUS_OK \a on success. + * @retval #OPUS_BAD_ARG \a len was less than 1. + * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. + */ +OPUS_EXPORT int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams); + +/** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to + * minimize space usage. + * @param[in,out] data const unsigned char*: The buffer containing the + * packet to strip. + * @param len opus_int32: The size of the packet. + * This must be at least 1. + * @param nb_streams opus_int32: The number of streams (not channels) in the packet. + * This must be at least 1. + * @returns The new size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len. + * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus_custom.h b/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus_custom.h new file mode 100644 index 000000000..2227be011 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus_custom.h @@ -0,0 +1,342 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008-2012 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +/** + @file opus_custom.h + @brief Opus-Custom reference implementation API + */ + +#ifndef OPUS_CUSTOM_H +#define OPUS_CUSTOM_H + +#include "opus_defines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CUSTOM_MODES +# define OPUS_CUSTOM_EXPORT OPUS_EXPORT +# define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT +#else +# define OPUS_CUSTOM_EXPORT +# ifdef OPUS_BUILD +# define OPUS_CUSTOM_EXPORT_STATIC static OPUS_INLINE +# else +# define OPUS_CUSTOM_EXPORT_STATIC +# endif +#endif + +/** @defgroup opus_custom Opus Custom + * @{ + * Opus Custom is an optional part of the Opus specification and + * reference implementation which uses a distinct API from the regular + * API and supports frame sizes that are not normally supported.\ Use + * of Opus Custom is discouraged for all but very special applications + * for which a frame size different from 2.5, 5, 10, or 20 ms is needed + * (for either complexity or latency reasons) and where interoperability + * is less important. + * + * In addition to the interoperability limitations the use of Opus custom + * disables a substantial chunk of the codec and generally lowers the + * quality available at a given bitrate. Normally when an application needs + * a different frame size from the codec it should buffer to match the + * sizes but this adds a small amount of delay which may be important + * in some very low latency applications. Some transports (especially + * constant rate RF transports) may also work best with frames of + * particular durations. + * + * Libopus only supports custom modes if they are enabled at compile time. + * + * The Opus Custom API is similar to the regular API but the + * @ref opus_encoder_create and @ref opus_decoder_create calls take + * an additional mode parameter which is a structure produced by + * a call to @ref opus_custom_mode_create. Both the encoder and decoder + * must create a mode using the same sample rate (fs) and frame size + * (frame size) so these parameters must either be signaled out of band + * or fixed in a particular implementation. + * + * Similar to regular Opus the custom modes support on the fly frame size + * switching, but the sizes available depend on the particular frame size in + * use. For some initial frame sizes on a single on the fly size is available. + */ + +/** Contains the state of an encoder. One encoder state is needed + for each stream. It is initialized once at the beginning of the + stream. Do *not* re-initialize the state for every frame. + @brief Encoder state + */ +typedef struct OpusCustomEncoder OpusCustomEncoder; + +/** State of the decoder. One decoder state is needed for each stream. + It is initialized once at the beginning of the stream. Do *not* + re-initialize the state for every frame. + @brief Decoder state + */ +typedef struct OpusCustomDecoder OpusCustomDecoder; + +/** The mode contains all the information necessary to create an + encoder. Both the encoder and decoder need to be initialized + with exactly the same mode, otherwise the output will be + corrupted. + @brief Mode configuration + */ +typedef struct OpusCustomMode OpusCustomMode; + +/** Creates a new mode struct. This will be passed to an encoder or + * decoder. The mode MUST NOT BE DESTROYED until the encoders and + * decoders that use it are destroyed as well. + * @param [in] Fs int: Sampling rate (8000 to 96000 Hz) + * @param [in] frame_size int: Number of samples (per channel) to encode in each + * packet (64 - 1024, prime factorization must contain zero or more 2s, 3s, or 5s and no other primes) + * @param [out] error int*: Returned error code (if NULL, no error will be returned) + * @return A newly created mode + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error); + +/** Destroys a mode struct. Only call this after all encoders and + * decoders using this mode are destroyed as well. + * @param [in] mode OpusCustomMode*: Mode to be freed. + */ +OPUS_CUSTOM_EXPORT void opus_custom_mode_destroy(OpusCustomMode *mode); + + +#if !defined(OPUS_BUILD) || defined(CELT_ENCODER_C) + +/* Encoder */ +/** Gets the size of an OpusCustomEncoder structure. + * @param [in] mode OpusCustomMode *: Mode configuration + * @param [in] channels int: Number of channels + * @returns size + */ +OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_encoder_get_size( + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1); + +# ifdef CUSTOM_MODES +/** Initializes a previously allocated encoder state + * The memory pointed to by st must be the size returned by opus_custom_encoder_get_size. + * This is intended for applications which use their own allocator instead of malloc. + * @see opus_custom_encoder_create(),opus_custom_encoder_get_size() + * To reset a previously initialized state use the OPUS_RESET_STATE CTL. + * @param [in] st OpusCustomEncoder*: Encoder state + * @param [in] mode OpusCustomMode *: Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * decoder) + * @param [in] channels int: Number of channels + * @return OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT int opus_custom_encoder_init( + OpusCustomEncoder *st, + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); +# endif +#endif + + +/** Creates a new encoder state. Each stream needs its own encoder + * state (can't be shared across simultaneous streams). + * @param [in] mode OpusCustomMode*: Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * decoder) + * @param [in] channels int: Number of channels + * @param [out] error int*: Returns an error code + * @return Newly created encoder state. +*/ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encoder_create( + const OpusCustomMode *mode, + int channels, + int *error +) OPUS_ARG_NONNULL(1); + + +/** Destroys an encoder state. + * @param[in] st OpusCustomEncoder*: State to be freed. + */ +OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st); + +/** Encodes a frame of audio. + * @param [in] st OpusCustomEncoder*: Encoder state + * @param [in] pcm float*: PCM audio in float format, with a normal range of +/-1.0. + * Samples with a range beyond +/-1.0 are supported but will + * be clipped by decoders using the integer API and should + * only be used if it is known that the far end supports + * extended dynamic range. There must be exactly + * frame_size samples per channel. + * @param [in] frame_size int: Number of samples per frame of input signal + * @param [out] compressed char *: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long. + * @param [in] maxCompressedBytes int: Maximum number of bytes to use for compressing the frame + * (can change from one frame to another) + * @return Number of bytes written to "compressed". + * If negative, an error has occurred (see error codes). It is IMPORTANT that + * the length returned be somehow transmitted to the decoder. Otherwise, no + * decoding is possible. + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode_float( + OpusCustomEncoder *st, + const float *pcm, + int frame_size, + unsigned char *compressed, + int maxCompressedBytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Encodes a frame of audio. + * @param [in] st OpusCustomEncoder*: Encoder state + * @param [in] pcm opus_int16*: PCM audio in signed 16-bit format (native endian). + * There must be exactly frame_size samples per channel. + * @param [in] frame_size int: Number of samples per frame of input signal + * @param [out] compressed char *: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long. + * @param [in] maxCompressedBytes int: Maximum number of bytes to use for compressing the frame + * (can change from one frame to another) + * @return Number of bytes written to "compressed". + * If negative, an error has occurred (see error codes). It is IMPORTANT that + * the length returned be somehow transmitted to the decoder. Otherwise, no + * decoding is possible. + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode( + OpusCustomEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *compressed, + int maxCompressedBytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on an Opus custom encoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @see opus_encoderctls + */ +OPUS_CUSTOM_EXPORT int opus_custom_encoder_ctl(OpusCustomEncoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1); + + +#if !defined(OPUS_BUILD) || defined(CELT_DECODER_C) +/* Decoder */ + +/** Gets the size of an OpusCustomDecoder structure. + * @param [in] mode OpusCustomMode *: Mode configuration + * @param [in] channels int: Number of channels + * @returns size + */ +OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_decoder_get_size( + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1); + +/** Initializes a previously allocated decoder state + * The memory pointed to by st must be the size returned by opus_custom_decoder_get_size. + * This is intended for applications which use their own allocator instead of malloc. + * @see opus_custom_decoder_create(),opus_custom_decoder_get_size() + * To reset a previously initialized state use the OPUS_RESET_STATE CTL. + * @param [in] st OpusCustomDecoder*: Decoder state + * @param [in] mode OpusCustomMode *: Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * encoder) + * @param [in] channels int: Number of channels + * @return OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_init( + OpusCustomDecoder *st, + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); + +#endif + + +/** Creates a new decoder state. Each stream needs its own decoder state (can't + * be shared across simultaneous streams). + * @param [in] mode OpusCustomMode: Contains all the information about the characteristics of the + * stream (must be the same characteristics as used for the encoder) + * @param [in] channels int: Number of channels + * @param [out] error int*: Returns an error code + * @return Newly created decoder state. + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decoder_create( + const OpusCustomMode *mode, + int channels, + int *error +) OPUS_ARG_NONNULL(1); + +/** Destroys a decoder state. + * @param[in] st OpusCustomDecoder*: State to be freed. + */ +OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st); + +/** Decode an opus custom frame with floating point output + * @param [in] st OpusCustomDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len int: Number of bytes in payload + * @param [out] pcm float*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(float) + * @param [in] frame_size Number of samples per channel of available space in *pcm. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode_float( + OpusCustomDecoder *st, + const unsigned char *data, + int len, + float *pcm, + int frame_size +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Decode an opus custom frame + * @param [in] st OpusCustomDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len int: Number of bytes in payload + * @param [out] pcm opus_int16*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size Number of samples per channel of available space in *pcm. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode( + OpusCustomDecoder *st, + const unsigned char *data, + int len, + opus_int16 *pcm, + int frame_size +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on an Opus custom decoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @see opus_genericctls + */ +OPUS_CUSTOM_EXPORT int opus_custom_decoder_ctl(OpusCustomDecoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_CUSTOM_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus_defines.h b/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus_defines.h new file mode 100644 index 000000000..ceee5b840 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus_defines.h @@ -0,0 +1,799 @@ +/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +/** + * @file opus_defines.h + * @brief Opus reference implementation constants + */ + +#ifndef OPUS_DEFINES_H +#define OPUS_DEFINES_H + +#include "opus_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup opus_errorcodes Error codes + * @{ + */ +/** No error @hideinitializer*/ +#define OPUS_OK 0 +/** One or more invalid/out of range arguments @hideinitializer*/ +#define OPUS_BAD_ARG -1 +/** Not enough bytes allocated in the buffer @hideinitializer*/ +#define OPUS_BUFFER_TOO_SMALL -2 +/** An internal error was detected @hideinitializer*/ +#define OPUS_INTERNAL_ERROR -3 +/** The compressed data passed is corrupted @hideinitializer*/ +#define OPUS_INVALID_PACKET -4 +/** Invalid/unsupported request number @hideinitializer*/ +#define OPUS_UNIMPLEMENTED -5 +/** An encoder or decoder structure is invalid or already freed @hideinitializer*/ +#define OPUS_INVALID_STATE -6 +/** Memory allocation has failed @hideinitializer*/ +#define OPUS_ALLOC_FAIL -7 +/**@}*/ + +/** @cond OPUS_INTERNAL_DOC */ +/**Export control for opus functions */ + +#ifndef OPUS_EXPORT +# if defined(_WIN32) +# if defined(OPUS_BUILD) && defined(DLL_EXPORT) +# define OPUS_EXPORT __declspec(dllexport) +# else +# define OPUS_EXPORT +# endif +# elif defined(__GNUC__) && defined(OPUS_BUILD) +# define OPUS_EXPORT __attribute__ ((visibility ("default"))) +# else +# define OPUS_EXPORT +# endif +#endif + +# if !defined(OPUS_GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define OPUS_GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define OPUS_GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if OPUS_GNUC_PREREQ(3,0) +# define OPUS_RESTRICT __restrict__ +# elif (defined(_MSC_VER) && _MSC_VER >= 1400) +# define OPUS_RESTRICT __restrict +# else +# define OPUS_RESTRICT +# endif +#else +# define OPUS_RESTRICT restrict +#endif + +#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if OPUS_GNUC_PREREQ(2,7) +# define OPUS_INLINE __inline__ +# elif (defined(_MSC_VER)) +# define OPUS_INLINE __inline +# else +# define OPUS_INLINE +# endif +#else +# define OPUS_INLINE inline +#endif + +/**Warning attributes for opus functions + * NONNULL is not used in OPUS_BUILD to avoid the compiler optimizing out + * some paranoid null checks. */ +#if defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4) +# define OPUS_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) +#else +# define OPUS_WARN_UNUSED_RESULT +#endif +#if !defined(OPUS_BUILD) && defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4) +# define OPUS_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x))) +#else +# define OPUS_ARG_NONNULL(_x) +#endif + +/** These are the actual Encoder CTL ID numbers. + * They should not be used directly by applications. + * In general, SETs should be even and GETs should be odd.*/ +#define OPUS_SET_APPLICATION_REQUEST 4000 +#define OPUS_GET_APPLICATION_REQUEST 4001 +#define OPUS_SET_BITRATE_REQUEST 4002 +#define OPUS_GET_BITRATE_REQUEST 4003 +#define OPUS_SET_MAX_BANDWIDTH_REQUEST 4004 +#define OPUS_GET_MAX_BANDWIDTH_REQUEST 4005 +#define OPUS_SET_VBR_REQUEST 4006 +#define OPUS_GET_VBR_REQUEST 4007 +#define OPUS_SET_BANDWIDTH_REQUEST 4008 +#define OPUS_GET_BANDWIDTH_REQUEST 4009 +#define OPUS_SET_COMPLEXITY_REQUEST 4010 +#define OPUS_GET_COMPLEXITY_REQUEST 4011 +#define OPUS_SET_INBAND_FEC_REQUEST 4012 +#define OPUS_GET_INBAND_FEC_REQUEST 4013 +#define OPUS_SET_PACKET_LOSS_PERC_REQUEST 4014 +#define OPUS_GET_PACKET_LOSS_PERC_REQUEST 4015 +#define OPUS_SET_DTX_REQUEST 4016 +#define OPUS_GET_DTX_REQUEST 4017 +#define OPUS_SET_VBR_CONSTRAINT_REQUEST 4020 +#define OPUS_GET_VBR_CONSTRAINT_REQUEST 4021 +#define OPUS_SET_FORCE_CHANNELS_REQUEST 4022 +#define OPUS_GET_FORCE_CHANNELS_REQUEST 4023 +#define OPUS_SET_SIGNAL_REQUEST 4024 +#define OPUS_GET_SIGNAL_REQUEST 4025 +#define OPUS_GET_LOOKAHEAD_REQUEST 4027 +/* #define OPUS_RESET_STATE 4028 */ +#define OPUS_GET_SAMPLE_RATE_REQUEST 4029 +#define OPUS_GET_FINAL_RANGE_REQUEST 4031 +#define OPUS_GET_PITCH_REQUEST 4033 +#define OPUS_SET_GAIN_REQUEST 4034 +#define OPUS_GET_GAIN_REQUEST 4045 /* Should have been 4035 */ +#define OPUS_SET_LSB_DEPTH_REQUEST 4036 +#define OPUS_GET_LSB_DEPTH_REQUEST 4037 +#define OPUS_GET_LAST_PACKET_DURATION_REQUEST 4039 +#define OPUS_SET_EXPERT_FRAME_DURATION_REQUEST 4040 +#define OPUS_GET_EXPERT_FRAME_DURATION_REQUEST 4041 +#define OPUS_SET_PREDICTION_DISABLED_REQUEST 4042 +#define OPUS_GET_PREDICTION_DISABLED_REQUEST 4043 +/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */ +#define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046 +#define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047 +#define OPUS_GET_IN_DTX_REQUEST 4049 + +/** Defines for the presence of extended APIs. */ +#define OPUS_HAVE_OPUS_PROJECTION_H + +/* Macros to trigger compilation errors when the wrong types are provided to a CTL */ +#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x)) +#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr))) +#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr))) +#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr))) +/** @endcond */ + +/** @defgroup opus_ctlvalues Pre-defined values for CTL interface + * @see opus_genericctls, opus_encoderctls + * @{ + */ +/* Values for the various encoder CTLs */ +#define OPUS_AUTO -1000 /**opus_int32: Allowed values: 0-10, inclusive. + * + * @hideinitializer */ +#define OPUS_SET_COMPLEXITY(x) OPUS_SET_COMPLEXITY_REQUEST, __opus_check_int(x) +/** Gets the encoder's complexity configuration. + * @see OPUS_SET_COMPLEXITY + * @param[out] x opus_int32 *: Returns a value in the range 0-10, + * inclusive. + * @hideinitializer */ +#define OPUS_GET_COMPLEXITY(x) OPUS_GET_COMPLEXITY_REQUEST, __opus_check_int_ptr(x) + +/** Configures the bitrate in the encoder. + * Rates from 500 to 512000 bits per second are meaningful, as well as the + * special values #OPUS_AUTO and #OPUS_BITRATE_MAX. + * The value #OPUS_BITRATE_MAX can be used to cause the codec to use as much + * rate as it can, which is useful for controlling the rate by adjusting the + * output buffer size. + * @see OPUS_GET_BITRATE + * @param[in] x opus_int32: Bitrate in bits per second. The default + * is determined based on the number of + * channels and the input sampling rate. + * @hideinitializer */ +#define OPUS_SET_BITRATE(x) OPUS_SET_BITRATE_REQUEST, __opus_check_int(x) +/** Gets the encoder's bitrate configuration. + * @see OPUS_SET_BITRATE + * @param[out] x opus_int32 *: Returns the bitrate in bits per second. + * The default is determined based on the + * number of channels and the input + * sampling rate. + * @hideinitializer */ +#define OPUS_GET_BITRATE(x) OPUS_GET_BITRATE_REQUEST, __opus_check_int_ptr(x) + +/** Enables or disables variable bitrate (VBR) in the encoder. + * The configured bitrate may not be met exactly because frames must + * be an integer number of bytes in length. + * @see OPUS_GET_VBR + * @see OPUS_SET_VBR_CONSTRAINT + * @param[in] x opus_int32: Allowed values: + *
+ *
0
Hard CBR. For LPC/hybrid modes at very low bit-rate, this can + * cause noticeable quality degradation.
+ *
1
VBR (default). The exact type of VBR is controlled by + * #OPUS_SET_VBR_CONSTRAINT.
+ *
+ * @hideinitializer */ +#define OPUS_SET_VBR(x) OPUS_SET_VBR_REQUEST, __opus_check_int(x) +/** Determine if variable bitrate (VBR) is enabled in the encoder. + * @see OPUS_SET_VBR + * @see OPUS_GET_VBR_CONSTRAINT + * @param[out] x opus_int32 *: Returns one of the following values: + *
+ *
0
Hard CBR.
+ *
1
VBR (default). The exact type of VBR may be retrieved via + * #OPUS_GET_VBR_CONSTRAINT.
+ *
+ * @hideinitializer */ +#define OPUS_GET_VBR(x) OPUS_GET_VBR_REQUEST, __opus_check_int_ptr(x) + +/** Enables or disables constrained VBR in the encoder. + * This setting is ignored when the encoder is in CBR mode. + * @warning Only the MDCT mode of Opus currently heeds the constraint. + * Speech mode ignores it completely, hybrid mode may fail to obey it + * if the LPC layer uses more bitrate than the constraint would have + * permitted. + * @see OPUS_GET_VBR_CONSTRAINT + * @see OPUS_SET_VBR + * @param[in] x opus_int32: Allowed values: + *
+ *
0
Unconstrained VBR.
+ *
1
Constrained VBR (default). This creates a maximum of one + * frame of buffering delay assuming a transport with a + * serialization speed of the nominal bitrate.
+ *
+ * @hideinitializer */ +#define OPUS_SET_VBR_CONSTRAINT(x) OPUS_SET_VBR_CONSTRAINT_REQUEST, __opus_check_int(x) +/** Determine if constrained VBR is enabled in the encoder. + * @see OPUS_SET_VBR_CONSTRAINT + * @see OPUS_GET_VBR + * @param[out] x opus_int32 *: Returns one of the following values: + *
+ *
0
Unconstrained VBR.
+ *
1
Constrained VBR (default).
+ *
+ * @hideinitializer */ +#define OPUS_GET_VBR_CONSTRAINT(x) OPUS_GET_VBR_CONSTRAINT_REQUEST, __opus_check_int_ptr(x) + +/** Configures mono/stereo forcing in the encoder. + * This can force the encoder to produce packets encoded as either mono or + * stereo, regardless of the format of the input audio. This is useful when + * the caller knows that the input signal is currently a mono source embedded + * in a stereo stream. + * @see OPUS_GET_FORCE_CHANNELS + * @param[in] x opus_int32: Allowed values: + *
+ *
#OPUS_AUTO
Not forced (default)
+ *
1
Forced mono
+ *
2
Forced stereo
+ *
+ * @hideinitializer */ +#define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x) +/** Gets the encoder's forced channel configuration. + * @see OPUS_SET_FORCE_CHANNELS + * @param[out] x opus_int32 *: + *
+ *
#OPUS_AUTO
Not forced (default)
+ *
1
Forced mono
+ *
2
Forced stereo
+ *
+ * @hideinitializer */ +#define OPUS_GET_FORCE_CHANNELS(x) OPUS_GET_FORCE_CHANNELS_REQUEST, __opus_check_int_ptr(x) + +/** Configures the maximum bandpass that the encoder will select automatically. + * Applications should normally use this instead of #OPUS_SET_BANDWIDTH + * (leaving that set to the default, #OPUS_AUTO). This allows the + * application to set an upper bound based on the type of input it is + * providing, but still gives the encoder the freedom to reduce the bandpass + * when the bitrate becomes too low, for better overall quality. + * @see OPUS_GET_MAX_BANDWIDTH + * @param[in] x opus_int32: Allowed values: + *
+ *
OPUS_BANDWIDTH_NARROWBAND
4 kHz passband
+ *
OPUS_BANDWIDTH_MEDIUMBAND
6 kHz passband
+ *
OPUS_BANDWIDTH_WIDEBAND
8 kHz passband
+ *
OPUS_BANDWIDTH_SUPERWIDEBAND
12 kHz passband
+ *
OPUS_BANDWIDTH_FULLBAND
20 kHz passband (default)
+ *
+ * @hideinitializer */ +#define OPUS_SET_MAX_BANDWIDTH(x) OPUS_SET_MAX_BANDWIDTH_REQUEST, __opus_check_int(x) + +/** Gets the encoder's configured maximum allowed bandpass. + * @see OPUS_SET_MAX_BANDWIDTH + * @param[out] x opus_int32 *: Allowed values: + *
+ *
#OPUS_BANDWIDTH_NARROWBAND
4 kHz passband
+ *
#OPUS_BANDWIDTH_MEDIUMBAND
6 kHz passband
+ *
#OPUS_BANDWIDTH_WIDEBAND
8 kHz passband
+ *
#OPUS_BANDWIDTH_SUPERWIDEBAND
12 kHz passband
+ *
#OPUS_BANDWIDTH_FULLBAND
20 kHz passband (default)
+ *
+ * @hideinitializer */ +#define OPUS_GET_MAX_BANDWIDTH(x) OPUS_GET_MAX_BANDWIDTH_REQUEST, __opus_check_int_ptr(x) + +/** Sets the encoder's bandpass to a specific value. + * This prevents the encoder from automatically selecting the bandpass based + * on the available bitrate. If an application knows the bandpass of the input + * audio it is providing, it should normally use #OPUS_SET_MAX_BANDWIDTH + * instead, which still gives the encoder the freedom to reduce the bandpass + * when the bitrate becomes too low, for better overall quality. + * @see OPUS_GET_BANDWIDTH + * @param[in] x opus_int32: Allowed values: + *
+ *
#OPUS_AUTO
(default)
+ *
#OPUS_BANDWIDTH_NARROWBAND
4 kHz passband
+ *
#OPUS_BANDWIDTH_MEDIUMBAND
6 kHz passband
+ *
#OPUS_BANDWIDTH_WIDEBAND
8 kHz passband
+ *
#OPUS_BANDWIDTH_SUPERWIDEBAND
12 kHz passband
+ *
#OPUS_BANDWIDTH_FULLBAND
20 kHz passband
+ *
+ * @hideinitializer */ +#define OPUS_SET_BANDWIDTH(x) OPUS_SET_BANDWIDTH_REQUEST, __opus_check_int(x) + +/** Configures the type of signal being encoded. + * This is a hint which helps the encoder's mode selection. + * @see OPUS_GET_SIGNAL + * @param[in] x opus_int32: Allowed values: + *
+ *
#OPUS_AUTO
(default)
+ *
#OPUS_SIGNAL_VOICE
Bias thresholds towards choosing LPC or Hybrid modes.
+ *
#OPUS_SIGNAL_MUSIC
Bias thresholds towards choosing MDCT modes.
+ *
+ * @hideinitializer */ +#define OPUS_SET_SIGNAL(x) OPUS_SET_SIGNAL_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured signal type. + * @see OPUS_SET_SIGNAL + * @param[out] x opus_int32 *: Returns one of the following values: + *
+ *
#OPUS_AUTO
(default)
+ *
#OPUS_SIGNAL_VOICE
Bias thresholds towards choosing LPC or Hybrid modes.
+ *
#OPUS_SIGNAL_MUSIC
Bias thresholds towards choosing MDCT modes.
+ *
+ * @hideinitializer */ +#define OPUS_GET_SIGNAL(x) OPUS_GET_SIGNAL_REQUEST, __opus_check_int_ptr(x) + + +/** Configures the encoder's intended application. + * The initial value is a mandatory argument to the encoder_create function. + * @see OPUS_GET_APPLICATION + * @param[in] x opus_int32: Returns one of the following values: + *
+ *
#OPUS_APPLICATION_VOIP
+ *
Process signal for improved speech intelligibility.
+ *
#OPUS_APPLICATION_AUDIO
+ *
Favor faithfulness to the original input.
+ *
#OPUS_APPLICATION_RESTRICTED_LOWDELAY
+ *
Configure the minimum possible coding delay by disabling certain modes + * of operation.
+ *
+ * @hideinitializer */ +#define OPUS_SET_APPLICATION(x) OPUS_SET_APPLICATION_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured application. + * @see OPUS_SET_APPLICATION + * @param[out] x opus_int32 *: Returns one of the following values: + *
+ *
#OPUS_APPLICATION_VOIP
+ *
Process signal for improved speech intelligibility.
+ *
#OPUS_APPLICATION_AUDIO
+ *
Favor faithfulness to the original input.
+ *
#OPUS_APPLICATION_RESTRICTED_LOWDELAY
+ *
Configure the minimum possible coding delay by disabling certain modes + * of operation.
+ *
+ * @hideinitializer */ +#define OPUS_GET_APPLICATION(x) OPUS_GET_APPLICATION_REQUEST, __opus_check_int_ptr(x) + +/** Gets the total samples of delay added by the entire codec. + * This can be queried by the encoder and then the provided number of samples can be + * skipped on from the start of the decoder's output to provide time aligned input + * and output. From the perspective of a decoding application the real data begins this many + * samples late. + * + * The decoder contribution to this delay is identical for all decoders, but the + * encoder portion of the delay may vary from implementation to implementation, + * version to version, or even depend on the encoder's initial configuration. + * Applications needing delay compensation should call this CTL rather than + * hard-coding a value. + * @param[out] x opus_int32 *: Number of lookahead samples + * @hideinitializer */ +#define OPUS_GET_LOOKAHEAD(x) OPUS_GET_LOOKAHEAD_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's use of inband forward error correction (FEC). + * @note This is only applicable to the LPC layer + * @see OPUS_GET_INBAND_FEC + * @param[in] x opus_int32: Allowed values: + *
+ *
0
Disable inband FEC (default).
+ *
1
Enable inband FEC.
+ *
+ * @hideinitializer */ +#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x) +/** Gets encoder's configured use of inband forward error correction. + * @see OPUS_SET_INBAND_FEC + * @param[out] x opus_int32 *: Returns one of the following values: + *
+ *
0
Inband FEC disabled (default).
+ *
1
Inband FEC enabled.
+ *
+ * @hideinitializer */ +#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's expected packet loss percentage. + * Higher values trigger progressively more loss resistant behavior in the encoder + * at the expense of quality at a given bitrate in the absence of packet loss, but + * greater quality under loss. + * @see OPUS_GET_PACKET_LOSS_PERC + * @param[in] x opus_int32: Loss percentage in the range 0-100, inclusive (default: 0). + * @hideinitializer */ +#define OPUS_SET_PACKET_LOSS_PERC(x) OPUS_SET_PACKET_LOSS_PERC_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured packet loss percentage. + * @see OPUS_SET_PACKET_LOSS_PERC + * @param[out] x opus_int32 *: Returns the configured loss percentage + * in the range 0-100, inclusive (default: 0). + * @hideinitializer */ +#define OPUS_GET_PACKET_LOSS_PERC(x) OPUS_GET_PACKET_LOSS_PERC_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's use of discontinuous transmission (DTX). + * @note This is only applicable to the LPC layer + * @see OPUS_GET_DTX + * @param[in] x opus_int32: Allowed values: + *
+ *
0
Disable DTX (default).
+ *
1
Enabled DTX.
+ *
+ * @hideinitializer */ +#define OPUS_SET_DTX(x) OPUS_SET_DTX_REQUEST, __opus_check_int(x) +/** Gets encoder's configured use of discontinuous transmission. + * @see OPUS_SET_DTX + * @param[out] x opus_int32 *: Returns one of the following values: + *
+ *
0
DTX disabled (default).
+ *
1
DTX enabled.
+ *
+ * @hideinitializer */ +#define OPUS_GET_DTX(x) OPUS_GET_DTX_REQUEST, __opus_check_int_ptr(x) +/** Configures the depth of signal being encoded. + * + * This is a hint which helps the encoder identify silence and near-silence. + * It represents the number of significant bits of linear intensity below + * which the signal contains ignorable quantization or other noise. + * + * For example, OPUS_SET_LSB_DEPTH(14) would be an appropriate setting + * for G.711 u-law input. OPUS_SET_LSB_DEPTH(16) would be appropriate + * for 16-bit linear pcm input with opus_encode_float(). + * + * When using opus_encode() instead of opus_encode_float(), or when libopus + * is compiled for fixed-point, the encoder uses the minimum of the value + * set here and the value 16. + * + * @see OPUS_GET_LSB_DEPTH + * @param[in] x opus_int32: Input precision in bits, between 8 and 24 + * (default: 24). + * @hideinitializer */ +#define OPUS_SET_LSB_DEPTH(x) OPUS_SET_LSB_DEPTH_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured signal depth. + * @see OPUS_SET_LSB_DEPTH + * @param[out] x opus_int32 *: Input precision in bits, between 8 and + * 24 (default: 24). + * @hideinitializer */ +#define OPUS_GET_LSB_DEPTH(x) OPUS_GET_LSB_DEPTH_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's use of variable duration frames. + * When variable duration is enabled, the encoder is free to use a shorter frame + * size than the one requested in the opus_encode*() call. + * It is then the user's responsibility + * to verify how much audio was encoded by checking the ToC byte of the encoded + * packet. The part of the audio that was not encoded needs to be resent to the + * encoder for the next call. Do not use this option unless you really + * know what you are doing. + * @see OPUS_GET_EXPERT_FRAME_DURATION + * @param[in] x opus_int32: Allowed values: + *
+ *
OPUS_FRAMESIZE_ARG
Select frame size from the argument (default).
+ *
OPUS_FRAMESIZE_2_5_MS
Use 2.5 ms frames.
+ *
OPUS_FRAMESIZE_5_MS
Use 5 ms frames.
+ *
OPUS_FRAMESIZE_10_MS
Use 10 ms frames.
+ *
OPUS_FRAMESIZE_20_MS
Use 20 ms frames.
+ *
OPUS_FRAMESIZE_40_MS
Use 40 ms frames.
+ *
OPUS_FRAMESIZE_60_MS
Use 60 ms frames.
+ *
OPUS_FRAMESIZE_80_MS
Use 80 ms frames.
+ *
OPUS_FRAMESIZE_100_MS
Use 100 ms frames.
+ *
OPUS_FRAMESIZE_120_MS
Use 120 ms frames.
+ *
+ * @hideinitializer */ +#define OPUS_SET_EXPERT_FRAME_DURATION(x) OPUS_SET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured use of variable duration frames. + * @see OPUS_SET_EXPERT_FRAME_DURATION + * @param[out] x opus_int32 *: Returns one of the following values: + *
+ *
OPUS_FRAMESIZE_ARG
Select frame size from the argument (default).
+ *
OPUS_FRAMESIZE_2_5_MS
Use 2.5 ms frames.
+ *
OPUS_FRAMESIZE_5_MS
Use 5 ms frames.
+ *
OPUS_FRAMESIZE_10_MS
Use 10 ms frames.
+ *
OPUS_FRAMESIZE_20_MS
Use 20 ms frames.
+ *
OPUS_FRAMESIZE_40_MS
Use 40 ms frames.
+ *
OPUS_FRAMESIZE_60_MS
Use 60 ms frames.
+ *
OPUS_FRAMESIZE_80_MS
Use 80 ms frames.
+ *
OPUS_FRAMESIZE_100_MS
Use 100 ms frames.
+ *
OPUS_FRAMESIZE_120_MS
Use 120 ms frames.
+ *
+ * @hideinitializer */ +#define OPUS_GET_EXPERT_FRAME_DURATION(x) OPUS_GET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int_ptr(x) + +/** If set to 1, disables almost all use of prediction, making frames almost + * completely independent. This reduces quality. + * @see OPUS_GET_PREDICTION_DISABLED + * @param[in] x opus_int32: Allowed values: + *
+ *
0
Enable prediction (default).
+ *
1
Disable prediction.
+ *
+ * @hideinitializer */ +#define OPUS_SET_PREDICTION_DISABLED(x) OPUS_SET_PREDICTION_DISABLED_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured prediction status. + * @see OPUS_SET_PREDICTION_DISABLED + * @param[out] x opus_int32 *: Returns one of the following values: + *
+ *
0
Prediction enabled (default).
+ *
1
Prediction disabled.
+ *
+ * @hideinitializer */ +#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x) + +/**@}*/ + +/** @defgroup opus_genericctls Generic CTLs + * + * These macros are used with the \c opus_decoder_ctl and + * \c opus_encoder_ctl calls to generate a particular + * request. + * + * When called on an \c OpusDecoder they apply to that + * particular decoder instance. When called on an + * \c OpusEncoder they apply to the corresponding setting + * on that encoder instance, if present. + * + * Some usage examples: + * + * @code + * int ret; + * opus_int32 pitch; + * ret = opus_decoder_ctl(dec_ctx, OPUS_GET_PITCH(&pitch)); + * if (ret == OPUS_OK) return ret; + * + * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE); + * opus_decoder_ctl(dec_ctx, OPUS_RESET_STATE); + * + * opus_int32 enc_bw, dec_bw; + * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&enc_bw)); + * opus_decoder_ctl(dec_ctx, OPUS_GET_BANDWIDTH(&dec_bw)); + * if (enc_bw != dec_bw) { + * printf("packet bandwidth mismatch!\n"); + * } + * @endcode + * + * @see opus_encoder, opus_decoder_ctl, opus_encoder_ctl, opus_decoderctls, opus_encoderctls + * @{ + */ + +/** Resets the codec state to be equivalent to a freshly initialized state. + * This should be called when switching streams in order to prevent + * the back to back decoding from giving different results from + * one at a time decoding. + * @hideinitializer */ +#define OPUS_RESET_STATE 4028 + +/** Gets the final state of the codec's entropy coder. + * This is used for testing purposes, + * The encoder and decoder state should be identical after coding a payload + * (assuming no data corruption or software bugs) + * + * @param[out] x opus_uint32 *: Entropy coder state + * + * @hideinitializer */ +#define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x) + +/** Gets the encoder's configured bandpass or the decoder's last bandpass. + * @see OPUS_SET_BANDWIDTH + * @param[out] x opus_int32 *: Returns one of the following values: + *
+ *
#OPUS_AUTO
(default)
+ *
#OPUS_BANDWIDTH_NARROWBAND
4 kHz passband
+ *
#OPUS_BANDWIDTH_MEDIUMBAND
6 kHz passband
+ *
#OPUS_BANDWIDTH_WIDEBAND
8 kHz passband
+ *
#OPUS_BANDWIDTH_SUPERWIDEBAND
12 kHz passband
+ *
#OPUS_BANDWIDTH_FULLBAND
20 kHz passband
+ *
+ * @hideinitializer */ +#define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __opus_check_int_ptr(x) + +/** Gets the sampling rate the encoder or decoder was initialized with. + * This simply returns the Fs value passed to opus_encoder_init() + * or opus_decoder_init(). + * @param[out] x opus_int32 *: Sampling rate of encoder or decoder. + * @hideinitializer + */ +#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x) + +/** If set to 1, disables the use of phase inversion for intensity stereo, + * improving the quality of mono downmixes, but slightly reducing normal + * stereo quality. Disabling phase inversion in the decoder does not comply + * with RFC 6716, although it does not cause any interoperability issue and + * is expected to become part of the Opus standard once RFC 6716 is updated + * by draft-ietf-codec-opus-update. + * @see OPUS_GET_PHASE_INVERSION_DISABLED + * @param[in] x opus_int32: Allowed values: + *
+ *
0
Enable phase inversion (default).
+ *
1
Disable phase inversion.
+ *
+ * @hideinitializer */ +#define OPUS_SET_PHASE_INVERSION_DISABLED(x) OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured phase inversion status. + * @see OPUS_SET_PHASE_INVERSION_DISABLED + * @param[out] x opus_int32 *: Returns one of the following values: + *
+ *
0
Stereo phase inversion enabled (default).
+ *
1
Stereo phase inversion disabled.
+ *
+ * @hideinitializer */ +#define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x) +/** Gets the DTX state of the encoder. + * Returns whether the last encoded frame was either a comfort noise update + * during DTX or not encoded because of DTX. + * @param[out] x opus_int32 *: Returns one of the following values: + *
+ *
0
The encoder is not in DTX.
+ *
1
The encoder is in DTX.
+ *
+ * @hideinitializer */ +#define OPUS_GET_IN_DTX(x) OPUS_GET_IN_DTX_REQUEST, __opus_check_int_ptr(x) + +/**@}*/ + +/** @defgroup opus_decoderctls Decoder related CTLs + * @see opus_genericctls, opus_encoderctls, opus_decoder + * @{ + */ + +/** Configures decoder gain adjustment. + * Scales the decoded output by a factor specified in Q8 dB units. + * This has a maximum range of -32768 to 32767 inclusive, and returns + * OPUS_BAD_ARG otherwise. The default is zero indicating no adjustment. + * This setting survives decoder reset. + * + * gain = pow(10, x/(20.0*256)) + * + * @param[in] x opus_int32: Amount to scale PCM signal by in Q8 dB units. + * @hideinitializer */ +#define OPUS_SET_GAIN(x) OPUS_SET_GAIN_REQUEST, __opus_check_int(x) +/** Gets the decoder's configured gain adjustment. @see OPUS_SET_GAIN + * + * @param[out] x opus_int32 *: Amount to scale PCM signal by in Q8 dB units. + * @hideinitializer */ +#define OPUS_GET_GAIN(x) OPUS_GET_GAIN_REQUEST, __opus_check_int_ptr(x) + +/** Gets the duration (in samples) of the last packet successfully decoded or concealed. + * @param[out] x opus_int32 *: Number of samples (at current sampling rate). + * @hideinitializer */ +#define OPUS_GET_LAST_PACKET_DURATION(x) OPUS_GET_LAST_PACKET_DURATION_REQUEST, __opus_check_int_ptr(x) + +/** Gets the pitch of the last decoded frame, if available. + * This can be used for any post-processing algorithm requiring the use of pitch, + * e.g. time stretching/shortening. If the last frame was not voiced, or if the + * pitch was not coded in the frame, then zero is returned. + * + * This CTL is only implemented for decoder instances. + * + * @param[out] x opus_int32 *: pitch period at 48 kHz (or 0 if not available) + * + * @hideinitializer */ +#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x) + +/**@}*/ + +/** @defgroup opus_libinfo Opus library information functions + * @{ + */ + +/** Converts an opus error code into a human readable string. + * + * @param[in] error int: Error number + * @returns Error string + */ +OPUS_EXPORT const char *opus_strerror(int error); + +/** Gets the libopus version string. + * + * Applications may look for the substring "-fixed" in the version string to + * determine whether they have a fixed-point or floating-point build at + * runtime. + * + * @returns Version string + */ +OPUS_EXPORT const char *opus_get_version_string(void); +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_DEFINES_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus_multistream.h b/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus_multistream.h new file mode 100644 index 000000000..babcee690 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus_multistream.h @@ -0,0 +1,660 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +/** + * @file opus_multistream.h + * @brief Opus reference implementation multistream API + */ + +#ifndef OPUS_MULTISTREAM_H +#define OPUS_MULTISTREAM_H + +#include "opus.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond OPUS_INTERNAL_DOC */ + +/** Macros to trigger compilation errors when the wrong types are provided to a + * CTL. */ +/**@{*/ +#define __opus_check_encstate_ptr(ptr) ((ptr) + ((ptr) - (OpusEncoder**)(ptr))) +#define __opus_check_decstate_ptr(ptr) ((ptr) + ((ptr) - (OpusDecoder**)(ptr))) +/**@}*/ + +/** These are the actual encoder and decoder CTL ID numbers. + * They should not be used directly by applications. + * In general, SETs should be even and GETs should be odd.*/ +/**@{*/ +#define OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST 5120 +#define OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST 5122 +/**@}*/ + +/** @endcond */ + +/** @defgroup opus_multistream_ctls Multistream specific encoder and decoder CTLs + * + * These are convenience macros that are specific to the + * opus_multistream_encoder_ctl() and opus_multistream_decoder_ctl() + * interface. + * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, and + * @ref opus_decoderctls may be applied to a multistream encoder or decoder as + * well. + * In addition, you may retrieve the encoder or decoder state for an specific + * stream via #OPUS_MULTISTREAM_GET_ENCODER_STATE or + * #OPUS_MULTISTREAM_GET_DECODER_STATE and apply CTLs to it individually. + */ +/**@{*/ + +/** Gets the encoder state for an individual stream of a multistream encoder. + * @param[in] x opus_int32: The index of the stream whose encoder you + * wish to retrieve. + * This must be non-negative and less than + * the streams parameter used + * to initialize the encoder. + * @param[out] y OpusEncoder**: Returns a pointer to the given + * encoder state. + * @retval OPUS_BAD_ARG The index of the requested stream was out of range. + * @hideinitializer + */ +#define OPUS_MULTISTREAM_GET_ENCODER_STATE(x,y) OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, __opus_check_int(x), __opus_check_encstate_ptr(y) + +/** Gets the decoder state for an individual stream of a multistream decoder. + * @param[in] x opus_int32: The index of the stream whose decoder you + * wish to retrieve. + * This must be non-negative and less than + * the streams parameter used + * to initialize the decoder. + * @param[out] y OpusDecoder**: Returns a pointer to the given + * decoder state. + * @retval OPUS_BAD_ARG The index of the requested stream was out of range. + * @hideinitializer + */ +#define OPUS_MULTISTREAM_GET_DECODER_STATE(x,y) OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST, __opus_check_int(x), __opus_check_decstate_ptr(y) + +/**@}*/ + +/** @defgroup opus_multistream Opus Multistream API + * @{ + * + * The multistream API allows individual Opus streams to be combined into a + * single packet, enabling support for up to 255 channels. Unlike an + * elementary Opus stream, the encoder and decoder must negotiate the channel + * configuration before the decoder can successfully interpret the data in the + * packets produced by the encoder. Some basic information, such as packet + * duration, can be computed without any special negotiation. + * + * The format for multistream Opus packets is defined in + * RFC 7845 + * and is based on the self-delimited Opus framing described in Appendix B of + * RFC 6716. + * Normal Opus packets are just a degenerate case of multistream Opus packets, + * and can be encoded or decoded with the multistream API by setting + * streams to 1 when initializing the encoder or + * decoder. + * + * Multistream Opus streams can contain up to 255 elementary Opus streams. + * These may be either "uncoupled" or "coupled", indicating that the decoder + * is configured to decode them to either 1 or 2 channels, respectively. + * The streams are ordered so that all coupled streams appear at the + * beginning. + * + * A mapping table defines which decoded channel i + * should be used for each input/output (I/O) channel j. This table is + * typically provided as an unsigned char array. + * Let i = mapping[j] be the index for I/O channel j. + * If i < 2*coupled_streams, then I/O channel j is + * encoded as the left channel of stream (i/2) if i + * is even, or as the right channel of stream (i/2) if + * i is odd. Otherwise, I/O channel j is encoded as + * mono in stream (i - coupled_streams), unless it has the special + * value 255, in which case it is omitted from the encoding entirely (the + * decoder will reproduce it as silence). Each value i must either + * be the special value 255 or be less than streams + coupled_streams. + * + * The output channels specified by the encoder + * should use the + * Vorbis + * channel ordering. A decoder may wish to apply an additional permutation + * to the mapping the encoder used to achieve a different output channel + * order (e.g. for outputing in WAV order). + * + * Each multistream packet contains an Opus packet for each stream, and all of + * the Opus packets in a single multistream packet must have the same + * duration. Therefore the duration of a multistream packet can be extracted + * from the TOC sequence of the first stream, which is located at the + * beginning of the packet, just like an elementary Opus stream: + * + * @code + * int nb_samples; + * int nb_frames; + * nb_frames = opus_packet_get_nb_frames(data, len); + * if (nb_frames < 1) + * return nb_frames; + * nb_samples = opus_packet_get_samples_per_frame(data, 48000) * nb_frames; + * @endcode + * + * The general encoding and decoding process proceeds exactly the same as in + * the normal @ref opus_encoder and @ref opus_decoder APIs. + * See their documentation for an overview of how to use the corresponding + * multistream functions. + */ + +/** Opus multistream encoder state. + * This contains the complete state of a multistream Opus encoder. + * It is position independent and can be freely copied. + * @see opus_multistream_encoder_create + * @see opus_multistream_encoder_init + */ +typedef struct OpusMSEncoder OpusMSEncoder; + +/** Opus multistream decoder state. + * This contains the complete state of a multistream Opus decoder. + * It is position independent and can be freely copied. + * @see opus_multistream_decoder_create + * @see opus_multistream_decoder_init + */ +typedef struct OpusMSDecoder OpusMSDecoder; + +/**\name Multistream encoder functions */ +/**@{*/ + +/** Gets the size of an OpusMSEncoder structure. + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than 255. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_encoder_get_size( + int streams, + int coupled_streams +); + +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_surround_encoder_get_size( + int channels, + int mapping_family +); + + +/** Allocates and initializes a multistream encoder state. + * Call opus_multistream_encoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than the number of channels. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than the number of input channels. + * @param[in] mapping const unsigned char[channels]: Mapping from + * encoded channels to input channels, as described in + * @ref opus_multistream. As an extra constraint, the + * multistream encoder does not allow encoding coupled + * streams for which one channel is unused since this + * is never a good idea. + * @param application int: The target encoder application. + * This must be one of the following: + *
+ *
#OPUS_APPLICATION_VOIP
+ *
Process signal for improved speech intelligibility.
+ *
#OPUS_APPLICATION_AUDIO
+ *
Favor faithfulness to the original input.
+ *
#OPUS_APPLICATION_RESTRICTED_LOWDELAY
+ *
Configure the minimum possible coding delay by disabling certain modes + * of operation.
+ *
+ * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_encoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application, + int *error +) OPUS_ARG_NONNULL(5); + +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_surround_encoder_create( + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + unsigned char *mapping, + int application, + int *error +) OPUS_ARG_NONNULL(4) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6); + +/** Initialize a previously allocated multistream encoder state. + * The memory pointed to by \a st must be at least the size returned by + * opus_multistream_encoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_multistream_encoder_create + * @see opus_multistream_encoder_get_size + * @param st OpusMSEncoder*: Multistream encoder state to initialize. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than the number of channels. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than the number of input channels. + * @param[in] mapping const unsigned char[channels]: Mapping from + * encoded channels to input channels, as described in + * @ref opus_multistream. As an extra constraint, the + * multistream encoder does not allow encoding coupled + * streams for which one channel is unused since this + * is never a good idea. + * @param application int: The target encoder application. + * This must be one of the following: + *
+ *
#OPUS_APPLICATION_VOIP
+ *
Process signal for improved speech intelligibility.
+ *
#OPUS_APPLICATION_AUDIO
+ *
Favor faithfulness to the original input.
+ *
#OPUS_APPLICATION_RESTRICTED_LOWDELAY
+ *
Configure the minimum possible coding delay by disabling certain modes + * of operation.
+ *
+ * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_multistream_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); + +OPUS_EXPORT int opus_multistream_surround_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + unsigned char *mapping, + int application +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6) OPUS_ARG_NONNULL(7); + +/** Encodes a multistream Opus frame. + * @param st OpusMSEncoder*: Multistream encoder state. + * @param[in] pcm const opus_int16*: The input signal as interleaved + * samples. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode( + OpusMSEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Encodes a multistream Opus frame from floating point input. + * @param st OpusMSEncoder*: Multistream encoder state. + * @param[in] pcm const float*: The input signal as interleaved + * samples with a normal range of + * +/-1.0. + * Samples with a range beyond +/-1.0 + * are supported but will be clipped by + * decoders using the integer API and + * should only be used if it is known + * that the far end supports extended + * dynamic range. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode_float( + OpusMSEncoder *st, + const float *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Frees an OpusMSEncoder allocated by + * opus_multistream_encoder_create(). + * @param st OpusMSEncoder*: Multistream encoder state to be freed. + */ +OPUS_EXPORT void opus_multistream_encoder_destroy(OpusMSEncoder *st); + +/** Perform a CTL function on a multistream Opus encoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusMSEncoder*: Multistream encoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_encoderctls, or @ref opus_multistream_ctls. + * @see opus_genericctls + * @see opus_encoderctls + * @see opus_multistream_ctls + */ +OPUS_EXPORT int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); + +/**@}*/ + +/**\name Multistream decoder functions */ +/**@{*/ + +/** Gets the size of an OpusMSDecoder structure. + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_decoder_get_size( + int streams, + int coupled_streams +); + +/** Allocates and initializes a multistream decoder state. + * Call opus_multistream_decoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] mapping const unsigned char[channels]: Mapping from + * coded channels to output channels, as described in + * @ref opus_multistream. + * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSDecoder *opus_multistream_decoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int *error +) OPUS_ARG_NONNULL(5); + +/** Intialize a previously allocated decoder state object. + * The memory pointed to by \a st must be at least the size returned by + * opus_multistream_encoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_multistream_decoder_create + * @see opus_multistream_deocder_get_size + * @param st OpusMSEncoder*: Multistream encoder state to initialize. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] mapping const unsigned char[channels]: Mapping from + * coded channels to output channels, as described in + * @ref opus_multistream. + * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_multistream_decoder_init( + OpusMSDecoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); + +/** Decode a multistream Opus packet. + * @param st OpusMSDecoder*: Multistream decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode( + OpusMSDecoder *st, + const unsigned char *data, + opus_int32 len, + opus_int16 *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Decode a multistream Opus packet with floating point output. + * @param st OpusMSDecoder*: Multistream decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode_float( + OpusMSDecoder *st, + const unsigned char *data, + opus_int32 len, + float *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on a multistream Opus decoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusMSDecoder*: Multistream decoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_decoderctls, or @ref opus_multistream_ctls. + * @see opus_genericctls + * @see opus_decoderctls + * @see opus_multistream_ctls + */ +OPUS_EXPORT int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); + +/** Frees an OpusMSDecoder allocated by + * opus_multistream_decoder_create(). + * @param st OpusMSDecoder: Multistream decoder state to be freed. + */ +OPUS_EXPORT void opus_multistream_decoder_destroy(OpusMSDecoder *st); + +/**@}*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_MULTISTREAM_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus_projection.h b/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus_projection.h new file mode 100644 index 000000000..9dabf4e85 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus_projection.h @@ -0,0 +1,568 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +/** + * @file opus_projection.h + * @brief Opus projection reference API + */ + +#ifndef OPUS_PROJECTION_H +#define OPUS_PROJECTION_H + +#include "opus_multistream.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond OPUS_INTERNAL_DOC */ + +/** These are the actual encoder and decoder CTL ID numbers. + * They should not be used directly by applications.c + * In general, SETs should be even and GETs should be odd.*/ +/**@{*/ +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST 6001 +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST 6003 +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST 6005 +/**@}*/ + + +/** @endcond */ + +/** @defgroup opus_projection_ctls Projection specific encoder and decoder CTLs + * + * These are convenience macros that are specific to the + * opus_projection_encoder_ctl() and opus_projection_decoder_ctl() + * interface. + * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, + * @ref opus_decoderctls, and @ref opus_multistream_ctls may be applied to a + * projection encoder or decoder as well. + */ +/**@{*/ + +/** Gets the gain (in dB. S7.8-format) of the demixing matrix from the encoder. + * @param[out] x opus_int32 *: Returns the gain (in dB. S7.8-format) + * of the demixing matrix. + * @hideinitializer + */ +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN(x) OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST, __opus_check_int_ptr(x) + + +/** Gets the size in bytes of the demixing matrix from the encoder. + * @param[out] x opus_int32 *: Returns the size in bytes of the + * demixing matrix. + * @hideinitializer + */ +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE(x) OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, __opus_check_int_ptr(x) + + +/** Copies the demixing matrix to the supplied pointer location. + * @param[out] x unsigned char *: Returns the demixing matrix to the + * supplied pointer location. + * @param y opus_int32: The size in bytes of the reserved memory at the + * pointer location. + * @hideinitializer + */ +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX(x,y) OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, x, __opus_check_int(y) + + +/**@}*/ + +/** Opus projection encoder state. + * This contains the complete state of a projection Opus encoder. + * It is position independent and can be freely copied. + * @see opus_projection_ambisonics_encoder_create + */ +typedef struct OpusProjectionEncoder OpusProjectionEncoder; + + +/** Opus projection decoder state. + * This contains the complete state of a projection Opus decoder. + * It is position independent and can be freely copied. + * @see opus_projection_decoder_create + * @see opus_projection_decoder_init + */ +typedef struct OpusProjectionDecoder OpusProjectionDecoder; + + +/**\name Projection encoder functions */ +/**@{*/ + +/** Gets the size of an OpusProjectionEncoder structure. + * @param channels int: The total number of input channels to encode. + * This must be no more than 255. + * @param mapping_family int: The mapping family to use for selecting + * the appropriate projection. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_projection_ambisonics_encoder_get_size( + int channels, + int mapping_family +); + + +/** Allocates and initializes a projection encoder state. + * Call opus_projection_encoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param mapping_family int: The mapping family to use for selecting + * the appropriate projection. + * @param[out] streams int *: The total number of streams that will + * be encoded from the input. + * @param[out] coupled_streams int *: Number of coupled (2 channel) + * streams that will be encoded from the input. + * @param application int: The target encoder application. + * This must be one of the following: + *
+ *
#OPUS_APPLICATION_VOIP
+ *
Process signal for improved speech intelligibility.
+ *
#OPUS_APPLICATION_AUDIO
+ *
Favor faithfulness to the original input.
+ *
#OPUS_APPLICATION_RESTRICTED_LOWDELAY
+ *
Configure the minimum possible coding delay by disabling certain modes + * of operation.
+ *
+ * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusProjectionEncoder *opus_projection_ambisonics_encoder_create( + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + int application, + int *error +) OPUS_ARG_NONNULL(4) OPUS_ARG_NONNULL(5); + + +/** Initialize a previously allocated projection encoder state. + * The memory pointed to by \a st must be at least the size returned by + * opus_projection_ambisonics_encoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_projection_ambisonics_encoder_create + * @see opus_projection_ambisonics_encoder_get_size + * @param st OpusProjectionEncoder*: Projection encoder state to initialize. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than the number of channels. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than the number of input channels. + * @param application int: The target encoder application. + * This must be one of the following: + *
+ *
#OPUS_APPLICATION_VOIP
+ *
Process signal for improved speech intelligibility.
+ *
#OPUS_APPLICATION_AUDIO
+ *
Favor faithfulness to the original input.
+ *
#OPUS_APPLICATION_RESTRICTED_LOWDELAY
+ *
Configure the minimum possible coding delay by disabling certain modes + * of operation.
+ *
+ * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_projection_ambisonics_encoder_init( + OpusProjectionEncoder *st, + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + int application +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6); + + +/** Encodes a projection Opus frame. + * @param st OpusProjectionEncoder*: Projection encoder state. + * @param[in] pcm const opus_int16*: The input signal as interleaved + * samples. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode( + OpusProjectionEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + + +/** Encodes a projection Opus frame from floating point input. + * @param st OpusProjectionEncoder*: Projection encoder state. + * @param[in] pcm const float*: The input signal as interleaved + * samples with a normal range of + * +/-1.0. + * Samples with a range beyond +/-1.0 + * are supported but will be clipped by + * decoders using the integer API and + * should only be used if it is known + * that the far end supports extended + * dynamic range. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode_float( + OpusProjectionEncoder *st, + const float *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + + +/** Frees an OpusProjectionEncoder allocated by + * opus_projection_ambisonics_encoder_create(). + * @param st OpusProjectionEncoder*: Projection encoder state to be freed. + */ +OPUS_EXPORT void opus_projection_encoder_destroy(OpusProjectionEncoder *st); + + +/** Perform a CTL function on a projection Opus encoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusProjectionEncoder*: Projection encoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_encoderctls, @ref opus_multistream_ctls, or + * @ref opus_projection_ctls + * @see opus_genericctls + * @see opus_encoderctls + * @see opus_multistream_ctls + * @see opus_projection_ctls + */ +OPUS_EXPORT int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); + + +/**@}*/ + +/**\name Projection decoder functions */ +/**@{*/ + +/** Gets the size of an OpusProjectionDecoder structure. + * @param channels int: The total number of output channels. + * This must be no more than 255. + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_projection_decoder_get_size( + int channels, + int streams, + int coupled_streams +); + + +/** Allocates and initializes a projection decoder state. + * Call opus_projection_decoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] demixing_matrix const unsigned char[demixing_matrix_size]: Demixing matrix + * that mapping from coded channels to output channels, + * as described in @ref opus_projection and + * @ref opus_projection_ctls. + * @param demixing_matrix_size opus_int32: The size in bytes of the + * demixing matrix, as + * described in @ref + * opus_projection_ctls. + * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusProjectionDecoder *opus_projection_decoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + unsigned char *demixing_matrix, + opus_int32 demixing_matrix_size, + int *error +) OPUS_ARG_NONNULL(5); + + +/** Intialize a previously allocated projection decoder state object. + * The memory pointed to by \a st must be at least the size returned by + * opus_projection_decoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_projection_decoder_create + * @see opus_projection_deocder_get_size + * @param st OpusProjectionDecoder*: Projection encoder state to initialize. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] demixing_matrix const unsigned char[demixing_matrix_size]: Demixing matrix + * that mapping from coded channels to output channels, + * as described in @ref opus_projection and + * @ref opus_projection_ctls. + * @param demixing_matrix_size opus_int32: The size in bytes of the + * demixing matrix, as + * described in @ref + * opus_projection_ctls. + * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_projection_decoder_init( + OpusProjectionDecoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + unsigned char *demixing_matrix, + opus_int32 demixing_matrix_size +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); + + +/** Decode a projection Opus packet. + * @param st OpusProjectionDecoder*: Projection decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode( + OpusProjectionDecoder *st, + const unsigned char *data, + opus_int32 len, + opus_int16 *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + + +/** Decode a projection Opus packet with floating point output. + * @param st OpusProjectionDecoder*: Projection decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode_float( + OpusProjectionDecoder *st, + const unsigned char *data, + opus_int32 len, + float *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + + +/** Perform a CTL function on a projection Opus decoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusProjectionDecoder*: Projection decoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_decoderctls, @ref opus_multistream_ctls, or + * @ref opus_projection_ctls. + * @see opus_genericctls + * @see opus_decoderctls + * @see opus_multistream_ctls + * @see opus_projection_ctls + */ +OPUS_EXPORT int opus_projection_decoder_ctl(OpusProjectionDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); + + +/** Frees an OpusProjectionDecoder allocated by + * opus_projection_decoder_create(). + * @param st OpusProjectionDecoder: Projection decoder state to be freed. + */ +OPUS_EXPORT void opus_projection_decoder_destroy(OpusProjectionDecoder *st); + + +/**@}*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_PROJECTION_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus_types.h b/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus_types.h new file mode 100644 index 000000000..7cf675580 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/include/opus_types.h @@ -0,0 +1,166 @@ +/* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */ +/* Modified by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ +/* opus_types.h based on ogg_types.h from libogg */ + +/** + @file opus_types.h + @brief Opus reference implementation types +*/ +#ifndef OPUS_TYPES_H +#define OPUS_TYPES_H + +#define opus_int int /* used for counters etc; at least 16 bits */ +#define opus_int64 long long +#define opus_int8 signed char + +#define opus_uint unsigned int /* used for counters etc; at least 16 bits */ +#define opus_uint64 unsigned long long +#define opus_uint8 unsigned char + +/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */ +#if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H)) +#include +# undef opus_int64 +# undef opus_int8 +# undef opus_uint64 +# undef opus_uint8 + typedef int8_t opus_int8; + typedef uint8_t opus_uint8; + typedef int16_t opus_int16; + typedef uint16_t opus_uint16; + typedef int32_t opus_int32; + typedef uint32_t opus_uint32; + typedef int64_t opus_int64; + typedef uint64_t opus_uint64; +#elif defined(_WIN32) + +# if defined(__CYGWIN__) +# include <_G_config.h> + typedef _G_int32_t opus_int32; + typedef _G_uint32_t opus_uint32; + typedef _G_int16 opus_int16; + typedef _G_uint16 opus_uint16; +# elif defined(__MINGW32__) + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; +# elif defined(__MWERKS__) + typedef int opus_int32; + typedef unsigned int opus_uint32; + typedef short opus_int16; + typedef unsigned short opus_uint16; +# else + /* MSVC/Borland */ + typedef __int32 opus_int32; + typedef unsigned __int32 opus_uint32; + typedef __int16 opus_int16; + typedef unsigned __int16 opus_uint16; +# endif + +#elif defined(__MACOS__) + +# include + typedef SInt16 opus_int16; + typedef UInt16 opus_uint16; + typedef SInt32 opus_int32; + typedef UInt32 opus_uint32; + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t opus_int16; + typedef u_int16_t opus_uint16; + typedef int32_t opus_int32; + typedef u_int32_t opus_uint32; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16 opus_int16; + typedef u_int16 opus_uint16; + typedef int32_t opus_int32; + typedef u_int32_t opus_uint32; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined(R5900) + + /* PS2 EE */ + typedef int opus_int32; + typedef unsigned opus_uint32; + typedef short opus_int16; + typedef unsigned short opus_uint16; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short opus_int16; + typedef unsigned short opus_uint16; + typedef signed int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef long opus_int32; + typedef unsigned long opus_uint32; + +#elif defined(CONFIG_TI_C6X) + + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#else + + /* Give up, take a reasonable guess */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#endif + +#endif /* OPUS_TYPES_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/m4/as-gcc-inline-assembly.m4 b/native/opennow-streamer/vendor/audiopus-sys/opus/m4/as-gcc-inline-assembly.m4 new file mode 100644 index 000000000..b0d2da414 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/m4/as-gcc-inline-assembly.m4 @@ -0,0 +1,98 @@ +dnl as-gcc-inline-assembly.m4 0.1.0 + +dnl autostars m4 macro for detection of gcc inline assembly + +dnl David Schleef + +dnl AS_COMPILER_FLAG(ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) +dnl Tries to compile with the given CFLAGS. +dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, +dnl and ACTION-IF-NOT-ACCEPTED otherwise. + +AC_DEFUN([AS_GCC_INLINE_ASSEMBLY], +[ + AC_MSG_CHECKING([if compiler supports gcc-style inline assembly]) + + AC_TRY_COMPILE([], [ +#ifdef __GNUC_MINOR__ +#if (__GNUC__ * 1000 + __GNUC_MINOR__) < 3004 +#error GCC before 3.4 has critical bugs compiling inline assembly +#endif +#endif +__asm__ (""::) ], [flag_ok=yes], [flag_ok=no]) + + if test "X$flag_ok" = Xyes ; then + $1 + true + else + $2 + true + fi + AC_MSG_RESULT([$flag_ok]) +]) + +AC_DEFUN([AS_ASM_ARM_NEON], +[ + AC_MSG_CHECKING([if assembler supports NEON instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__("vorr d0,d0,d0")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) + +AC_DEFUN([AS_ASM_ARM_NEON_FORCE], +[ + AC_MSG_CHECKING([if assembler supports NEON instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__(".arch armv7-a\n.fpu neon\n.object_arch armv4t\nvorr d0,d0,d0")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) + +AC_DEFUN([AS_ASM_ARM_MEDIA], +[ + AC_MSG_CHECKING([if assembler supports ARMv6 media instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__("shadd8 r3,r3,r3")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) + +AC_DEFUN([AS_ASM_ARM_MEDIA_FORCE], +[ + AC_MSG_CHECKING([if assembler supports ARMv6 media instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__(".arch armv6\n.object_arch armv4t\nshadd8 r3,r3,r3")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) + +AC_DEFUN([AS_ASM_ARM_EDSP], +[ + AC_MSG_CHECKING([if assembler supports EDSP instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__("qadd r3,r3,r3")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) + +AC_DEFUN([AS_ASM_ARM_EDSP_FORCE], +[ + AC_MSG_CHECKING([if assembler supports EDSP instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__(".arch armv5te\n.object_arch armv4t\nqadd r3,r3,r3")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/m4/ax_add_fortify_source.m4 b/native/opennow-streamer/vendor/audiopus-sys/opus/m4/ax_add_fortify_source.m4 new file mode 100644 index 000000000..1c89e4108 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/m4/ax_add_fortify_source.m4 @@ -0,0 +1,53 @@ +# =========================================================================== +# Modified from https://www.gnu.org/software/autoconf-archive/ax_add_fortify_source.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_ADD_FORTIFY_SOURCE +# +# DESCRIPTION +# +# Check whether -D_FORTIFY_SOURCE=2 can be added to CFLAGS without macro +# redefinition warnings. Some distributions (such as Gentoo Linux) enable +# _FORTIFY_SOURCE globally in their compilers, leading to unnecessary +# warnings in the form of +# +# :0:0: error: "_FORTIFY_SOURCE" redefined [-Werror] +# : note: this is the location of the previous definition +# +# which is a problem if -Werror is enabled. This macro checks whether +# _FORTIFY_SOURCE is already defined, and if not, adds -D_FORTIFY_SOURCE=2 +# to CFLAGS. +# +# LICENSE +# +# Copyright (c) 2017 David Seifert +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 1 + +AC_DEFUN([AX_ADD_FORTIFY_SOURCE],[ + AC_MSG_CHECKING([whether to add -D_FORTIFY_SOURCE=2 to CFLAGS]) + AC_LINK_IFELSE([ + AC_LANG_SOURCE( + [[ + int main() { + #ifndef _FORTIFY_SOURCE + return 0; + #else + this_is_an_error; + #endif + } + ]] + )], [ + AC_MSG_RESULT([yes]) + CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" + ], [ + AC_MSG_RESULT([no]) + ]) +]) diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/m4/opus-intrinsics.m4 b/native/opennow-streamer/vendor/audiopus-sys/opus/m4/opus-intrinsics.m4 new file mode 100644 index 000000000..a262ca181 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/m4/opus-intrinsics.m4 @@ -0,0 +1,29 @@ +dnl opus-intrinsics.m4 +dnl macro for testing for support for compiler intrinsics, either by default or with a compiler flag + +dnl OPUS_CHECK_INTRINSICS(NAME-OF-INTRINSICS, COMPILER-FLAG-FOR-INTRINSICS, VAR-IF-PRESENT, VAR-IF-DEFAULT, TEST-PROGRAM-HEADER, TEST-PROGRAM-BODY) +AC_DEFUN([OPUS_CHECK_INTRINSICS], +[ + AC_MSG_CHECKING([if compiler supports $1 intrinsics]) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM($5, $6)], + [ + $3=1 + $4=1 + AC_MSG_RESULT([yes]) + ],[ + $4=0 + AC_MSG_RESULT([no]) + AC_MSG_CHECKING([if compiler supports $1 intrinsics with $2]) + save_CFLAGS="$CFLAGS"; CFLAGS="$CFLAGS $2" + AC_LINK_IFELSE([AC_LANG_PROGRAM($5, $6)], + [ + AC_MSG_RESULT([yes]) + $3=1 + ],[ + AC_MSG_RESULT([no]) + $3=0 + ]) + CFLAGS="$save_CFLAGS" + ]) +]) diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/meson.build b/native/opennow-streamer/vendor/audiopus-sys/opus/meson.build new file mode 100644 index 000000000..41f69353f --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/meson.build @@ -0,0 +1,675 @@ +project('opus', 'c', + version: run_command('meson/get-version.py', '--package-version', check: true).stdout().strip(), + meson_version: '>=0.54.0', + default_options: ['warning_level=2', + 'c_std=gnu99', + 'buildtype=debugoptimized']) + +libversion = run_command('meson/get-version.py', '--libtool-version', check: true).stdout().strip() +macosversion = run_command('meson/get-version.py', '--darwin-version', check: true).stdout().strip() + +cc = meson.get_compiler('c') +host_system = host_machine.system() +host_cpu_family = host_machine.cpu_family() +top_srcdir = meson.current_source_dir() +top_builddir = meson.current_build_dir() + +opus_includes = include_directories('.', 'include', 'celt', 'silk') +opus_public_includes = include_directories('include') + +add_project_arguments('-DOPUS_BUILD', language: 'c') +add_project_arguments('-DHAVE_CONFIG_H', language: 'c') + +if host_system == 'windows' + if cc.get_argument_syntax() == 'msvc' + add_project_arguments('-D_CRT_SECURE_NO_WARNINGS', language: 'c') + endif +endif + +if cc.get_argument_syntax() == 'gnu' + add_project_arguments('-D_FORTIFY_SOURCE=2', language: 'c') +endif + +# Check for extra compiler args +additional_c_args = [] +if cc.get_argument_syntax() != 'msvc' + additional_c_args += [ + '-fvisibility=hidden', + '-Wcast-align', + '-Wnested-externs', + '-Wshadow', + '-Wstrict-prototypes', + ] + + # On Windows, -fstack-protector-strong adds a libssp-0.dll dependency and + # prevents static linking + if host_system != 'windows' + additional_c_args += ['-fstack-protector-strong'] + endif +endif + +foreach arg : additional_c_args + if cc.has_argument(arg) + add_project_arguments(arg, language: 'c') + endif +endforeach + +# Windows MSVC warnings +if cc.get_id() == 'msvc' + # Ignore several spurious warnings. + # If a warning is completely useless and spammy, use '/wdXXXX' to suppress it + # If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once + # NOTE: Only add warnings here if you are sure they're spurious + add_project_arguments('/wd4035', '/wd4715', '/wd4116', '/wd4046', '/wd4068', + '/wd4820', '/wd4244', '/wd4255', '/wd4668', + language : 'c') +endif + +opus_version = meson.project_version() + +opus_conf = configuration_data() +opus_conf.set('PACKAGE_BUGREPORT', '"opus@xiph.org"') +opus_conf.set('PACKAGE_NAME', '"opus"') +opus_conf.set('PACKAGE_STRING', '"opus @0@"'.format(opus_version)) +opus_conf.set('PACKAGE_TARNAME', '"opus"') +opus_conf.set('PACKAGE_URL', '""') +opus_conf.set('PACKAGE_VERSION', '"@0@"'.format(opus_version)) + +# FIXME: optional Ne10 dependency +have_arm_ne10 = false + +libm = cc.find_library('m', required : false) + +opus_conf.set('HAVE_LRINTF', cc.has_function('lrintf', prefix: '#include ', dependencies: libm)) +opus_conf.set('HAVE_LRINT', cc.has_function('lrint', prefix: '#include ', dependencies: libm)) +opus_conf.set('HAVE___MALLOC_HOOK', cc.has_function('__malloc_hook', prefix: '#include ')) +opus_conf.set('HAVE_STDINT_H', cc.check_header('stdint.h')) + +# Check for restrict keyword +restrict_tmpl = ''' +typedef int * int_ptr; +int foo (int_ptr @0@ ip, int * @0@ baz[]) { + return ip[0]; +} +int main (int argc, char ** argv) { + int s[1]; + int * @0@ t = s; + t[0] = 0; + return foo(t, (void *)0); +}''' +# Define restrict to the equivalent of the C99 restrict keyword, or to +# nothing if this is not supported. Do not define if restrict is +# supported directly. +if not cc.compiles(restrict_tmpl.format('restrict'), name : 'restrict keyword') + if cc.compiles(restrict_tmpl.format('__restrict'), name : '__restrict') + opus_conf.set('restrict', '__restrict') + elif cc.compiles(restrict_tmpl.format('__restrict__'), name : '__restrict__') + opus_conf.set('restrict', '__restrict') + elif cc.compiles(restrict_tmpl.format('_Restrict'), name : '_Restrict') + opus_conf.set('restrict', '_Restrict') + else + opus_conf.set('restrict', '/**/') + endif +endif + +# Check for C99 variable-size arrays, or alloca() as fallback +msg_use_alloca = false +if cc.compiles('''static int x; + char some_func (void) { + char a[++x]; + a[sizeof a - 1] = 0; + int N; + return a[0]; + }''', name : 'C99 variable-size arrays') + opus_conf.set('VAR_ARRAYS', 1) + msg_use_alloca = 'NO (using C99 variable-size arrays instead)' +elif cc.compiles('''#include + void some_func (void) { + int foo=10; + int * array = alloca(foo); + }''', name : 'alloca (alloca.h)') + opus_conf.set('USE_ALLOCA', true) + opus_conf.set('HAVE_ALLOCA_H', true) + msg_use_alloca = true +elif cc.compiles('''#include + #include + void some_func (void) { + int foo=10; + int * array = alloca(foo); + }''', name : 'alloca (std)') + opus_conf.set('USE_ALLOCA', true) + msg_use_alloca = true +endif + +opts = [ + [ 'fixed-point', 'FIXED_POINT' ], + [ 'fixed-point-debug', 'FIXED_DEBUG' ], + [ 'custom-modes', 'CUSTOM_MODES' ], + [ 'float-approx', 'FLOAT_APPROX' ], + [ 'assertions', 'ENABLE_ASSERTIONS' ], + [ 'hardening', 'ENABLE_HARDENING' ], + [ 'fuzzing', 'FUZZING' ], + [ 'check-asm', 'OPUS_CHECK_ASM' ], +] + +foreach opt : opts + # we assume these are all boolean options + opt_foo = get_option(opt[0]) + if opt_foo + opus_conf.set(opt[1], 1) + endif + set_variable('opt_' + opt[0].underscorify(), opt_foo) +endforeach + +opt_asm = get_option('asm') +opt_rtcd = get_option('rtcd') +opt_intrinsics = get_option('intrinsics') +extra_programs = get_option('extra-programs') +opt_tests = get_option('tests') + +disable_float_api = not get_option('float-api') +if disable_float_api + opus_conf.set('DISABLE_FLOAT_API', 1) +endif + +# This is for the description in the pkg-config .pc file +if opt_fixed_point + pc_build = 'fixed-point' +else + pc_build = 'floating-point' +endif +if opt_custom_modes + pc_build = pc_build + ', custom modes' +endif + +rtcd_support = [] +# With GCC, Clang, ICC, etc, we differentiate between 'may support this SIMD' +# and 'presume we have this SIMD' by checking whether the SIMD / intrinsics can +# be compiled by the compiler as-is (presume) or with SIMD cflags (may have). +# With MSVC, the compiler will always build SIMD/intrinsics targeting all +# specific instruction sets supported by that version of the compiler. No +# special arguments are ever needed. If runtime CPU detection is not disabled, +# we must always assume that we only 'may have' it. +opus_can_presume_simd = true +if cc.get_argument_syntax() == 'msvc' + if opt_rtcd.disabled() + warning('Building with an MSVC-like compiler and runtime CPU detection is disabled. Outputs may not run on all @0@ CPUs.'.format(host_cpu_family)) + else + opus_can_presume_simd = false + endif +endif + +opus_arm_external_asm = false + +asm_tmpl = ''' +int main (int argc, char ** argv) { + __asm__("@0@"); + return 0; +}''' + +asm_optimization = [] +inline_optimization = [] +if not opt_asm.disabled() + # Currently we only have inline asm for fixed-point + if host_cpu_family == 'arm' and opt_fixed_point + opus_conf.set('OPUS_ARM_ASM', true) + + # Check if compiler supports gcc-style inline assembly + if cc.compiles('''#ifdef __GNUC_MINOR__ + #if (__GNUC__ * 1000 + __GNUC_MINOR__) < 3004 + #error GCC before 3.4 has critical bugs compiling inline assembly + #endif + #endif + __asm__ (""::)''', + name : 'compiler supports gcc-style inline assembly') + + opus_conf.set('OPUS_ARM_INLINE_ASM', 1) + + # AS_ASM_ARM_EDSP + if cc.compiles(asm_tmpl.format('qadd r3,r3,r3'), + name : 'assembler supports EDSP instructions on ARM') + opus_conf.set('OPUS_ARM_INLINE_EDSP', 1) + inline_optimization += ['ESDP'] + endif + + # AS_ASM_ARM_MEDIA + if cc.compiles(asm_tmpl.format('shadd8 r3,r3,r3'), + name : 'assembler supports ARMv6 media instructions on ARM') + opus_conf.set('OPUS_ARM_INLINE_MEDIA', 1) + inline_optimization += ['Media'] + endif + + # AS_ASM_ARM_NEON + if cc.compiles(asm_tmpl.format('vorr d0,d0,d0'), + name : 'assembler supports NEON instructions on ARM') + opus_conf.set('OPUS_ARM_INLINE_NEON', 1) + inline_optimization += ['NEON'] + endif + endif + + # We need Perl to translate RVCT-syntax asm to gas syntax + perl = find_program('perl', required: get_option('asm')) + if perl.found() + opus_arm_external_asm = true + # opus_arm_presume_* mean we can and will use those instructions + # directly without doing runtime CPU detection. + # opus_arm_may_have_* mean we can emit those instructions, but we can + # only use them after runtime detection. + # The same rules apply for x86 assembly and intrinsics. + + opus_arm_may_have_edsp = opus_conf.has('OPUS_ARM_INLINE_EDSP') + opus_arm_presume_edsp = opus_arm_may_have_edsp and opus_can_presume_simd + + opus_arm_may_have_media = opus_conf.has('OPUS_ARM_INLINE_MEDIA') + opus_arm_presume_media = opus_arm_may_have_media and opus_can_presume_simd + + opus_arm_may_have_neon = opus_conf.has('OPUS_ARM_INLINE_NEON') + opus_arm_presume_neon = opus_arm_may_have_neon and opus_can_presume_simd + + if not opt_rtcd.disabled() + if not opus_arm_may_have_edsp + message('Trying to force-enable armv5e EDSP instructions...') + # AS_ASM_ARM_EDSP_FORCE + opus_arm_may_have_edsp = cc.compiles(asm_tmpl.format('.arch armv5te\n.object_arch armv4t\nqadd r3,r3,r3'), + name : 'Assembler supports EDSP instructions on ARM (forced)') + endif + if not opus_arm_may_have_media + message('Trying to force-enable ARMv6 media instructions...') + opus_arm_may_have_media = cc.compiles(asm_tmpl.format('.arch armv6\n.object_arch armv4t\nshadd8 r3,r3,r3'), + name : 'Assembler supports ARMv6 media instructions on ARM (forced)') + endif + if not opus_arm_may_have_neon + message('Trying to force-enable NEON instructions...') + opus_arm_may_have_neon = cc.compiles(asm_tmpl.format('.arch armv7-a\n.fpu neon\n.object_arch armv4t\nvorr d0,d0,d0'), + name : 'Assembler supports NEON instructions on ARM (forced)') + endif + endif + + if opus_arm_may_have_edsp + opus_conf.set('OPUS_ARM_MAY_HAVE_EDSP', 1) + if opus_arm_presume_edsp + opus_conf.set('OPUS_ARM_PRESUME_EDSP', 1) + asm_optimization += ['EDSP'] + else + rtcd_support += ['EDSP'] + endif + endif + if opus_arm_may_have_media + opus_conf.set('OPUS_ARM_MAY_HAVE_MEDIA', 1) + if opus_arm_presume_media + opus_conf.set('OPUS_ARM_PRESUME_MEDIA', 1) + asm_optimization += ['Media'] + else + rtcd_support += ['Media'] + endif + endif + if opus_arm_may_have_neon + opus_conf.set('OPUS_ARM_MAY_HAVE_NEON', 1) + if opus_arm_presume_neon + opus_conf.set('OPUS_ARM_PRESUME_NEON', 1) + asm_optimization += ['NEON'] + else + rtcd_support += ['NEON'] + endif + endif + + if cc.get_define('__APPLE__') + arm2gnu_args = ['--apple'] + else + arm2gnu_args = [] + endif + endif # found perl + else # arm + enable fixed point + if opt_asm.enabled() + error('asm option is enabled, but no assembly support for ' + host_cpu_family) + endif + endif +endif # enable asm + +# Check whether we require assembly and we support assembly on this arch, +# but none were detected. Can happen because of incorrect compiler flags, such +# as missing -mfloat-abi=softfp on ARM32 softfp architectures. +if opt_asm.enabled() and (asm_optimization.length() + inline_optimization.length()) == 0 + error('asm option was enabled, but no assembly support was detected') +endif + +# XXX: NEON has hardfp vs softfp compiler configuration issues +# When targeting ARM32 softfp, we sometimes need to explicitly pass +# -mfloat-abi=softfp to enable NEON. F.ex., on Android. It should +# be set in the cross file. +arm_neon_intr_link_args = ['-mfpu=neon'] + +have_sse = false +have_sse2 = false +have_sse4_1 = false +have_avx = false # no avx opus code yet +have_neon_intr = false + +intrinsics_support = [] +if not opt_intrinsics.disabled() + if host_cpu_family in ['arm', 'aarch64'] + # Check for ARMv7/AArch64 neon intrinsics + intrin_check = ''' + #include + int main (void) { + static float32x4_t A0, A1, SUMM; + SUMM = vmlaq_f32(SUMM, A0, A1); + return (int)vgetq_lane_f32(SUMM, 0); + }''' + intrin_name = 'ARMv7/AArch64 NEON' + if cc.links(intrin_check, + name: 'compiler supports @0@ intrinsics'.format(intrin_name)) + opus_arm_presume_neon_intr = opus_can_presume_simd + opus_arm_may_have_neon_intr = true + else + opus_arm_presume_neon_intr = false + if cc.links(intrin_check, + args: arm_neon_intr_link_args, + name: 'compiler supports @0@ intrinsics with @1@'.format(intrin_name, ' '.join(arm_neon_intr_link_args))) + opus_arm_may_have_neon_intr = true + else + opus_arm_may_have_neon_intr = false + endif + endif + + if opus_arm_may_have_neon_intr + have_neon_intr = true + intrinsics_support += [intrin_name] + opus_conf.set('OPUS_ARM_MAY_HAVE_NEON_INTR', 1) + if opus_arm_presume_neon_intr + opus_conf.set('OPUS_ARM_PRESUME_NEON_INTR', 1) + else + rtcd_support += [intrin_name] + opus_neon_intr_args = arm_neon_intr_link_args + endif + else + message('Compiler does not support @0@ intrinsics'.format(intrin_name)) + endif + + # Check for aarch64 neon intrinsics + intrin_check = ''' + #include + int main (void) { + static int32_t IN; + static int16_t OUT; + OUT = vqmovns_s32(IN); + }''' + intrin_name = 'AArch64 NEON' + if cc.links(intrin_check, + name: 'compiler supports @0@ intrinsics'.format(intrin_name)) + opus_arm_presume_aarch64_neon_intr = opus_can_presume_simd + opus_arm_may_have_aarch64_neon_intr = true + else + opus_arm_presume_aarch64_neon_intr = false + if cc.links(intrin_check, + args: arm_neon_intr_link_args, + name: 'compiler supports @0@ intrinsics with @1@'.format(intrin_name, ' '.join(arm_neon_intr_link_args))) + opus_arm_may_have_aarch64_neon_intr = true + else + opus_arm_may_have_aarch64_neon_intr = false + endif + endif + + if opus_arm_may_have_aarch64_neon_intr + intrinsics_support += [intrin_name] + opus_conf.set('OPUS_X86_MAY_HAVE_AARCH64_NEON_INTR', 1) + if opus_arm_presume_aarch64_neon_intr + opus_conf.set('OPUS_X86_PRESUME_AARCH64_NEON_INTR', 1) + endif + else + message('Compiler does not support @0@ intrinsics'.format(intrin_name)) + endif + elif host_cpu_family in ['x86', 'x86_64'] + # XXX: allow external override/specification of the flags + x86_intrinsics = [ + [ 'SSE', 'xmmintrin.h', '__m128', '_mm_setzero_ps()', ['-msse'] ], + [ 'SSE2', 'emmintrin.h', '__m128i', '_mm_setzero_si128()', ['-msse2'] ], + [ 'SSE4.1', 'smmintrin.h', '__m128i', '_mm_setzero_si128(); mtest = _mm_cmpeq_epi64(mtest, mtest)', ['-msse4.1'] ], + [ 'AVX', 'immintrin.h', '__m256', '_mm256_setzero_ps()', ['-mavx'] ], + ] + + foreach intrin : x86_intrinsics + intrin_check = '''#include <@0@> + int main (int argc, char ** argv) { + static @1@ mtest; + mtest = @2@; + return *((unsigned char *) &mtest) != 0; + }'''.format(intrin[1],intrin[2],intrin[3]) + intrin_name = intrin[0] + # Intrinsics arguments are not available with MSVC-like compilers + intrin_args = cc.get_argument_syntax() == 'msvc' ? [] : intrin[4] + if cc.links(intrin_check, name : 'compiler supports @0@ intrinsics'.format(intrin_name)) + may_have_intrin = true + presume_intrin = opus_can_presume_simd + elif intrin_args.length() > 0 + presume_intrin = false + if cc.links(intrin_check, + args : intrin_args, + name : 'compiler supports @0@ intrinsics with @1@'.format(intrin_name, ' '.join(intrin_args))) + may_have_intrin = true + else + may_have_intrin = false + endif + endif + if may_have_intrin + intrinsics_support += [intrin_name] + intrin_lower_name = intrin_name.to_lower().underscorify() + set_variable('have_' + intrin_lower_name, true) + opus_conf.set('OPUS_X86_MAY_HAVE_' + intrin_name.underscorify(), 1) + if presume_intrin + opus_conf.set('OPUS_X86_PRESUME_' + intrin_name.underscorify(), 1) + else + rtcd_support += [intrin_name] + set_variable('opus_@0@_args'.format(intrin_lower_name), intrin_args) + endif + else + message('Compiler does not support @0@ intrinsics'.format(intrin_name)) + endif + endforeach + + if not opt_rtcd.disabled() + get_cpuid_by_asm = false + cpuid_asm_code = ''' + #include + int main (int argc, char ** argv) { + unsigned int CPUInfo0; + unsigned int CPUInfo1; + unsigned int CPUInfo2; + unsigned int CPUInfo3; + unsigned int InfoType; + #if defined(__i386__) && defined(__PIC__) + __asm__ __volatile__ ( + "xchg %%ebx, %1\n" + "cpuid\n" + "xchg %%ebx, %1\n": + "=a" (CPUInfo0), + "=r" (CPUInfo1), + "=c" (CPUInfo2), + "=d" (CPUInfo3) : + "a" (InfoType), "c" (0) + ); + #else + __asm__ __volatile__ ( + "cpuid": + "=a" (CPUInfo0), + "=b" (CPUInfo1), + "=c" (CPUInfo2), + "=d" (CPUInfo3) : + "a" (InfoType), "c" (0) + ); + #endif + return 0; + }''' + cpuid_c_code = ''' + #include + int main (int argc, char ** argv) { + unsigned int CPUInfo0; + unsigned int CPUInfo1; + unsigned int CPUInfo2; + unsigned int CPUInfo3; + unsigned int InfoType; + __get_cpuid(InfoType, &CPUInfo0, &CPUInfo1, &CPUInfo2, &CPUInfo3); + return 0; + }''' + cpuid_msvc_code = ''' + #include + int main (void) { + int CPUInfo, InfoType; + __cpuid(&CPUInfo, InfoType); + }''' + if cc.links(cpuid_asm_code, name : 'Get X86 CPU info via inline assembly') + opus_conf.set('CPU_INFO_BY_ASM', 1) + elif cc.links(cpuid_c_code, name : 'Get X86 CPU info via C method') + opus_conf.set('CPU_INFO_BY_C', 1) + elif cc.get_define('_MSC_VER') != '' and cc.links(cpuid_msvc_code) + message('Getting X86 CPU info via __cpuid') + else + if opt_intrinsics.enabled() and opt_rtcd.enabled() + error('intrinsics and rtcd options are enabled, but no Get CPU Info method detected') + endif + warning('Get CPU Info method not detected, no rtcd for intrinsics') + endif + endif # opt_rtcd + else + if opt_intrinsics.enabled() + error('intrinsics option enabled, but no intrinsics support for ' + host_machine.get_cpu()) + endif + warning('No intrinsics support for ' + host_machine.get_cpu()) + endif +endif + +# Check whether we require intrinsics and we support intrinsics on this arch, +# but none were detected. Can happen because of incorrect compiler flags, such +# as missing -mfloat-abi=softfp on ARM32 softfp architectures. +if opt_intrinsics.enabled() and intrinsics_support.length() == 0 + error('intrinsics option was enabled, but none were detected') +endif + +if opt_rtcd.disabled() + rtcd_support = 'disabled' +else + if rtcd_support.length() > 0 + opus_conf.set('OPUS_HAVE_RTCD', 1) + else + if intrinsics_support.length() == 0 + rtcd_support = 'none' + if opt_rtcd.enabled() + error('rtcd option is enabled, but no support for intrinsics or assembly is available') + endif + else + rtcd_support = 'not needed' + endif + endif +endif + +# extract source file lists from .mk files +mk_files = ['silk_sources.mk', 'opus_headers.mk', 'opus_sources.mk', 'silk_headers.mk', 'celt_sources.mk', 'celt_headers.mk'] +lines = run_command('meson/read-sources-list.py', mk_files, check: true).stdout().strip().split('\n') +sources = {} +foreach l : lines + a = l.split(' = ') + var_name = a[0] + file_list = a[1].split() + sources += {var_name: files(file_list)} +endforeach + +subdir('include') +subdir('silk') +subdir('celt') +subdir('src') + +configure_file(output: 'config.h', configuration: opus_conf) + +if not opt_tests.disabled() + subdir('celt/tests') + subdir('silk/tests') + subdir('tests') +endif + +# pkg-config files (not using pkg module so we can use the existing .pc.in file) +pkgconf = configuration_data() + +pkgconf.set('prefix', join_paths(get_option('prefix'))) +pkgconf.set('exec_prefix', '${prefix}') +pkgconf.set('libdir', '${prefix}/@0@'.format(get_option('libdir'))) +pkgconf.set('includedir', '${prefix}/@0@'.format(get_option('includedir'))) +pkgconf.set('VERSION', opus_version) +pkgconf.set('PC_BUILD', pc_build) +pkgconf.set('LIBM', libm.found() ? '-lm' : '') + +pkg_install_dir = '@0@/pkgconfig'.format(get_option('libdir')) + +configure_file(input : 'opus.pc.in', + output : 'opus.pc', + configuration : pkgconf, + install_dir : pkg_install_dir) + +# The uninstalled one has hardcoded libtool + static lib stuff, skip it for now +#configure_file(input : 'opus-uninstalled.pc.in', +# output : 'opus-uninstalled.pc', +# configuration : pkgconf, +# install : false) + +doxygen = find_program('doxygen', required: get_option('docs')) +if doxygen.found() + subdir('doc') +endif + +summary( + { + 'C99 var arrays': opus_conf.has('VAR_ARRAYS'), + 'C99 lrintf': opus_conf.has('HAVE_LRINTF'), + 'Use alloca': msg_use_alloca, + }, + section: 'Compiler support', + bool_yn: true, + list_sep: ', ', +) + +# Parse optimization status +foreach status : [['inline_optimization', opt_asm], + ['asm_optimization', opt_asm], + ['intrinsics_support', opt_intrinsics]] + res = status[0] + opt = status[1] + resval = get_variable(res) + if opt.disabled() + set_variable(res, 'disabled') + elif resval.length() == 0 + if host_cpu_family not in ['arm', 'aarch64', 'x86', 'x86_64'] + set_variable(res, 'No optimizations for your platform, please send patches') + else + set_variable(res, 'none') + endif + endif +endforeach + +summary( + { + 'Floating point support': not opt_fixed_point, + 'Fast float approximations': opt_float_approx, + 'Fixed point debugging': opt_fixed_point_debug, + 'Inline assembly optimizations': inline_optimization, + 'External assembly optimizations': asm_optimization, + 'Intrinsics optimizations': intrinsics_support, + 'Run-time CPU detection': rtcd_support, + }, + section: 'Optimizations', + bool_yn: true, + list_sep: ', ', +) +summary( + { + 'Custom modes': opt_custom_modes, + 'Assertions': opt_assertions, + 'Hardening': opt_hardening, + 'Fuzzing': opt_fuzzing, + 'Check ASM': opt_check_asm, + 'API documentation': doxygen.found(), + 'Extra programs': not extra_programs.disabled(), + 'Tests': not opt_tests.disabled(), + }, + section: 'General configuration', + bool_yn: true, + list_sep: ', ', +) diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/meson/get-version.py b/native/opennow-streamer/vendor/audiopus-sys/opus/meson/get-version.py new file mode 100755 index 000000000..0e8b8623a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/meson/get-version.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +# +# Opus get-version.py +# +# Extracts versions for build: +# - Opus package version based on 'git describe' or $srcroot/package_version +# - libtool version based on configure.ac +# - macos lib version based on configure.ac +# +# Usage: +# get-version.py [--package-version | --libtool-version | --darwin-version] +import argparse +import subprocess +import os +import sys +import shutil + +if __name__ == '__main__': + arg_parser = argparse.ArgumentParser(description='Extract Opus package version or libtool version') + group = arg_parser.add_mutually_exclusive_group(required=True) + group.add_argument('--libtool-version', action='store_true') + group.add_argument('--package-version', action='store_true') + group.add_argument('--darwin-version', action='store_true') + args = arg_parser.parse_args() + + srcroot = os.path.normpath(os.path.join(os.path.dirname(__file__), '..')) + + # package version + if args.package_version: + package_version = None + + # check if git checkout + git_dir = os.path.join(srcroot, '.git') + is_git = os.path.isdir(git_dir) + have_git = shutil.which('git') is not None + + if is_git and have_git: + git_cmd = subprocess.run(['git', '--git-dir=' + git_dir, 'describe', 'HEAD'], stdout=subprocess.PIPE) + if git_cmd.returncode: + print('ERROR: Could not extract package version via `git describe` in', srcroot, file=sys.stderr) + sys.exit(-1) + package_version = git_cmd.stdout.decode('ascii').strip().lstrip('v') + else: + with open(os.path.join(srcroot, 'package_version'), 'r') as f: + for line in f: + if line.startswith('PACKAGE_VERSION="'): + package_version = line[17:].strip().lstrip('v').rstrip('"') + if package_version: + break + + if not package_version: + print('ERROR: Could not extract package version from package_version file in', srcroot, file=sys.stderr) + sys.exit(-1) + + print(package_version) + sys.exit(0) + + # libtool version + darwin version + elif args.libtool_version or args.darwin_version: + opus_lt_cur = None + opus_lt_rev = None + opus_lt_age = None + + with open(os.path.join(srcroot, 'configure.ac'), 'r') as f: + for line in f: + if line.strip().startswith('OPUS_LT_CURRENT='): + opus_lt_cur = line[16:].strip() + elif line.strip().startswith('OPUS_LT_REVISION='): + opus_lt_rev = line[17:].strip() + elif line.strip().startswith('OPUS_LT_AGE='): + opus_lt_age = line[12:].strip() + + if opus_lt_cur and opus_lt_rev and opus_lt_age: + opus_lt_cur = int(opus_lt_cur) + opus_lt_rev = int(opus_lt_rev) + opus_lt_age = int(opus_lt_age) + if args.libtool_version: + print('{}.{}.{}'.format(opus_lt_cur - opus_lt_age, opus_lt_age, opus_lt_rev)) + elif args.darwin_version: + print('{}.{}.{}'.format(opus_lt_cur + 1, 0, 0)) + sys.exit(0) + else: + print('ERROR: Could not extract libtool version from configure.ac file in', srcroot, file=sys.stderr) + sys.exit(-1) + else: + sys.exit(-1) diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/meson/read-sources-list.py b/native/opennow-streamer/vendor/audiopus-sys/opus/meson/read-sources-list.py new file mode 100755 index 000000000..fcbec5019 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/meson/read-sources-list.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# +# opus/read-sources-list.py +# +# Parses .mk files and extracts list of source files. +# Prints one line per source file list, with filenames space-separated. + +import sys + +if len(sys.argv) < 2: + sys.exit('Usage: {} sources_foo.mk [sources_bar.mk...]'.format(sys.argv[0])) + +for input_fn in sys.argv[1:]: + with open(input_fn, 'r', encoding='utf8') as f: + text = f.read() + text = text.replace('\\\n', '') + + # Remove empty lines + lines = [line for line in text.split('\n') if line.strip()] + + # Print SOURCES_XYZ = file1.c file2.c + for line in lines: + values = line.strip().split('=', maxsplit=2) + if len(values) != 2: + raise RuntimeError('Unable to parse line "{}" from file "{}"'.format(line, input_fn)) + var, files = values + sources_list = [f for f in files.split(' ') if f] + print(var.strip(), '=', ' '.join(sources_list)) diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/meson_options.txt b/native/opennow-streamer/vendor/audiopus-sys/opus/meson_options.txt new file mode 100644 index 000000000..360ff2635 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/meson_options.txt @@ -0,0 +1,22 @@ +# Optimizations +option('fixed-point', type : 'boolean', value : false, description : 'Compile without floating point (for machines without a fast enough FPU') +option('fixed-point-debug', type : 'boolean', value : false, description : 'Debug fixed-point implementation') +option('float-api', type : 'boolean', value : true, description : 'Compile with or without the floating point API (for machines with no float library') +option('float-approx', type : 'boolean', value : false, description : 'Enable fast approximations for floating point (not supported on all platforms)') +option('rtcd', type : 'feature', value : 'auto', description : 'Run-time CPU capabilities detection') +option('asm', type : 'feature', value : 'auto', description : 'Assembly optimizations for ARM (fixed-point)') +option('intrinsics', type : 'feature', value : 'auto', description : 'Intrinsics optimizations for ARM NEON or x86') + +option('custom-modes', type : 'boolean', value : false, description : 'Enable non-Opus modes, e.g. 44.1 kHz & 2^n frames') +option('extra-programs', type : 'feature', value : 'auto', description : 'Extra programs (demo and tests)') +option('assertions', type : 'boolean', value : false, description : 'Additional software error checking') +option('hardening', type : 'boolean', value : true, description : 'Run-time checks that are cheap and safe for use in production') +option('fuzzing', type : 'boolean', value : false, description : 'Causes the encoder to make random decisions') +option('check-asm', type : 'boolean', value : false, description : 'Run bit-exactness checks between optimized and c implementations') + +# common feature options +option('tests', type : 'feature', value : 'auto', description : 'Build tests') +option('docs', type: 'feature', value: 'auto', description: 'Build API documentation') + +# other options +option('docdir', type: 'string', value: 'doc/opus', description: 'Directory to install documentation into (default: DATADIR/doc/opus') diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/opus-uninstalled.pc.in b/native/opennow-streamer/vendor/audiopus-sys/opus/opus-uninstalled.pc.in new file mode 100644 index 000000000..19f5c933d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/opus-uninstalled.pc.in @@ -0,0 +1,12 @@ +# Opus codec reference implementation uninstalled pkg-config file + +libdir=${pcfiledir}/.libs +includedir=${pcfiledir} + +Name: opus uninstalled +Description: Opus IETF audio codec (not installed, @PC_BUILD@) +Version: @VERSION@ +Requires: +Conflicts: +Libs: ${libdir}/libopus.la @LIBM@ +Cflags: -I${pcfiledir}/@top_srcdir@/include diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/opus.m4 b/native/opennow-streamer/vendor/audiopus-sys/opus/opus.m4 new file mode 100644 index 000000000..47f5ec496 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/opus.m4 @@ -0,0 +1,117 @@ +# Configure paths for libopus +# Gregory Maxwell 08-30-2012 +# Shamelessly stolen from Jack Moffitt (libogg) who +# Shamelessly stole from Owen Taylor and Manish Singh + +dnl XIPH_PATH_OPUS([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Test for libopus, and define OPUS_CFLAGS and OPUS_LIBS +dnl +AC_DEFUN([XIPH_PATH_OPUS], +[dnl +dnl Get the cflags and libraries +dnl +AC_ARG_WITH(opus,AC_HELP_STRING([--with-opus=PFX],[Prefix where opus is installed (optional)]), opus_prefix="$withval", opus_prefix="") +AC_ARG_WITH(opus-libraries,AC_HELP_STRING([--with-opus-libraries=DIR],[Directory where the opus library is installed (optional)]), opus_libraries="$withval", opus_libraries="") +AC_ARG_WITH(opus-includes,AC_HELP_STRING([--with-opus-includes=DIR],[Directory where the opus header files are installed (optional)]), opus_includes="$withval", opus_includes="") +AC_ARG_ENABLE(opustest,AC_HELP_STRING([--disable-opustest],[Do not try to compile and run a test opus program]),, enable_opustest=yes) + + if test "x$opus_libraries" != "x" ; then + OPUS_LIBS="-L$opus_libraries" + elif test "x$opus_prefix" = "xno" || test "x$opus_prefix" = "xyes" ; then + OPUS_LIBS="" + elif test "x$opus_prefix" != "x" ; then + OPUS_LIBS="-L$opus_prefix/lib" + elif test "x$prefix" != "xNONE" ; then + OPUS_LIBS="-L$prefix/lib" + fi + + if test "x$opus_prefix" != "xno" ; then + OPUS_LIBS="$OPUS_LIBS -lopus" + fi + + if test "x$opus_includes" != "x" ; then + OPUS_CFLAGS="-I$opus_includes" + elif test "x$opus_prefix" = "xno" || test "x$opus_prefix" = "xyes" ; then + OPUS_CFLAGS="" + elif test "x$opus_prefix" != "x" ; then + OPUS_CFLAGS="-I$opus_prefix/include" + elif test "x$prefix" != "xNONE"; then + OPUS_CFLAGS="-I$prefix/include" + fi + + AC_MSG_CHECKING(for Opus) + if test "x$opus_prefix" = "xno" ; then + no_opus="disabled" + enable_opustest="no" + else + no_opus="" + fi + + + if test "x$enable_opustest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $OPUS_CFLAGS" + LIBS="$LIBS $OPUS_LIBS" +dnl +dnl Now check if the installed Opus is sufficiently new. +dnl + rm -f conf.opustest + AC_TRY_RUN([ +#include +#include +#include +#include + +int main () +{ + system("touch conf.opustest"); + return 0; +} + +],, no_opus=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + + if test "x$no_opus" = "xdisabled" ; then + AC_MSG_RESULT(no) + ifelse([$2], , :, [$2]) + elif test "x$no_opus" = "x" ; then + AC_MSG_RESULT(yes) + ifelse([$1], , :, [$1]) + else + AC_MSG_RESULT(no) + if test -f conf.opustest ; then + : + else + echo "*** Could not run Opus test program, checking why..." + CFLAGS="$CFLAGS $OPUS_CFLAGS" + LIBS="$LIBS $OPUS_LIBS" + AC_TRY_LINK([ +#include +#include +], [ return 0; ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding Opus or finding the wrong" + echo "*** version of Opus. If it is not finding Opus, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occurred. This usually means Opus was incorrectly installed" + echo "*** or that you have moved Opus since it was installed." ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + OPUS_CFLAGS="" + OPUS_LIBS="" + ifelse([$2], , :, [$2]) + fi + AC_SUBST(OPUS_CFLAGS) + AC_SUBST(OPUS_LIBS) + rm -f conf.opustest +]) diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/opus.pc.in b/native/opennow-streamer/vendor/audiopus-sys/opus/opus.pc.in new file mode 100644 index 000000000..6946e7de5 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/opus.pc.in @@ -0,0 +1,16 @@ +# Opus codec reference implementation pkg-config file + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Opus +Description: Opus IETF audio codec (@PC_BUILD@ build) +URL: https://opus-codec.org/ +Version: @VERSION@ +Requires: +Conflicts: +Libs: -L${libdir} -lopus +Libs.private: @LIBM@ +Cflags: -I${includedir}/opus diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/opus_headers.mk b/native/opennow-streamer/vendor/audiopus-sys/opus/opus_headers.mk new file mode 100644 index 000000000..27596f2a4 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/opus_headers.mk @@ -0,0 +1,9 @@ +OPUS_HEAD = \ +include/opus.h \ +include/opus_multistream.h \ +include/opus_projection.h \ +src/opus_private.h \ +src/analysis.h \ +src/mapping_matrix.h \ +src/mlp.h \ +src/tansig_table.h diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/opus_sources.mk b/native/opennow-streamer/vendor/audiopus-sys/opus/opus_sources.mk new file mode 100644 index 000000000..44153b570 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/opus_sources.mk @@ -0,0 +1,16 @@ +OPUS_SOURCES = \ +src/opus.c \ +src/opus_decoder.c \ +src/opus_encoder.c \ +src/opus_multistream.c \ +src/opus_multistream_encoder.c \ +src/opus_multistream_decoder.c \ +src/repacketizer.c \ +src/opus_projection_encoder.c \ +src/opus_projection_decoder.c \ +src/mapping_matrix.c + +OPUS_SOURCES_FLOAT = \ +src/analysis.c \ +src/mlp.c \ +src/mlp_data.c diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/releases.sha2 b/native/opennow-streamer/vendor/audiopus-sys/opus/releases.sha2 new file mode 100644 index 000000000..334976b14 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/releases.sha2 @@ -0,0 +1,79 @@ +b2f75c4ac5ab837845eb028413fae2a28754bfb0a6d76416e2af1441ef447649 opus-0.9.0.tar.gz +4e379a98ba95bbbfe9087ef10fdd05c8ac9060b6d695f587ea82a7b43a0df4fe opus-0.9.10.tar.gz +b1cad6846a8f819a141009fe3f8f10c946e8eff7e9c2339cd517bb136cc59eae opus-0.9.14.tar.gz +206221afc47b87496588013bd4523e1e9f556336c0813f4372773fc536dd4293 opus-0.9.1.tar.gz +6e85c1b57e1d7b7dfe2928bf92586b96b73a9067e054ede45bd8e6d24bd30582 opus-0.9.2.tar.gz +d916e34c18a396eb7dffc47af754f441af52a290b761e20db9aedb65928c699e opus-0.9.3.tar.gz +53801066fa97329768e7b871fd1495740269ec46802e1c9051aa7e78c6edee5b opus-0.9.5.tar.gz +3bfaeb25f4b4a625a0bc994d6fc6f6776a05193f60099e0a99f7530c6b256309 opus-0.9.6.tar.gz +1b69772c31c5cbaa43d1dfa5b1c495fc29712e8e0ff69d6f8ad46459e5c6715f opus-0.9.7.tar.gz +4aa30d2e0652ffb4a7a22cc8a29c4ce78267626f560a2d9213b1d2d4e618cf36 opus-0.9.8.tar.gz +2f62359f09151fa3b242040dc9b4c5b6bda15557c5daea59c8420f1a2ff328b7 opus-0.9.9.tar.gz +43bcea51afa531f32a6a5fdd9cba4bd496993e26a141217db3cccce6caa7cd74 opus-1.0.0-rc.tar.gz +9250fcc74472d45c1e14745542ec9c8d09982538aefed56962495614be3e0d2d opus-1.0.0.tar.gz +76bc0a31502a51dae9ab737b4db043b9ecfcd0b5861f0bfda41b662bd5b92227 opus-1.0.1-rc2.tar.gz +3de8d6809dac38971ebb305532d4ea532519d3bed08985f25d6c557f9ce5e8ff opus-1.0.1-rc3.tar.gz +8044397a6365a07117b08cbe8f9818bf7c93746908806ba74a2917187bbdda5f opus-1.0.1-rc.tar.gz +80fa5c3caf2ac0fd68f8a22cce1564fc46b368c773a17554887d0066fe1841ef opus-1.0.1.tar.gz +da615edbee5d019c1833071d69a4782c19f178cf9ca1401375036ecef25cd78a opus-1.0.2.tar.gz +191a089c92dbc403de6980463dd3604b65beb12d283c607e246c8076363cb49c opus-1.0.3.tar.gz +a8d40efe87f6c3e76725391457d46277878c7a816ae1642843261463133fa5c8 opus-1.1-alpha.tar.gz +ec1784287f385aef994b64734aaecae04860e61aa50fc6eef6643fa7e40dd193 opus-1.1-beta.tar.gz +8aa16360f59a94d3e38f38f28d24039f7663179682cbae82aa42f1dd9e52e6ed opus-1.1-rc.tar.gz +ebc87a086d4fe677c5e42d56888b1fd25af858e4179eae4f8656270410dffac3 opus-1.1-rc2.tar.gz +cbfd09c58cc10a4d3fcb727ad5d46d7bb549f8185ac922ee28b4581b52a7bee9 opus-1.1-rc3.tar.gz +b9727015a58affcf3db527322bf8c4d2fcf39f5f6b8f15dbceca20206cbe1d95 opus-1.1.tar.gz +0c668639dcd16b14709fc9dc49e6686606f5a256f2eaa1ebaa2f39a66f8626cd opus-1.1.1-beta.tar.gz +66f2a5877c8803dc9a5a44b4f3d0bdc8f06bd066324222d144eb255612b68152 opus-1.1.1-rc.tar.gz +9b84ff56bd7720d5554103c557664efac2b8b18acc4bbcc234cb881ab9a3371e opus-1.1.1.tar.gz +0e290078e31211baa7b5886bcc8ab6bc048b9fc83882532da4a1a45e58e907fd opus-1.1.2.tar.gz +58b6fe802e7e30182e95d0cde890c0ace40b6f125cffc50635f0ad2eef69b633 opus-1.1.3.tar.gz +9122b6b380081dd2665189f97bfd777f04f92dc3ab6698eea1dbb27ad59d8692 opus-1.1.4.tar.gz +eb84981ca0f40a3e5d5e58d2e8582cb2fee05a022825a6dfe14d14b04eb563e4 opus-1.1.5.tar.gz +654a9bebb73266271a28edcfff431e4cfd9bfcde71f42849a0cdd73bece803a7 opus-1.2-alpha.tar.gz +c0e90507259cf21ce7b2c82fb9ac55367d8543dae91cc3d4d2c59afd37f44023 opus-1.2-alpha2.tar.gz +291e979a8a2fb679ed35a5dff5d761a9d9a5e22586fd07934ed94461e2636c7a opus-1.2-beta.tar.gz +85343fdaed96529d94c1e1f3a210fa51240d04ca62fa01e97ef02f88020c2ce9 opus-1.2-rc1.tar.gz +77db45a87b51578fbc49555ef1b10926179861d854eb2613207dc79d9ec0a9a9 opus-1.2.tar.gz +cfafd339ccd9c5ef8d6ab15d7e1a412c054bf4cb4ecbbbcc78c12ef2def70732 opus-1.2.1.tar.gz +7f56e058c9549d03ae35511ad9e16ef6d1eb257836830d54abff0f495f17e187 opus-1.3-beta.tar.gz +96fa28598e8ccd558b297277ad59a045c551ba0e06d65a9675938e084f837669 opus-1.3-rc.tar.gz +f6bab321fb81db984766f1e4d340a9e71a5ca2c5d4d53f4ee072e84afda271ca opus-1.3-rc2.tar.gz +4f3d69aefdf2dbaf9825408e452a8a414ffc60494c70633560700398820dc550 opus-1.3.tar.gz +65b58e1e25b2a114157014736a3d9dfeaad8d41be1c8179866f144a2fb44ff9d opus-1.3.1.tar.gz +94ac78ca4f74c4e43bc9fe4ec1ad0aa36f38ab90f45b0727c40dd1e96096e767 opus_testvectors-draft11.tar.gz +94ac78ca4f74c4e43bc9fe4ec1ad0aa36f38ab90f45b0727c40dd1e96096e767 opus_testvectors.tar.gz +6b26a22f9ba87b2b836906a9bb7afec5f8e54d49553b1200382520ee6fedfa55 opus_testvectors-rfc8251.tar.gz +5d2b99757bcb628bab2611f3ed27af6f35276ce3abc96c0ed4399d6c6463dda5 opus-tools-0.1.2.tar.gz +008317297d6ce84f84992abf8cc948a048a4fa135e1d1caf429fafde8965a792 opus-tools-0.1.3.tar.gz +de80485c5afa1fd83c0e16a0dd4860470c872997a7dd0a58e99b2ee8a93e5168 opus-tools-0.1.4.tar.gz +76678d0eb7a9b3d793bd0243f9ced9ab0ecdab263f5232ed940c8f5795fb0405 opus-tools-0.1.5.tar.gz +cc86dbc2a4d76da7e1ed9afee85448c8f798c465a5412233f178783220f3a2c1 opus-tools-0.1.6.tar.gz +e0f08d301555dffc417604269b5a85d2bd197f259c7d6c957f370ffd33d6d9cd opus-tools-0.1.7.tar.gz +e4e188579ea1c4e4d5066460d4a7214a7eafe3539e9a4466fdc98af41ba4a2f6 opus-tools-0.1.8.tar.gz +b1873dd78c7fbc98cf65d6e10cfddb5c2c03b3af93f922139a2104baedb4643a opus-tools-0.1.9.tar.gz +a2357532d19471b70666e0e0ec17d514246d8b3cb2eb168f68bb0f6fd372b28c opus-tools-0.1.10.tar.gz +b4e56cb00d3e509acfba9a9b627ffd8273b876b4e2408642259f6da28fa0ff86 opus-tools-0.2.tar.gz +bd6d14e8897a2f80065ef34a516c70e74f8e00060abdbc238e79e5f99bca3e96 libopusenc-0.1.tar.gz +02e6e0b14cbbe0569d948a46420f9c9a81d93bba32dc576a4007cbf96da68ef3 libopusenc-0.1.1.tar.gz +c79e95eeee43a0b965e9b2c59a243763a8f8b0a7e71441df2aa9084f6171c73a libopusenc-0.2.tar.gz +8298db61a8d3d63e41c1a80705baa8ce9ff3f50452ea7ec1c19a564fe106cbb9 libopusenc-0.2.1.tar.gz +8071b968475c1a17f54b6840d6de9d9ee20f930e827b0401abe3c4cf4f3bf30a opusfile-0.1.tar.gz +b4a678b3b6c4adfb6aff1f67ef658becfe146ea7c7ff228e99543762171557f9 opusfile-0.2.tar.gz +4248927f2c4e316ea5b84fb02bd100bfec8fa4624a6910d77f0af7f0c6cb8baa opusfile-0.3.tar.gz +9836ea11706c44f36de92c4c9b1248e03a4c521e7fb2cff18a0cb4f8b0e79140 opusfile-0.4.tar.gz +f187906b1b35f7f0d7de6a759b4aab512a9279d23adb35d8009e7e33bd6a922a opusfile-0.4.zip +2ce52d006aeeec9f10260dbe3073c4636954a1ab19c82b8baafefe0180aa4a39 opusfile-0.5.tar.gz +b940d62beb15b5974764574b9f265481fe5b6ee16902fb705727546caf956261 opusfile-0.5.zip +2428717b356e139f18ed2fdb5ad990b5654a238907a0058200b39c46a7d03ea6 opusfile-0.6.tar.gz +753339225193df605372944889023b9b3c5378d672e8784d69fa241cd465278c opusfile-0.6.zip +9e2bed13bc729058591a0f1cab2505e8cfd8e7ac460bf10a78bcc3b125e7c301 opusfile-0.7.tar.gz +346967d7989bb83b05949483b76bd0f69a12c59bd8b4457e864902b52bb0ac34 opusfile-0.7.zip +2c231ed3cfaa1b3173f52d740e5bbd77d51b9dfecb87014b404917fba4b855a4 opusfile-0.8.tar.gz +89dff4342c3b789574cbea5c57f11b96d4ebe4d28ab90248c1783ea569b1e9e3 opusfile-0.8.zip +f75fb500e40b122775ac1a71ad80c4477698842a8fe9da4a1b4a1a9f16e4e979 opusfile-0.9.tar.gz +e9591da4d4c9e857436c2d46a28a9e470fa5355ea5a76d4d582f137d18755d36 opusfile-0.9.zip +48e03526ba87ef9cf5f1c47b5ebe3aa195bd89b912a57060c36184a6cd19412f opusfile-0.10.tar.gz +9d9e95d01817ecf48bf6daaea8f071f9b45bd1751ca1fc8ce50e5075eb2bc3c8 opusfile-0.10.zip +74ce9b6cf4da103133e7b5c95df810ceb7195471e1162ed57af415fabf5603bf opusfile-0.11.tar.gz +23c5168026c4f1fc34843650135b409d0fc8cf452508163b4ece8077256ac6ff opusfile-0.11.zip diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/scripts/dump_rnn.py b/native/opennow-streamer/vendor/audiopus-sys/opus/scripts/dump_rnn.py new file mode 100755 index 000000000..dd66403b5 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/scripts/dump_rnn.py @@ -0,0 +1,57 @@ +#!/usr/bin/python + +from __future__ import print_function + +from keras.models import Sequential +from keras.layers import Dense +from keras.layers import LSTM +from keras.layers import GRU +from keras.models import load_model +from keras import backend as K + +import numpy as np + +def printVector(f, vector, name): + v = np.reshape(vector, (-1)); + #print('static const float ', name, '[', len(v), '] = \n', file=f) + f.write('static const opus_int16 {}[{}] = {{\n '.format(name, len(v))) + for i in range(0, len(v)): + f.write('{}'.format(int(round(8192*v[i])))) + if (i!=len(v)-1): + f.write(',') + else: + break; + if (i%8==7): + f.write("\n ") + else: + f.write(" ") + #print(v, file=f) + f.write('\n};\n\n') + return; + +def binary_crossentrop2(y_true, y_pred): + return K.mean(2*K.abs(y_true-0.5) * K.binary_crossentropy(y_pred, y_true), axis=-1) + + +model = load_model("weights.hdf5", custom_objects={'binary_crossentrop2': binary_crossentrop2}) + +weights = model.get_weights() + +f = open('rnn_weights.c', 'w') + +f.write('/*This file is automatically generated from a Keras model*/\n\n') +f.write('#ifdef HAVE_CONFIG_H\n#include "config.h"\n#endif\n\n#include "mlp.h"\n\n') + +printVector(f, weights[0], 'layer0_weights') +printVector(f, weights[1], 'layer0_bias') +printVector(f, weights[2], 'layer1_weights') +printVector(f, weights[3], 'layer1_recur_weights') +printVector(f, weights[4], 'layer1_bias') +printVector(f, weights[5], 'layer2_weights') +printVector(f, weights[6], 'layer2_bias') + +f.write('const DenseLayer layer0 = {\n layer0_bias,\n layer0_weights,\n 25, 16, 0\n};\n\n') +f.write('const GRULayer layer1 = {\n layer1_bias,\n layer1_weights,\n layer1_recur_weights,\n 16, 12\n};\n\n') +f.write('const DenseLayer layer2 = {\n layer2_bias,\n layer2_weights,\n 12, 2, 1\n};\n\n') + +f.close() diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/scripts/rnn_train.py b/native/opennow-streamer/vendor/audiopus-sys/opus/scripts/rnn_train.py new file mode 100755 index 000000000..ffdaa1e7d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/scripts/rnn_train.py @@ -0,0 +1,67 @@ +#!/usr/bin/python + +from __future__ import print_function + +from keras.models import Sequential +from keras.models import Model +from keras.layers import Input +from keras.layers import Dense +from keras.layers import LSTM +from keras.layers import GRU +from keras.layers import SimpleRNN +from keras.layers import Dropout +from keras import losses +import h5py + +from keras import backend as K +import numpy as np + +def binary_crossentrop2(y_true, y_pred): + return K.mean(2*K.abs(y_true-0.5) * K.binary_crossentropy(y_pred, y_true), axis=-1) + +print('Build model...') +#model = Sequential() +#model.add(Dense(16, activation='tanh', input_shape=(None, 25))) +#model.add(GRU(12, dropout=0.0, recurrent_dropout=0.0, activation='tanh', recurrent_activation='sigmoid', return_sequences=True)) +#model.add(Dense(2, activation='sigmoid')) + +main_input = Input(shape=(None, 25), name='main_input') +x = Dense(16, activation='tanh')(main_input) +x = GRU(12, dropout=0.1, recurrent_dropout=0.1, activation='tanh', recurrent_activation='sigmoid', return_sequences=True)(x) +x = Dense(2, activation='sigmoid')(x) +model = Model(inputs=main_input, outputs=x) + +batch_size = 64 + +print('Loading data...') +with h5py.File('features.h5', 'r') as hf: + all_data = hf['features'][:] +print('done.') + +window_size = 1500 + +nb_sequences = len(all_data)/window_size +print(nb_sequences, ' sequences') +x_train = all_data[:nb_sequences*window_size, :-2] +x_train = np.reshape(x_train, (nb_sequences, window_size, 25)) + +y_train = np.copy(all_data[:nb_sequences*window_size, -2:]) +y_train = np.reshape(y_train, (nb_sequences, window_size, 2)) + +all_data = 0; +x_train = x_train.astype('float32') +y_train = y_train.astype('float32') + +print(len(x_train), 'train sequences. x shape =', x_train.shape, 'y shape = ', y_train.shape) + +# try using different optimizers and different optimizer configs +model.compile(loss=binary_crossentrop2, + optimizer='adam', + metrics=['binary_accuracy']) + +print('Train...') +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=200, + validation_data=(x_train, y_train)) +model.save("newweights.hdf5") diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/A2NLSF.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/A2NLSF.c new file mode 100644 index 000000000..b487686ff --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/A2NLSF.c @@ -0,0 +1,267 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +/* Conversion between prediction filter coefficients and NLSFs */ +/* Requires the order to be an even number */ +/* A piecewise linear approximation maps LSF <-> cos(LSF) */ +/* Therefore the result is not accurate NLSFs, but the two */ +/* functions are accurate inverses of each other */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "tables.h" + +/* Number of binary divisions, when not in low complexity mode */ +#define BIN_DIV_STEPS_A2NLSF_FIX 3 /* must be no higher than 16 - log2( LSF_COS_TAB_SZ_FIX ) */ +#define MAX_ITERATIONS_A2NLSF_FIX 16 + +/* Helper function for A2NLSF(..) */ +/* Transforms polynomials from cos(n*f) to cos(f)^n */ +static OPUS_INLINE void silk_A2NLSF_trans_poly( + opus_int32 *p, /* I/O Polynomial */ + const opus_int dd /* I Polynomial order (= filter order / 2 ) */ +) +{ + opus_int k, n; + + for( k = 2; k <= dd; k++ ) { + for( n = dd; n > k; n-- ) { + p[ n - 2 ] -= p[ n ]; + } + p[ k - 2 ] -= silk_LSHIFT( p[ k ], 1 ); + } +} +/* Helper function for A2NLSF(..) */ +/* Polynomial evaluation */ +static OPUS_INLINE opus_int32 silk_A2NLSF_eval_poly( /* return the polynomial evaluation, in Q16 */ + opus_int32 *p, /* I Polynomial, Q16 */ + const opus_int32 x, /* I Evaluation point, Q12 */ + const opus_int dd /* I Order */ +) +{ + opus_int n; + opus_int32 x_Q16, y32; + + y32 = p[ dd ]; /* Q16 */ + x_Q16 = silk_LSHIFT( x, 4 ); + + if ( opus_likely( 8 == dd ) ) + { + y32 = silk_SMLAWW( p[ 7 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 6 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 5 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 4 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 3 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 2 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 1 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 0 ], y32, x_Q16 ); + } + else + { + for( n = dd - 1; n >= 0; n-- ) { + y32 = silk_SMLAWW( p[ n ], y32, x_Q16 ); /* Q16 */ + } + } + return y32; +} + +static OPUS_INLINE void silk_A2NLSF_init( + const opus_int32 *a_Q16, + opus_int32 *P, + opus_int32 *Q, + const opus_int dd +) +{ + opus_int k; + + /* Convert filter coefs to even and odd polynomials */ + P[dd] = silk_LSHIFT( 1, 16 ); + Q[dd] = silk_LSHIFT( 1, 16 ); + for( k = 0; k < dd; k++ ) { + P[ k ] = -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ]; /* Q16 */ + Q[ k ] = -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ]; /* Q16 */ + } + + /* Divide out zeros as we have that for even filter orders, */ + /* z = 1 is always a root in Q, and */ + /* z = -1 is always a root in P */ + for( k = dd; k > 0; k-- ) { + P[ k - 1 ] -= P[ k ]; + Q[ k - 1 ] += Q[ k ]; + } + + /* Transform polynomials from cos(n*f) to cos(f)^n */ + silk_A2NLSF_trans_poly( P, dd ); + silk_A2NLSF_trans_poly( Q, dd ); +} + +/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */ +/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */ +void silk_A2NLSF( + opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */ + opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */ + const opus_int d /* I Filter order (must be even) */ +) +{ + opus_int i, k, m, dd, root_ix, ffrac; + opus_int32 xlo, xhi, xmid; + opus_int32 ylo, yhi, ymid, thr; + opus_int32 nom, den; + opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 Q[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 *PQ[ 2 ]; + opus_int32 *p; + + /* Store pointers to array */ + PQ[ 0 ] = P; + PQ[ 1 ] = Q; + + dd = silk_RSHIFT( d, 1 ); + + silk_A2NLSF_init( a_Q16, P, Q, dd ); + + /* Find roots, alternating between P and Q */ + p = P; /* Pointer to polynomial */ + + xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + + if( ylo < 0 ) { + /* Set the first NLSF to zero and move on to the next */ + NLSF[ 0 ] = 0; + p = Q; /* Pointer to polynomial */ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + root_ix = 1; /* Index of current root */ + } else { + root_ix = 0; /* Index of current root */ + } + k = 1; /* Loop counter */ + i = 0; /* Counter for bandwidth expansions applied */ + thr = 0; + while( 1 ) { + /* Evaluate polynomial */ + xhi = silk_LSFCosTab_FIX_Q12[ k ]; /* Q12 */ + yhi = silk_A2NLSF_eval_poly( p, xhi, dd ); + + /* Detect zero crossing */ + if( ( ylo <= 0 && yhi >= thr ) || ( ylo >= 0 && yhi <= -thr ) ) { + if( yhi == 0 ) { + /* If the root lies exactly at the end of the current */ + /* interval, look for the next root in the next interval */ + thr = 1; + } else { + thr = 0; + } + /* Binary division */ + ffrac = -256; + for( m = 0; m < BIN_DIV_STEPS_A2NLSF_FIX; m++ ) { + /* Evaluate polynomial */ + xmid = silk_RSHIFT_ROUND( xlo + xhi, 1 ); + ymid = silk_A2NLSF_eval_poly( p, xmid, dd ); + + /* Detect zero crossing */ + if( ( ylo <= 0 && ymid >= 0 ) || ( ylo >= 0 && ymid <= 0 ) ) { + /* Reduce frequency */ + xhi = xmid; + yhi = ymid; + } else { + /* Increase frequency */ + xlo = xmid; + ylo = ymid; + ffrac = silk_ADD_RSHIFT( ffrac, 128, m ); + } + } + + /* Interpolate */ + if( silk_abs( ylo ) < 65536 ) { + /* Avoid dividing by zero */ + den = ylo - yhi; + nom = silk_LSHIFT( ylo, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) + silk_RSHIFT( den, 1 ); + if( den != 0 ) { + ffrac += silk_DIV32( nom, den ); + } + } else { + /* No risk of dividing by zero because abs(ylo - yhi) >= abs(ylo) >= 65536 */ + ffrac += silk_DIV32( ylo, silk_RSHIFT( ylo - yhi, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) ); + } + NLSF[ root_ix ] = (opus_int16)silk_min_32( silk_LSHIFT( (opus_int32)k, 8 ) + ffrac, silk_int16_MAX ); + + silk_assert( NLSF[ root_ix ] >= 0 ); + + root_ix++; /* Next root */ + if( root_ix >= d ) { + /* Found all roots */ + break; + } + /* Alternate pointer to polynomial */ + p = PQ[ root_ix & 1 ]; + + /* Evaluate polynomial */ + xlo = silk_LSFCosTab_FIX_Q12[ k - 1 ]; /* Q12*/ + ylo = silk_LSHIFT( 1 - ( root_ix & 2 ), 12 ); + } else { + /* Increment loop counter */ + k++; + xlo = xhi; + ylo = yhi; + thr = 0; + + if( k > LSF_COS_TAB_SZ_FIX ) { + i++; + if( i > MAX_ITERATIONS_A2NLSF_FIX ) { + /* Set NLSFs to white spectrum and exit */ + NLSF[ 0 ] = (opus_int16)silk_DIV32_16( 1 << 15, d + 1 ); + for( k = 1; k < d; k++ ) { + NLSF[ k ] = (opus_int16)silk_ADD16( NLSF[ k-1 ], NLSF[ 0 ] ); + } + return; + } + + /* Error: Apply progressively more bandwidth expansion and run again */ + silk_bwexpander_32( a_Q16, d, 65536 - silk_LSHIFT( 1, i ) ); + + silk_A2NLSF_init( a_Q16, P, Q, dd ); + p = P; /* Pointer to polynomial */ + xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + if( ylo < 0 ) { + /* Set the first NLSF to zero and move on to the next */ + NLSF[ 0 ] = 0; + p = Q; /* Pointer to polynomial */ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + root_ix = 1; /* Index of current root */ + } else { + root_ix = 0; /* Index of current root */ + } + k = 1; /* Reset loop counter */ + } + } + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/API.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/API.h new file mode 100644 index 000000000..4d90ff9aa --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/API.h @@ -0,0 +1,135 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_API_H +#define SILK_API_H + +#include "control.h" +#include "typedef.h" +#include "errors.h" +#include "entenc.h" +#include "entdec.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define SILK_MAX_FRAMES_PER_PACKET 3 + +/* Struct for TOC (Table of Contents) */ +typedef struct { + opus_int VADFlag; /* Voice activity for packet */ + opus_int VADFlags[ SILK_MAX_FRAMES_PER_PACKET ]; /* Voice activity for each frame in packet */ + opus_int inbandFECFlag; /* Flag indicating if packet contains in-band FEC */ +} silk_TOC_struct; + +/****************************************/ +/* Encoder functions */ +/****************************************/ + +/***********************************************/ +/* Get size in bytes of the Silk encoder state */ +/***********************************************/ +opus_int silk_Get_Encoder_Size( /* O Returns error code */ + opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */ +); + +/*************************/ +/* Init or reset encoder */ +/*************************/ +opus_int silk_InitEncoder( /* O Returns error code */ + void *encState, /* I/O State */ + int arch, /* I Run-time architecture */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +); + +/**************************/ +/* Encode frame with Silk */ +/**************************/ +/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */ +/* encControl->payloadSize_ms is set to */ +opus_int silk_Encode( /* O Returns error code */ + void *encState, /* I/O State */ + silk_EncControlStruct *encControl, /* I Control status */ + const opus_int16 *samplesIn, /* I Speech sample input vector */ + opus_int nSamplesIn, /* I Number of samples in input vector */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */ + const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */ + int activity /* I Decision of Opus voice activity detector */ +); + +/****************************************/ +/* Decoder functions */ +/****************************************/ + +/***********************************************/ +/* Get size in bytes of the Silk decoder state */ +/***********************************************/ +opus_int silk_Get_Decoder_Size( /* O Returns error code */ + opus_int *decSizeBytes /* O Number of bytes in SILK decoder state */ +); + +/*************************/ +/* Init or Reset decoder */ +/*************************/ +opus_int silk_InitDecoder( /* O Returns error code */ + void *decState /* I/O State */ +); + +/******************/ +/* Decode a frame */ +/******************/ +opus_int silk_Decode( /* O Returns error code */ + void* decState, /* I/O State */ + silk_DecControlStruct* decControl, /* I/O Control Structure */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int newPacketFlag, /* I Indicates first decoder call for this packet */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 *samplesOut, /* O Decoded output speech vector */ + opus_int32 *nSamplesOut, /* O Number of samples decoded */ + int arch /* I Run-time architecture */ +); + +#if 0 +/**************************************/ +/* Get table of contents for a packet */ +/**************************************/ +opus_int silk_get_TOC( + const opus_uint8 *payload, /* I Payload data */ + const opus_int nBytesIn, /* I Number of input bytes */ + const opus_int nFramesPerPayload, /* I Number of SILK frames per payload */ + silk_TOC_struct *Silk_TOC /* O Type of content */ +); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/CNG.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/CNG.c new file mode 100644 index 000000000..2a910099e --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/CNG.c @@ -0,0 +1,188 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/* Generates excitation for CNG LPC synthesis */ +static OPUS_INLINE void silk_CNG_exc( + opus_int32 exc_Q14[], /* O CNG excitation signal Q10 */ + opus_int32 exc_buf_Q14[], /* I Random samples buffer Q10 */ + opus_int length, /* I Length */ + opus_int32 *rand_seed /* I/O Seed to random index generator */ +) +{ + opus_int32 seed; + opus_int i, idx, exc_mask; + + exc_mask = CNG_BUF_MASK_MAX; + while( exc_mask > length ) { + exc_mask = silk_RSHIFT( exc_mask, 1 ); + } + + seed = *rand_seed; + for( i = 0; i < length; i++ ) { + seed = silk_RAND( seed ); + idx = (opus_int)( silk_RSHIFT( seed, 24 ) & exc_mask ); + silk_assert( idx >= 0 ); + silk_assert( idx <= CNG_BUF_MASK_MAX ); + exc_Q14[ i ] = exc_buf_Q14[ idx ]; + } + *rand_seed = seed; +} + +void silk_CNG_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +) +{ + opus_int i, NLSF_step_Q15, NLSF_acc_Q15; + + NLSF_step_Q15 = silk_DIV32_16( silk_int16_MAX, psDec->LPC_order + 1 ); + NLSF_acc_Q15 = 0; + for( i = 0; i < psDec->LPC_order; i++ ) { + NLSF_acc_Q15 += NLSF_step_Q15; + psDec->sCNG.CNG_smth_NLSF_Q15[ i ] = NLSF_acc_Q15; + } + psDec->sCNG.CNG_smth_Gain_Q16 = 0; + psDec->sCNG.rand_seed = 3176576; +} + +/* Updates CNG estimate, and applies the CNG when packet was lost */ +void silk_CNG( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O Signal */ + opus_int length /* I Length of residual */ +) +{ + opus_int i, subfr; + opus_int32 LPC_pred_Q10, max_Gain_Q16, gain_Q16, gain_Q10; + opus_int16 A_Q12[ MAX_LPC_ORDER ]; + silk_CNG_struct *psCNG = &psDec->sCNG; + SAVE_STACK; + + if( psDec->fs_kHz != psCNG->fs_kHz ) { + /* Reset state */ + silk_CNG_Reset( psDec ); + + psCNG->fs_kHz = psDec->fs_kHz; + } + if( psDec->lossCnt == 0 && psDec->prevSignalType == TYPE_NO_VOICE_ACTIVITY ) { + /* Update CNG parameters */ + + /* Smoothing of LSF's */ + for( i = 0; i < psDec->LPC_order; i++ ) { + psCNG->CNG_smth_NLSF_Q15[ i ] += silk_SMULWB( (opus_int32)psDec->prevNLSF_Q15[ i ] - (opus_int32)psCNG->CNG_smth_NLSF_Q15[ i ], CNG_NLSF_SMTH_Q16 ); + } + /* Find the subframe with the highest gain */ + max_Gain_Q16 = 0; + subfr = 0; + for( i = 0; i < psDec->nb_subfr; i++ ) { + if( psDecCtrl->Gains_Q16[ i ] > max_Gain_Q16 ) { + max_Gain_Q16 = psDecCtrl->Gains_Q16[ i ]; + subfr = i; + } + } + /* Update CNG excitation buffer with excitation from this subframe */ + silk_memmove( &psCNG->CNG_exc_buf_Q14[ psDec->subfr_length ], psCNG->CNG_exc_buf_Q14, ( psDec->nb_subfr - 1 ) * psDec->subfr_length * sizeof( opus_int32 ) ); + silk_memcpy( psCNG->CNG_exc_buf_Q14, &psDec->exc_Q14[ subfr * psDec->subfr_length ], psDec->subfr_length * sizeof( opus_int32 ) ); + + /* Smooth gains */ + for( i = 0; i < psDec->nb_subfr; i++ ) { + psCNG->CNG_smth_Gain_Q16 += silk_SMULWB( psDecCtrl->Gains_Q16[ i ] - psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_Q16 ); + /* If the smoothed gain is 3 dB greater than this subframe's gain, use this subframe's gain to adapt faster. */ + if( silk_SMULWW( psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_THRESHOLD_Q16 ) > psDecCtrl->Gains_Q16[ i ] ) { + psCNG->CNG_smth_Gain_Q16 = psDecCtrl->Gains_Q16[ i ]; + } + } + } + + /* Add CNG when packet is lost or during DTX */ + if( psDec->lossCnt ) { + VARDECL( opus_int32, CNG_sig_Q14 ); + ALLOC( CNG_sig_Q14, length + MAX_LPC_ORDER, opus_int32 ); + + /* Generate CNG excitation */ + gain_Q16 = silk_SMULWW( psDec->sPLC.randScale_Q14, psDec->sPLC.prevGain_Q16[1] ); + if( gain_Q16 >= (1 << 21) || psCNG->CNG_smth_Gain_Q16 > (1 << 23) ) { + gain_Q16 = silk_SMULTT( gain_Q16, gain_Q16 ); + gain_Q16 = silk_SUB_LSHIFT32(silk_SMULTT( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 ); + gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 16 ); + } else { + gain_Q16 = silk_SMULWW( gain_Q16, gain_Q16 ); + gain_Q16 = silk_SUB_LSHIFT32(silk_SMULWW( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 ); + gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 8 ); + } + gain_Q10 = silk_RSHIFT( gain_Q16, 6 ); + + silk_CNG_exc( CNG_sig_Q14 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, length, &psCNG->rand_seed ); + + /* Convert CNG NLSF to filter representation */ + silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order, psDec->arch ); + + /* Generate CNG signal, by synthesis filtering */ + silk_memcpy( CNG_sig_Q14, psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + celt_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 ); + for( i = 0; i < length; i++ ) { + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); + if( psDec->LPC_order == 16 ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 11 ], A_Q12[ 10 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 12 ], A_Q12[ 11 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 13 ], A_Q12[ 12 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 14 ], A_Q12[ 13 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 15 ], A_Q12[ 14 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12[ 15 ] ); + } + + /* Update states */ + CNG_sig_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( CNG_sig_Q14[ MAX_LPC_ORDER + i ], silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ) ); + + /* Scale with Gain and add to input signal */ + frame[ i ] = (opus_int16)silk_ADD_SAT16( frame[ i ], silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( CNG_sig_Q14[ MAX_LPC_ORDER + i ], gain_Q10 ), 8 ) ) ); + + } + silk_memcpy( psCNG->CNG_synth_state, &CNG_sig_Q14[ length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + } else { + silk_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order * sizeof( opus_int32 ) ); + } + RESTORE_STACK; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/HP_variable_cutoff.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/HP_variable_cutoff.c new file mode 100644 index 000000000..bbe10f04c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/HP_variable_cutoff.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef FIXED_POINT +#include "main_FIX.h" +#else +#include "main_FLP.h" +#endif +#include "tuning_parameters.h" + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +) +{ + opus_int quality_Q15; + opus_int32 pitch_freq_Hz_Q16, pitch_freq_log_Q7, delta_freq_Q7; + silk_encoder_state *psEncC1 = &state_Fxx[ 0 ].sCmn; + + /* Adaptive cutoff frequency: estimate low end of pitch frequency range */ + if( psEncC1->prevSignalType == TYPE_VOICED ) { + /* difference, in log domain */ + pitch_freq_Hz_Q16 = silk_DIV32_16( silk_LSHIFT( silk_MUL( psEncC1->fs_kHz, 1000 ), 16 ), psEncC1->prevLag ); + pitch_freq_log_Q7 = silk_lin2log( pitch_freq_Hz_Q16 ) - ( 16 << 7 ); + + /* adjustment based on quality */ + quality_Q15 = psEncC1->input_quality_bands_Q15[ 0 ]; + pitch_freq_log_Q7 = silk_SMLAWB( pitch_freq_log_Q7, silk_SMULWB( silk_LSHIFT( -quality_Q15, 2 ), quality_Q15 ), + pitch_freq_log_Q7 - ( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ) ) ); + + /* delta_freq = pitch_freq_log - psEnc->variable_HP_smth1; */ + delta_freq_Q7 = pitch_freq_log_Q7 - silk_RSHIFT( psEncC1->variable_HP_smth1_Q15, 8 ); + if( delta_freq_Q7 < 0 ) { + /* less smoothing for decreasing pitch frequency, to track something close to the minimum */ + delta_freq_Q7 = silk_MUL( delta_freq_Q7, 3 ); + } + + /* limit delta, to reduce impact of outliers in pitch estimation */ + delta_freq_Q7 = silk_LIMIT_32( delta_freq_Q7, -SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ), SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ) ); + + /* update smoother */ + psEncC1->variable_HP_smth1_Q15 = silk_SMLAWB( psEncC1->variable_HP_smth1_Q15, + silk_SMULBB( psEncC1->speech_activity_Q8, delta_freq_Q7 ), SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF1, 16 ) ); + + /* limit frequency range */ + psEncC1->variable_HP_smth1_Q15 = silk_LIMIT_32( psEncC1->variable_HP_smth1_Q15, + silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ), + silk_LSHIFT( silk_lin2log( VARIABLE_HP_MAX_CUTOFF_HZ ), 8 ) ); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/Inlines.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/Inlines.h new file mode 100644 index 000000000..ec986cdfd --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/Inlines.h @@ -0,0 +1,188 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +/*! \file silk_Inlines.h + * \brief silk_Inlines.h defines OPUS_INLINE signal processing functions. + */ + +#ifndef SILK_FIX_INLINES_H +#define SILK_FIX_INLINES_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* count leading zeros of opus_int64 */ +static OPUS_INLINE opus_int32 silk_CLZ64( opus_int64 in ) +{ + opus_int32 in_upper; + + in_upper = (opus_int32)silk_RSHIFT64(in, 32); + if (in_upper == 0) { + /* Search in the lower 32 bits */ + return 32 + silk_CLZ32( (opus_int32) in ); + } else { + /* Search in the upper 32 bits */ + return silk_CLZ32( in_upper ); + } +} + +/* get number of leading zeros and fractional part (the bits right after the leading one */ +static OPUS_INLINE void silk_CLZ_FRAC( + opus_int32 in, /* I input */ + opus_int32 *lz, /* O number of leading zeros */ + opus_int32 *frac_Q7 /* O the 7 bits right after the leading one */ +) +{ + opus_int32 lzeros = silk_CLZ32(in); + + * lz = lzeros; + * frac_Q7 = silk_ROR32(in, 24 - lzeros) & 0x7f; +} + +/* Approximation of square root */ +/* Accuracy: < +/- 10% for output values > 15 */ +/* < +/- 2.5% for output values > 120 */ +static OPUS_INLINE opus_int32 silk_SQRT_APPROX( opus_int32 x ) +{ + opus_int32 y, lz, frac_Q7; + + if( x <= 0 ) { + return 0; + } + + silk_CLZ_FRAC(x, &lz, &frac_Q7); + + if( lz & 1 ) { + y = 32768; + } else { + y = 46214; /* 46214 = sqrt(2) * 32768 */ + } + + /* get scaling right */ + y >>= silk_RSHIFT(lz, 1); + + /* increment using fractional part of input */ + y = silk_SMLAWB(y, y, silk_SMULBB(213, frac_Q7)); + + return y; +} + +/* Divide two int32 values and return result as int32 in a given Q-domain */ +static OPUS_INLINE opus_int32 silk_DIV32_varQ( /* O returns a good approximation of "(a32 << Qres) / b32" */ + const opus_int32 a32, /* I numerator (Q0) */ + const opus_int32 b32, /* I denominator (Q0) */ + const opus_int Qres /* I Q-domain of result (>= 0) */ +) +{ + opus_int a_headrm, b_headrm, lshift; + opus_int32 b32_inv, a32_nrm, b32_nrm, result; + + silk_assert( b32 != 0 ); + silk_assert( Qres >= 0 ); + + /* Compute number of bits head room and normalize inputs */ + a_headrm = silk_CLZ32( silk_abs(a32) ) - 1; + a32_nrm = silk_LSHIFT(a32, a_headrm); /* Q: a_headrm */ + b_headrm = silk_CLZ32( silk_abs(b32) ) - 1; + b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = silk_SMULWB(a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation */ + /* It's OK to overflow because the final value of a32_nrm should always be small */ + a32_nrm = silk_SUB32_ovflw(a32_nrm, silk_LSHIFT_ovflw( silk_SMMUL(b32_nrm, result), 3 )); /* Q: a_headrm */ + + /* Refinement */ + result = silk_SMLAWB(result, a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Convert to Qres domain */ + lshift = 29 + a_headrm - b_headrm - Qres; + if( lshift < 0 ) { + return silk_LSHIFT_SAT32(result, -lshift); + } else { + if( lshift < 32){ + return silk_RSHIFT(result, lshift); + } else { + /* Avoid undefined result */ + return 0; + } + } +} + +/* Invert int32 value and return result as int32 in a given Q-domain */ +static OPUS_INLINE opus_int32 silk_INVERSE32_varQ( /* O returns a good approximation of "(1 << Qres) / b32" */ + const opus_int32 b32, /* I denominator (Q0) */ + const opus_int Qres /* I Q-domain of result (> 0) */ +) +{ + opus_int b_headrm, lshift; + opus_int32 b32_inv, b32_nrm, err_Q32, result; + + silk_assert( b32 != 0 ); + silk_assert( Qres > 0 ); + + /* Compute number of bits head room and normalize input */ + b_headrm = silk_CLZ32( silk_abs(b32) ) - 1; + b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = silk_LSHIFT(b32_inv, 16); /* Q: 61 - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation from one */ + err_Q32 = silk_LSHIFT( ((opus_int32)1<<29) - silk_SMULWB(b32_nrm, b32_inv), 3 ); /* Q32 */ + + /* Refinement */ + result = silk_SMLAWW(result, err_Q32, b32_inv); /* Q: 61 - b_headrm */ + + /* Convert to Qres domain */ + lshift = 61 - b_headrm - Qres; + if( lshift <= 0 ) { + return silk_LSHIFT_SAT32(result, -lshift); + } else { + if( lshift < 32){ + return silk_RSHIFT(result, lshift); + }else{ + /* Avoid undefined result */ + return 0; + } + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_FIX_INLINES_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/LPC_analysis_filter.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/LPC_analysis_filter.c new file mode 100644 index 000000000..d34b5eb70 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/LPC_analysis_filter.c @@ -0,0 +1,111 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "celt_lpc.h" + +/*******************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first d output samples are set to zero */ +/*******************************************/ + +/* OPT: Using celt_fir() for this function should be faster, but it may cause + integer overflows in intermediate values (not final results), which the + current implementation silences by casting to unsigned. Enabling + this should be safe in pretty much all cases, even though it is not technically + C89-compliant. */ +#define USE_CELT_FIR 0 + +void silk_LPC_analysis_filter( + opus_int16 *out, /* O Output signal */ + const opus_int16 *in, /* I Input signal */ + const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */ + const opus_int32 len, /* I Signal length */ + const opus_int32 d, /* I Filter order */ + int arch /* I Run-time architecture */ +) +{ + opus_int j; +#if defined(FIXED_POINT) && USE_CELT_FIR + opus_int16 num[SILK_MAX_ORDER_LPC]; +#else + int ix; + opus_int32 out32_Q12, out32; + const opus_int16 *in_ptr; +#endif + + celt_assert( d >= 6 ); + celt_assert( (d & 1) == 0 ); + celt_assert( d <= len ); + +#if defined(FIXED_POINT) && USE_CELT_FIR + celt_assert( d <= SILK_MAX_ORDER_LPC ); + for ( j = 0; j < d; j++ ) { + num[ j ] = -B[ j ]; + } + celt_fir( in + d, num, out + d, len - d, d, arch ); + for ( j = 0; j < d; j++ ) { + out[ j ] = 0; + } +#else + (void)arch; + for( ix = d; ix < len; ix++ ) { + in_ptr = &in[ ix - 1 ]; + + out32_Q12 = silk_SMULBB( in_ptr[ 0 ], B[ 0 ] ); + /* Allowing wrap around so that two wraps can cancel each other. The rare + cases where the result wraps around can only be triggered by invalid streams*/ + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -1 ], B[ 1 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -2 ], B[ 2 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -3 ], B[ 3 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -4 ], B[ 4 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -5 ], B[ 5 ] ); + for( j = 6; j < d; j += 2 ) { + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j ], B[ j ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j - 1 ], B[ j + 1 ] ); + } + + /* Subtract prediction */ + out32_Q12 = silk_SUB32_ovflw( silk_LSHIFT( (opus_int32)in_ptr[ 1 ], 12 ), out32_Q12 ); + + /* Scale to Q0 */ + out32 = silk_RSHIFT_ROUND( out32_Q12, 12 ); + + /* Saturate output */ + out[ ix ] = (opus_int16)silk_SAT16( out32 ); + } + + /* Set first d output samples to zero */ + silk_memset( out, 0, d * sizeof( opus_int16 ) ); +#endif +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/LPC_fit.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/LPC_fit.c new file mode 100644 index 000000000..c0690a1fc --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/LPC_fit.c @@ -0,0 +1,82 @@ +/*********************************************************************** +Copyright (c) 2013, Koen Vos. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Convert int32 coefficients to int16 coefs and make sure there's no wrap-around. + This logic is reused in _celt_lpc(). Any bug fixes should also be applied there. */ +void silk_LPC_fit( + opus_int16 *a_QOUT, /* O Output signal */ + opus_int32 *a_QIN, /* I/O Input signal */ + const opus_int QOUT, /* I Input Q domain */ + const opus_int QIN, /* I Input Q domain */ + const opus_int d /* I Filter order */ +) +{ + opus_int i, k, idx = 0; + opus_int32 maxabs, absval, chirp_Q16; + + /* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */ + for( i = 0; i < 10; i++ ) { + /* Find maximum absolute value and its index */ + maxabs = 0; + for( k = 0; k < d; k++ ) { + absval = silk_abs( a_QIN[k] ); + if( absval > maxabs ) { + maxabs = absval; + idx = k; + } + } + maxabs = silk_RSHIFT_ROUND( maxabs, QIN - QOUT ); + + if( maxabs > silk_int16_MAX ) { + /* Reduce magnitude of prediction coefficients */ + maxabs = silk_min( maxabs, 163838 ); /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */ + chirp_Q16 = SILK_FIX_CONST( 0.999, 16 ) - silk_DIV32( silk_LSHIFT( maxabs - silk_int16_MAX, 14 ), + silk_RSHIFT32( silk_MUL( maxabs, idx + 1), 2 ) ); + silk_bwexpander_32( a_QIN, d, chirp_Q16 ); + } else { + break; + } + } + + if( i == 10 ) { + /* Reached the last iteration, clip the coefficients */ + for( k = 0; k < d; k++ ) { + a_QOUT[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( a_QIN[ k ], QIN - QOUT ) ); + a_QIN[ k ] = silk_LSHIFT( (opus_int32)a_QOUT[ k ], QIN - QOUT ); + } + } else { + for( k = 0; k < d; k++ ) { + a_QOUT[ k ] = (opus_int16)silk_RSHIFT_ROUND( a_QIN[ k ], QIN - QOUT ); + } + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/LPC_inv_pred_gain.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/LPC_inv_pred_gain.c new file mode 100644 index 000000000..a3746a6ef --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/LPC_inv_pred_gain.c @@ -0,0 +1,141 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "define.h" + +#define QA 24 +#define A_LIMIT SILK_FIX_CONST( 0.99975, QA ) + +#define MUL32_FRAC_Q(a32, b32, Q) ((opus_int32)(silk_RSHIFT_ROUND64(silk_SMULL(a32, b32), Q))) + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +static opus_int32 LPC_inverse_pred_gain_QA_c( /* O Returns inverse prediction gain in energy domain, Q30 */ + opus_int32 A_QA[ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k, n, mult2Q; + opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp1, tmp2; + + invGain_Q30 = SILK_FIX_CONST( 1, 30 ); + for( k = order - 1; k > 0; k-- ) { + /* Check for stability */ + if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( A_QA[ k ], 31 - QA ); + + /* rc_mult1_Q30 range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) ); + silk_assert( rc_mult1_Q30 > ( 1 << 15 ) ); /* reduce A_LIMIT if fails */ + silk_assert( rc_mult1_Q30 <= ( 1 << 30 ) ); + + /* Update inverse gain */ + /* invGain_Q30 range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= ( 1 << 30 ) ); + if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + return 0; + } + + /* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */ + mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) ); + rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 ); + + /* Update AR coefficient */ + for( n = 0; n < (k + 1) >> 1; n++ ) { + opus_int64 tmp64; + tmp1 = A_QA[ n ]; + tmp2 = A_QA[ k - n - 1 ]; + tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp1, + MUL32_FRAC_Q( tmp2, rc_Q31, 31 ) ), rc_mult2 ), mult2Q); + if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { + return 0; + } + A_QA[ n ] = ( opus_int32 )tmp64; + tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp2, + MUL32_FRAC_Q( tmp1, rc_Q31, 31 ) ), rc_mult2), mult2Q); + if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { + return 0; + } + A_QA[ k - n - 1 ] = ( opus_int32 )tmp64; + } + } + + /* Check for stability */ + if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( A_QA[ 0 ], 31 - QA ); + + /* Range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) ); + + /* Update inverse gain */ + /* Range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= ( 1 << 30 ) ); + if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + return 0; + } + + return invGain_Q30; +} + +/* For input in Q12 domain */ +opus_int32 silk_LPC_inverse_pred_gain_c( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k; + opus_int32 Atmp_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 DC_resp = 0; + + /* Increase Q domain of the AR coefficients */ + for( k = 0; k < order; k++ ) { + DC_resp += (opus_int32)A_Q12[ k ]; + Atmp_QA[ k ] = silk_LSHIFT32( (opus_int32)A_Q12[ k ], QA - 12 ); + } + /* If the DC is unstable, we don't even need to do the full calculations */ + if( DC_resp >= 4096 ) { + return 0; + } + return LPC_inverse_pred_gain_QA_c( Atmp_QA, order ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/LP_variable_cutoff.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/LP_variable_cutoff.c new file mode 100644 index 000000000..79112ad35 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/LP_variable_cutoff.c @@ -0,0 +1,135 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + Elliptic/Cauer filters designed with 0.1 dB passband ripple, + 80 dB minimum stopband attenuation, and + [0.95 : 0.15 : 0.35] normalized cut off frequencies. +*/ + +#include "main.h" + +/* Helper function, interpolates the filter taps */ +static OPUS_INLINE void silk_LP_interpolate_filter_taps( + opus_int32 B_Q28[ TRANSITION_NB ], + opus_int32 A_Q28[ TRANSITION_NA ], + const opus_int ind, + const opus_int32 fac_Q16 +) +{ + opus_int nb, na; + + if( ind < TRANSITION_INT_NUM - 1 ) { + if( fac_Q16 > 0 ) { + if( fac_Q16 < 32768 ) { /* fac_Q16 is in range of a 16-bit int */ + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = silk_SMLAWB( + silk_Transition_LP_B_Q28[ ind ][ nb ], + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] - + silk_Transition_LP_B_Q28[ ind ][ nb ], + fac_Q16 ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = silk_SMLAWB( + silk_Transition_LP_A_Q28[ ind ][ na ], + silk_Transition_LP_A_Q28[ ind + 1 ][ na ] - + silk_Transition_LP_A_Q28[ ind ][ na ], + fac_Q16 ); + } + } else { /* ( fac_Q16 - ( 1 << 16 ) ) is in range of a 16-bit int */ + silk_assert( fac_Q16 - ( 1 << 16 ) == silk_SAT16( fac_Q16 - ( 1 << 16 ) ) ); + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = silk_SMLAWB( + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ], + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] - + silk_Transition_LP_B_Q28[ ind ][ nb ], + fac_Q16 - ( (opus_int32)1 << 16 ) ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = silk_SMLAWB( + silk_Transition_LP_A_Q28[ ind + 1 ][ na ], + silk_Transition_LP_A_Q28[ ind + 1 ][ na ] - + silk_Transition_LP_A_Q28[ ind ][ na ], + fac_Q16 - ( (opus_int32)1 << 16 ) ); + } + } + } else { + silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ ind ], TRANSITION_NB * sizeof( opus_int32 ) ); + silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ ind ], TRANSITION_NA * sizeof( opus_int32 ) ); + } + } else { + silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NB * sizeof( opus_int32 ) ); + silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NA * sizeof( opus_int32 ) ); + } +} + +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting psEncC->mode <> 0; */ +/* Deactivate by setting psEncC->mode = 0; */ +void silk_LP_variable_cutoff( + silk_LP_state *psLP, /* I/O LP filter state */ + opus_int16 *frame, /* I/O Low-pass filtered output signal */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int32 B_Q28[ TRANSITION_NB ], A_Q28[ TRANSITION_NA ], fac_Q16 = 0; + opus_int ind = 0; + + silk_assert( psLP->transition_frame_no >= 0 && psLP->transition_frame_no <= TRANSITION_FRAMES ); + + /* Run filter if needed */ + if( psLP->mode != 0 ) { + /* Calculate index and interpolation factor for interpolation */ +#if( TRANSITION_INT_STEPS == 64 ) + fac_Q16 = silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 - 6 ); +#else + fac_Q16 = silk_DIV32_16( silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 ), TRANSITION_FRAMES ); +#endif + ind = silk_RSHIFT( fac_Q16, 16 ); + fac_Q16 -= silk_LSHIFT( ind, 16 ); + + silk_assert( ind >= 0 ); + silk_assert( ind < TRANSITION_INT_NUM ); + + /* Interpolate filter coefficients */ + silk_LP_interpolate_filter_taps( B_Q28, A_Q28, ind, fac_Q16 ); + + /* Update transition frame number for next frame */ + psLP->transition_frame_no = silk_LIMIT( psLP->transition_frame_no + psLP->mode, 0, TRANSITION_FRAMES ); + + /* ARMA low-pass filtering */ + silk_assert( TRANSITION_NB == 3 && TRANSITION_NA == 2 ); + silk_biquad_alt_stride1( frame, B_Q28, A_Q28, psLP->In_LP_State, frame, frame_length); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/MacroCount.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/MacroCount.h new file mode 100644 index 000000000..dab2f57a6 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/MacroCount.h @@ -0,0 +1,710 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SIGPROCFIX_API_MACROCOUNT_H +#define SIGPROCFIX_API_MACROCOUNT_H + +#ifdef silk_MACRO_COUNT +#include +#define varDefine opus_int64 ops_count = 0; + +extern opus_int64 ops_count; + +static OPUS_INLINE opus_int64 silk_SaveCount(){ + return(ops_count); +} + +static OPUS_INLINE opus_int64 silk_SaveResetCount(){ + opus_int64 ret; + + ret = ops_count; + ops_count = 0; + return(ret); +} + +static OPUS_INLINE silk_PrintCount(){ + printf("ops_count = %d \n ", (opus_int32)ops_count); +} + +#undef silk_MUL +static OPUS_INLINE opus_int32 silk_MUL(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 4; + ret = a32 * b32; + return ret; +} + +#undef silk_MUL_uint +static OPUS_INLINE opus_uint32 silk_MUL_uint(opus_uint32 a32, opus_uint32 b32){ + opus_uint32 ret; + ops_count += 4; + ret = a32 * b32; + return ret; +} +#undef silk_MLA +static OPUS_INLINE opus_int32 silk_MLA(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 4; + ret = a32 + b32 * c32; + return ret; +} + +#undef silk_MLA_uint +static OPUS_INLINE opus_int32 silk_MLA_uint(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32){ + opus_uint32 ret; + ops_count += 4; + ret = a32 + b32 * c32; + return ret; +} + +#undef silk_SMULWB +static OPUS_INLINE opus_int32 silk_SMULWB(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 5; + ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16); + return ret; +} +#undef silk_SMLAWB +static OPUS_INLINE opus_int32 silk_SMLAWB(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 5; + ret = ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16))); + return ret; +} + +#undef silk_SMULWT +static OPUS_INLINE opus_int32 silk_SMULWT(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 4; + ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16); + return ret; +} +#undef silk_SMLAWT +static OPUS_INLINE opus_int32 silk_SMLAWT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 4; + ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16)); + return ret; +} + +#undef silk_SMULBB +static OPUS_INLINE opus_int32 silk_SMULBB(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 1; + ret = (opus_int32)((opus_int16)a32) * (opus_int32)((opus_int16)b32); + return ret; +} +#undef silk_SMLABB +static OPUS_INLINE opus_int32 silk_SMLABB(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32); + return ret; +} + +#undef silk_SMULBT +static OPUS_INLINE opus_int32 silk_SMULBT(opus_int32 a32, opus_int32 b32 ){ + opus_int32 ret; + ops_count += 4; + ret = ((opus_int32)((opus_int16)a32)) * (b32 >> 16); + return ret; +} + +#undef silk_SMLABT +static OPUS_INLINE opus_int32 silk_SMLABT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16); + return ret; +} + +#undef silk_SMULTT +static OPUS_INLINE opus_int32 silk_SMULTT(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 1; + ret = (a32 >> 16) * (b32 >> 16); + return ret; +} + +#undef silk_SMLATT +static OPUS_INLINE opus_int32 silk_SMLATT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + (b32 >> 16) * (c32 >> 16); + return ret; +} + + +/* multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode)*/ +#undef silk_MLA_ovflw +#define silk_MLA_ovflw silk_MLA + +#undef silk_SMLABB_ovflw +#define silk_SMLABB_ovflw silk_SMLABB + +#undef silk_SMLABT_ovflw +#define silk_SMLABT_ovflw silk_SMLABT + +#undef silk_SMLATT_ovflw +#define silk_SMLATT_ovflw silk_SMLATT + +#undef silk_SMLAWB_ovflw +#define silk_SMLAWB_ovflw silk_SMLAWB + +#undef silk_SMLAWT_ovflw +#define silk_SMLAWT_ovflw silk_SMLAWT + +#undef silk_SMULL +static OPUS_INLINE opus_int64 silk_SMULL(opus_int32 a32, opus_int32 b32){ + opus_int64 ret; + ops_count += 8; + ret = ((opus_int64)(a32) * /*(opus_int64)*/(b32)); + return ret; +} + +#undef silk_SMLAL +static OPUS_INLINE opus_int64 silk_SMLAL(opus_int64 a64, opus_int32 b32, opus_int32 c32){ + opus_int64 ret; + ops_count += 8; + ret = a64 + ((opus_int64)(b32) * /*(opus_int64)*/(c32)); + return ret; +} +#undef silk_SMLALBB +static OPUS_INLINE opus_int64 silk_SMLALBB(opus_int64 a64, opus_int16 b16, opus_int16 c16){ + opus_int64 ret; + ops_count += 4; + ret = a64 + ((opus_int64)(b16) * /*(opus_int64)*/(c16)); + return ret; +} + +#undef SigProcFIX_CLZ16 +static OPUS_INLINE opus_int32 SigProcFIX_CLZ16(opus_int16 in16) +{ + opus_int32 out32 = 0; + ops_count += 10; + if( in16 == 0 ) { + return 16; + } + /* test nibbles */ + if( in16 & 0xFF00 ) { + if( in16 & 0xF000 ) { + in16 >>= 12; + } else { + out32 += 4; + in16 >>= 8; + } + } else { + if( in16 & 0xFFF0 ) { + out32 += 8; + in16 >>= 4; + } else { + out32 += 12; + } + } + /* test bits and return */ + if( in16 & 0xC ) { + if( in16 & 0x8 ) + return out32 + 0; + else + return out32 + 1; + } else { + if( in16 & 0xE ) + return out32 + 2; + else + return out32 + 3; + } +} + +#undef SigProcFIX_CLZ32 +static OPUS_INLINE opus_int32 SigProcFIX_CLZ32(opus_int32 in32) +{ + /* test highest 16 bits and convert to opus_int16 */ + ops_count += 2; + if( in32 & 0xFFFF0000 ) { + return SigProcFIX_CLZ16((opus_int16)(in32 >> 16)); + } else { + return SigProcFIX_CLZ16((opus_int16)in32) + 16; + } +} + +#undef silk_DIV32 +static OPUS_INLINE opus_int32 silk_DIV32(opus_int32 a32, opus_int32 b32){ + ops_count += 64; + return a32 / b32; +} + +#undef silk_DIV32_16 +static OPUS_INLINE opus_int32 silk_DIV32_16(opus_int32 a32, opus_int32 b32){ + ops_count += 32; + return a32 / b32; +} + +#undef silk_SAT8 +static OPUS_INLINE opus_int8 silk_SAT8(opus_int64 a){ + opus_int8 tmp; + ops_count += 1; + tmp = (opus_int8)((a) > silk_int8_MAX ? silk_int8_MAX : \ + ((a) < silk_int8_MIN ? silk_int8_MIN : (a))); + return(tmp); +} + +#undef silk_SAT16 +static OPUS_INLINE opus_int16 silk_SAT16(opus_int64 a){ + opus_int16 tmp; + ops_count += 1; + tmp = (opus_int16)((a) > silk_int16_MAX ? silk_int16_MAX : \ + ((a) < silk_int16_MIN ? silk_int16_MIN : (a))); + return(tmp); +} +#undef silk_SAT32 +static OPUS_INLINE opus_int32 silk_SAT32(opus_int64 a){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : \ + ((a) < silk_int32_MIN ? silk_int32_MIN : (a))); + return(tmp); +} +#undef silk_POS_SAT32 +static OPUS_INLINE opus_int32 silk_POS_SAT32(opus_int64 a){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : (a)); + return(tmp); +} + +#undef silk_ADD_POS_SAT8 +static OPUS_INLINE opus_int8 silk_ADD_POS_SAT8(opus_int64 a, opus_int64 b){ + opus_int8 tmp; + ops_count += 1; + tmp = (opus_int8)((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b))); + return(tmp); +} +#undef silk_ADD_POS_SAT16 +static OPUS_INLINE opus_int16 silk_ADD_POS_SAT16(opus_int64 a, opus_int64 b){ + opus_int16 tmp; + ops_count += 1; + tmp = (opus_int16)((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b))); + return(tmp); +} + +#undef silk_ADD_POS_SAT32 +static OPUS_INLINE opus_int32 silk_ADD_POS_SAT32(opus_int64 a, opus_int64 b){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((((a)+(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b))); + return(tmp); +} + +#undef silk_LSHIFT8 +static OPUS_INLINE opus_int8 silk_LSHIFT8(opus_int8 a, opus_int32 shift){ + opus_int8 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT16 +static OPUS_INLINE opus_int16 silk_LSHIFT16(opus_int16 a, opus_int32 shift){ + opus_int16 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT32 +static OPUS_INLINE opus_int32 silk_LSHIFT32(opus_int32 a, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT64 +static OPUS_INLINE opus_int64 silk_LSHIFT64(opus_int64 a, opus_int shift){ + ops_count += 1; + return a << shift; +} + +#undef silk_LSHIFT_ovflw +static OPUS_INLINE opus_int32 silk_LSHIFT_ovflw(opus_int32 a, opus_int32 shift){ + ops_count += 1; + return a << shift; +} + +#undef silk_LSHIFT_uint +static OPUS_INLINE opus_uint32 silk_LSHIFT_uint(opus_uint32 a, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a << shift; + return ret; +} + +#undef silk_RSHIFT8 +static OPUS_INLINE opus_int8 silk_RSHIFT8(opus_int8 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT16 +static OPUS_INLINE opus_int16 silk_RSHIFT16(opus_int16 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT32 +static OPUS_INLINE opus_int32 silk_RSHIFT32(opus_int32 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT64 +static OPUS_INLINE opus_int64 silk_RSHIFT64(opus_int64 a, opus_int64 shift){ + ops_count += 1; + return a >> shift; +} + +#undef silk_RSHIFT_uint +static OPUS_INLINE opus_uint32 silk_RSHIFT_uint(opus_uint32 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} + +#undef silk_ADD_LSHIFT +static OPUS_INLINE opus_int32 silk_ADD_LSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_LSHIFT32 +static OPUS_INLINE opus_int32 silk_ADD_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_LSHIFT_uint +static OPUS_INLINE opus_uint32 silk_ADD_LSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_RSHIFT +static OPUS_INLINE opus_int32 silk_ADD_RSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_ADD_RSHIFT32 +static OPUS_INLINE opus_int32 silk_ADD_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_ADD_RSHIFT_uint +static OPUS_INLINE opus_uint32 silk_ADD_RSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_SUB_LSHIFT32 +static OPUS_INLINE opus_int32 silk_SUB_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a - (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_SUB_RSHIFT32 +static OPUS_INLINE opus_int32 silk_SUB_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a - (b >> shift); + return ret; /* shift > 0*/ +} + +#undef silk_RSHIFT_ROUND +static OPUS_INLINE opus_int32 silk_RSHIFT_ROUND(opus_int32 a, opus_int32 shift){ + opus_int32 ret; + ops_count += 3; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +#undef silk_RSHIFT_ROUND64 +static OPUS_INLINE opus_int64 silk_RSHIFT_ROUND64(opus_int64 a, opus_int32 shift){ + opus_int64 ret; + ops_count += 6; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +#undef silk_abs_int64 +static OPUS_INLINE opus_int64 silk_abs_int64(opus_int64 a){ + ops_count += 1; + return (((a) > 0) ? (a) : -(a)); /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN*/ +} + +#undef silk_abs_int32 +static OPUS_INLINE opus_int32 silk_abs_int32(opus_int32 a){ + ops_count += 1; + return silk_abs(a); +} + + +#undef silk_min +static silk_min(a, b){ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_max +static silk_max(a, b){ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_sign +static silk_sign(a){ + ops_count += 1; + return ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 )); +} + +#undef silk_ADD16 +static OPUS_INLINE opus_int16 silk_ADD16(opus_int16 a, opus_int16 b){ + opus_int16 ret; + ops_count += 1; + ret = a + b; + return ret; +} + +#undef silk_ADD32 +static OPUS_INLINE opus_int32 silk_ADD32(opus_int32 a, opus_int32 b){ + opus_int32 ret; + ops_count += 1; + ret = a + b; + return ret; +} + +#undef silk_ADD64 +static OPUS_INLINE opus_int64 silk_ADD64(opus_int64 a, opus_int64 b){ + opus_int64 ret; + ops_count += 2; + ret = a + b; + return ret; +} + +#undef silk_SUB16 +static OPUS_INLINE opus_int16 silk_SUB16(opus_int16 a, opus_int16 b){ + opus_int16 ret; + ops_count += 1; + ret = a - b; + return ret; +} + +#undef silk_SUB32 +static OPUS_INLINE opus_int32 silk_SUB32(opus_int32 a, opus_int32 b){ + opus_int32 ret; + ops_count += 1; + ret = a - b; + return ret; +} + +#undef silk_SUB64 +static OPUS_INLINE opus_int64 silk_SUB64(opus_int64 a, opus_int64 b){ + opus_int64 ret; + ops_count += 2; + ret = a - b; + return ret; +} + +#undef silk_ADD_SAT16 +static OPUS_INLINE opus_int16 silk_ADD_SAT16( opus_int16 a16, opus_int16 b16 ) { + opus_int16 res; + /* Nb will be counted in AKP_add32 and silk_SAT16*/ + res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) ); + return res; +} + +#undef silk_ADD_SAT32 +static OPUS_INLINE opus_int32 silk_ADD_SAT32(opus_int32 a32, opus_int32 b32){ + opus_int32 res; + ops_count += 1; + res = ((((a32) + (b32)) & 0x80000000) == 0 ? \ + ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \ + ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) ); + return res; +} + +#undef silk_ADD_SAT64 +static OPUS_INLINE opus_int64 silk_ADD_SAT64( opus_int64 a64, opus_int64 b64 ) { + opus_int64 res; + ops_count += 1; + res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \ + ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \ + ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) ); + return res; +} + +#undef silk_SUB_SAT16 +static OPUS_INLINE opus_int16 silk_SUB_SAT16( opus_int16 a16, opus_int16 b16 ) { + opus_int16 res; + silk_assert(0); + /* Nb will be counted in sub-macros*/ + res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) ); + return res; +} + +#undef silk_SUB_SAT32 +static OPUS_INLINE opus_int32 silk_SUB_SAT32( opus_int32 a32, opus_int32 b32 ) { + opus_int32 res; + ops_count += 1; + res = ((((a32)-(b32)) & 0x80000000) == 0 ? \ + (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \ + ((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) ); + return res; +} + +#undef silk_SUB_SAT64 +static OPUS_INLINE opus_int64 silk_SUB_SAT64( opus_int64 a64, opus_int64 b64 ) { + opus_int64 res; + ops_count += 1; + res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \ + (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \ + ((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) ); + + return res; +} + +#undef silk_SMULWW +static OPUS_INLINE opus_int32 silk_SMULWW(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + /* Nb will be counted in sub-macros*/ + ret = silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)); + return ret; +} + +#undef silk_SMLAWW +static OPUS_INLINE opus_int32 silk_SMLAWW(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + /* Nb will be counted in sub-macros*/ + ret = silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16)); + return ret; +} + +#undef silk_min_int +static OPUS_INLINE opus_int silk_min_int(opus_int a, opus_int b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} + +#undef silk_min_16 +static OPUS_INLINE opus_int16 silk_min_16(opus_int16 a, opus_int16 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_min_32 +static OPUS_INLINE opus_int32 silk_min_32(opus_int32 a, opus_int32 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_min_64 +static OPUS_INLINE opus_int64 silk_min_64(opus_int64 a, opus_int64 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} + +/* silk_min() versions with typecast in the function call */ +#undef silk_max_int +static OPUS_INLINE opus_int silk_max_int(opus_int a, opus_int b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_max_16 +static OPUS_INLINE opus_int16 silk_max_16(opus_int16 a, opus_int16 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_max_32 +static OPUS_INLINE opus_int32 silk_max_32(opus_int32 a, opus_int32 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} + +#undef silk_max_64 +static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} + + +#undef silk_LIMIT_int +static OPUS_INLINE opus_int silk_LIMIT_int(opus_int a, opus_int limit1, opus_int limit2) +{ + opus_int ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + + return(ret); +} + +#undef silk_LIMIT_16 +static OPUS_INLINE opus_int16 silk_LIMIT_16(opus_int16 a, opus_int16 limit1, opus_int16 limit2) +{ + opus_int16 ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + +return(ret); +} + + +#undef silk_LIMIT_32 +static OPUS_INLINE opus_int32 silk_LIMIT_32(opus_int32 a, opus_int32 limit1, opus_int32 limit2) +{ + opus_int32 ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + return(ret); +} + +#else +#define varDefine +#define silk_SaveCount() + +#endif +#endif + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/MacroDebug.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/MacroDebug.h new file mode 100644 index 000000000..8dd4ce2ee --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/MacroDebug.h @@ -0,0 +1,951 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Copyright (C) 2012 Xiph.Org Foundation +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef MACRO_DEBUG_H +#define MACRO_DEBUG_H + +/* Redefine macro functions with extensive assertion in DEBUG mode. + As functions can't be undefined, this file can't work with SigProcFIX_MacroCount.h */ + +#if ( defined (FIXED_DEBUG) || ( 0 && defined (_DEBUG) ) ) && !defined (silk_MACRO_COUNT) + +#undef silk_ADD16 +#define silk_ADD16(a,b) silk_ADD16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_ADD16_(opus_int16 a, opus_int16 b, char *file, int line){ + opus_int16 ret; + + ret = a + b; + if ( ret != silk_ADD_SAT16( a, b ) ) + { + fprintf (stderr, "silk_ADD16(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_ADD32 +#define silk_ADD32(a,b) silk_ADD32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_ADD32_(opus_int32 a, opus_int32 b, char *file, int line){ + opus_int32 ret; + + ret = a + b; + if ( ret != silk_ADD_SAT32( a, b ) ) + { + fprintf (stderr, "silk_ADD32(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_ADD64 +#define silk_ADD64(a,b) silk_ADD64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_ADD64_(opus_int64 a, opus_int64 b, char *file, int line){ + opus_int64 ret; + + ret = a + b; + if ( ret != silk_ADD_SAT64( a, b ) ) + { + fprintf (stderr, "silk_ADD64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SUB16 +#define silk_SUB16(a,b) silk_SUB16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_SUB16_(opus_int16 a, opus_int16 b, char *file, int line){ + opus_int16 ret; + + ret = a - b; + if ( ret != silk_SUB_SAT16( a, b ) ) + { + fprintf (stderr, "silk_SUB16(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SUB32 +#define silk_SUB32(a,b) silk_SUB32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SUB32_(opus_int32 a, opus_int32 b, char *file, int line){ + opus_int32 ret; + + ret = a - b; + if ( ret != silk_SUB_SAT32( a, b ) ) + { + fprintf (stderr, "silk_SUB32(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SUB64 +#define silk_SUB64(a,b) silk_SUB64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_SUB64_(opus_int64 a, opus_int64 b, char *file, int line){ + opus_int64 ret; + + ret = a - b; + if ( ret != silk_SUB_SAT64( a, b ) ) + { + fprintf (stderr, "silk_SUB64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_ADD_SAT16 +#define silk_ADD_SAT16(a,b) silk_ADD_SAT16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_ADD_SAT16_( opus_int16 a16, opus_int16 b16, char *file, int line) { + opus_int16 res; + res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) ); + if ( res != silk_SAT16( (opus_int32)a16 + (opus_int32)b16 ) ) + { + fprintf (stderr, "silk_ADD_SAT16(%d, %d) in %s: line %d\n", a16, b16, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_ADD_SAT32 +#define silk_ADD_SAT32(a,b) silk_ADD_SAT32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_ADD_SAT32_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 res; + res = ((((opus_uint32)(a32) + (opus_uint32)(b32)) & 0x80000000) == 0 ? \ + ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \ + ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) ); + if ( res != silk_SAT32( (opus_int64)a32 + (opus_int64)b32 ) ) + { + fprintf (stderr, "silk_ADD_SAT32(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_ADD_SAT64 +#define silk_ADD_SAT64(a,b) silk_ADD_SAT64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_ADD_SAT64_( opus_int64 a64, opus_int64 b64, char *file, int line) { + opus_int64 res; + int fail = 0; + res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \ + ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \ + ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) ); + if( res != a64 + b64 ) { + /* Check that we saturated to the correct extreme value */ + if ( !(( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) || + ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) ) ) + { + fail = 1; + } + } else { + /* Saturation not necessary */ + fail = res != a64 + b64; + } + if ( fail ) + { + fprintf (stderr, "silk_ADD_SAT64(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_SUB_SAT16 +#define silk_SUB_SAT16(a,b) silk_SUB_SAT16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_SUB_SAT16_( opus_int16 a16, opus_int16 b16, char *file, int line ) { + opus_int16 res; + res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) ); + if ( res != silk_SAT16( (opus_int32)a16 - (opus_int32)b16 ) ) + { + fprintf (stderr, "silk_SUB_SAT16(%d, %d) in %s: line %d\n", a16, b16, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_SUB_SAT32 +#define silk_SUB_SAT32(a,b) silk_SUB_SAT32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SUB_SAT32_( opus_int32 a32, opus_int32 b32, char *file, int line ) { + opus_int32 res; + res = ((((opus_uint32)(a32)-(opus_uint32)(b32)) & 0x80000000) == 0 ? \ + (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \ + ((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) ); + if ( res != silk_SAT32( (opus_int64)a32 - (opus_int64)b32 ) ) + { + fprintf (stderr, "silk_SUB_SAT32(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_SUB_SAT64 +#define silk_SUB_SAT64(a,b) silk_SUB_SAT64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_SUB_SAT64_( opus_int64 a64, opus_int64 b64, char *file, int line ) { + opus_int64 res; + int fail = 0; + res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \ + (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \ + ((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) ); + if( res != a64 - b64 ) { + /* Check that we saturated to the correct extreme value */ + if( !(( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) || + ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) )) + { + fail = 1; + } + } else { + /* Saturation not necessary */ + fail = res != a64 - b64; + } + if ( fail ) + { + fprintf (stderr, "silk_SUB_SAT64(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_MUL +#define silk_MUL(a,b) silk_MUL_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_MUL_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret; + opus_int64 ret64; + ret = a32 * b32; + ret64 = (opus_int64)a32 * (opus_int64)b32; + if ( (opus_int64)ret != ret64 ) + { + fprintf (stderr, "silk_MUL(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_MUL_uint +#define silk_MUL_uint(a,b) silk_MUL_uint_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_MUL_uint_(opus_uint32 a32, opus_uint32 b32, char *file, int line){ + opus_uint32 ret; + ret = a32 * b32; + if ( (opus_uint64)ret != (opus_uint64)a32 * (opus_uint64)b32 ) + { + fprintf (stderr, "silk_MUL_uint(%u, %u) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_MLA +#define silk_MLA(a,b,c) silk_MLA_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_MLA_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + b32 * c32; + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32 ) + { + fprintf (stderr, "silk_MLA(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_MLA_uint +#define silk_MLA_uint(a,b,c) silk_MLA_uint_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_MLA_uint_(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32, char *file, int line){ + opus_uint32 ret; + ret = a32 + b32 * c32; + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32 ) + { + fprintf (stderr, "silk_MLA_uint(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULWB +#define silk_SMULWB(a,b) silk_SMULWB_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMULWB_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret; + ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16); + if ( (opus_int64)ret != ((opus_int64)a32 * (opus_int16)b32) >> 16 ) + { + fprintf (stderr, "silk_SMULWB(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMLAWB +#define silk_SMLAWB(a,b,c) silk_SMLAWB_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLAWB_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = silk_ADD32( a32, silk_SMULWB( b32, c32 ) ); + if ( silk_ADD32( a32, silk_SMULWB( b32, c32 ) ) != silk_ADD_SAT32( a32, silk_SMULWB( b32, c32 ) ) ) + { + fprintf (stderr, "silk_SMLAWB(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULWT +#define silk_SMULWT(a,b) silk_SMULWT_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMULWT_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret; + ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16); + if ( (opus_int64)ret != ((opus_int64)a32 * (b32 >> 16)) >> 16 ) + { + fprintf (stderr, "silk_SMULWT(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMLAWT +#define silk_SMLAWT(a,b,c) silk_SMLAWT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLAWT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16)); + if ( (opus_int64)ret != (opus_int64)a32 + (((opus_int64)b32 * (c32 >> 16)) >> 16) ) + { + fprintf (stderr, "silk_SMLAWT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULL +#define silk_SMULL(a,b) silk_SMULL_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_SMULL_(opus_int64 a64, opus_int64 b64, char *file, int line){ + opus_int64 ret64; + int fail = 0; + ret64 = a64 * b64; + if( b64 != 0 ) { + fail = a64 != (ret64 / b64); + } else if( a64 != 0 ) { + fail = b64 != (ret64 / a64); + } + if ( fail ) + { + fprintf (stderr, "silk_SMULL(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret64; +} + +/* no checking needed for silk_SMULBB */ +#undef silk_SMLABB +#define silk_SMLABB(a,b,c) silk_SMLABB_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLABB_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32); + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int16)c32 ) + { + fprintf (stderr, "silk_SMLABB(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +/* no checking needed for silk_SMULBT */ +#undef silk_SMLABT +#define silk_SMLABT(a,b,c) silk_SMLABT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLABT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16); + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (c32 >> 16) ) + { + fprintf (stderr, "silk_SMLABT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +/* no checking needed for silk_SMULTT */ +#undef silk_SMLATT +#define silk_SMLATT(a,b,c) silk_SMLATT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLATT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + (b32 >> 16) * (c32 >> 16); + if ( (opus_int64)ret != (opus_int64)a32 + (b32 >> 16) * (c32 >> 16) ) + { + fprintf (stderr, "silk_SMLATT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULWW +#define silk_SMULWW(a,b) silk_SMULWW_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMULWW_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret, tmp1, tmp2; + opus_int64 ret64; + int fail = 0; + + ret = silk_SMULWB( a32, b32 ); + tmp1 = silk_RSHIFT_ROUND( b32, 16 ); + tmp2 = silk_MUL( a32, tmp1 ); + + fail |= (opus_int64)tmp2 != (opus_int64) a32 * (opus_int64) tmp1; + + tmp1 = ret; + ret = silk_ADD32( tmp1, tmp2 ); + fail |= silk_ADD32( tmp1, tmp2 ) != silk_ADD_SAT32( tmp1, tmp2 ); + + ret64 = silk_RSHIFT64( silk_SMULL( a32, b32 ), 16 ); + fail |= (opus_int64)ret != ret64; + + if ( fail ) + { + fprintf (stderr, "silk_SMULWT(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + + return ret; +} + +#undef silk_SMLAWW +#define silk_SMLAWW(a,b,c) silk_SMLAWW_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLAWW_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret, tmp; + + tmp = silk_SMULWW( b32, c32 ); + ret = silk_ADD32( a32, tmp ); + if ( ret != silk_ADD_SAT32( a32, tmp ) ) + { + fprintf (stderr, "silk_SMLAWW(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */ +#undef silk_MLA_ovflw +#define silk_MLA_ovflw(a32, b32, c32) ((a32) + ((b32) * (c32))) +#undef silk_SMLABB_ovflw +#define silk_SMLABB_ovflw(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32))) + +/* no checking needed for silk_SMULL + no checking needed for silk_SMLAL + no checking needed for silk_SMLALBB + no checking needed for SigProcFIX_CLZ16 + no checking needed for SigProcFIX_CLZ32*/ + +#undef silk_DIV32 +#define silk_DIV32(a,b) silk_DIV32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_DIV32_(opus_int32 a32, opus_int32 b32, char *file, int line){ + if ( b32 == 0 ) + { + fprintf (stderr, "silk_DIV32(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a32 / b32; +} + +#undef silk_DIV32_16 +#define silk_DIV32_16(a,b) silk_DIV32_16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_DIV32_16_(opus_int32 a32, opus_int32 b32, char *file, int line){ + int fail = 0; + fail |= b32 == 0; + fail |= b32 > silk_int16_MAX; + fail |= b32 < silk_int16_MIN; + if ( fail ) + { + fprintf (stderr, "silk_DIV32_16(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a32 / b32; +} + +/* no checking needed for silk_SAT8 + no checking needed for silk_SAT16 + no checking needed for silk_SAT32 + no checking needed for silk_POS_SAT32 + no checking needed for silk_ADD_POS_SAT8 + no checking needed for silk_ADD_POS_SAT16 + no checking needed for silk_ADD_POS_SAT32 */ + +#undef silk_LSHIFT8 +#define silk_LSHIFT8(a,b) silk_LSHIFT8_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int8 silk_LSHIFT8_(opus_int8 a, opus_int32 shift, char *file, int line){ + opus_int8 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 8; + fail |= (opus_int64)ret != ((opus_int64)a) << shift; + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT8(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT16 +#define silk_LSHIFT16(a,b) silk_LSHIFT16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_LSHIFT16_(opus_int16 a, opus_int32 shift, char *file, int line){ + opus_int16 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 16; + fail |= (opus_int64)ret != ((opus_int64)a) << shift; + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT16(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT32 +#define silk_LSHIFT32(a,b) silk_LSHIFT32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_LSHIFT32_(opus_int32 a, opus_int32 shift, char *file, int line){ + opus_int32 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 32; + fail |= (opus_int64)ret != ((opus_int64)a) << shift; + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT32(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT64 +#define silk_LSHIFT64(a,b) silk_LSHIFT64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_LSHIFT64_(opus_int64 a, opus_int shift, char *file, int line){ + opus_int64 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 64; + fail |= (ret>>shift) != ((opus_int64)a); + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT_ovflw +#define silk_LSHIFT_ovflw(a,b) silk_LSHIFT_ovflw_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_LSHIFT_ovflw_(opus_int32 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift >= 32) ) /* no check for overflow */ + { + fprintf (stderr, "silk_LSHIFT_ovflw(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a << shift; +} + +#undef silk_LSHIFT_uint +#define silk_LSHIFT_uint(a,b) silk_LSHIFT_uint_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_LSHIFT_uint_(opus_uint32 a, opus_int32 shift, char *file, int line){ + opus_uint32 ret; + ret = a << shift; + if ( (shift < 0) || ((opus_int64)ret != ((opus_int64)a) << shift)) + { + fprintf (stderr, "silk_LSHIFT_uint(%u, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_RSHIFT8 +#define silk_RSHITF8(a,b) silk_RSHIFT8_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int8 silk_RSHIFT8_(opus_int8 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>=8) ) + { + fprintf (stderr, "silk_RSHITF8(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT16 +#define silk_RSHITF16(a,b) silk_RSHIFT16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_RSHIFT16_(opus_int16 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>=16) ) + { + fprintf (stderr, "silk_RSHITF16(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT32 +#define silk_RSHIFT32(a,b) silk_RSHIFT32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_RSHIFT32_(opus_int32 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>=32) ) + { + fprintf (stderr, "silk_RSHITF32(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT64 +#define silk_RSHIFT64(a,b) silk_RSHIFT64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_RSHIFT64_(opus_int64 a, opus_int64 shift, char *file, int line){ + if ( (shift < 0) || (shift>=64) ) + { + fprintf (stderr, "silk_RSHITF64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT_uint +#define silk_RSHIFT_uint(a,b) silk_RSHIFT_uint_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_RSHIFT_uint_(opus_uint32 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>32) ) + { + fprintf (stderr, "silk_RSHIFT_uint(%u, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_ADD_LSHIFT +#define silk_ADD_LSHIFT(a,b,c) silk_ADD_LSHIFT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE int silk_ADD_LSHIFT_(int a, int b, int shift, char *file, int line){ + opus_int16 ret; + ret = a + (b << shift); + if ( (shift < 0) || (shift>15) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_ADD_LSHIFT(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_LSHIFT32 +#define silk_ADD_LSHIFT32(a,b,c) silk_ADD_LSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_ADD_LSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a + (b << shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_ADD_LSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_LSHIFT_uint +#define silk_ADD_LSHIFT_uint(a,b,c) silk_ADD_LSHIFT_uint_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_ADD_LSHIFT_uint_(opus_uint32 a, opus_uint32 b, opus_int32 shift, char *file, int line){ + opus_uint32 ret; + ret = a + (b << shift); + if ( (shift < 0) || (shift>32) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_ADD_LSHIFT_uint(%u, %u, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_RSHIFT +#define silk_ADD_RSHIFT(a,b,c) silk_ADD_RSHIFT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE int silk_ADD_RSHIFT_(int a, int b, int shift, char *file, int line){ + opus_int16 ret; + ret = a + (b >> shift); + if ( (shift < 0) || (shift>15) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_ADD_RSHIFT(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_ADD_RSHIFT32 +#define silk_ADD_RSHIFT32(a,b,c) silk_ADD_RSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_ADD_RSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a + (b >> shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_ADD_RSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_ADD_RSHIFT_uint +#define silk_ADD_RSHIFT_uint(a,b,c) silk_ADD_RSHIFT_uint_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_ADD_RSHIFT_uint_(opus_uint32 a, opus_uint32 b, opus_int32 shift, char *file, int line){ + opus_uint32 ret; + ret = a + (b >> shift); + if ( (shift < 0) || (shift>32) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_ADD_RSHIFT_uint(%u, %u, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_SUB_LSHIFT32 +#define silk_SUB_LSHIFT32(a,b,c) silk_SUB_LSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SUB_LSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a - (b << shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a - (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_SUB_LSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_SUB_RSHIFT32 +#define silk_SUB_RSHIFT32(a,b,c) silk_SUB_RSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SUB_RSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a - (b >> shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a - (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_SUB_RSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_RSHIFT_ROUND +#define silk_RSHIFT_ROUND(a,b) silk_RSHIFT_ROUND_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_RSHIFT_ROUND_(opus_int32 a, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + /* the marco definition can't handle a shift of zero */ + if ( (shift <= 0) || (shift>31) || ((opus_int64)ret != ((opus_int64)a + ((opus_int64)1 << (shift - 1))) >> shift) ) + { + fprintf (stderr, "silk_RSHIFT_ROUND(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_RSHIFT_ROUND64 +#define silk_RSHIFT_ROUND64(a,b) silk_RSHIFT_ROUND64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_RSHIFT_ROUND64_(opus_int64 a, opus_int32 shift, char *file, int line){ + opus_int64 ret; + /* the marco definition can't handle a shift of zero */ + if ( (shift <= 0) || (shift>=64) ) + { + fprintf (stderr, "silk_RSHIFT_ROUND64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +/* silk_abs is used on floats also, so doesn't work... */ +/*#undef silk_abs +static OPUS_INLINE opus_int32 silk_abs(opus_int32 a){ + silk_assert(a != 0x80000000); + return (((a) > 0) ? (a) : -(a)); // Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN +}*/ + +#undef silk_abs_int64 +#define silk_abs_int64(a) silk_abs_int64_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_abs_int64_(opus_int64 a, char *file, int line){ + if ( a == silk_int64_MIN ) + { + fprintf (stderr, "silk_abs_int64(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return (((a) > 0) ? (a) : -(a)); /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */ +} + +#undef silk_abs_int32 +#define silk_abs_int32(a) silk_abs_int32_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_abs_int32_(opus_int32 a, char *file, int line){ + if ( a == silk_int32_MIN ) + { + fprintf (stderr, "silk_abs_int32(%d) in %s: line %d\n", a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return silk_abs(a); +} + +#undef silk_CHECK_FIT8 +#define silk_CHECK_FIT8(a) silk_CHECK_FIT8_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int8 silk_CHECK_FIT8_( opus_int64 a, char *file, int line ){ + opus_int8 ret; + ret = (opus_int8)a; + if ( (opus_int64)ret != a ) + { + fprintf (stderr, "silk_CHECK_FIT8(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return( ret ); +} + +#undef silk_CHECK_FIT16 +#define silk_CHECK_FIT16(a) silk_CHECK_FIT16_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_CHECK_FIT16_( opus_int64 a, char *file, int line ){ + opus_int16 ret; + ret = (opus_int16)a; + if ( (opus_int64)ret != a ) + { + fprintf (stderr, "silk_CHECK_FIT16(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return( ret ); +} + +#undef silk_CHECK_FIT32 +#define silk_CHECK_FIT32(a) silk_CHECK_FIT32_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_CHECK_FIT32_( opus_int64 a, char *file, int line ){ + opus_int32 ret; + ret = (opus_int32)a; + if ( (opus_int64)ret != a ) + { + fprintf (stderr, "silk_CHECK_FIT32(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return( ret ); +} + +/* no checking for silk_NSHIFT_MUL_32_32 + no checking for silk_NSHIFT_MUL_16_16 + no checking needed for silk_min + no checking needed for silk_max + no checking needed for silk_sign +*/ + +#endif +#endif /* MACRO_DEBUG_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF2A.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF2A.c new file mode 100644 index 000000000..d5b773063 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF2A.c @@ -0,0 +1,141 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* conversion between prediction filter coefficients and LSFs */ +/* order should be even */ +/* a piecewise linear approximation maps LSF <-> cos(LSF) */ +/* therefore the result is not accurate LSFs, but the two */ +/* functions are accurate inverses of each other */ + +#include "SigProc_FIX.h" +#include "tables.h" + +#define QA 16 + +/* helper function for NLSF2A(..) */ +static OPUS_INLINE void silk_NLSF2A_find_poly( + opus_int32 *out, /* O intermediate polynomial, QA [dd+1] */ + const opus_int32 *cLSF, /* I vector of interleaved 2*cos(LSFs), QA [d] */ + opus_int dd /* I polynomial order (= 1/2 * filter order) */ +) +{ + opus_int k, n; + opus_int32 ftmp; + + out[0] = silk_LSHIFT( 1, QA ); + out[1] = -cLSF[0]; + for( k = 1; k < dd; k++ ) { + ftmp = cLSF[2*k]; /* QA*/ + out[k+1] = silk_LSHIFT( out[k-1], 1 ) - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[k] ), QA ); + for( n = k; n > 1; n-- ) { + out[n] += out[n-2] - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[n-1] ), QA ); + } + out[1] -= ftmp; + } +} + +/* compute whitening filter coefficients from normalized line spectral frequencies */ +void silk_NLSF2A( + opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */ + const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */ + const opus_int d, /* I filter order (should be even) */ + int arch /* I Run-time architecture */ +) +{ + /* This ordering was found to maximize quality. It improves numerical accuracy of + silk_NLSF2A_find_poly() compared to "standard" ordering. */ + static const unsigned char ordering16[16] = { + 0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1 + }; + static const unsigned char ordering10[10] = { + 0, 9, 6, 3, 4, 5, 8, 1, 2, 7 + }; + const unsigned char *ordering; + opus_int k, i, dd; + opus_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta; + opus_int32 a32_QA1[ SILK_MAX_ORDER_LPC ]; + + silk_assert( LSF_COS_TAB_SZ_FIX == 128 ); + celt_assert( d==10 || d==16 ); + + /* convert LSFs to 2*cos(LSF), using piecewise linear curve from table */ + ordering = d == 16 ? ordering16 : ordering10; + for( k = 0; k < d; k++ ) { + silk_assert( NLSF[k] >= 0 ); + + /* f_int on a scale 0-127 (rounded down) */ + f_int = silk_RSHIFT( NLSF[k], 15 - 7 ); + + /* f_frac, range: 0..255 */ + f_frac = NLSF[k] - silk_LSHIFT( f_int, 15 - 7 ); + + silk_assert(f_int >= 0); + silk_assert(f_int < LSF_COS_TAB_SZ_FIX ); + + /* Read start and end value from table */ + cos_val = silk_LSFCosTab_FIX_Q12[ f_int ]; /* Q12 */ + delta = silk_LSFCosTab_FIX_Q12[ f_int + 1 ] - cos_val; /* Q12, with a range of 0..200 */ + + /* Linear interpolation */ + cos_LSF_QA[ordering[k]] = silk_RSHIFT_ROUND( silk_LSHIFT( cos_val, 8 ) + silk_MUL( delta, f_frac ), 20 - QA ); /* QA */ + } + + dd = silk_RSHIFT( d, 1 ); + + /* generate even and odd polynomials using convolution */ + silk_NLSF2A_find_poly( P, &cos_LSF_QA[ 0 ], dd ); + silk_NLSF2A_find_poly( Q, &cos_LSF_QA[ 1 ], dd ); + + /* convert even and odd polynomials to opus_int32 Q12 filter coefs */ + for( k = 0; k < dd; k++ ) { + Ptmp = P[ k+1 ] + P[ k ]; + Qtmp = Q[ k+1 ] - Q[ k ]; + + /* the Ptmp and Qtmp values at this stage need to fit in int32 */ + a32_QA1[ k ] = -Qtmp - Ptmp; /* QA+1 */ + a32_QA1[ d-k-1 ] = Qtmp - Ptmp; /* QA+1 */ + } + + /* Convert int32 coefficients to Q12 int16 coefs */ + silk_LPC_fit( a_Q12, a32_QA1, 12, QA + 1, d ); + + for( i = 0; silk_LPC_inverse_pred_gain( a_Q12, d, arch ) == 0 && i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) { + /* Prediction coefficients are (too close to) unstable; apply bandwidth expansion */ + /* on the unscaled coefficients, convert to Q12 and measure again */ + silk_bwexpander_32( a32_QA1, d, 65536 - silk_LSHIFT( 2, i ) ); + for( k = 0; k < d; k++ ) { + a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */ + } + } +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_VQ.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_VQ.c new file mode 100644 index 000000000..b83182a79 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_VQ.c @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */ +void silk_NLSF_VQ( + opus_int32 err_Q24[], /* O Quantization errors [K] */ + const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */ + const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */ + const opus_int16 pWght_Q9[], /* I Codebook weights [K*LPC_order] */ + const opus_int K, /* I Number of codebook vectors */ + const opus_int LPC_order /* I Number of LPCs */ +) +{ + opus_int i, m; + opus_int32 diff_Q15, diffw_Q24, sum_error_Q24, pred_Q24; + const opus_int16 *w_Q9_ptr; + const opus_uint8 *cb_Q8_ptr; + + celt_assert( ( LPC_order & 1 ) == 0 ); + + /* Loop over codebook */ + cb_Q8_ptr = pCB_Q8; + w_Q9_ptr = pWght_Q9; + for( i = 0; i < K; i++ ) { + sum_error_Q24 = 0; + pred_Q24 = 0; + for( m = LPC_order-2; m >= 0; m -= 2 ) { + /* Compute weighted absolute predictive quantization error for index m + 1 */ + diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m + 1 ], (opus_int32)cb_Q8_ptr[ m + 1 ], 7 ); /* range: [ -32767 : 32767 ]*/ + diffw_Q24 = silk_SMULBB( diff_Q15, w_Q9_ptr[ m + 1 ] ); + sum_error_Q24 = silk_ADD32( sum_error_Q24, silk_abs( silk_SUB_RSHIFT32( diffw_Q24, pred_Q24, 1 ) ) ); + pred_Q24 = diffw_Q24; + + /* Compute weighted absolute predictive quantization error for index m */ + diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m ], (opus_int32)cb_Q8_ptr[ m ], 7 ); /* range: [ -32767 : 32767 ]*/ + diffw_Q24 = silk_SMULBB( diff_Q15, w_Q9_ptr[ m ] ); + sum_error_Q24 = silk_ADD32( sum_error_Q24, silk_abs( silk_SUB_RSHIFT32( diffw_Q24, pred_Q24, 1 ) ) ); + pred_Q24 = diffw_Q24; + + silk_assert( sum_error_Q24 >= 0 ); + } + err_Q24[ i ] = sum_error_Q24; + cb_Q8_ptr += LPC_order; + w_Q9_ptr += LPC_order; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_VQ_weights_laroia.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_VQ_weights_laroia.c new file mode 100644 index 000000000..9873bcde1 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_VQ_weights_laroia.c @@ -0,0 +1,80 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "define.h" +#include "SigProc_FIX.h" + +/* +R. Laroia, N. Phamdo and N. Farvardin, "Robust and Efficient Quantization of Speech LSP +Parameters Using Structured Vector Quantization", Proc. IEEE Int. Conf. Acoust., Speech, +Signal Processing, pp. 641-644, 1991. +*/ + +/* Laroia low complexity NLSF weights */ +void silk_NLSF_VQ_weights_laroia( + opus_int16 *pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */ + const opus_int16 *pNLSF_Q15, /* I Pointer to input vector [D] */ + const opus_int D /* I Input vector dimension (even) */ +) +{ + opus_int k; + opus_int32 tmp1_int, tmp2_int; + + celt_assert( D > 0 ); + celt_assert( ( D & 1 ) == 0 ); + + /* First value */ + tmp1_int = silk_max_int( pNLSF_Q15[ 0 ], 1 ); + tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int ); + tmp2_int = silk_max_int( pNLSF_Q15[ 1 ] - pNLSF_Q15[ 0 ], 1 ); + tmp2_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp2_int ); + pNLSFW_Q_OUT[ 0 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ 0 ] > 0 ); + + /* Main loop */ + for( k = 1; k < D - 1; k += 2 ) { + tmp1_int = silk_max_int( pNLSF_Q15[ k + 1 ] - pNLSF_Q15[ k ], 1 ); + tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int ); + pNLSFW_Q_OUT[ k ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ k ] > 0 ); + + tmp2_int = silk_max_int( pNLSF_Q15[ k + 2 ] - pNLSF_Q15[ k + 1 ], 1 ); + tmp2_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp2_int ); + pNLSFW_Q_OUT[ k + 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ k + 1 ] > 0 ); + } + + /* Last value */ + tmp1_int = silk_max_int( ( 1 << 15 ) - pNLSF_Q15[ D - 1 ], 1 ); + tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int ); + pNLSFW_Q_OUT[ D - 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ D - 1 ] > 0 ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_decode.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_decode.c new file mode 100644 index 000000000..eeb0ba8c9 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_decode.c @@ -0,0 +1,93 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Predictive dequantizer for NLSF residuals */ +static OPUS_INLINE void silk_NLSF_residual_dequant( /* O Returns RD value in Q30 */ + opus_int16 x_Q10[], /* O Output [ order ] */ + const opus_int8 indices[], /* I Quantization indices [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 order /* I Number of input values */ +) +{ + opus_int i, out_Q10, pred_Q10; + + out_Q10 = 0; + for( i = order-1; i >= 0; i-- ) { + pred_Q10 = silk_RSHIFT( silk_SMULBB( out_Q10, (opus_int16)pred_coef_Q8[ i ] ), 8 ); + out_Q10 = silk_LSHIFT( indices[ i ], 10 ); + if( out_Q10 > 0 ) { + out_Q10 = silk_SUB16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( out_Q10 < 0 ) { + out_Q10 = silk_ADD16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } + out_Q10 = silk_SMLAWB( pred_Q10, (opus_int32)out_Q10, quant_step_size_Q16 ); + x_Q10[ i ] = out_Q10; + } +} + + +/***********************/ +/* NLSF vector decoder */ +/***********************/ +void silk_NLSF_decode( + opus_int16 *pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + const silk_NLSF_CB_struct *psNLSF_CB /* I Codebook object */ +) +{ + opus_int i; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_int16 res_Q10[ MAX_LPC_ORDER ]; + opus_int32 NLSF_Q15_tmp; + const opus_uint8 *pCB_element; + const opus_int16 *pCB_Wght_Q9; + + /* Unpack entropy table indices and predictor for current CB1 index */ + silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, NLSFIndices[ 0 ] ); + + /* Predictive residual dequantizer */ + silk_NLSF_residual_dequant( res_Q10, &NLSFIndices[ 1 ], pred_Q8, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->order ); + + /* Apply inverse square-rooted weights to first stage and add to output */ + pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ NLSFIndices[ 0 ] * psNLSF_CB->order ]; + pCB_Wght_Q9 = &psNLSF_CB->CB1_Wght_Q9[ NLSFIndices[ 0 ] * psNLSF_CB->order ]; + for( i = 0; i < psNLSF_CB->order; i++ ) { + NLSF_Q15_tmp = silk_ADD_LSHIFT32( silk_DIV32_16( silk_LSHIFT( (opus_int32)res_Q10[ i ], 14 ), pCB_Wght_Q9[ i ] ), (opus_int16)pCB_element[ i ], 7 ); + pNLSF_Q15[ i ] = (opus_int16)silk_LIMIT( NLSF_Q15_tmp, 0, 32767 ); + } + + /* NLSF stabilization */ + silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_del_dec_quant.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_del_dec_quant.c new file mode 100644 index 000000000..44a16acd0 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_del_dec_quant.c @@ -0,0 +1,215 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Delayed-decision quantizer for NLSF residuals */ +opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */ + opus_int8 indices[], /* O Quantization indices [ order ] */ + const opus_int16 x_Q10[], /* I Input [ order ] */ + const opus_int16 w_Q5[], /* I Weights [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */ + const opus_uint8 ec_rates_Q5[], /* I Rates [] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */ + const opus_int32 mu_Q20, /* I R/D tradeoff */ + const opus_int16 order /* I Number of input values */ +) +{ + opus_int i, j, nStates, ind_tmp, ind_min_max, ind_max_min, in_Q10, res_Q10; + opus_int pred_Q10, diff_Q10, rate0_Q5, rate1_Q5; + opus_int16 out0_Q10, out1_Q10; + opus_int32 RD_tmp_Q25, min_Q25, min_max_Q25, max_min_Q25; + opus_int ind_sort[ NLSF_QUANT_DEL_DEC_STATES ]; + opus_int8 ind[ NLSF_QUANT_DEL_DEC_STATES ][ MAX_LPC_ORDER ]; + opus_int16 prev_out_Q10[ 2 * NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_Q25[ 2 * NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_min_Q25[ NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_max_Q25[ NLSF_QUANT_DEL_DEC_STATES ]; + const opus_uint8 *rates_Q5; + + opus_int out0_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT]; + opus_int out1_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT]; + + for (i = -NLSF_QUANT_MAX_AMPLITUDE_EXT; i <= NLSF_QUANT_MAX_AMPLITUDE_EXT-1; i++) + { + out0_Q10 = silk_LSHIFT( i, 10 ); + out1_Q10 = silk_ADD16( out0_Q10, 1024 ); + if( i > 0 ) { + out0_Q10 = silk_SUB16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( i == 0 ) { + out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( i == -1 ) { + out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else { + out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + out1_Q10 = silk_ADD16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } + out0_Q10_table[ i + NLSF_QUANT_MAX_AMPLITUDE_EXT ] = silk_RSHIFT( silk_SMULBB( out0_Q10, quant_step_size_Q16 ), 16 ); + out1_Q10_table[ i + NLSF_QUANT_MAX_AMPLITUDE_EXT ] = silk_RSHIFT( silk_SMULBB( out1_Q10, quant_step_size_Q16 ), 16 ); + } + + silk_assert( (NLSF_QUANT_DEL_DEC_STATES & (NLSF_QUANT_DEL_DEC_STATES-1)) == 0 ); /* must be power of two */ + + nStates = 1; + RD_Q25[ 0 ] = 0; + prev_out_Q10[ 0 ] = 0; + for( i = order - 1; i >= 0; i-- ) { + rates_Q5 = &ec_rates_Q5[ ec_ix[ i ] ]; + in_Q10 = x_Q10[ i ]; + for( j = 0; j < nStates; j++ ) { + pred_Q10 = silk_RSHIFT( silk_SMULBB( (opus_int16)pred_coef_Q8[ i ], prev_out_Q10[ j ] ), 8 ); + res_Q10 = silk_SUB16( in_Q10, pred_Q10 ); + ind_tmp = silk_RSHIFT( silk_SMULBB( inv_quant_step_size_Q6, res_Q10 ), 16 ); + ind_tmp = silk_LIMIT( ind_tmp, -NLSF_QUANT_MAX_AMPLITUDE_EXT, NLSF_QUANT_MAX_AMPLITUDE_EXT-1 ); + ind[ j ][ i ] = (opus_int8)ind_tmp; + + /* compute outputs for ind_tmp and ind_tmp + 1 */ + out0_Q10 = out0_Q10_table[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT ]; + out1_Q10 = out1_Q10_table[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT ]; + + out0_Q10 = silk_ADD16( out0_Q10, pred_Q10 ); + out1_Q10 = silk_ADD16( out1_Q10, pred_Q10 ); + prev_out_Q10[ j ] = out0_Q10; + prev_out_Q10[ j + nStates ] = out1_Q10; + + /* compute RD for ind_tmp and ind_tmp + 1 */ + if( ind_tmp + 1 >= NLSF_QUANT_MAX_AMPLITUDE ) { + if( ind_tmp + 1 == NLSF_QUANT_MAX_AMPLITUDE ) { + rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ]; + rate1_Q5 = 280; + } else { + rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, 43, ind_tmp ); + rate1_Q5 = silk_ADD16( rate0_Q5, 43 ); + } + } else if( ind_tmp <= -NLSF_QUANT_MAX_AMPLITUDE ) { + if( ind_tmp == -NLSF_QUANT_MAX_AMPLITUDE ) { + rate0_Q5 = 280; + rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ]; + } else { + rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, -43, ind_tmp ); + rate1_Q5 = silk_SUB16( rate0_Q5, 43 ); + } + } else { + rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ]; + rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ]; + } + RD_tmp_Q25 = RD_Q25[ j ]; + diff_Q10 = silk_SUB16( in_Q10, out0_Q10 ); + RD_Q25[ j ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate0_Q5 ); + diff_Q10 = silk_SUB16( in_Q10, out1_Q10 ); + RD_Q25[ j + nStates ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate1_Q5 ); + } + + if( nStates <= NLSF_QUANT_DEL_DEC_STATES/2 ) { + /* double number of states and copy */ + for( j = 0; j < nStates; j++ ) { + ind[ j + nStates ][ i ] = ind[ j ][ i ] + 1; + } + nStates = silk_LSHIFT( nStates, 1 ); + for( j = nStates; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + ind[ j ][ i ] = ind[ j - nStates ][ i ]; + } + } else { + /* sort lower and upper half of RD_Q25, pairwise */ + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( RD_Q25[ j ] > RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] ) { + RD_max_Q25[ j ] = RD_Q25[ j ]; + RD_min_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ]; + RD_Q25[ j ] = RD_min_Q25[ j ]; + RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] = RD_max_Q25[ j ]; + /* swap prev_out values */ + out0_Q10 = prev_out_Q10[ j ]; + prev_out_Q10[ j ] = prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ]; + prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ] = out0_Q10; + ind_sort[ j ] = j + NLSF_QUANT_DEL_DEC_STATES; + } else { + RD_min_Q25[ j ] = RD_Q25[ j ]; + RD_max_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ]; + ind_sort[ j ] = j; + } + } + /* compare the highest RD values of the winning half with the lowest one in the losing half, and copy if necessary */ + /* afterwards ind_sort[] will contain the indices of the NLSF_QUANT_DEL_DEC_STATES winning RD values */ + while( 1 ) { + min_max_Q25 = silk_int32_MAX; + max_min_Q25 = 0; + ind_min_max = 0; + ind_max_min = 0; + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( min_max_Q25 > RD_max_Q25[ j ] ) { + min_max_Q25 = RD_max_Q25[ j ]; + ind_min_max = j; + } + if( max_min_Q25 < RD_min_Q25[ j ] ) { + max_min_Q25 = RD_min_Q25[ j ]; + ind_max_min = j; + } + } + if( min_max_Q25 >= max_min_Q25 ) { + break; + } + /* copy ind_min_max to ind_max_min */ + ind_sort[ ind_max_min ] = ind_sort[ ind_min_max ] ^ NLSF_QUANT_DEL_DEC_STATES; + RD_Q25[ ind_max_min ] = RD_Q25[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ]; + prev_out_Q10[ ind_max_min ] = prev_out_Q10[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ]; + RD_min_Q25[ ind_max_min ] = 0; + RD_max_Q25[ ind_min_max ] = silk_int32_MAX; + silk_memcpy( ind[ ind_max_min ], ind[ ind_min_max ], MAX_LPC_ORDER * sizeof( opus_int8 ) ); + } + /* increment index if it comes from the upper half */ + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + ind[ j ][ i ] += silk_RSHIFT( ind_sort[ j ], NLSF_QUANT_DEL_DEC_STATES_LOG2 ); + } + } + } + + /* last sample: find winner, copy indices and return RD value */ + ind_tmp = 0; + min_Q25 = silk_int32_MAX; + for( j = 0; j < 2 * NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( min_Q25 > RD_Q25[ j ] ) { + min_Q25 = RD_Q25[ j ]; + ind_tmp = j; + } + } + for( j = 0; j < order; j++ ) { + indices[ j ] = ind[ ind_tmp & ( NLSF_QUANT_DEL_DEC_STATES - 1 ) ][ j ]; + silk_assert( indices[ j ] >= -NLSF_QUANT_MAX_AMPLITUDE_EXT ); + silk_assert( indices[ j ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT ); + } + indices[ 0 ] += silk_RSHIFT( ind_tmp, NLSF_QUANT_DEL_DEC_STATES_LOG2 ); + silk_assert( indices[ 0 ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT ); + silk_assert( min_Q25 >= 0 ); + return min_Q25; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_encode.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_encode.c new file mode 100644 index 000000000..01ac7db78 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_encode.c @@ -0,0 +1,124 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/***********************/ +/* NLSF vector encoder */ +/***********************/ +opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + opus_int16 *pNLSF_Q15, /* I/O (Un)quantized NLSF vector [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int16 *pW_Q2, /* I NLSF weight vector [ LPC_ORDER ] */ + const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */ + const opus_int nSurvivors, /* I Max survivors after first stage */ + const opus_int signalType /* I Signal type: 0/1/2 */ +) +{ + opus_int i, s, ind1, bestIndex, prob_Q8, bits_q7; + opus_int32 W_tmp_Q9, ret; + VARDECL( opus_int32, err_Q24 ); + VARDECL( opus_int32, RD_Q25 ); + VARDECL( opus_int, tempIndices1 ); + VARDECL( opus_int8, tempIndices2 ); + opus_int16 res_Q10[ MAX_LPC_ORDER ]; + opus_int16 NLSF_tmp_Q15[ MAX_LPC_ORDER ]; + opus_int16 W_adj_Q5[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + const opus_uint8 *pCB_element, *iCDF_ptr; + const opus_int16 *pCB_Wght_Q9; + SAVE_STACK; + + celt_assert( signalType >= 0 && signalType <= 2 ); + silk_assert( NLSF_mu_Q20 <= 32767 && NLSF_mu_Q20 >= 0 ); + + /* NLSF stabilization */ + silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order ); + + /* First stage: VQ */ + ALLOC( err_Q24, psNLSF_CB->nVectors, opus_int32 ); + silk_NLSF_VQ( err_Q24, pNLSF_Q15, psNLSF_CB->CB1_NLSF_Q8, psNLSF_CB->CB1_Wght_Q9, psNLSF_CB->nVectors, psNLSF_CB->order ); + + /* Sort the quantization errors */ + ALLOC( tempIndices1, nSurvivors, opus_int ); + silk_insertion_sort_increasing( err_Q24, tempIndices1, psNLSF_CB->nVectors, nSurvivors ); + + ALLOC( RD_Q25, nSurvivors, opus_int32 ); + ALLOC( tempIndices2, nSurvivors * MAX_LPC_ORDER, opus_int8 ); + + /* Loop over survivors */ + for( s = 0; s < nSurvivors; s++ ) { + ind1 = tempIndices1[ s ]; + + /* Residual after first stage */ + pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ ind1 * psNLSF_CB->order ]; + pCB_Wght_Q9 = &psNLSF_CB->CB1_Wght_Q9[ ind1 * psNLSF_CB->order ]; + for( i = 0; i < psNLSF_CB->order; i++ ) { + NLSF_tmp_Q15[ i ] = silk_LSHIFT16( (opus_int16)pCB_element[ i ], 7 ); + W_tmp_Q9 = pCB_Wght_Q9[ i ]; + res_Q10[ i ] = (opus_int16)silk_RSHIFT( silk_SMULBB( pNLSF_Q15[ i ] - NLSF_tmp_Q15[ i ], W_tmp_Q9 ), 14 ); + W_adj_Q5[ i ] = silk_DIV32_varQ( (opus_int32)pW_Q2[ i ], silk_SMULBB( W_tmp_Q9, W_tmp_Q9 ), 21 ); + } + + /* Unpack entropy table indices and predictor for current CB1 index */ + silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, ind1 ); + + /* Trellis quantizer */ + RD_Q25[ s ] = silk_NLSF_del_dec_quant( &tempIndices2[ s * MAX_LPC_ORDER ], res_Q10, W_adj_Q5, pred_Q8, ec_ix, + psNLSF_CB->ec_Rates_Q5, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->invQuantStepSize_Q6, NLSF_mu_Q20, psNLSF_CB->order ); + + /* Add rate for first stage */ + iCDF_ptr = &psNLSF_CB->CB1_iCDF[ ( signalType >> 1 ) * psNLSF_CB->nVectors ]; + if( ind1 == 0 ) { + prob_Q8 = 256 - iCDF_ptr[ ind1 ]; + } else { + prob_Q8 = iCDF_ptr[ ind1 - 1 ] - iCDF_ptr[ ind1 ]; + } + bits_q7 = ( 8 << 7 ) - silk_lin2log( prob_Q8 ); + RD_Q25[ s ] = silk_SMLABB( RD_Q25[ s ], bits_q7, silk_RSHIFT( NLSF_mu_Q20, 2 ) ); + } + + /* Find the lowest rate-distortion error */ + silk_insertion_sort_increasing( RD_Q25, &bestIndex, nSurvivors, 1 ); + + NLSFIndices[ 0 ] = (opus_int8)tempIndices1[ bestIndex ]; + silk_memcpy( &NLSFIndices[ 1 ], &tempIndices2[ bestIndex * MAX_LPC_ORDER ], psNLSF_CB->order * sizeof( opus_int8 ) ); + + /* Decode */ + silk_NLSF_decode( pNLSF_Q15, NLSFIndices, psNLSF_CB ); + + ret = RD_Q25[ 0 ]; + RESTORE_STACK; + return ret; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_stabilize.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_stabilize.c new file mode 100644 index 000000000..8f3426b91 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_stabilize.c @@ -0,0 +1,142 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* NLSF stabilizer: */ +/* */ +/* - Moves NLSFs further apart if they are too close */ +/* - Moves NLSFs away from borders if they are too close */ +/* - High effort to achieve a modification with minimum */ +/* Euclidean distance to input vector */ +/* - Output are sorted NLSF coefficients */ +/* */ + +#include "SigProc_FIX.h" + +/* Constant Definitions */ +#define MAX_LOOPS 20 + +/* NLSF stabilizer, for a single input data vector */ +void silk_NLSF_stabilize( + opus_int16 *NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */ + const opus_int16 *NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const opus_int L /* I Number of NLSF parameters in the input vector */ +) +{ + opus_int i, I=0, k, loops; + opus_int16 center_freq_Q15; + opus_int32 diff_Q15, min_diff_Q15, min_center_Q15, max_center_Q15; + + /* This is necessary to ensure an output within range of a opus_int16 */ + silk_assert( NDeltaMin_Q15[L] >= 1 ); + + for( loops = 0; loops < MAX_LOOPS; loops++ ) { + /**************************/ + /* Find smallest distance */ + /**************************/ + /* First element */ + min_diff_Q15 = NLSF_Q15[0] - NDeltaMin_Q15[0]; + I = 0; + /* Middle elements */ + for( i = 1; i <= L-1; i++ ) { + diff_Q15 = NLSF_Q15[i] - ( NLSF_Q15[i-1] + NDeltaMin_Q15[i] ); + if( diff_Q15 < min_diff_Q15 ) { + min_diff_Q15 = diff_Q15; + I = i; + } + } + /* Last element */ + diff_Q15 = ( 1 << 15 ) - ( NLSF_Q15[L-1] + NDeltaMin_Q15[L] ); + if( diff_Q15 < min_diff_Q15 ) { + min_diff_Q15 = diff_Q15; + I = L; + } + + /***************************************************/ + /* Now check if the smallest distance non-negative */ + /***************************************************/ + if( min_diff_Q15 >= 0 ) { + return; + } + + if( I == 0 ) { + /* Move away from lower limit */ + NLSF_Q15[0] = NDeltaMin_Q15[0]; + + } else if( I == L) { + /* Move away from higher limit */ + NLSF_Q15[L-1] = ( 1 << 15 ) - NDeltaMin_Q15[L]; + + } else { + /* Find the lower extreme for the location of the current center frequency */ + min_center_Q15 = 0; + for( k = 0; k < I; k++ ) { + min_center_Q15 += NDeltaMin_Q15[k]; + } + min_center_Q15 += silk_RSHIFT( NDeltaMin_Q15[I], 1 ); + + /* Find the upper extreme for the location of the current center frequency */ + max_center_Q15 = 1 << 15; + for( k = L; k > I; k-- ) { + max_center_Q15 -= NDeltaMin_Q15[k]; + } + max_center_Q15 -= silk_RSHIFT( NDeltaMin_Q15[I], 1 ); + + /* Move apart, sorted by value, keeping the same center frequency */ + center_freq_Q15 = (opus_int16)silk_LIMIT_32( silk_RSHIFT_ROUND( (opus_int32)NLSF_Q15[I-1] + (opus_int32)NLSF_Q15[I], 1 ), + min_center_Q15, max_center_Q15 ); + NLSF_Q15[I-1] = center_freq_Q15 - silk_RSHIFT( NDeltaMin_Q15[I], 1 ); + NLSF_Q15[I] = NLSF_Q15[I-1] + NDeltaMin_Q15[I]; + } + } + + /* Safe and simple fall back method, which is less ideal than the above */ + if( loops == MAX_LOOPS ) + { + /* Insertion sort (fast for already almost sorted arrays): */ + /* Best case: O(n) for an already sorted array */ + /* Worst case: O(n^2) for an inversely sorted array */ + silk_insertion_sort_increasing_all_values_int16( &NLSF_Q15[0], L ); + + /* First NLSF should be no less than NDeltaMin[0] */ + NLSF_Q15[0] = silk_max_int( NLSF_Q15[0], NDeltaMin_Q15[0] ); + + /* Keep delta_min distance between the NLSFs */ + for( i = 1; i < L; i++ ) + NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], silk_ADD_SAT16( NLSF_Q15[i-1], NDeltaMin_Q15[i] ) ); + + /* Last NLSF should be no higher than 1 - NDeltaMin[L] */ + NLSF_Q15[L-1] = silk_min_int( NLSF_Q15[L-1], (1<<15) - NDeltaMin_Q15[L] ); + + /* Keep NDeltaMin distance between the NLSFs */ + for( i = L-2; i >= 0; i-- ) + NLSF_Q15[i] = silk_min_int( NLSF_Q15[i], NLSF_Q15[i+1] - NDeltaMin_Q15[i+1] ); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_unpack.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_unpack.c new file mode 100644 index 000000000..17bd23f75 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NLSF_unpack.c @@ -0,0 +1,55 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Unpack predictor values and indices for entropy coding tables */ +void silk_NLSF_unpack( + opus_int16 ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */ + opus_uint8 pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int CB1_index /* I Index of vector in first LSF codebook */ +) +{ + opus_int i; + opus_uint8 entry; + const opus_uint8 *ec_sel_ptr; + + ec_sel_ptr = &psNLSF_CB->ec_sel[ CB1_index * psNLSF_CB->order / 2 ]; + for( i = 0; i < psNLSF_CB->order; i += 2 ) { + entry = *ec_sel_ptr++; + ec_ix [ i ] = silk_SMULBB( silk_RSHIFT( entry, 1 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 ); + pred_Q8[ i ] = psNLSF_CB->pred_Q8[ i + ( entry & 1 ) * ( psNLSF_CB->order - 1 ) ]; + ec_ix [ i + 1 ] = silk_SMULBB( silk_RSHIFT( entry, 5 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 ); + pred_Q8[ i + 1 ] = psNLSF_CB->pred_Q8[ i + ( silk_RSHIFT( entry, 4 ) & 1 ) * ( psNLSF_CB->order - 1 ) + 1 ]; + } +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NSQ.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NSQ.c new file mode 100644 index 000000000..1d64d8e25 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NSQ.c @@ -0,0 +1,437 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" +#include "NSQ.h" + + +static OPUS_INLINE void silk_nsq_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int16 x16[], /* I input */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +); + +#if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +static OPUS_INLINE void silk_noise_shape_quantizer( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int shapingLPCOrder, /* I Noise shaping AR filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + int arch /* I Architecture */ +); +#endif + +void silk_NSQ_c +( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int k, lag, start_idx, LSF_interpolation_flag; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + SAVE_STACK; + + NSQ->rand_seed = psIndices->Seed; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + /* Set up pointers to start of sub frame */ + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->rewhite_flag = 1; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + } + } + + silk_nsq_scale_states( psEncC, NSQ, x16, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType ); + + silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14, + AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], Lambda_Q10, + offset_Q10, psEncC->subfr_length, psEncC->shapingLPCOrder, psEncC->predictLPCOrder, psEncC->arch ); + + x16 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Update lagPrev for next frame */ + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech and noise shaping signals */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; +} + +/***********************************/ +/* silk_noise_shape_quantizer */ +/***********************************/ + +#if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +static OPUS_INLINE +#endif +void silk_noise_shape_quantizer( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int shapingLPCOrder, /* I Noise shaping AR filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + int arch /* I Architecture */ +) +{ + opus_int i; + opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13; + opus_int32 n_LF_Q12, r_Q10, rr_Q10, q1_Q0, q1_Q10, q2_Q10, rd1_Q20, rd2_Q20; + opus_int32 exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr; +#ifdef silk_short_prediction_create_arch_coef + opus_int32 a_Q12_arch[MAX_LPC_ORDER]; +#endif + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + /* Set up short term AR state */ + psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ]; + +#ifdef silk_short_prediction_create_arch_coef + silk_short_prediction_create_arch_coef(a_Q12_arch, a_Q12, predictLPCOrder); +#endif + + for( i = 0; i < length; i++ ) { + /* Generate dither */ + NSQ->rand_seed = silk_RAND( NSQ->rand_seed ); + + /* Short-term prediction */ + LPC_pred_Q10 = silk_noise_shape_quantizer_short_prediction(psLPC_Q14, a_Q12, a_Q12_arch, predictLPCOrder, arch); + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q13 = 2; + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + pred_lag_ptr++; + } else { + LTP_pred_Q13 = 0; + } + + /* Noise shape feedback */ + celt_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + n_AR_Q12 = silk_NSQ_noise_shape_feedback_loop(&NSQ->sDiff_shp_Q14, NSQ->sAR2_Q14, AR_shp_Q13, shapingLPCOrder, arch); + + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sLF_AR_shp_Q14, Tilt_Q14 ); + + n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 ); + n_LF_Q12 = silk_SMLAWT( n_LF_Q12, NSQ->sLF_AR_shp_Q14, LF_shp_Q14 ); + + celt_assert( lag > 0 || signalType != TYPE_VOICED ); + + /* Combine prediction and noise shaping signals */ + tmp1 = silk_SUB32( silk_LSHIFT32( LPC_pred_Q10, 2 ), n_AR_Q12 ); /* Q12 */ + tmp1 = silk_SUB32( tmp1, n_LF_Q12 ); /* Q12 */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q13 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_SMLAWT( n_LTP_Q13, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_LSHIFT( n_LTP_Q13, 1 ); + shp_lag_ptr++; + + tmp2 = silk_SUB32( LTP_pred_Q13, n_LTP_Q13 ); /* Q13 */ + tmp1 = silk_ADD_LSHIFT32( tmp2, tmp1, 1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 3 ); /* Q10 */ + } else { + tmp1 = silk_RSHIFT_ROUND( tmp1, 2 ); /* Q10 */ + } + + r_Q10 = silk_SUB32( x_sc_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if( NSQ->rand_seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if (Lambda_Q10 > 2048) { + /* For aggressive RDO, the bias becomes more than one pulse. */ + int rdo_offset = Lambda_Q10/2 - 512; + if (q1_Q10 > rdo_offset) { + q1_Q0 = silk_RSHIFT( q1_Q10 - rdo_offset, 10 ); + } else if (q1_Q10 < -rdo_offset) { + q1_Q0 = silk_RSHIFT( q1_Q10 + rdo_offset, 10 ); + } else if (q1_Q10 < 0) { + q1_Q0 = -1; + } else { + q1_Q0 = 0; + } + } + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* Q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q20 = silk_SMLABB( rd1_Q20, rr_Q10, rr_Q10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q20 = silk_SMLABB( rd2_Q20, rr_Q10, rr_Q10 ); + + if( rd2_Q20 < rd1_Q20 ) { + q1_Q10 = q2_Q10; + } + + pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 ); + + /* Excitation */ + exc_Q14 = silk_LSHIFT( q1_Q10, 4 ); + if ( NSQ->rand_seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD_LSHIFT32( exc_Q14, LTP_pred_Q13, 1 ); + xq_Q14 = silk_ADD_LSHIFT32( LPC_exc_Q14, LPC_pred_Q10, 4 ); + + /* Scale XQ back to normal level before saving */ + xq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( xq_Q14, Gain_Q10 ), 8 ) ); + + /* Update states */ + psLPC_Q14++; + *psLPC_Q14 = xq_Q14; + NSQ->sDiff_shp_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_sc_Q10[ i ], 4 ); + sLF_AR_shp_Q14 = silk_SUB_LSHIFT32( NSQ->sDiff_shp_Q14, n_AR_Q12, 2 ); + NSQ->sLF_AR_shp_Q14 = sLF_AR_shp_Q14; + + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx ] = silk_SUB_LSHIFT32( sLF_AR_shp_Q14, n_LF_Q12, 2 ); + sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q14, 1 ); + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Make dither dependent on quantized signal */ + NSQ->rand_seed = silk_ADD32_ovflw( NSQ->rand_seed, pulses[ i ] ); + } + + /* Update LPC synth buffer */ + silk_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); +} + +static OPUS_INLINE void silk_nsq_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int16 x16[], /* I input */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +) +{ + opus_int i, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Scale input */ + inv_gain_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 ); + for( i = 0; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x16[ i ], inv_gain_Q26 ); + } + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + + /* Scale long-term shaping state */ + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + NSQ->sLF_AR_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q14 ); + NSQ->sDiff_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sDiff_shp_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + NSQ->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + NSQ->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] ); + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NSQ.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NSQ.h new file mode 100644 index 000000000..971832f66 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NSQ.h @@ -0,0 +1,101 @@ +/*********************************************************************** +Copyright (c) 2014 Vidyo. +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ +#ifndef SILK_NSQ_H +#define SILK_NSQ_H + +#include "SigProc_FIX.h" + +#undef silk_short_prediction_create_arch_coef + +static OPUS_INLINE opus_int32 silk_noise_shape_quantizer_short_prediction_c(const opus_int32 *buf32, const opus_int16 *coef16, opus_int order) +{ + opus_int32 out; + silk_assert( order == 10 || order == 16 ); + + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + out = silk_RSHIFT( order, 1 ); + out = silk_SMLAWB( out, buf32[ 0 ], coef16[ 0 ] ); + out = silk_SMLAWB( out, buf32[ -1 ], coef16[ 1 ] ); + out = silk_SMLAWB( out, buf32[ -2 ], coef16[ 2 ] ); + out = silk_SMLAWB( out, buf32[ -3 ], coef16[ 3 ] ); + out = silk_SMLAWB( out, buf32[ -4 ], coef16[ 4 ] ); + out = silk_SMLAWB( out, buf32[ -5 ], coef16[ 5 ] ); + out = silk_SMLAWB( out, buf32[ -6 ], coef16[ 6 ] ); + out = silk_SMLAWB( out, buf32[ -7 ], coef16[ 7 ] ); + out = silk_SMLAWB( out, buf32[ -8 ], coef16[ 8 ] ); + out = silk_SMLAWB( out, buf32[ -9 ], coef16[ 9 ] ); + + if( order == 16 ) + { + out = silk_SMLAWB( out, buf32[ -10 ], coef16[ 10 ] ); + out = silk_SMLAWB( out, buf32[ -11 ], coef16[ 11 ] ); + out = silk_SMLAWB( out, buf32[ -12 ], coef16[ 12 ] ); + out = silk_SMLAWB( out, buf32[ -13 ], coef16[ 13 ] ); + out = silk_SMLAWB( out, buf32[ -14 ], coef16[ 14 ] ); + out = silk_SMLAWB( out, buf32[ -15 ], coef16[ 15 ] ); + } + return out; +} + +#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) ((void)arch,silk_noise_shape_quantizer_short_prediction_c(in, coef, order)) + +static OPUS_INLINE opus_int32 silk_NSQ_noise_shape_feedback_loop_c(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order) +{ + opus_int32 out; + opus_int32 tmp1, tmp2; + opus_int j; + + tmp2 = data0[0]; + tmp1 = data1[0]; + data1[0] = tmp2; + + out = silk_RSHIFT(order, 1); + out = silk_SMLAWB(out, tmp2, coef[0]); + + for (j = 2; j < order; j += 2) { + tmp2 = data1[j - 1]; + data1[j - 1] = tmp1; + out = silk_SMLAWB(out, tmp1, coef[j - 1]); + tmp1 = data1[j + 0]; + data1[j + 0] = tmp2; + out = silk_SMLAWB(out, tmp2, coef[j]); + } + data1[order - 1] = tmp1; + out = silk_SMLAWB(out, tmp1, coef[order - 1]); + /* Q11 -> Q12 */ + out = silk_LSHIFT32( out, 1 ); + return out; +} + +#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) ((void)arch,silk_NSQ_noise_shape_feedback_loop_c(data0, data1, coef, order)) + +#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +#include "arm/NSQ_neon.h" +#endif + +#endif /* SILK_NSQ_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NSQ_del_dec.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NSQ_del_dec.c new file mode 100644 index 000000000..00e749c3b --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/NSQ_del_dec.c @@ -0,0 +1,733 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" +#include "NSQ.h" + + +typedef struct { + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ]; + opus_int32 RandState[ DECISION_DELAY ]; + opus_int32 Q_Q10[ DECISION_DELAY ]; + opus_int32 Xq_Q14[ DECISION_DELAY ]; + opus_int32 Pred_Q15[ DECISION_DELAY ]; + opus_int32 Shape_Q14[ DECISION_DELAY ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_AR_Q14; + opus_int32 Diff_Q14; + opus_int32 Seed; + opus_int32 SeedInit; + opus_int32 RD_Q10; +} NSQ_del_dec_struct; + +typedef struct { + opus_int32 Q_Q10; + opus_int32 RD_Q10; + opus_int32 xq_Q14; + opus_int32 LF_AR_Q14; + opus_int32 Diff_Q14; + opus_int32 sLTP_shp_Q14; + opus_int32 LPC_exc_Q14; +} NSQ_sample_struct; + +typedef NSQ_sample_struct NSQ_sample_pair[ 2 ]; + +#if defined(MIPSr1_ASM) +#include "mips/NSQ_del_dec_mipsr1.h" +#endif +static OPUS_INLINE void silk_nsq_del_dec_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int16 x16[], /* I Input */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +); + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay, /* I */ + int arch /* I */ +); + +void silk_NSQ_del_dec_c( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr; + opus_int last_smple_idx, smpl_buf_idx, decisionDelay; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + opus_int32 RDmin_Q10, Gain_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + VARDECL( opus_int32, delayedGain_Q10 ); + VARDECL( NSQ_del_dec_struct, psDelDec ); + NSQ_del_dec_struct *psDD; + SAVE_STACK; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + /* Initialize delayed decision states */ + ALLOC( psDelDec, psEncC->nStatesDelayedDecision, NSQ_del_dec_struct ); + silk_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) ); + for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psDD->Seed = ( k + psIndices->Seed ) & 3; + psDD->SeedInit = psDD->Seed; + psDD->RD_Q10 = 0; + psDD->LF_AR_Q14 = NSQ->sLF_AR_shp_Q14; + psDD->Diff_Q14 = NSQ->sDiff_shp_Q14; + psDD->Shape_Q14[ 0 ] = NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ]; + silk_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) ); + } + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + smpl_buf_idx = 0; /* index of oldest samples */ + + decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length ); + + /* For voiced frames limit the decision delay to lower than the pitch lag */ + if( psIndices->signalType == TYPE_VOICED ) { + for( k = 0; k < psEncC->nb_subfr; k++ ) { + decisionDelay = silk_min_int( decisionDelay, pitchL[ k ] - LTP_ORDER / 2 - 1 ); + } + } else { + if( lag > 0 ) { + decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 ); + } + } + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 ); + /* Set up pointers to start of sub frame */ + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + subfr = 0; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + if( k == 2 ) { + /* RESET DELAYED DECISIONS */ + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) { + if( psDelDec[ i ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ i ].RD_Q10; + Winner_ind = i; + } + } + for( i = 0; i < psEncC->nStatesDelayedDecision; i++ ) { + if( i != Winner_ind ) { + psDelDec[ i ].RD_Q10 += ( silk_int32_MAX >> 4 ); + silk_assert( psDelDec[ i ].RD_Q10 >= 0 ); + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + last_smple_idx = smpl_buf_idx + decisionDelay; + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY; + if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY; + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gains_Q16[ 1 ] ), 14 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + + subfr = 0; + } + + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + NSQ->rewhite_flag = 1; + } + } + + silk_nsq_del_dec_scale_states( psEncC, NSQ, psDelDec, x16, x_sc_Q10, sLTP, sLTP_Q15, k, + psEncC->nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay ); + + silk_noise_shape_quantizer_del_dec( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, + delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], + Gains_Q16[ k ], Lambda_Q10, offset_Q10, psEncC->subfr_length, subfr++, psEncC->shapingLPCOrder, + psEncC->predictLPCOrder, psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay, psEncC->arch ); + + x16 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ k ].RD_Q10; + Winner_ind = k; + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + psIndices->Seed = psDD->SeedInit; + last_smple_idx = smpl_buf_idx + decisionDelay; + Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 ); + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY; + if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY; + + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gain_Q10 ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + silk_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) ); + + /* Update states */ + NSQ->sLF_AR_shp_Q14 = psDD->LF_AR_Q14; + NSQ->sDiff_shp_Q14 = psDD->Diff_Q14; + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech signal */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; +} + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +#ifndef OVERRIDE_silk_noise_shape_quantizer_del_dec +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay, /* I */ + int arch /* I */ +) +{ + opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + opus_int32 Winner_rand_state; + opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14; + opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10; + opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14; +#ifdef silk_short_prediction_create_arch_coef + opus_int32 a_Q12_arch[MAX_LPC_ORDER]; +#endif + + VARDECL( NSQ_sample_pair, psSampleState ); + NSQ_del_dec_struct *psDD; + NSQ_sample_struct *psSS; + SAVE_STACK; + + celt_assert( nStatesDelayedDecision > 0 ); + ALLOC( psSampleState, nStatesDelayedDecision, NSQ_sample_pair ); + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + +#ifdef silk_short_prediction_create_arch_coef + silk_short_prediction_create_arch_coef(a_Q12_arch, a_Q12, predictLPCOrder); +#endif + + for( i = 0; i < length; i++ ) { + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q14 = 2; + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */ + pred_lag_ptr++; + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = silk_SMULWB( silk_ADD_SAT32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */ + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + /* Delayed decision state */ + psDD = &psDelDec[ k ]; + + /* Sample state */ + psSS = psSampleState[ k ]; + + /* Generate dither */ + psDD->Seed = silk_RAND( psDD->Seed ); + + /* Pointer used in short term prediction and shaping */ + psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ]; + /* Short-term prediction */ + LPC_pred_Q14 = silk_noise_shape_quantizer_short_prediction(psLPC_Q14, a_Q12, a_Q12_arch, predictLPCOrder, arch); + LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */ + + /* Noise shape feedback */ + celt_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( psDD->Diff_Q14, psDD->sAR2_Q14[ 0 ], warping_Q16 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ 0 ] = tmp2; + n_AR_Q14 = silk_RSHIFT( shapingLPCOrder, 1 ); + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 ); + psDD->sAR2_Q14[ j - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ j - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ j + 0 ] = tmp2; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ j ] ); + } + psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */ + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */ + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */ + + n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */ + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1 = silk_ADD_SAT32( n_AR_Q14, n_LF_Q14 ); /* Q14 */ + tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */ + tmp1 = silk_SUB_SAT32( tmp2, tmp1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */ + + r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if ( psDD->Seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if (Lambda_Q10 > 2048) { + /* For aggressive RDO, the bias becomes more than one pulse. */ + int rdo_offset = Lambda_Q10/2 - 512; + if (q1_Q10 > rdo_offset) { + q1_Q0 = silk_RSHIFT( q1_Q10 - rdo_offset, 10 ); + } else if (q1_Q10 < -rdo_offset) { + q1_Q0 = silk_RSHIFT( q1_Q10 + rdo_offset, 10 ); + } else if (q1_Q10 < 0) { + q1_Q0 = -1; + } else { + q1_Q0 = 0; + } + } + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 ); + + if( rd1_Q10 < rd2_Q10 ) { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 0 ].Q_Q10 = q1_Q10; + psSS[ 1 ].Q_Q10 = q2_Q10; + } else { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 0 ].Q_Q10 = q2_Q10; + psSS[ 1 ].Q_Q10 = q1_Q10; + } + + /* Update states for best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + psSS[ 0 ].Diff_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_Q10[ i ], 4 ); + sLF_AR_shp_Q14 = silk_SUB32( psSS[ 0 ].Diff_Q14, n_AR_Q14 ); + psSS[ 0 ].sLTP_shp_Q14 = silk_SUB_SAT32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 0 ].xq_Q14 = xq_Q14; + + /* Update states for second best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + psSS[ 1 ].Diff_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_Q10[ i ], 4 ); + sLF_AR_shp_Q14 = silk_SUB32( psSS[ 1 ].Diff_Q14, n_AR_Q14 ); + psSS[ 1 ].sLTP_shp_Q14 = silk_SUB_SAT32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 1 ].xq_Q14 = xq_Q14; + } + + *smpl_buf_idx = ( *smpl_buf_idx - 1 ) % DECISION_DELAY; + if( *smpl_buf_idx < 0 ) *smpl_buf_idx += DECISION_DELAY; + last_smple_idx = ( *smpl_buf_idx + decisionDelay ) % DECISION_DELAY; + + /* Find winner */ + RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + Winner_ind = k; + } + } + + /* Increase RD values of expired states */ + Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ]; + for( k = 0; k < nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) { + psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 ); + psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 ); + silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 ); + } + } + + /* Find worst in first set and best in second set */ + RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10; + RDmax_ind = 0; + RDmin_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + /* find worst in first set */ + if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) { + RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + RDmax_ind = k; + } + /* find best in second set */ + if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10; + RDmin_ind = k; + } + } + + /* Replace a state if best from second set outperforms worst in first set */ + if( RDmin_Q10 < RDmax_Q10 ) { + silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i, + ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) ); + silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) ); + } + + /* Write samples from winner to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + if( subfr > 0 || i >= decisionDelay ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ]; + sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ]; + } + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Update states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psSS = &psSampleState[ k ][ 0 ]; + psDD->LF_AR_Q14 = psSS->LF_AR_Q14; + psDD->Diff_Q14 = psSS->Diff_Q14; + psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14; + psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14; + psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10; + psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 ); + psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14; + psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) ); + psDD->RandState[ *smpl_buf_idx ] = psDD->Seed; + psDD->RD_Q10 = psSS->RD_Q10; + } + delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10; + } + /* Update LPC states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + } + RESTORE_STACK; +} +#endif /* OVERRIDE_silk_noise_shape_quantizer_del_dec */ + +static OPUS_INLINE void silk_nsq_del_dec_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int16 x16[], /* I Input */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +) +{ + opus_int i, k, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26; + NSQ_del_dec_struct *psDD; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Scale input */ + inv_gain_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 ); + for( i = 0; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x16[ i ], inv_gain_Q26 ); + } + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + + /* Scale long-term shaping state */ + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + + /* Scale scalar states */ + psDD->LF_AR_Q14 = silk_SMULWW( gain_adj_Q16, psDD->LF_AR_Q14 ); + psDD->Diff_Q14 = silk_SMULWW( gain_adj_Q16, psDD->Diff_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + psDD->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + psDD->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] ); + } + for( i = 0; i < DECISION_DELAY; i++ ) { + psDD->Pred_Q15[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Pred_Q15[ i ] ); + psDD->Shape_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Shape_Q14[ i ] ); + } + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/PLC.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/PLC.c new file mode 100644 index 000000000..4667440db --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/PLC.c @@ -0,0 +1,446 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" +#include "PLC.h" + +#define NB_ATT 2 +static const opus_int16 HARM_ATT_Q15[NB_ATT] = { 32440, 31130 }; /* 0.99, 0.95 */ +static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = { 31130, 26214 }; /* 0.95, 0.8 */ +static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */ + +static OPUS_INLINE void silk_PLC_update( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl /* I/O Decoder control */ +); + +static OPUS_INLINE void silk_PLC_conceal( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* O LPC residual signal */ + int arch /* I Run-time architecture */ +); + + +void silk_PLC_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +) +{ + psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 ); + psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 ); + psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 ); + psDec->sPLC.subfr_length = 20; + psDec->sPLC.nb_subfr = 2; +} + +void silk_PLC( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O signal */ + opus_int lost, /* I Loss flag */ + int arch /* I Run-time architecture */ +) +{ + /* PLC control function */ + if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) { + silk_PLC_Reset( psDec ); + psDec->sPLC.fs_kHz = psDec->fs_kHz; + } + + if( lost ) { + /****************************/ + /* Generate Signal */ + /****************************/ + silk_PLC_conceal( psDec, psDecCtrl, frame, arch ); + + psDec->lossCnt++; + } else { + /****************************/ + /* Update state */ + /****************************/ + silk_PLC_update( psDec, psDecCtrl ); + } +} + +/**************************************************/ +/* Update state of PLC */ +/**************************************************/ +static OPUS_INLINE void silk_PLC_update( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl /* I/O Decoder control */ +) +{ + opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14; + opus_int i, j; + silk_PLC_struct *psPLC; + + psPLC = &psDec->sPLC; + + /* Update parameters used in case of packet loss */ + psDec->prevSignalType = psDec->indices.signalType; + LTP_Gain_Q14 = 0; + if( psDec->indices.signalType == TYPE_VOICED ) { + /* Find the parameters for the last subframe which contains a pitch pulse */ + for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) { + if( j == psDec->nb_subfr ) { + break; + } + temp_LTP_Gain_Q14 = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER + i ]; + } + if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) { + LTP_Gain_Q14 = temp_LTP_Gain_Q14; + silk_memcpy( psPLC->LTPCoef_Q14, + &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ], + LTP_ORDER * sizeof( opus_int16 ) ); + + psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 ); + } + } + + silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) ); + psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14; + + /* Limit LT coefs */ + if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) { + opus_int scale_Q10; + opus_int32 tmp; + + tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 ); + scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); + for( i = 0; i < LTP_ORDER; i++ ) { + psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 ); + } + } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) { + opus_int scale_Q14; + opus_int32 tmp; + + tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 ); + scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); + for( i = 0; i < LTP_ORDER; i++ ) { + psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 ); + } + } + } else { + psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 ); + silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 )); + } + + /* Save LPC coeficients */ + silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) ); + psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14; + + /* Save last two gains */ + silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) ); + + psPLC->subfr_length = psDec->subfr_length; + psPLC->nb_subfr = psDec->nb_subfr; +} + +static OPUS_INLINE void silk_PLC_energy(opus_int32 *energy1, opus_int *shift1, opus_int32 *energy2, opus_int *shift2, + const opus_int32 *exc_Q14, const opus_int32 *prevGain_Q10, int subfr_length, int nb_subfr) +{ + int i, k; + VARDECL( opus_int16, exc_buf ); + opus_int16 *exc_buf_ptr; + SAVE_STACK; + ALLOC( exc_buf, 2*subfr_length, opus_int16 ); + /* Find random noise component */ + /* Scale previous excitation signal */ + exc_buf_ptr = exc_buf; + for( k = 0; k < 2; k++ ) { + for( i = 0; i < subfr_length; i++ ) { + exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( + silk_SMULWW( exc_Q14[ i + ( k + nb_subfr - 2 ) * subfr_length ], prevGain_Q10[ k ] ), 8 ) ); + } + exc_buf_ptr += subfr_length; + } + /* Find the subframe with lowest energy of the last two and use that as random noise generator */ + silk_sum_sqr_shift( energy1, shift1, exc_buf, subfr_length ); + silk_sum_sqr_shift( energy2, shift2, &exc_buf[ subfr_length ], subfr_length ); + RESTORE_STACK; +} + +static OPUS_INLINE void silk_PLC_conceal( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* O LPC residual signal */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, j, k; + opus_int lag, idx, sLTP_buf_idx, shift1, shift2; + opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30; + opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr; + opus_int32 LPC_pred_Q10, LTP_pred_Q12; + opus_int16 rand_scale_Q14; + opus_int16 *B_Q14; + opus_int32 *sLPC_Q14_ptr; + opus_int16 A_Q12[ MAX_LPC_ORDER ]; +#ifdef SMALL_FOOTPRINT + opus_int16 *sLTP; +#else + VARDECL( opus_int16, sLTP ); +#endif + VARDECL( opus_int32, sLTP_Q14 ); + silk_PLC_struct *psPLC = &psDec->sPLC; + opus_int32 prevGain_Q10[2]; + SAVE_STACK; + + ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 ); +#ifdef SMALL_FOOTPRINT + /* Ugly hack that breaks aliasing rules to save stack: put sLTP at the very end of sLTP_Q14. */ + sLTP = ((opus_int16*)&sLTP_Q14[psDec->ltp_mem_length + psDec->frame_length])-psDec->ltp_mem_length; +#else + ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 ); +#endif + + prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6); + prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6); + + if( psDec->first_frame_after_reset ) { + silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) ); + } + + silk_PLC_energy(&energy1, &shift1, &energy2, &shift2, psDec->exc_Q14, prevGain_Q10, psDec->subfr_length, psDec->nb_subfr); + + if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) { + /* First sub-frame has lowest energy */ + rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ]; + } else { + /* Second sub-frame has lowest energy */ + rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ]; + } + + /* Set up Gain to random noise component */ + B_Q14 = psPLC->LTPCoef_Q14; + rand_scale_Q14 = psPLC->randScale_Q14; + + /* Set up attenuation gains */ + harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + if( psDec->prevSignalType == TYPE_VOICED ) { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + } else { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + } + + /* LPC concealment. Apply BWE to previous LPC */ + silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) ); + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); + + /* First Lost frame */ + if( psDec->lossCnt == 0 ) { + rand_scale_Q14 = 1 << 14; + + /* Reduce random noise Gain for voiced frames */ + if( psDec->prevSignalType == TYPE_VOICED ) { + for( i = 0; i < LTP_ORDER; i++ ) { + rand_scale_Q14 -= B_Q14[ i ]; + } + rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */ + rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 ); + } else { + /* Reduce random noise for unvoiced frames with high LPC gain */ + opus_int32 invGain_Q30, down_scale_Q30; + + invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order, arch ); + + down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 ); + down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 ); + down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES ); + + rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 ); + } + } + + rand_seed = psPLC->rand_seed; + lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); + sLTP_buf_idx = psDec->ltp_mem_length; + + /* Rewhiten LTP state */ + idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; + celt_assert( idx > 0 ); + silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order, arch ); + /* Scale LTP state */ + inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 ); + inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 ); + for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) { + sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] ); + } + + /***************************/ + /* LTP synthesis filtering */ + /***************************/ + for( k = 0; k < psDec->nb_subfr; k++ ) { + /* Set up pointer */ + pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q12 = 2; + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); + pred_lag_ptr++; + + /* Generate LPC excitation */ + rand_seed = silk_RAND( rand_seed ); + idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK; + sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 ); + sLTP_buf_idx++; + } + + /* Gradually reduce LTP gain */ + for( j = 0; j < LTP_ORDER; j++ ) { + B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 ); + } + /* Gradually reduce excitation gain */ + rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); + + /* Slowly increase pitch lag */ + psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 ); + psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) ); + lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); + } + + /***************************/ + /* LPC synthesis filtering */ + /***************************/ + sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ]; + + /* Copy LPC state */ + silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + celt_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */ + for( i = 0; i < psDec->frame_length; i++ ) { + /* partly unrolled */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); + for( j = 10; j < psDec->LPC_order; j++ ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] ); + } + + /* Add prediction to LPC excitation */ + sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], + silk_LSHIFT_SAT32( LPC_pred_Q10, 4 )); + + /* Scale with Gain */ + frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) ); + } + + /* Save LPC state */ + silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + /**************************************/ + /* Update states */ + /**************************************/ + psPLC->rand_seed = rand_seed; + psPLC->randScale_Q14 = rand_scale_Q14; + for( i = 0; i < MAX_NB_SUBFR; i++ ) { + psDecCtrl->pitchL[ i ] = lag; + } + RESTORE_STACK; +} + +/* Glues concealed frames with new good received frames */ +void silk_PLC_glue_frames( + silk_decoder_state *psDec, /* I/O decoder state */ + opus_int16 frame[], /* I/O signal */ + opus_int length /* I length of signal */ +) +{ + opus_int i, energy_shift; + opus_int32 energy; + silk_PLC_struct *psPLC; + psPLC = &psDec->sPLC; + + if( psDec->lossCnt ) { + /* Calculate energy in concealed residual */ + silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length ); + + psPLC->last_frame_lost = 1; + } else { + if( psDec->sPLC.last_frame_lost ) { + /* Calculate residual in decoded signal if last frame was lost */ + silk_sum_sqr_shift( &energy, &energy_shift, frame, length ); + + /* Normalize energies */ + if( energy_shift > psPLC->conc_energy_shift ) { + psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift ); + } else if( energy_shift < psPLC->conc_energy_shift ) { + energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift ); + } + + /* Fade in the energy difference */ + if( energy > psPLC->conc_energy ) { + opus_int32 frac_Q24, LZ; + opus_int32 gain_Q16, slope_Q16; + + LZ = silk_CLZ32( psPLC->conc_energy ); + LZ = LZ - 1; + psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ ); + energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) ); + + frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) ); + + gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 ); + slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length ); + /* Make slope 4x steeper to avoid missing onsets after DTX */ + slope_Q16 = silk_LSHIFT( slope_Q16, 2 ); + + for( i = 0; i < length; i++ ) { + frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] ); + gain_Q16 += slope_Q16; + if( gain_Q16 > (opus_int32)1 << 16 ) { + break; + } + } + } + } + psPLC->last_frame_lost = 0; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/PLC.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/PLC.h new file mode 100644 index 000000000..6438f5163 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/PLC.h @@ -0,0 +1,62 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_PLC_H +#define SILK_PLC_H + +#include "main.h" + +#define BWE_COEF 0.99 +#define V_PITCH_GAIN_START_MIN_Q14 11469 /* 0.7 in Q14 */ +#define V_PITCH_GAIN_START_MAX_Q14 15565 /* 0.95 in Q14 */ +#define MAX_PITCH_LAG_MS 18 +#define RAND_BUF_SIZE 128 +#define RAND_BUF_MASK ( RAND_BUF_SIZE - 1 ) +#define LOG2_INV_LPC_GAIN_HIGH_THRES 3 /* 2^3 = 8 dB LPC gain */ +#define LOG2_INV_LPC_GAIN_LOW_THRES 8 /* 2^8 = 24 dB LPC gain */ +#define PITCH_DRIFT_FAC_Q16 655 /* 0.01 in Q16 */ + +void silk_PLC_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +); + +void silk_PLC( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O signal */ + opus_int lost, /* I Loss flag */ + int arch /* I Run-time architecture */ +); + +void silk_PLC_glue_frames( + silk_decoder_state *psDec, /* I/O decoder state */ + opus_int16 frame[], /* I/O signal */ + opus_int length /* I length of signal */ +); + +#endif + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/SigProc_FIX.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/SigProc_FIX.h new file mode 100644 index 000000000..f9ae32632 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/SigProc_FIX.h @@ -0,0 +1,641 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FIX_H +#define SILK_SIGPROC_FIX_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/*#define silk_MACRO_COUNT */ /* Used to enable WMOPS counting */ + +#define SILK_MAX_ORDER_LPC 24 /* max order of the LPC analysis in schur() and k2a() */ + +#include /* for memset(), memcpy(), memmove() */ +#include "typedef.h" +#include "resampler_structs.h" +#include "macros.h" +#include "cpu_support.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) +#include "x86/SigProc_FIX_sse.h" +#endif + +#if (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#include "arm/biquad_alt_arm.h" +#include "arm/LPC_inv_pred_gain_arm.h" +#endif + +/********************************************************************/ +/* SIGNAL PROCESSING FUNCTIONS */ +/********************************************************************/ + +/*! + * Initialize/reset the resampler state for a given pair of input/output sampling rates +*/ +opus_int silk_resampler_init( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int32 Fs_Hz_in, /* I Input sampling rate (Hz) */ + opus_int32 Fs_Hz_out, /* I Output sampling rate (Hz) */ + opus_int forEnc /* I If 1: encoder; if 0: decoder */ +); + +/*! + * Resampler: convert from one sampling rate to another + */ +opus_int silk_resampler( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! +* Downsample 2x, mediocre quality +*/ +void silk_resampler_down2( + opus_int32 *S, /* I/O State vector [ 2 ] */ + opus_int16 *out, /* O Output signal [ len ] */ + const opus_int16 *in, /* I Input signal [ floor(len/2) ] */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! + * Downsample by a factor 2/3, low quality +*/ +void silk_resampler_down2_3( + opus_int32 *S, /* I/O State vector [ 6 ] */ + opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */ + const opus_int16 *in, /* I Input signal [ inLen ] */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! + * second order ARMA filter; + * slower than biquad() but uses more precise coefficients + * can handle (slowly) varying coefficients + */ +void silk_biquad_alt_stride1( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +); + +void silk_biquad_alt_stride2_c( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +); + +/* Variable order MA prediction error filter. */ +void silk_LPC_analysis_filter( + opus_int16 *out, /* O Output signal */ + const opus_int16 *in, /* I Input signal */ + const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */ + const opus_int32 len, /* I Signal length */ + const opus_int32 d, /* I Filter order */ + int arch /* I Run-time architecture */ +); + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander( + opus_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */ +); + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander_32( + opus_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor in Q16 */ +); + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +opus_int32 silk_LPC_inverse_pred_gain_c( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +); + +/* Split signal in two decimated bands using first-order allpass filters */ +void silk_ana_filt_bank_1( + const opus_int16 *in, /* I Input signal [N] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *outL, /* O Low band [N/2] */ + opus_int16 *outH, /* O High band [N/2] */ + const opus_int32 N /* I Number of input samples */ +); + +#if !defined(OVERRIDE_silk_biquad_alt_stride2) +#define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((void)(arch), silk_biquad_alt_stride2_c(in, B_Q28, A_Q28, S, out, len)) +#endif + +#if !defined(OVERRIDE_silk_LPC_inverse_pred_gain) +#define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((void)(arch), silk_LPC_inverse_pred_gain_c(A_Q12, order)) +#endif + +/********************************************************************/ +/* SCALAR FUNCTIONS */ +/********************************************************************/ + +/* Approximation of 128 * log2() (exact inverse of approx 2^() below) */ +/* Convert input to a log scale */ +opus_int32 silk_lin2log( + const opus_int32 inLin /* I input in linear scale */ +); + +/* Approximation of a sigmoid function */ +opus_int silk_sigm_Q15( + opus_int in_Q5 /* I */ +); + +/* Approximation of 2^() (exact inverse of approx log2() above) */ +/* Convert input to a linear scale */ +opus_int32 silk_log2lin( + const opus_int32 inLog_Q7 /* I input on log scale */ +); + +/* Compute number of bits to right shift the sum of squares of a vector */ +/* of int16s to make it fit in an int32 */ +void silk_sum_sqr_shift( + opus_int32 *energy, /* O Energy of x, after shifting to the right */ + opus_int *shift, /* O Number of bits right shift applied to energy */ + const opus_int16 *x, /* I Input vector */ + opus_int len /* I Length of input vector */ +); + +/* Calculates the reflection coefficients from the correlation sequence */ +/* Faster than schur64(), but much less accurate. */ +/* uses SMLAWB(), requiring armv5E and higher. */ +opus_int32 silk_schur( /* O Returns residual energy */ + opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */ + const opus_int32 *c, /* I correlations [order+1] */ + const opus_int32 order /* I prediction order */ +); + +/* Calculates the reflection coefficients from the correlation sequence */ +/* Slower than schur(), but more accurate. */ +/* Uses SMULL(), available on armv4 */ +opus_int32 silk_schur64( /* O returns residual energy */ + opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */ + const opus_int32 c[], /* I Correlations [order+1] */ + opus_int32 order /* I Prediction order */ +); + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */ + const opus_int32 order /* I Prediction order */ +); + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_Q16( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */ + const opus_int32 order /* I Prediction order */ +); + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +/* every other sample of window is linearly interpolated, for speed */ +void silk_apply_sine_window( + opus_int16 px_win[], /* O Pointer to windowed signal */ + const opus_int16 px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +); + +/* Compute autocorrelation */ +void silk_autocorr( + opus_int32 *results, /* O Result (length correlationCount) */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *inputData, /* I Input data to correlate */ + const opus_int inputDataSize, /* I Length of input */ + const opus_int correlationCount, /* I Number of correlation taps to compute */ + int arch /* I Run-time architecture */ +); + +void silk_decode_pitch( + opus_int16 lagIndex, /* I */ + opus_int8 contourIndex, /* O */ + opus_int pitch_lags[], /* O 4 pitch values */ + const opus_int Fs_kHz, /* I sampling frequency (kHz) */ + const opus_int nb_subfr /* I number of sub frames */ +); + +opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const opus_int16 *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O 4 pitch lag values */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */ + const opus_int search_thres2_Q13, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I Sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr, /* I number of 5 ms subframes */ + int arch /* I Run-time architecture */ +); + +/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */ +/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */ +void silk_A2NLSF( + opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */ + opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */ + const opus_int d /* I Filter order (must be even) */ +); + +/* compute whitening filter coefficients from normalized line spectral frequencies */ +void silk_NLSF2A( + opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */ + const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */ + const opus_int d, /* I filter order (should be even) */ + int arch /* I Run-time architecture */ +); + +/* Convert int32 coefficients to int16 coefs and make sure there's no wrap-around */ +void silk_LPC_fit( + opus_int16 *a_QOUT, /* O Output signal */ + opus_int32 *a_QIN, /* I/O Input signal */ + const opus_int QOUT, /* I Input Q domain */ + const opus_int QIN, /* I Input Q domain */ + const opus_int d /* I Filter order */ +); + +void silk_insertion_sort_increasing( + opus_int32 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +void silk_insertion_sort_decreasing_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +void silk_insertion_sort_increasing_all_values_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + const opus_int L /* I Vector length */ +); + +/* NLSF stabilizer, for a single input data vector */ +void silk_NLSF_stabilize( + opus_int16 *NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */ + const opus_int16 *NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const opus_int L /* I Number of NLSF parameters in the input vector */ +); + +/* Laroia low complexity NLSF weights */ +void silk_NLSF_VQ_weights_laroia( + opus_int16 *pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */ + const opus_int16 *pNLSF_Q15, /* I Pointer to input vector [D] */ + const opus_int D /* I Input vector dimension (even) */ +); + +/* Compute reflection coefficients from input signal */ +void silk_burg_modified_c( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +); + +/* Copy and multiply a vector by a constant */ +void silk_scale_copy_vector16( + opus_int16 *data_out, + const opus_int16 *data_in, + opus_int32 gain_Q16, /* I Gain in Q16 */ + const opus_int dataSize /* I Length */ +); + +/* Some for the LTP related function requires Q26 to work.*/ +void silk_scale_vector32_Q26_lshift_18( + opus_int32 *data1, /* I/O Q0/Q18 */ + opus_int32 gain_Q26, /* I Q26 */ + opus_int dataSize /* I length */ +); + +/********************************************************************/ +/* INLINE ARM MATH */ +/********************************************************************/ + +/* return sum( inVec1[i] * inVec2[i] ) */ + +opus_int32 silk_inner_prod_aligned( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int len, /* I vector lengths */ + int arch /* I Run-time architecture */ +); + + +opus_int32 silk_inner_prod_aligned_scale( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int scale, /* I number of bits to shift */ + const opus_int len /* I vector lengths */ +); + +opus_int64 silk_inner_prod16_aligned_64_c( + const opus_int16 *inVec1, /* I input vector 1 */ + const opus_int16 *inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +); + +/********************************************************************/ +/* MACROS */ +/********************************************************************/ + +/* Rotate a32 right by 'rot' bits. Negative rot values result in rotating + left. Output is 32bit int. + Note: contemporary compilers recognize the C expression below and + compile it into a 'ror' instruction if available. No need for OPUS_INLINE ASM! */ +static OPUS_INLINE opus_int32 silk_ROR32( opus_int32 a32, opus_int rot ) +{ + opus_uint32 x = (opus_uint32) a32; + opus_uint32 r = (opus_uint32) rot; + opus_uint32 m = (opus_uint32) -rot; + if( rot == 0 ) { + return a32; + } else if( rot < 0 ) { + return (opus_int32) ((x << m) | (x >> (32 - m))); + } else { + return (opus_int32) ((x << (32 - r)) | (x >> r)); + } +} + +/* Allocate opus_int16 aligned to 4-byte memory address */ +#if EMBEDDED_ARM +#define silk_DWORD_ALIGN __attribute__((aligned(4))) +#else +#define silk_DWORD_ALIGN +#endif + +/* Useful Macros that can be adjusted to other platforms */ +#define silk_memcpy(dest, src, size) memcpy((dest), (src), (size)) +#define silk_memset(dest, src, size) memset((dest), (src), (size)) +#define silk_memmove(dest, src, size) memmove((dest), (src), (size)) + +/* Fixed point macros */ + +/* (a32 * b32) output have to be 32bit int */ +#define silk_MUL(a32, b32) ((a32) * (b32)) + +/* (a32 * b32) output have to be 32bit uint */ +#define silk_MUL_uint(a32, b32) silk_MUL(a32, b32) + +/* a32 + (b32 * c32) output have to be 32bit int */ +#define silk_MLA(a32, b32, c32) silk_ADD32((a32),((b32) * (c32))) + +/* a32 + (b32 * c32) output have to be 32bit uint */ +#define silk_MLA_uint(a32, b32, c32) silk_MLA(a32, b32, c32) + +/* ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ +#define silk_SMULTT(a32, b32) (((a32) >> 16) * ((b32) >> 16)) + +/* a32 + ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ +#define silk_SMLATT(a32, b32, c32) silk_ADD32((a32),((b32) >> 16) * ((c32) >> 16)) + +#define silk_SMLALBB(a64, b16, c16) silk_ADD64((a64),(opus_int64)((opus_int32)(b16) * (opus_int32)(c16))) + +/* (a32 * b32) */ +#define silk_SMULL(a32, b32) ((opus_int64)(a32) * /*(opus_int64)*/(b32)) + +/* Adds two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour + (just standard two's complement implementation-specific behaviour) */ +#define silk_ADD32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) + (opus_uint32)(b))) +/* Subtractss two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour + (just standard two's complement implementation-specific behaviour) */ +#define silk_SUB32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) - (opus_uint32)(b))) + +/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */ +#define silk_MLA_ovflw(a32, b32, c32) silk_ADD32_ovflw((a32), (opus_uint32)(b32) * (opus_uint32)(c32)) +#define silk_SMLABB_ovflw(a32, b32, c32) (silk_ADD32_ovflw((a32) , ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32)))) + +#define silk_DIV32_16(a32, b16) ((opus_int32)((a32) / (b16))) +#define silk_DIV32(a32, b32) ((opus_int32)((a32) / (b32))) + +/* These macros enables checking for overflow in silk_API_Debug.h*/ +#define silk_ADD16(a, b) ((a) + (b)) +#define silk_ADD32(a, b) ((a) + (b)) +#define silk_ADD64(a, b) ((a) + (b)) + +#define silk_SUB16(a, b) ((a) - (b)) +#define silk_SUB32(a, b) ((a) - (b)) +#define silk_SUB64(a, b) ((a) - (b)) + +#define silk_SAT8(a) ((a) > silk_int8_MAX ? silk_int8_MAX : \ + ((a) < silk_int8_MIN ? silk_int8_MIN : (a))) +#define silk_SAT16(a) ((a) > silk_int16_MAX ? silk_int16_MAX : \ + ((a) < silk_int16_MIN ? silk_int16_MIN : (a))) +#define silk_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : \ + ((a) < silk_int32_MIN ? silk_int32_MIN : (a))) + +#define silk_CHECK_FIT8(a) (a) +#define silk_CHECK_FIT16(a) (a) +#define silk_CHECK_FIT32(a) (a) + +#define silk_ADD_SAT16(a, b) (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a), (b) ) ) +#define silk_ADD_SAT64(a, b) ((((a) + (b)) & 0x8000000000000000LL) == 0 ? \ + ((((a) & (b)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a)+(b)) : \ + ((((a) | (b)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a)+(b)) ) + +#define silk_SUB_SAT16(a, b) (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a), (b) ) ) +#define silk_SUB_SAT64(a, b) ((((a)-(b)) & 0x8000000000000000LL) == 0 ? \ + (( (a) & ((b)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a)-(b)) : \ + ((((a)^0x8000000000000000LL) & (b) & 0x8000000000000000LL) ? silk_int64_MAX : (a)-(b)) ) + +/* Saturation for positive input values */ +#define silk_POS_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : (a)) + +/* Add with saturation for positive input values */ +#define silk_ADD_POS_SAT8(a, b) ((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b))) +#define silk_ADD_POS_SAT16(a, b) ((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b))) +#define silk_ADD_POS_SAT32(a, b) ((((opus_uint32)(a)+(opus_uint32)(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b))) + +#define silk_LSHIFT8(a, shift) ((opus_int8)((opus_uint8)(a)<<(shift))) /* shift >= 0, shift < 8 */ +#define silk_LSHIFT16(a, shift) ((opus_int16)((opus_uint16)(a)<<(shift))) /* shift >= 0, shift < 16 */ +#define silk_LSHIFT32(a, shift) ((opus_int32)((opus_uint32)(a)<<(shift))) /* shift >= 0, shift < 32 */ +#define silk_LSHIFT64(a, shift) ((opus_int64)((opus_uint64)(a)<<(shift))) /* shift >= 0, shift < 64 */ +#define silk_LSHIFT(a, shift) silk_LSHIFT32(a, shift) /* shift >= 0, shift < 32 */ + +#define silk_RSHIFT8(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 8 */ +#define silk_RSHIFT16(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 16 */ +#define silk_RSHIFT32(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 32 */ +#define silk_RSHIFT64(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 64 */ +#define silk_RSHIFT(a, shift) silk_RSHIFT32(a, shift) /* shift >= 0, shift < 32 */ + +/* saturates before shifting */ +#define silk_LSHIFT_SAT32(a, shift) (silk_LSHIFT32( silk_LIMIT( (a), silk_RSHIFT32( silk_int32_MIN, (shift) ), \ + silk_RSHIFT32( silk_int32_MAX, (shift) ) ), (shift) )) + +#define silk_LSHIFT_ovflw(a, shift) ((opus_int32)((opus_uint32)(a) << (shift))) /* shift >= 0, allowed to overflow */ +#define silk_LSHIFT_uint(a, shift) ((a) << (shift)) /* shift >= 0 */ +#define silk_RSHIFT_uint(a, shift) ((a) >> (shift)) /* shift >= 0 */ + +#define silk_ADD_LSHIFT(a, b, shift) ((a) + silk_LSHIFT((b), (shift))) /* shift >= 0 */ +#define silk_ADD_LSHIFT32(a, b, shift) silk_ADD32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_ADD_LSHIFT_uint(a, b, shift) ((a) + silk_LSHIFT_uint((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT(a, b, shift) ((a) + silk_RSHIFT((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT32(a, b, shift) silk_ADD32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT_uint(a, b, shift) ((a) + silk_RSHIFT_uint((b), (shift))) /* shift >= 0 */ +#define silk_SUB_LSHIFT32(a, b, shift) silk_SUB32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_SUB_RSHIFT32(a, b, shift) silk_SUB32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */ + +/* Requires that shift > 0 */ +#define silk_RSHIFT_ROUND(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) +#define silk_RSHIFT_ROUND64(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) + +/* Number of rightshift required to fit the multiplication */ +#define silk_NSHIFT_MUL_32_32(a, b) ( -(31- (32-silk_CLZ32(silk_abs(a)) + (32-silk_CLZ32(silk_abs(b))))) ) +#define silk_NSHIFT_MUL_16_16(a, b) ( -(15- (16-silk_CLZ16(silk_abs(a)) + (16-silk_CLZ16(silk_abs(b))))) ) + + +#define silk_min(a, b) (((a) < (b)) ? (a) : (b)) +#define silk_max(a, b) (((a) > (b)) ? (a) : (b)) + +/* Macro to convert floating-point constants to fixed-point */ +#define SILK_FIX_CONST( C, Q ) ((opus_int32)((C) * ((opus_int64)1 << (Q)) + 0.5)) + +/* silk_min() versions with typecast in the function call */ +static OPUS_INLINE opus_int silk_min_int(opus_int a, opus_int b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int16 silk_min_16(opus_int16 a, opus_int16 b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int32 silk_min_32(opus_int32 a, opus_int32 b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int64 silk_min_64(opus_int64 a, opus_int64 b) +{ + return (((a) < (b)) ? (a) : (b)); +} + +/* silk_min() versions with typecast in the function call */ +static OPUS_INLINE opus_int silk_max_int(opus_int a, opus_int b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int16 silk_max_16(opus_int16 a, opus_int16 b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int32 silk_max_32(opus_int32 a, opus_int32 b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b) +{ + return (((a) > (b)) ? (a) : (b)); +} + +#define silk_LIMIT( a, limit1, limit2) ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))) + +#define silk_LIMIT_int silk_LIMIT +#define silk_LIMIT_16 silk_LIMIT +#define silk_LIMIT_32 silk_LIMIT + +#define silk_abs(a) (((a) > 0) ? (a) : -(a)) /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */ +#define silk_abs_int(a) (((a) ^ ((a) >> (8 * sizeof(a) - 1))) - ((a) >> (8 * sizeof(a) - 1))) +#define silk_abs_int32(a) (((a) ^ ((a) >> 31)) - ((a) >> 31)) +#define silk_abs_int64(a) (((a) > 0) ? (a) : -(a)) + +#define silk_sign(a) ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 )) + +/* PSEUDO-RANDOM GENERATOR */ +/* Make sure to store the result as the seed for the next call (also in between */ +/* frames), otherwise result won't be random at all. When only using some of the */ +/* bits, take the most significant bits by right-shifting. */ +#define RAND_MULTIPLIER 196314165 +#define RAND_INCREMENT 907633515 +#define silk_RAND(seed) (silk_MLA_ovflw((RAND_INCREMENT), (seed), (RAND_MULTIPLIER))) + +/* Add some multiplication functions that can be easily mapped to ARM. */ + +/* silk_SMMUL: Signed top word multiply. + ARMv6 2 instruction cycles. + ARMv3M+ 3 instruction cycles. use SMULL and ignore LSB registers.(except xM)*/ +/*#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT(silk_SMLAL(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)), 16)*/ +/* the following seems faster on x86 */ +#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT64(silk_SMULL((a32), (b32)), 32) + +#if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +#define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \ + ((void)(arch), silk_burg_modified_c(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch)) + +#define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \ + ((void)(arch),silk_inner_prod16_aligned_64_c(inVec1, inVec2, len)) +#endif + +#include "Inlines.h" +#include "MacroCount.h" +#include "MacroDebug.h" + +#ifdef OPUS_ARM_INLINE_ASM +#include "arm/SigProc_FIX_armv4.h" +#endif + +#ifdef OPUS_ARM_INLINE_EDSP +#include "arm/SigProc_FIX_armv5e.h" +#endif + +#if defined(MIPSr1_ASM) +#include "mips/sigproc_fix_mipsr1.h" +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_SIGPROC_FIX_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/VAD.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/VAD.c new file mode 100644 index 000000000..d0cda5216 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/VAD.c @@ -0,0 +1,360 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/* Silk VAD noise level estimation */ +# if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +static OPUS_INLINE void silk_VAD_GetNoiseLevels( + const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); +#endif + +/**********************************/ +/* Initialization of the Silk VAD */ +/**********************************/ +opus_int silk_VAD_Init( /* O Return value, 0 if success */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +) +{ + opus_int b, ret = 0; + + /* reset state memory */ + silk_memset( psSilk_VAD, 0, sizeof( silk_VAD_state ) ); + + /* init noise levels */ + /* Initialize array with approx pink noise levels (psd proportional to inverse of frequency) */ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NoiseLevelBias[ b ] = silk_max_32( silk_DIV32_16( VAD_NOISE_LEVELS_BIAS, b + 1 ), 1 ); + } + + /* Initialize state */ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NL[ b ] = silk_MUL( 100, psSilk_VAD->NoiseLevelBias[ b ] ); + psSilk_VAD->inv_NL[ b ] = silk_DIV32( silk_int32_MAX, psSilk_VAD->NL[ b ] ); + } + psSilk_VAD->counter = 15; + + /* init smoothed energy-to-noise ratio*/ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NrgRatioSmth_Q8[ b ] = 100 * 256; /* 100 * 256 --> 20 dB SNR */ + } + + return( ret ); +} + +/* Weighting factors for tilt measure */ +static const opus_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 }; + +/***************************************/ +/* Get the speech activity level in Q8 */ +/***************************************/ +opus_int silk_VAD_GetSA_Q8_c( /* O Return value, 0 if success */ + silk_encoder_state *psEncC, /* I/O Encoder state */ + const opus_int16 pIn[] /* I PCM input */ +) +{ + opus_int SA_Q15, pSNR_dB_Q7, input_tilt; + opus_int decimated_framelength1, decimated_framelength2; + opus_int decimated_framelength; + opus_int dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s; + opus_int32 sumSquared, smooth_coef_Q16; + opus_int16 HPstateTmp; + VARDECL( opus_int16, X ); + opus_int32 Xnrg[ VAD_N_BANDS ]; + opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ]; + opus_int32 speech_nrg, x_tmp; + opus_int X_offset[ VAD_N_BANDS ]; + opus_int ret = 0; + silk_VAD_state *psSilk_VAD = &psEncC->sVAD; + SAVE_STACK; + + /* Safety checks */ + silk_assert( VAD_N_BANDS == 4 ); + celt_assert( MAX_FRAME_LENGTH >= psEncC->frame_length ); + celt_assert( psEncC->frame_length <= 512 ); + celt_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) ); + + /***********************/ + /* Filter and Decimate */ + /***********************/ + decimated_framelength1 = silk_RSHIFT( psEncC->frame_length, 1 ); + decimated_framelength2 = silk_RSHIFT( psEncC->frame_length, 2 ); + decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 ); + /* Decimate into 4 bands: + 0 L 3L L 3L 5L + - -- - -- -- + 8 8 2 4 4 + + [0-1 kHz| temp. |1-2 kHz| 2-4 kHz | 4-8 kHz | + + They're arranged to allow the minimal ( frame_length / 4 ) extra + scratch space during the downsampling process */ + X_offset[ 0 ] = 0; + X_offset[ 1 ] = decimated_framelength + decimated_framelength2; + X_offset[ 2 ] = X_offset[ 1 ] + decimated_framelength; + X_offset[ 3 ] = X_offset[ 2 ] + decimated_framelength2; + ALLOC( X, X_offset[ 3 ] + decimated_framelength1, opus_int16 ); + + /* 0-8 kHz to 0-4 kHz and 4-8 kHz */ + silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ], + X, &X[ X_offset[ 3 ] ], psEncC->frame_length ); + + /* 0-4 kHz to 0-2 kHz and 2-4 kHz */ + silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState1[ 0 ], + X, &X[ X_offset[ 2 ] ], decimated_framelength1 ); + + /* 0-2 kHz to 0-1 kHz and 1-2 kHz */ + silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState2[ 0 ], + X, &X[ X_offset[ 1 ] ], decimated_framelength2 ); + + /*********************************************/ + /* HP filter on lowest band (differentiator) */ + /*********************************************/ + X[ decimated_framelength - 1 ] = silk_RSHIFT( X[ decimated_framelength - 1 ], 1 ); + HPstateTmp = X[ decimated_framelength - 1 ]; + for( i = decimated_framelength - 1; i > 0; i-- ) { + X[ i - 1 ] = silk_RSHIFT( X[ i - 1 ], 1 ); + X[ i ] -= X[ i - 1 ]; + } + X[ 0 ] -= psSilk_VAD->HPstate; + psSilk_VAD->HPstate = HPstateTmp; + + /*************************************/ + /* Calculate the energy in each band */ + /*************************************/ + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Find the decimated framelength in the non-uniformly divided bands */ + decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) ); + + /* Split length into subframe lengths */ + dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 ); + dec_subframe_offset = 0; + + /* Compute energy per sub-frame */ + /* initialize with summed energy of last subframe */ + Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ]; + for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) { + sumSquared = 0; + for( i = 0; i < dec_subframe_length; i++ ) { + /* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2. */ + /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */ + x_tmp = silk_RSHIFT( + X[ X_offset[ b ] + i + dec_subframe_offset ], 3 ); + sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp ); + + /* Safety check */ + silk_assert( sumSquared >= 0 ); + } + + /* Add/saturate summed energy of current subframe */ + if( s < VAD_INTERNAL_SUBFRAMES - 1 ) { + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared ); + } else { + /* Look-ahead subframe */ + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) ); + } + + dec_subframe_offset += dec_subframe_length; + } + psSilk_VAD->XnrgSubfr[ b ] = sumSquared; + } + + /********************/ + /* Noise estimation */ + /********************/ + silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD ); + + /***********************************************/ + /* Signal-plus-noise to noise ratio estimation */ + /***********************************************/ + sumSquared = 0; + input_tilt = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ]; + if( speech_nrg > 0 ) { + /* Divide, with sufficient resolution */ + if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 ); + } else { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 ); + } + + /* Convert to log domain */ + SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128; + + /* Sum-of-squares */ + sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */ + + /* Tilt measure */ + if( speech_nrg < ( (opus_int32)1 << 20 ) ) { + /* Scale down SNR value for small subband speech energies */ + SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 ); + } + input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 ); + } else { + NrgToNoiseRatio_Q8[ b ] = 256; + } + } + + /* Mean-of-squares */ + sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */ + + /* Root-mean-square approximation, scale to dBs, and write to output pointer */ + pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */ + + /*********************************/ + /* Speech Probability Estimation */ + /*********************************/ + SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 ); + + /**************************/ + /* Frequency Tilt Measure */ + /**************************/ + psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 ); + + /**************************************************/ + /* Scale the sigmoid output based on power levels */ + /**************************************************/ + speech_nrg = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Accumulate signal-without-noise energies, higher frequency bands have more weight */ + speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 ); + } + + if( psEncC->frame_length == 20 * psEncC->fs_kHz ) { + speech_nrg = silk_RSHIFT32( speech_nrg, 1 ); + } + /* Power scaling */ + if( speech_nrg <= 0 ) { + SA_Q15 = silk_RSHIFT( SA_Q15, 1 ); + } else if( speech_nrg < 16384 ) { + speech_nrg = silk_LSHIFT32( speech_nrg, 16 ); + + /* square-root */ + speech_nrg = silk_SQRT_APPROX( speech_nrg ); + SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 ); + } + + /* Copy the resulting speech activity in Q8 */ + psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX ); + + /***********************************/ + /* Energy Level and SNR estimation */ + /***********************************/ + /* Smoothing coefficient */ + smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) ); + + if( psEncC->frame_length == 10 * psEncC->fs_kHz ) { + smooth_coef_Q16 >>= 1; + } + + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* compute smoothed energy-to-noise ratio per band */ + psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ], + NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 ); + + /* signal to noise ratio in dB per band */ + SNR_Q7 = 3 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 ); + /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */ + psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) ); + } + + RESTORE_STACK; + return( ret ); +} + +/**************************/ +/* Noise level estimation */ +/**************************/ +# if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +static OPUS_INLINE +#endif +void silk_VAD_GetNoiseLevels( + const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +) +{ + opus_int k; + opus_int32 nl, nrg, inv_nrg; + opus_int coef, min_coef; + + /* Initially faster smoothing */ + if( psSilk_VAD->counter < 1000 ) { /* 1000 = 20 sec */ + min_coef = silk_DIV32_16( silk_int16_MAX, silk_RSHIFT( psSilk_VAD->counter, 4 ) + 1 ); + /* Increment frame counter */ + psSilk_VAD->counter++; + } else { + min_coef = 0; + } + + for( k = 0; k < VAD_N_BANDS; k++ ) { + /* Get old noise level estimate for current band */ + nl = psSilk_VAD->NL[ k ]; + silk_assert( nl >= 0 ); + + /* Add bias */ + nrg = silk_ADD_POS_SAT32( pX[ k ], psSilk_VAD->NoiseLevelBias[ k ] ); + silk_assert( nrg > 0 ); + + /* Invert energies */ + inv_nrg = silk_DIV32( silk_int32_MAX, nrg ); + silk_assert( inv_nrg >= 0 ); + + /* Less update when subband energy is high */ + if( nrg > silk_LSHIFT( nl, 3 ) ) { + coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 >> 3; + } else if( nrg < nl ) { + coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16; + } else { + coef = silk_SMULWB( silk_SMULWW( inv_nrg, nl ), VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 << 1 ); + } + + /* Initially faster smoothing */ + coef = silk_max_int( coef, min_coef ); + + /* Smooth inverse energies */ + psSilk_VAD->inv_NL[ k ] = silk_SMLAWB( psSilk_VAD->inv_NL[ k ], inv_nrg - psSilk_VAD->inv_NL[ k ], coef ); + silk_assert( psSilk_VAD->inv_NL[ k ] >= 0 ); + + /* Compute noise level by inverting again */ + nl = silk_DIV32( silk_int32_MAX, psSilk_VAD->inv_NL[ k ] ); + silk_assert( nl >= 0 ); + + /* Limit noise levels (guarantee 7 bits of head room) */ + nl = silk_min( nl, 0x00FFFFFF ); + + /* Store as part of state */ + psSilk_VAD->NL[ k ] = nl; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/VQ_WMat_EC.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/VQ_WMat_EC.c new file mode 100644 index 000000000..0f3d545c4 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/VQ_WMat_EC.c @@ -0,0 +1,131 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */ +void silk_VQ_WMat_EC_c( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *res_nrg_Q15, /* O best residual energy */ + opus_int32 *rate_dist_Q8, /* O best total bitrate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int32 *XX_Q17, /* I correlation matrix */ + const opus_int32 *xX_Q17, /* I correlation vector */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int subfr_len, /* I number of samples per subframe */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + const opus_int L /* I number of vectors in codebook */ +) +{ + opus_int k, gain_tmp_Q7; + const opus_int8 *cb_row_Q7; + opus_int32 neg_xX_Q24[ 5 ]; + opus_int32 sum1_Q15, sum2_Q24; + opus_int32 bits_res_Q8, bits_tot_Q8; + + /* Negate and convert to new Q domain */ + neg_xX_Q24[ 0 ] = -silk_LSHIFT32( xX_Q17[ 0 ], 7 ); + neg_xX_Q24[ 1 ] = -silk_LSHIFT32( xX_Q17[ 1 ], 7 ); + neg_xX_Q24[ 2 ] = -silk_LSHIFT32( xX_Q17[ 2 ], 7 ); + neg_xX_Q24[ 3 ] = -silk_LSHIFT32( xX_Q17[ 3 ], 7 ); + neg_xX_Q24[ 4 ] = -silk_LSHIFT32( xX_Q17[ 4 ], 7 ); + + /* Loop over codebook */ + *rate_dist_Q8 = silk_int32_MAX; + *res_nrg_Q15 = silk_int32_MAX; + cb_row_Q7 = cb_Q7; + /* In things go really bad, at least *ind is set to something safe. */ + *ind = 0; + for( k = 0; k < L; k++ ) { + opus_int32 penalty; + gain_tmp_Q7 = cb_gain_Q7[k]; + /* Weighted rate */ + /* Quantization error: 1 - 2 * xX * cb + cb' * XX * cb */ + sum1_Q15 = SILK_FIX_CONST( 1.001, 15 ); + + /* Penalty for too large gain */ + penalty = silk_LSHIFT32( silk_max( silk_SUB32( gain_tmp_Q7, max_gain_Q7 ), 0 ), 11 ); + + /* first row of XX_Q17 */ + sum2_Q24 = silk_MLA( neg_xX_Q24[ 0 ], XX_Q17[ 1 ], cb_row_Q7[ 1 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 2 ], cb_row_Q7[ 2 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 3 ], cb_row_Q7[ 3 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 4 ], cb_row_Q7[ 4 ] ); + sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 0 ], cb_row_Q7[ 0 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 0 ] ); + + /* second row of XX_Q17 */ + sum2_Q24 = silk_MLA( neg_xX_Q24[ 1 ], XX_Q17[ 7 ], cb_row_Q7[ 2 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 8 ], cb_row_Q7[ 3 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 9 ], cb_row_Q7[ 4 ] ); + sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 6 ], cb_row_Q7[ 1 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 1 ] ); + + /* third row of XX_Q17 */ + sum2_Q24 = silk_MLA( neg_xX_Q24[ 2 ], XX_Q17[ 13 ], cb_row_Q7[ 3 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 14 ], cb_row_Q7[ 4 ] ); + sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 12 ], cb_row_Q7[ 2 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 2 ] ); + + /* fourth row of XX_Q17 */ + sum2_Q24 = silk_MLA( neg_xX_Q24[ 3 ], XX_Q17[ 19 ], cb_row_Q7[ 4 ] ); + sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 18 ], cb_row_Q7[ 3 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 3 ] ); + + /* last row of XX_Q17 */ + sum2_Q24 = silk_LSHIFT32( neg_xX_Q24[ 4 ], 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 24 ], cb_row_Q7[ 4 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 4 ] ); + + /* find best */ + if( sum1_Q15 >= 0 ) { + /* Translate residual energy to bits using high-rate assumption (6 dB ==> 1 bit/sample) */ + bits_res_Q8 = silk_SMULBB( subfr_len, silk_lin2log( sum1_Q15 + penalty) - (15 << 7) ); + /* In the following line we reduce the codelength component by half ("-1"); seems to slghtly improve quality */ + bits_tot_Q8 = silk_ADD_LSHIFT32( bits_res_Q8, cl_Q5[ k ], 3-1 ); + if( bits_tot_Q8 <= *rate_dist_Q8 ) { + *rate_dist_Q8 = bits_tot_Q8; + *res_nrg_Q15 = sum1_Q15 + penalty; + *ind = (opus_int8)k; + *gain_Q7 = gain_tmp_Q7; + } + } + + /* Go to next cbk vector */ + cb_row_Q7 += LTP_ORDER; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/ana_filt_bank_1.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/ana_filt_bank_1.c new file mode 100644 index 000000000..24cfb03fd --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/ana_filt_bank_1.c @@ -0,0 +1,74 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Coefficients for 2-band filter bank based on first-order allpass filters */ +static opus_int16 A_fb1_20 = 5394 << 1; +static opus_int16 A_fb1_21 = -24290; /* (opus_int16)(20623 << 1) */ + +/* Split signal into two decimated bands using first-order allpass filters */ +void silk_ana_filt_bank_1( + const opus_int16 *in, /* I Input signal [N] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *outL, /* O Low band [N/2] */ + opus_int16 *outH, /* O High band [N/2] */ + const opus_int32 N /* I Number of input samples */ +) +{ + opus_int k, N2 = silk_RSHIFT( N, 1 ); + opus_int32 in32, X, Y, out_1, out_2; + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < N2; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 ); + + /* All-pass section for even input sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMLAWB( Y, Y, A_fb1_21 ); + out_1 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 ); + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = silk_SUB32( in32, S[ 1 ] ); + X = silk_SMULWB( Y, A_fb1_20 ); + out_2 = silk_ADD32( S[ 1 ], X ); + S[ 1 ] = silk_ADD32( in32, X ); + + /* Add/subtract, convert back to int16 and store to output */ + outL[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_ADD32( out_2, out_1 ), 11 ) ); + outH[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SUB32( out_2, out_1 ), 11 ) ); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/LPC_inv_pred_gain_arm.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/LPC_inv_pred_gain_arm.h new file mode 100644 index 000000000..9895b555c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/LPC_inv_pred_gain_arm.h @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_LPC_INV_PRED_GAIN_ARM_H +# define SILK_LPC_INV_PRED_GAIN_ARM_H + +# include "celt/arm/armcpu.h" + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +opus_int32 silk_LPC_inverse_pred_gain_neon( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +); + +# if !defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_PRESUME_NEON) +# define OVERRIDE_silk_LPC_inverse_pred_gain (1) +# define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((void)(arch), PRESUME_NEON(silk_LPC_inverse_pred_gain)(A_Q12, order)) +# endif +# endif + +# if !defined(OVERRIDE_silk_LPC_inverse_pred_gain) +/*Is run-time CPU detection enabled on this platform?*/ +# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern opus_int32 (*const SILK_LPC_INVERSE_PRED_GAIN_IMPL[OPUS_ARCHMASK+1])(const opus_int16 *A_Q12, const opus_int order); +# define OVERRIDE_silk_LPC_inverse_pred_gain (1) +# define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((*SILK_LPC_INVERSE_PRED_GAIN_IMPL[(arch)&OPUS_ARCHMASK])(A_Q12, order)) +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_silk_LPC_inverse_pred_gain (1) +# define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((void)(arch), silk_LPC_inverse_pred_gain_neon(A_Q12, order)) +# endif +# endif + +#endif /* end SILK_LPC_INV_PRED_GAIN_ARM_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/LPC_inv_pred_gain_neon_intr.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/LPC_inv_pred_gain_neon_intr.c new file mode 100644 index 000000000..726e6667b --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/LPC_inv_pred_gain_neon_intr.c @@ -0,0 +1,288 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "SigProc_FIX.h" +#include "define.h" + +#define QA 24 +#define A_LIMIT SILK_FIX_CONST( 0.99975, QA ) + +#define MUL32_FRAC_Q(a32, b32, Q) ((opus_int32)(silk_RSHIFT_ROUND64(silk_SMULL(a32, b32), Q))) + +/* The difficulty is how to judge a 64-bit signed integer tmp64 is 32-bit overflowed, + * since NEON has no 64-bit min, max or comparison instructions. + * A failed idea is to compare the results of vmovn(tmp64) and vqmovn(tmp64) whether they are equal or not. + * However, this idea fails when the tmp64 is something like 0xFFFFFFF980000000. + * Here we know that mult2Q >= 1, so the highest bit (bit 63, sign bit) of tmp64 must equal to bit 62. + * tmp64 was shifted left by 1 and we got tmp64'. If high_half(tmp64') != 0 and high_half(tmp64') != -1, + * then we know that bit 31 to bit 63 of tmp64 can not all be the sign bit, and therefore tmp64 is 32-bit overflowed. + * That is, we judge if tmp64' > 0x00000000FFFFFFFF, or tmp64' <= 0xFFFFFFFF00000000. + * We use narrowing shift right 31 bits to tmp32' to save data bandwidth and instructions. + * That is, we judge if tmp32' > 0x00000000, or tmp32' <= 0xFFFFFFFF. + */ + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +static OPUS_INLINE opus_int32 LPC_inverse_pred_gain_QA_neon( /* O Returns inverse prediction gain in energy domain, Q30 */ + opus_int32 A_QA[ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k, n, mult2Q; + opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp1, tmp2; + opus_int32 max, min; + int32x4_t max_s32x4, min_s32x4; + int32x2_t max_s32x2, min_s32x2; + + max_s32x4 = vdupq_n_s32( silk_int32_MIN ); + min_s32x4 = vdupq_n_s32( silk_int32_MAX ); + invGain_Q30 = SILK_FIX_CONST( 1, 30 ); + for( k = order - 1; k > 0; k-- ) { + int32x2_t rc_Q31_s32x2, rc_mult2_s32x2; + int64x2_t mult2Q_s64x2; + + /* Check for stability */ + if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( A_QA[ k ], 31 - QA ); + + /* rc_mult1_Q30 range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) ); + silk_assert( rc_mult1_Q30 > ( 1 << 15 ) ); /* reduce A_LIMIT if fails */ + silk_assert( rc_mult1_Q30 <= ( 1 << 30 ) ); + + /* Update inverse gain */ + /* invGain_Q30 range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= ( 1 << 30 ) ); + if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + return 0; + } + + /* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */ + mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) ); + rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 ); + + /* Update AR coefficient */ + rc_Q31_s32x2 = vdup_n_s32( rc_Q31 ); + mult2Q_s64x2 = vdupq_n_s64( -mult2Q ); + rc_mult2_s32x2 = vdup_n_s32( rc_mult2 ); + + for( n = 0; n < ( ( k + 1 ) >> 1 ) - 3; n += 4 ) { + /* We always calculate extra elements of A_QA buffer when ( k % 4 ) != 0, to take the advantage of SIMD parallelization. */ + int32x4_t tmp1_s32x4, tmp2_s32x4, t0_s32x4, t1_s32x4, s0_s32x4, s1_s32x4, t_QA0_s32x4, t_QA1_s32x4; + int64x2_t t0_s64x2, t1_s64x2, t2_s64x2, t3_s64x2; + tmp1_s32x4 = vld1q_s32( A_QA + n ); + tmp2_s32x4 = vld1q_s32( A_QA + k - n - 4 ); + tmp2_s32x4 = vrev64q_s32( tmp2_s32x4 ); + tmp2_s32x4 = vcombine_s32( vget_high_s32( tmp2_s32x4 ), vget_low_s32( tmp2_s32x4 ) ); + t0_s32x4 = vqrdmulhq_lane_s32( tmp2_s32x4, rc_Q31_s32x2, 0 ); + t1_s32x4 = vqrdmulhq_lane_s32( tmp1_s32x4, rc_Q31_s32x2, 0 ); + t_QA0_s32x4 = vqsubq_s32( tmp1_s32x4, t0_s32x4 ); + t_QA1_s32x4 = vqsubq_s32( tmp2_s32x4, t1_s32x4 ); + t0_s64x2 = vmull_s32( vget_low_s32 ( t_QA0_s32x4 ), rc_mult2_s32x2 ); + t1_s64x2 = vmull_s32( vget_high_s32( t_QA0_s32x4 ), rc_mult2_s32x2 ); + t2_s64x2 = vmull_s32( vget_low_s32 ( t_QA1_s32x4 ), rc_mult2_s32x2 ); + t3_s64x2 = vmull_s32( vget_high_s32( t_QA1_s32x4 ), rc_mult2_s32x2 ); + t0_s64x2 = vrshlq_s64( t0_s64x2, mult2Q_s64x2 ); + t1_s64x2 = vrshlq_s64( t1_s64x2, mult2Q_s64x2 ); + t2_s64x2 = vrshlq_s64( t2_s64x2, mult2Q_s64x2 ); + t3_s64x2 = vrshlq_s64( t3_s64x2, mult2Q_s64x2 ); + t0_s32x4 = vcombine_s32( vmovn_s64( t0_s64x2 ), vmovn_s64( t1_s64x2 ) ); + t1_s32x4 = vcombine_s32( vmovn_s64( t2_s64x2 ), vmovn_s64( t3_s64x2 ) ); + s0_s32x4 = vcombine_s32( vshrn_n_s64( t0_s64x2, 31 ), vshrn_n_s64( t1_s64x2, 31 ) ); + s1_s32x4 = vcombine_s32( vshrn_n_s64( t2_s64x2, 31 ), vshrn_n_s64( t3_s64x2, 31 ) ); + max_s32x4 = vmaxq_s32( max_s32x4, s0_s32x4 ); + min_s32x4 = vminq_s32( min_s32x4, s0_s32x4 ); + max_s32x4 = vmaxq_s32( max_s32x4, s1_s32x4 ); + min_s32x4 = vminq_s32( min_s32x4, s1_s32x4 ); + t1_s32x4 = vrev64q_s32( t1_s32x4 ); + t1_s32x4 = vcombine_s32( vget_high_s32( t1_s32x4 ), vget_low_s32( t1_s32x4 ) ); + vst1q_s32( A_QA + n, t0_s32x4 ); + vst1q_s32( A_QA + k - n - 4, t1_s32x4 ); + } + for( ; n < (k + 1) >> 1; n++ ) { + opus_int64 tmp64; + tmp1 = A_QA[ n ]; + tmp2 = A_QA[ k - n - 1 ]; + tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp1, + MUL32_FRAC_Q( tmp2, rc_Q31, 31 ) ), rc_mult2 ), mult2Q); + if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { + return 0; + } + A_QA[ n ] = ( opus_int32 )tmp64; + tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp2, + MUL32_FRAC_Q( tmp1, rc_Q31, 31 ) ), rc_mult2), mult2Q); + if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { + return 0; + } + A_QA[ k - n - 1 ] = ( opus_int32 )tmp64; + } + } + + /* Check for stability */ + if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) { + return 0; + } + + max_s32x2 = vmax_s32( vget_low_s32( max_s32x4 ), vget_high_s32( max_s32x4 ) ); + min_s32x2 = vmin_s32( vget_low_s32( min_s32x4 ), vget_high_s32( min_s32x4 ) ); + max_s32x2 = vmax_s32( max_s32x2, vreinterpret_s32_s64( vshr_n_s64( vreinterpret_s64_s32( max_s32x2 ), 32 ) ) ); + min_s32x2 = vmin_s32( min_s32x2, vreinterpret_s32_s64( vshr_n_s64( vreinterpret_s64_s32( min_s32x2 ), 32 ) ) ); + max = vget_lane_s32( max_s32x2, 0 ); + min = vget_lane_s32( min_s32x2, 0 ); + if( ( max > 0 ) || ( min < -1 ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( A_QA[ 0 ], 31 - QA ); + + /* Range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) ); + + /* Update inverse gain */ + /* Range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= ( 1 << 30 ) ); + if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + return 0; + } + + return invGain_Q30; +} + +/* For input in Q12 domain */ +opus_int32 silk_LPC_inverse_pred_gain_neon( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +) +{ +#ifdef OPUS_CHECK_ASM + const opus_int32 invGain_Q30_c = silk_LPC_inverse_pred_gain_c( A_Q12, order ); +#endif + + opus_int32 invGain_Q30; + if( ( SILK_MAX_ORDER_LPC != 24 ) || ( order & 1 )) { + invGain_Q30 = silk_LPC_inverse_pred_gain_c( A_Q12, order ); + } + else { + opus_int32 Atmp_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 DC_resp; + int16x8_t t0_s16x8, t1_s16x8, t2_s16x8; + int32x4_t t0_s32x4; + const opus_int leftover = order & 7; + + /* Increase Q domain of the AR coefficients */ + t0_s16x8 = vld1q_s16( A_Q12 + 0 ); + t1_s16x8 = vld1q_s16( A_Q12 + 8 ); + if ( order > 16 ) { + t2_s16x8 = vld1q_s16( A_Q12 + 16 ); + } + t0_s32x4 = vpaddlq_s16( t0_s16x8 ); + + switch( order - leftover ) + { + case 24: + t0_s32x4 = vpadalq_s16( t0_s32x4, t2_s16x8 ); + vst1q_s32( Atmp_QA + 16, vshll_n_s16( vget_low_s16 ( t2_s16x8 ), QA - 12 ) ); + vst1q_s32( Atmp_QA + 20, vshll_n_s16( vget_high_s16( t2_s16x8 ), QA - 12 ) ); + /* FALLTHROUGH */ + + case 16: + t0_s32x4 = vpadalq_s16( t0_s32x4, t1_s16x8 ); + vst1q_s32( Atmp_QA + 8, vshll_n_s16( vget_low_s16 ( t1_s16x8 ), QA - 12 ) ); + vst1q_s32( Atmp_QA + 12, vshll_n_s16( vget_high_s16( t1_s16x8 ), QA - 12 ) ); + /* FALLTHROUGH */ + + case 8: + { + const int32x2_t t_s32x2 = vpadd_s32( vget_low_s32( t0_s32x4 ), vget_high_s32( t0_s32x4 ) ); + const int64x1_t t_s64x1 = vpaddl_s32( t_s32x2 ); + DC_resp = vget_lane_s32( vreinterpret_s32_s64( t_s64x1 ), 0 ); + vst1q_s32( Atmp_QA + 0, vshll_n_s16( vget_low_s16 ( t0_s16x8 ), QA - 12 ) ); + vst1q_s32( Atmp_QA + 4, vshll_n_s16( vget_high_s16( t0_s16x8 ), QA - 12 ) ); + } + break; + + default: + DC_resp = 0; + break; + } + A_Q12 += order - leftover; + + switch( leftover ) + { + case 6: + DC_resp += (opus_int32)A_Q12[ 5 ]; + DC_resp += (opus_int32)A_Q12[ 4 ]; + Atmp_QA[ order - leftover + 5 ] = silk_LSHIFT32( (opus_int32)A_Q12[ 5 ], QA - 12 ); + Atmp_QA[ order - leftover + 4 ] = silk_LSHIFT32( (opus_int32)A_Q12[ 4 ], QA - 12 ); + /* FALLTHROUGH */ + + case 4: + DC_resp += (opus_int32)A_Q12[ 3 ]; + DC_resp += (opus_int32)A_Q12[ 2 ]; + Atmp_QA[ order - leftover + 3 ] = silk_LSHIFT32( (opus_int32)A_Q12[ 3 ], QA - 12 ); + Atmp_QA[ order - leftover + 2 ] = silk_LSHIFT32( (opus_int32)A_Q12[ 2 ], QA - 12 ); + /* FALLTHROUGH */ + + case 2: + DC_resp += (opus_int32)A_Q12[ 1 ]; + DC_resp += (opus_int32)A_Q12[ 0 ]; + Atmp_QA[ order - leftover + 1 ] = silk_LSHIFT32( (opus_int32)A_Q12[ 1 ], QA - 12 ); + Atmp_QA[ order - leftover + 0 ] = silk_LSHIFT32( (opus_int32)A_Q12[ 0 ], QA - 12 ); + /* FALLTHROUGH */ + + default: + break; + } + + /* If the DC is unstable, we don't even need to do the full calculations */ + if( DC_resp >= 4096 ) { + invGain_Q30 = 0; + } else { + invGain_Q30 = LPC_inverse_pred_gain_QA_neon( Atmp_QA, order ); + } + } + +#ifdef OPUS_CHECK_ASM + silk_assert( invGain_Q30_c == invGain_Q30 ); +#endif + + return invGain_Q30; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/NSQ_del_dec_arm.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/NSQ_del_dec_arm.h new file mode 100644 index 000000000..9e76e1692 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/NSQ_del_dec_arm.h @@ -0,0 +1,100 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_NSQ_DEL_DEC_ARM_H +#define SILK_NSQ_DEL_DEC_ARM_H + +#include "celt/arm/armcpu.h" + +#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +void silk_NSQ_del_dec_neon( + const silk_encoder_state *psEncC, silk_nsq_state *NSQ, + SideInfoIndices *psIndices, const opus_int16 x16[], opus_int8 pulses[], + const opus_int16 PredCoef_Q12[2 * MAX_LPC_ORDER], + const opus_int16 LTPCoef_Q14[LTP_ORDER * MAX_NB_SUBFR], + const opus_int16 AR_Q13[MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER], + const opus_int HarmShapeGain_Q14[MAX_NB_SUBFR], + const opus_int Tilt_Q14[MAX_NB_SUBFR], + const opus_int32 LF_shp_Q14[MAX_NB_SUBFR], + const opus_int32 Gains_Q16[MAX_NB_SUBFR], + const opus_int pitchL[MAX_NB_SUBFR], const opus_int Lambda_Q10, + const opus_int LTP_scale_Q14); + +#if !defined(OPUS_HAVE_RTCD) +#define OVERRIDE_silk_NSQ_del_dec (1) +#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, \ + LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, \ + LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, \ + LTP_scale_Q14, arch) \ + ((void)(arch), \ + PRESUME_NEON(silk_NSQ_del_dec)( \ + psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, \ + AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, \ + Lambda_Q10, LTP_scale_Q14)) +#endif +#endif + +#if !defined(OVERRIDE_silk_NSQ_del_dec) +/*Is run-time CPU detection enabled on this platform?*/ +#if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && \ + !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern void (*const SILK_NSQ_DEL_DEC_IMPL[OPUS_ARCHMASK + 1])( + const silk_encoder_state *psEncC, silk_nsq_state *NSQ, + SideInfoIndices *psIndices, const opus_int16 x16[], opus_int8 pulses[], + const opus_int16 PredCoef_Q12[2 * MAX_LPC_ORDER], + const opus_int16 LTPCoef_Q14[LTP_ORDER * MAX_NB_SUBFR], + const opus_int16 AR_Q13[MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER], + const opus_int HarmShapeGain_Q14[MAX_NB_SUBFR], + const opus_int Tilt_Q14[MAX_NB_SUBFR], + const opus_int32 LF_shp_Q14[MAX_NB_SUBFR], + const opus_int32 Gains_Q16[MAX_NB_SUBFR], + const opus_int pitchL[MAX_NB_SUBFR], const opus_int Lambda_Q10, + const opus_int LTP_scale_Q14); +#define OVERRIDE_silk_NSQ_del_dec (1) +#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, \ + LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, \ + LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, \ + LTP_scale_Q14, arch) \ + ((*SILK_NSQ_DEL_DEC_IMPL[(arch)&OPUS_ARCHMASK])( \ + psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, \ + AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, \ + Lambda_Q10, LTP_scale_Q14)) +#elif defined(OPUS_ARM_PRESUME_NEON_INTR) +#define OVERRIDE_silk_NSQ_del_dec (1) +#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, \ + LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, \ + LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, \ + LTP_scale_Q14, arch) \ + ((void)(arch), \ + silk_NSQ_del_dec_neon(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, \ + LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, \ + LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, \ + LTP_scale_Q14)) +#endif +#endif + +#endif /* end SILK_NSQ_DEL_DEC_ARM_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/NSQ_del_dec_neon_intr.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/NSQ_del_dec_neon_intr.c new file mode 100644 index 000000000..212410f36 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/NSQ_del_dec_neon_intr.c @@ -0,0 +1,1124 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifdef OPUS_CHECK_ASM +# include +#endif +#include "main.h" +#include "stack_alloc.h" + +/* NEON intrinsics optimization now can only parallelize up to 4 delay decision states. */ +/* If there are more states, C function is called, and this optimization must be expanded. */ +#define NEON_MAX_DEL_DEC_STATES 4 + +typedef struct { + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 RandState[ DECISION_DELAY ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Q_Q10[ DECISION_DELAY ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Xq_Q14[ DECISION_DELAY ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Pred_Q15[ DECISION_DELAY ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Shape_Q14[ DECISION_DELAY ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 LF_AR_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Diff_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Seed[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 SeedInit[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 RD_Q10[ NEON_MAX_DEL_DEC_STATES ]; +} NSQ_del_decs_struct; + +typedef struct { + opus_int32 Q_Q10[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 RD_Q10[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 xq_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 LF_AR_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Diff_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 sLTP_shp_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 LPC_exc_Q14[ NEON_MAX_DEL_DEC_STATES ]; +} NSQ_samples_struct; + +static OPUS_INLINE void silk_nsq_del_dec_scale_states_neon( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_decs_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int16 x16[], /* I Input */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +); + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_neon( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_decs_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay /* I */ +); + +static OPUS_INLINE void copy_winner_state_kernel( + const NSQ_del_decs_struct *psDelDec, + const opus_int offset, + const opus_int last_smple_idx, + const opus_int Winner_ind, + const int32x2_t gain_lo_s32x2, + const int32x2_t gain_hi_s32x2, + const int32x4_t shift_s32x4, + int32x4_t t0_s32x4, + int32x4_t t1_s32x4, + opus_int8 *const pulses, + opus_int16 *pxq, + silk_nsq_state *NSQ +) +{ + int16x8_t t_s16x8; + int32x4_t o0_s32x4, o1_s32x4; + + t0_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 0 ][ Winner_ind ], t0_s32x4, 0 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 1 ][ Winner_ind ], t0_s32x4, 1 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 2 ][ Winner_ind ], t0_s32x4, 2 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 3 ][ Winner_ind ], t0_s32x4, 3 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 4 ][ Winner_ind ], t1_s32x4, 0 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 5 ][ Winner_ind ], t1_s32x4, 1 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 6 ][ Winner_ind ], t1_s32x4, 2 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 7 ][ Winner_ind ], t1_s32x4, 3 ); + t_s16x8 = vcombine_s16( vrshrn_n_s32( t0_s32x4, 10 ), vrshrn_n_s32( t1_s32x4, 10 ) ); + vst1_s8( &pulses[ offset ], vmovn_s16( t_s16x8 ) ); + + t0_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 0 ][ Winner_ind ], t0_s32x4, 0 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 1 ][ Winner_ind ], t0_s32x4, 1 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 2 ][ Winner_ind ], t0_s32x4, 2 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 3 ][ Winner_ind ], t0_s32x4, 3 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 4 ][ Winner_ind ], t1_s32x4, 0 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 5 ][ Winner_ind ], t1_s32x4, 1 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 6 ][ Winner_ind ], t1_s32x4, 2 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 7 ][ Winner_ind ], t1_s32x4, 3 ); + o0_s32x4 = vqdmulhq_lane_s32( t0_s32x4, gain_lo_s32x2, 0 ); + o1_s32x4 = vqdmulhq_lane_s32( t1_s32x4, gain_lo_s32x2, 0 ); + o0_s32x4 = vmlaq_lane_s32( o0_s32x4, t0_s32x4, gain_hi_s32x2, 0 ); + o1_s32x4 = vmlaq_lane_s32( o1_s32x4, t1_s32x4, gain_hi_s32x2, 0 ); + o0_s32x4 = vrshlq_s32( o0_s32x4, shift_s32x4 ); + o1_s32x4 = vrshlq_s32( o1_s32x4, shift_s32x4 ); + vst1_s16( &pxq[ offset + 0 ], vqmovn_s32( o0_s32x4 ) ); + vst1_s16( &pxq[ offset + 4 ], vqmovn_s32( o1_s32x4 ) ); + + t0_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 0 ][ Winner_ind ], t0_s32x4, 0 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 1 ][ Winner_ind ], t0_s32x4, 1 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 2 ][ Winner_ind ], t0_s32x4, 2 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 3 ][ Winner_ind ], t0_s32x4, 3 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 4 ][ Winner_ind ], t1_s32x4, 0 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 5 ][ Winner_ind ], t1_s32x4, 1 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 6 ][ Winner_ind ], t1_s32x4, 2 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 7 ][ Winner_ind ], t1_s32x4, 3 ); + vst1q_s32( &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx + offset + 0 ], t0_s32x4 ); + vst1q_s32( &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx + offset + 4 ], t1_s32x4 ); +} + +static OPUS_INLINE void copy_winner_state( + const NSQ_del_decs_struct *psDelDec, + const opus_int decisionDelay, + const opus_int smpl_buf_idx, + const opus_int Winner_ind, + const opus_int32 gain, + const opus_int32 shift, + opus_int8 *const pulses, + opus_int16 *pxq, + silk_nsq_state *NSQ +) +{ + opus_int i, last_smple_idx; + const int32x2_t gain_lo_s32x2 = vdup_n_s32( silk_LSHIFT32( gain & 0x0000FFFF, 15 ) ); + const int32x2_t gain_hi_s32x2 = vdup_n_s32( gain >> 16 ); + const int32x4_t shift_s32x4 = vdupq_n_s32( -shift ); + int32x4_t t0_s32x4, t1_s32x4; + + t0_s32x4 = t1_s32x4 = vdupq_n_s32( 0 ); /* initialization */ + last_smple_idx = smpl_buf_idx + decisionDelay - 1 + DECISION_DELAY; + if( last_smple_idx >= DECISION_DELAY ) last_smple_idx -= DECISION_DELAY; + if( last_smple_idx >= DECISION_DELAY ) last_smple_idx -= DECISION_DELAY; + + for( i = 0; ( i < ( decisionDelay - 7 ) ) && ( last_smple_idx >= 7 ); i += 8, last_smple_idx -= 8 ) { + copy_winner_state_kernel( psDelDec, i - decisionDelay, last_smple_idx, Winner_ind, gain_lo_s32x2, gain_hi_s32x2, shift_s32x4, t0_s32x4, t1_s32x4, pulses, pxq, NSQ ); + } + for( ; ( i < decisionDelay ) && ( last_smple_idx >= 0 ); i++, last_smple_idx-- ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDelDec->Q_Q10[ last_smple_idx ][ Winner_ind ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( psDelDec->Xq_Q14[ last_smple_idx ][ Winner_ind ], gain ), shift ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDelDec->Shape_Q14[ last_smple_idx ][ Winner_ind ]; + } + + last_smple_idx += DECISION_DELAY; + for( ; i < ( decisionDelay - 7 ); i++, last_smple_idx-- ) { + copy_winner_state_kernel( psDelDec, i - decisionDelay, last_smple_idx, Winner_ind, gain_lo_s32x2, gain_hi_s32x2, shift_s32x4, t0_s32x4, t1_s32x4, pulses, pxq, NSQ ); + } + for( ; i < decisionDelay; i++, last_smple_idx-- ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDelDec->Q_Q10[ last_smple_idx ][ Winner_ind ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( psDelDec->Xq_Q14[ last_smple_idx ][ Winner_ind ], gain ), shift ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDelDec->Shape_Q14[ last_smple_idx ][ Winner_ind ]; + } +} + +void silk_NSQ_del_dec_neon( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ +#ifdef OPUS_CHECK_ASM + silk_nsq_state NSQ_c; + SideInfoIndices psIndices_c; + opus_int8 pulses_c[ MAX_FRAME_LENGTH ]; + const opus_int8 *const pulses_a = pulses; + + ( void )pulses_a; + silk_memcpy( &NSQ_c, NSQ, sizeof( NSQ_c ) ); + silk_memcpy( &psIndices_c, psIndices, sizeof( psIndices_c ) ); + silk_memcpy( pulses_c, pulses, sizeof( pulses_c ) ); + silk_NSQ_del_dec_c( psEncC, &NSQ_c, &psIndices_c, x16, pulses_c, PredCoef_Q12, LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, + pitchL, Lambda_Q10, LTP_scale_Q14 ); +#endif + + /* The optimization parallelizes the different delay decision states. */ + if(( psEncC->nStatesDelayedDecision > NEON_MAX_DEL_DEC_STATES ) || ( psEncC->nStatesDelayedDecision <= 2 )) { + /* NEON intrinsics optimization now can only parallelize up to 4 delay decision states. */ + /* If there are more states, C function is called, and this optimization must be expanded. */ + /* When the number of delay decision states is less than 3, there are penalties using this */ + /* optimization, and C function is called. */ + /* When the number of delay decision states is 2, it's better to specialize another */ + /* structure NSQ_del_dec2_struct and optimize with shorter NEON registers. (Low priority) */ + silk_NSQ_del_dec_c( psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, + Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14 ); + } else { + opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr; + opus_int smpl_buf_idx, decisionDelay; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + opus_int32 RDmin_Q10, Gain_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + VARDECL( opus_int32, delayedGain_Q10 ); + VARDECL( NSQ_del_decs_struct, psDelDec ); + int32x4_t t_s32x4; + SAVE_STACK; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + /* Initialize delayed decision states */ + ALLOC( psDelDec, 1, NSQ_del_decs_struct ); + /* Only RandState and RD_Q10 need to be initialized to 0. */ + silk_memset( psDelDec->RandState, 0, sizeof( psDelDec->RandState ) ); + vst1q_s32( psDelDec->RD_Q10, vdupq_n_s32( 0 ) ); + + for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) { + psDelDec->SeedInit[ k ] = psDelDec->Seed[ k ] = ( k + psIndices->Seed ) & 3; + } + vst1q_s32( psDelDec->LF_AR_Q14, vld1q_dup_s32( &NSQ->sLF_AR_shp_Q14 ) ); + vst1q_s32( psDelDec->Diff_Q14, vld1q_dup_s32( &NSQ->sDiff_shp_Q14 ) ); + vst1q_s32( psDelDec->Shape_Q14[ 0 ], vld1q_dup_s32( &NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ] ) ); + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + vst1q_s32( psDelDec->sLPC_Q14[ i ], vld1q_dup_s32( &NSQ->sLPC_Q14[ i ] ) ); + } + for( i = 0; i < (opus_int)( sizeof( NSQ->sAR2_Q14 ) / sizeof( NSQ->sAR2_Q14[ 0 ] ) ); i++ ) { + vst1q_s32( psDelDec->sAR2_Q14[ i ], vld1q_dup_s32( &NSQ->sAR2_Q14[ i ] ) ); + } + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + smpl_buf_idx = 0; /* index of oldest samples */ + + decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length ); + + /* For voiced frames limit the decision delay to lower than the pitch lag */ + if( psIndices->signalType == TYPE_VOICED ) { + opus_int pitch_min = pitchL[ 0 ]; + for( k = 1; k < psEncC->nb_subfr; k++ ) { + pitch_min = silk_min_int( pitch_min, pitchL[ k ] ); + } + decisionDelay = silk_min_int( decisionDelay, pitch_min - LTP_ORDER / 2 - 1 ); + } else { + if( lag > 0 ) { + decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 ); + } + } + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 ); + /* Set up pointers to start of sub frame */ + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + subfr = 0; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + if( k == 2 ) { + /* RESET DELAYED DECISIONS */ + /* Find winner */ + int32x4_t RD_Q10_s32x4; + RDmin_Q10 = psDelDec->RD_Q10[ 0 ]; + Winner_ind = 0; + for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) { + if( psDelDec->RD_Q10[ i ] < RDmin_Q10 ) { + RDmin_Q10 = psDelDec->RD_Q10[ i ]; + Winner_ind = i; + } + } + psDelDec->RD_Q10[ Winner_ind ] -= ( silk_int32_MAX >> 4 ); + RD_Q10_s32x4 = vld1q_s32( psDelDec->RD_Q10 ); + RD_Q10_s32x4 = vaddq_s32( RD_Q10_s32x4, vdupq_n_s32( silk_int32_MAX >> 4 ) ); + vst1q_s32( psDelDec->RD_Q10, RD_Q10_s32x4 ); + + /* Copy final part of signals from winner state to output and long-term filter states */ + copy_winner_state( psDelDec, decisionDelay, smpl_buf_idx, Winner_ind, Gains_Q16[ 1 ], 14, pulses, pxq, NSQ ); + + subfr = 0; + } + + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + silk_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + NSQ->rewhite_flag = 1; + } + } + + silk_nsq_del_dec_scale_states_neon( psEncC, NSQ, psDelDec, x16, x_sc_Q10, sLTP, sLTP_Q15, k, + LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay ); + + silk_noise_shape_quantizer_del_dec_neon( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, + delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], + Gains_Q16[ k ], Lambda_Q10, offset_Q10, psEncC->subfr_length, subfr++, psEncC->shapingLPCOrder, + psEncC->predictLPCOrder, psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay ); + + x16 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Find winner */ + RDmin_Q10 = psDelDec->RD_Q10[ 0 ]; + Winner_ind = 0; + for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) { + if( psDelDec->RD_Q10[ k ] < RDmin_Q10 ) { + RDmin_Q10 = psDelDec->RD_Q10[ k ]; + Winner_ind = k; + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psIndices->Seed = psDelDec->SeedInit[ Winner_ind ]; + Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 ); + copy_winner_state( psDelDec, decisionDelay, smpl_buf_idx, Winner_ind, Gain_Q10, 8, pulses, pxq, NSQ ); + + t_s32x4 = vdupq_n_s32( 0 ); /* initialization */ + for( i = 0; i < ( NSQ_LPC_BUF_LENGTH - 3 ); i += 4 ) { + t_s32x4 = vld1q_lane_s32( &psDelDec->sLPC_Q14[ i + 0 ][ Winner_ind ], t_s32x4, 0 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sLPC_Q14[ i + 1 ][ Winner_ind ], t_s32x4, 1 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sLPC_Q14[ i + 2 ][ Winner_ind ], t_s32x4, 2 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sLPC_Q14[ i + 3 ][ Winner_ind ], t_s32x4, 3 ); + vst1q_s32( &NSQ->sLPC_Q14[ i ], t_s32x4 ); + } + + for( ; i < NSQ_LPC_BUF_LENGTH; i++ ) { + NSQ->sLPC_Q14[ i ] = psDelDec->sLPC_Q14[ i ][ Winner_ind ]; + } + + for( i = 0; i < (opus_int)( sizeof( NSQ->sAR2_Q14 ) / sizeof( NSQ->sAR2_Q14[ 0 ] ) - 3 ); i += 4 ) { + t_s32x4 = vld1q_lane_s32( &psDelDec->sAR2_Q14[ i + 0 ][ Winner_ind ], t_s32x4, 0 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sAR2_Q14[ i + 1 ][ Winner_ind ], t_s32x4, 1 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sAR2_Q14[ i + 2 ][ Winner_ind ], t_s32x4, 2 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sAR2_Q14[ i + 3 ][ Winner_ind ], t_s32x4, 3 ); + vst1q_s32( &NSQ->sAR2_Q14[ i ], t_s32x4 ); + } + + for( ; i < (opus_int)( sizeof( NSQ->sAR2_Q14 ) / sizeof( NSQ->sAR2_Q14[ 0 ] ) ); i++ ) { + NSQ->sAR2_Q14[ i ] = psDelDec->sAR2_Q14[ i ][ Winner_ind ]; + } + + /* Update states */ + NSQ->sLF_AR_shp_Q14 = psDelDec->LF_AR_Q14[ Winner_ind ]; + NSQ->sDiff_shp_Q14 = psDelDec->Diff_Q14[ Winner_ind ]; + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech signal */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; + } + +#ifdef OPUS_CHECK_ASM + silk_assert( !memcmp( &NSQ_c, NSQ, sizeof( NSQ_c ) ) ); + silk_assert( !memcmp( &psIndices_c, psIndices, sizeof( psIndices_c ) ) ); + silk_assert( !memcmp( pulses_c, pulses_a, sizeof( pulses_c ) ) ); +#endif +} + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +/* Note: Function silk_short_prediction_create_arch_coef_neon() defined in NSQ_neon.h is actually a hacking C function. */ +/* Therefore here we append "_local" to the NEON function name to avoid confusion. */ +static OPUS_INLINE void silk_short_prediction_create_arch_coef_neon_local(opus_int32 *out, const opus_int16 *in, opus_int order) +{ + int16x8_t t_s16x8; + int32x4_t t0_s32x4, t1_s32x4, t2_s32x4, t3_s32x4; + silk_assert( order == 10 || order == 16 ); + + t_s16x8 = vld1q_s16( in + 0 ); /* 7 6 5 4 3 2 1 0 */ + t_s16x8 = vrev64q_s16( t_s16x8 ); /* 4 5 6 7 0 1 2 3 */ + t2_s32x4 = vshll_n_s16( vget_high_s16( t_s16x8 ), 15 ); /* 4 5 6 7 */ + t3_s32x4 = vshll_n_s16( vget_low_s16( t_s16x8 ), 15 ); /* 0 1 2 3 */ + + if( order == 16 ) { + t_s16x8 = vld1q_s16( in + 8 ); /* F E D C B A 9 8 */ + t_s16x8 = vrev64q_s16( t_s16x8 ); /* C D E F 8 9 A B */ + t0_s32x4 = vshll_n_s16( vget_high_s16( t_s16x8 ), 15 ); /* C D E F */ + t1_s32x4 = vshll_n_s16( vget_low_s16( t_s16x8 ), 15 ); /* 8 9 A B */ + } else { + int16x4_t t_s16x4; + + t0_s32x4 = vdupq_n_s32( 0 ); /* zero zero zero zero */ + t_s16x4 = vld1_s16( in + 6 ); /* 9 8 7 6 */ + t_s16x4 = vrev64_s16( t_s16x4 ); /* 6 7 8 9 */ + t1_s32x4 = vshll_n_s16( t_s16x4, 15 ); + t1_s32x4 = vcombine_s32( vget_low_s32(t0_s32x4), vget_low_s32( t1_s32x4 ) ); /* 8 9 zero zero */ + } + vst1q_s32( out + 0, t0_s32x4 ); + vst1q_s32( out + 4, t1_s32x4 ); + vst1q_s32( out + 8, t2_s32x4 ); + vst1q_s32( out + 12, t3_s32x4 ); +} + +static OPUS_INLINE int32x4_t silk_SMLAWB_lane0_neon( + const int32x4_t out_s32x4, + const int32x4_t in_s32x4, + const int32x2_t coef_s32x2 +) +{ + return vaddq_s32( out_s32x4, vqdmulhq_lane_s32( in_s32x4, coef_s32x2, 0 ) ); +} + +static OPUS_INLINE int32x4_t silk_SMLAWB_lane1_neon( + const int32x4_t out_s32x4, + const int32x4_t in_s32x4, + const int32x2_t coef_s32x2 +) +{ + return vaddq_s32( out_s32x4, vqdmulhq_lane_s32( in_s32x4, coef_s32x2, 1 ) ); +} + +/* Note: This function has different return value than silk_noise_shape_quantizer_short_prediction_neon(). */ +/* Therefore here we append "_local" to the function name to avoid confusion. */ +static OPUS_INLINE int32x4_t silk_noise_shape_quantizer_short_prediction_neon_local(const opus_int32 *buf32, const opus_int32 *a_Q12_arch, opus_int order) +{ + const int32x4_t a_Q12_arch0_s32x4 = vld1q_s32( a_Q12_arch + 0 ); + const int32x4_t a_Q12_arch1_s32x4 = vld1q_s32( a_Q12_arch + 4 ); + const int32x4_t a_Q12_arch2_s32x4 = vld1q_s32( a_Q12_arch + 8 ); + const int32x4_t a_Q12_arch3_s32x4 = vld1q_s32( a_Q12_arch + 12 ); + int32x4_t LPC_pred_Q14_s32x4; + + silk_assert( order == 10 || order == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q14_s32x4 = vdupq_n_s32( silk_RSHIFT( order, 1 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 0 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch0_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 1 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch0_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 2 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch0_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 3 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch0_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 4 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch1_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 5 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch1_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 6 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch1_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 7 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch1_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 8 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch2_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 9 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch2_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 10 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch2_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 11 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch2_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 12 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch3_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 13 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch3_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 14 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch3_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 15 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch3_s32x4 ) ); + + return LPC_pred_Q14_s32x4; +} + +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_neon( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_decs_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay /* I */ +) +{ + opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + opus_int32 Winner_rand_state; + opus_int32 LTP_pred_Q14, n_LTP_Q14; + opus_int32 RDmin_Q10, RDmax_Q10; + opus_int32 Gain_Q10; + opus_int32 *pred_lag_ptr, *shp_lag_ptr; + opus_int32 a_Q12_arch[MAX_LPC_ORDER]; + const int32x2_t warping_Q16_s32x2 = vdup_n_s32( silk_LSHIFT32( warping_Q16, 16 ) >> 1 ); + const opus_int32 LF_shp_Q29 = silk_LSHIFT32( LF_shp_Q14, 16 ) >> 1; + opus_int32 AR_shp_Q28[ MAX_SHAPE_LPC_ORDER ]; + const uint32x4_t rand_multiplier_u32x4 = vdupq_n_u32( RAND_MULTIPLIER ); + const uint32x4_t rand_increment_u32x4 = vdupq_n_u32( RAND_INCREMENT ); + + VARDECL( NSQ_samples_struct, psSampleState ); + SAVE_STACK; + + silk_assert( nStatesDelayedDecision > 0 ); + silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + ALLOC( psSampleState, 2, NSQ_samples_struct ); + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + for( i = 0; i < ( MAX_SHAPE_LPC_ORDER - 7 ); i += 8 ) { + const int16x8_t t_s16x8 = vld1q_s16( AR_shp_Q13 + i ); + vst1q_s32( AR_shp_Q28 + i + 0, vshll_n_s16( vget_low_s16( t_s16x8 ), 15 ) ); + vst1q_s32( AR_shp_Q28 + i + 4, vshll_n_s16( vget_high_s16( t_s16x8 ), 15 ) ); + } + + for( ; i < MAX_SHAPE_LPC_ORDER; i++ ) { + AR_shp_Q28[i] = silk_LSHIFT32( AR_shp_Q13[i], 15 ); + } + + silk_short_prediction_create_arch_coef_neon_local( a_Q12_arch, a_Q12, predictLPCOrder ); + + for( i = 0; i < length; i++ ) { + int32x4_t Seed_s32x4, LPC_pred_Q14_s32x4; + int32x4_t sign_s32x4, tmp1_s32x4, tmp2_s32x4; + int32x4_t n_AR_Q14_s32x4, n_LF_Q14_s32x4; + int32x2_t AR_shp_Q28_s32x2; + int16x4_t r_Q10_s16x4, rr_Q10_s16x4; + + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q14 = 2; + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */ + pred_lag_ptr++; + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */ + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + + /* Generate dither */ + Seed_s32x4 = vld1q_s32( psDelDec->Seed ); + Seed_s32x4 = vreinterpretq_s32_u32( vmlaq_u32( rand_increment_u32x4, vreinterpretq_u32_s32( Seed_s32x4 ), rand_multiplier_u32x4 ) ); + vst1q_s32( psDelDec->Seed, Seed_s32x4 ); + + /* Short-term prediction */ + LPC_pred_Q14_s32x4 = silk_noise_shape_quantizer_short_prediction_neon_local(psDelDec->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 16 + i ], a_Q12_arch, predictLPCOrder); + LPC_pred_Q14_s32x4 = vshlq_n_s32( LPC_pred_Q14_s32x4, 4 ); /* Q10 -> Q14 */ + + /* Noise shape feedback */ + /* Output of lowpass section */ + tmp2_s32x4 = silk_SMLAWB_lane0_neon( vld1q_s32( psDelDec->Diff_Q14 ), vld1q_s32( psDelDec->sAR2_Q14[ 0 ] ), warping_Q16_s32x2 ); + /* Output of allpass section */ + tmp1_s32x4 = vsubq_s32( vld1q_s32( psDelDec->sAR2_Q14[ 1 ] ), tmp2_s32x4 ); + tmp1_s32x4 = silk_SMLAWB_lane0_neon( vld1q_s32( psDelDec->sAR2_Q14[ 0 ] ), tmp1_s32x4, warping_Q16_s32x2 ); + vst1q_s32( psDelDec->sAR2_Q14[ 0 ], tmp2_s32x4 ); + AR_shp_Q28_s32x2 = vld1_s32( AR_shp_Q28 ); + n_AR_Q14_s32x4 = vaddq_s32( vdupq_n_s32( silk_RSHIFT( shapingLPCOrder, 1 ) ), vqdmulhq_lane_s32( tmp2_s32x4, AR_shp_Q28_s32x2, 0 ) ); + + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + /* Output of allpass section */ + tmp2_s32x4 = vsubq_s32( vld1q_s32( psDelDec->sAR2_Q14[ j + 0 ] ), tmp1_s32x4 ); + tmp2_s32x4 = silk_SMLAWB_lane0_neon( vld1q_s32( psDelDec->sAR2_Q14[ j - 1 ] ), tmp2_s32x4, warping_Q16_s32x2 ); + vst1q_s32( psDelDec->sAR2_Q14[ j - 1 ], tmp1_s32x4 ); + n_AR_Q14_s32x4 = vaddq_s32( n_AR_Q14_s32x4, vqdmulhq_lane_s32( tmp1_s32x4, AR_shp_Q28_s32x2, 1 ) ); + /* Output of allpass section */ + tmp1_s32x4 = vsubq_s32( vld1q_s32( psDelDec->sAR2_Q14[ j + 1 ] ), tmp2_s32x4 ); + tmp1_s32x4 = silk_SMLAWB_lane0_neon( vld1q_s32( psDelDec->sAR2_Q14[ j + 0 ] ), tmp1_s32x4, warping_Q16_s32x2 ); + vst1q_s32( psDelDec->sAR2_Q14[ j + 0 ], tmp2_s32x4 ); + AR_shp_Q28_s32x2 = vld1_s32( &AR_shp_Q28[ j ] ); + n_AR_Q14_s32x4 = vaddq_s32( n_AR_Q14_s32x4, vqdmulhq_lane_s32( tmp2_s32x4, AR_shp_Q28_s32x2, 0 ) ); + } + vst1q_s32( psDelDec->sAR2_Q14[ shapingLPCOrder - 1 ], tmp1_s32x4 ); + n_AR_Q14_s32x4 = vaddq_s32( n_AR_Q14_s32x4, vqdmulhq_lane_s32( tmp1_s32x4, AR_shp_Q28_s32x2, 1 ) ); + n_AR_Q14_s32x4 = vshlq_n_s32( n_AR_Q14_s32x4, 1 ); /* Q11 -> Q12 */ + n_AR_Q14_s32x4 = vaddq_s32( n_AR_Q14_s32x4, vqdmulhq_n_s32( vld1q_s32( psDelDec->LF_AR_Q14 ), silk_LSHIFT32( Tilt_Q14, 16 ) >> 1 ) ); /* Q12 */ + n_AR_Q14_s32x4 = vshlq_n_s32( n_AR_Q14_s32x4, 2 ); /* Q12 -> Q14 */ + n_LF_Q14_s32x4 = vqdmulhq_n_s32( vld1q_s32( psDelDec->Shape_Q14[ *smpl_buf_idx ] ), LF_shp_Q29 ); /* Q12 */ + n_LF_Q14_s32x4 = vaddq_s32( n_LF_Q14_s32x4, vqdmulhq_n_s32( vld1q_s32( psDelDec->LF_AR_Q14 ), silk_LSHIFT32( LF_shp_Q14 >> 16 , 15 ) ) ); /* Q12 */ + n_LF_Q14_s32x4 = vshlq_n_s32( n_LF_Q14_s32x4, 2 ); /* Q12 -> Q14 */ + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1_s32x4 = vaddq_s32( n_AR_Q14_s32x4, n_LF_Q14_s32x4 ); /* Q14 */ + tmp2_s32x4 = vaddq_s32( vdupq_n_s32( n_LTP_Q14 ), LPC_pred_Q14_s32x4 ); /* Q13 */ + tmp1_s32x4 = vsubq_s32( tmp2_s32x4, tmp1_s32x4 ); /* Q13 */ + tmp1_s32x4 = vrshrq_n_s32( tmp1_s32x4, 4 ); /* Q10 */ + tmp1_s32x4 = vsubq_s32( vdupq_n_s32( x_Q10[ i ] ), tmp1_s32x4 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + sign_s32x4 = vreinterpretq_s32_u32( vcltq_s32( Seed_s32x4, vdupq_n_s32( 0 ) ) ); + tmp1_s32x4 = veorq_s32( tmp1_s32x4, sign_s32x4 ); + tmp1_s32x4 = vsubq_s32( tmp1_s32x4, sign_s32x4 ); + tmp1_s32x4 = vmaxq_s32( tmp1_s32x4, vdupq_n_s32( -( 31 << 10 ) ) ); + tmp1_s32x4 = vminq_s32( tmp1_s32x4, vdupq_n_s32( 30 << 10 ) ); + r_Q10_s16x4 = vmovn_s32( tmp1_s32x4 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + { + int16x4_t q1_Q10_s16x4 = vsub_s16( r_Q10_s16x4, vdup_n_s16( offset_Q10 ) ); + int16x4_t q1_Q0_s16x4 = vshr_n_s16( q1_Q10_s16x4, 10 ); + int16x4_t q2_Q10_s16x4; + int32x4_t rd1_Q10_s32x4, rd2_Q10_s32x4; + uint32x4_t t_u32x4; + + if( Lambda_Q10 > 2048 ) { + /* For aggressive RDO, the bias becomes more than one pulse. */ + const int rdo_offset = Lambda_Q10/2 - 512; + const uint16x4_t greaterThanRdo = vcgt_s16( q1_Q10_s16x4, vdup_n_s16( rdo_offset ) ); + const uint16x4_t lessThanMinusRdo = vclt_s16( q1_Q10_s16x4, vdup_n_s16( -rdo_offset ) ); + /* If Lambda_Q10 > 32767, then q1_Q0, q1_Q10 and q2_Q10 must change to 32-bit. */ + silk_assert( Lambda_Q10 <= 32767 ); + + q1_Q0_s16x4 = vreinterpret_s16_u16( vclt_s16( q1_Q10_s16x4, vdup_n_s16( 0 ) ) ); + q1_Q0_s16x4 = vbsl_s16( greaterThanRdo, vsub_s16( q1_Q10_s16x4, vdup_n_s16( rdo_offset ) ), q1_Q0_s16x4 ); + q1_Q0_s16x4 = vbsl_s16( lessThanMinusRdo, vadd_s16( q1_Q10_s16x4, vdup_n_s16( rdo_offset ) ), q1_Q0_s16x4 ); + q1_Q0_s16x4 = vshr_n_s16( q1_Q0_s16x4, 10 ); + } + { + const uint16x4_t equal0_u16x4 = vceq_s16( q1_Q0_s16x4, vdup_n_s16( 0 ) ); + const uint16x4_t equalMinus1_u16x4 = vceq_s16( q1_Q0_s16x4, vdup_n_s16( -1 ) ); + const uint16x4_t lessThanMinus1_u16x4 = vclt_s16( q1_Q0_s16x4, vdup_n_s16( -1 ) ); + int16x4_t tmp1_s16x4, tmp2_s16x4; + + q1_Q10_s16x4 = vshl_n_s16( q1_Q0_s16x4, 10 ); + tmp1_s16x4 = vadd_s16( q1_Q10_s16x4, vdup_n_s16( offset_Q10 - QUANT_LEVEL_ADJUST_Q10 ) ); + q1_Q10_s16x4 = vadd_s16( q1_Q10_s16x4, vdup_n_s16( offset_Q10 + QUANT_LEVEL_ADJUST_Q10 ) ); + q1_Q10_s16x4 = vbsl_s16( lessThanMinus1_u16x4, q1_Q10_s16x4, tmp1_s16x4 ); + q1_Q10_s16x4 = vbsl_s16( equal0_u16x4, vdup_n_s16( offset_Q10 ), q1_Q10_s16x4 ); + q1_Q10_s16x4 = vbsl_s16( equalMinus1_u16x4, vdup_n_s16( offset_Q10 - ( 1024 - QUANT_LEVEL_ADJUST_Q10 ) ), q1_Q10_s16x4 ); + q2_Q10_s16x4 = vadd_s16( q1_Q10_s16x4, vdup_n_s16( 1024 ) ); + q2_Q10_s16x4 = vbsl_s16( equal0_u16x4, vdup_n_s16( offset_Q10 + 1024 - QUANT_LEVEL_ADJUST_Q10 ), q2_Q10_s16x4 ); + q2_Q10_s16x4 = vbsl_s16( equalMinus1_u16x4, vdup_n_s16( offset_Q10 ), q2_Q10_s16x4 ); + tmp1_s16x4 = q1_Q10_s16x4; + tmp2_s16x4 = q2_Q10_s16x4; + tmp1_s16x4 = vbsl_s16( vorr_u16( equalMinus1_u16x4, lessThanMinus1_u16x4 ), vneg_s16( tmp1_s16x4 ), tmp1_s16x4 ); + tmp2_s16x4 = vbsl_s16( lessThanMinus1_u16x4, vneg_s16( tmp2_s16x4 ), tmp2_s16x4 ); + rd1_Q10_s32x4 = vmull_s16( tmp1_s16x4, vdup_n_s16( Lambda_Q10 ) ); + rd2_Q10_s32x4 = vmull_s16( tmp2_s16x4, vdup_n_s16( Lambda_Q10 ) ); + } + + rr_Q10_s16x4 = vsub_s16( r_Q10_s16x4, q1_Q10_s16x4 ); + rd1_Q10_s32x4 = vmlal_s16( rd1_Q10_s32x4, rr_Q10_s16x4, rr_Q10_s16x4 ); + rd1_Q10_s32x4 = vshrq_n_s32( rd1_Q10_s32x4, 10 ); + + rr_Q10_s16x4 = vsub_s16( r_Q10_s16x4, q2_Q10_s16x4 ); + rd2_Q10_s32x4 = vmlal_s16( rd2_Q10_s32x4, rr_Q10_s16x4, rr_Q10_s16x4 ); + rd2_Q10_s32x4 = vshrq_n_s32( rd2_Q10_s32x4, 10 ); + + tmp2_s32x4 = vld1q_s32( psDelDec->RD_Q10 ); + tmp1_s32x4 = vaddq_s32( tmp2_s32x4, vminq_s32( rd1_Q10_s32x4, rd2_Q10_s32x4 ) ); + tmp2_s32x4 = vaddq_s32( tmp2_s32x4, vmaxq_s32( rd1_Q10_s32x4, rd2_Q10_s32x4 ) ); + vst1q_s32( psSampleState[ 0 ].RD_Q10, tmp1_s32x4 ); + vst1q_s32( psSampleState[ 1 ].RD_Q10, tmp2_s32x4 ); + t_u32x4 = vcltq_s32( rd1_Q10_s32x4, rd2_Q10_s32x4 ); + tmp1_s32x4 = vbslq_s32( t_u32x4, vmovl_s16( q1_Q10_s16x4 ), vmovl_s16( q2_Q10_s16x4 ) ); + tmp2_s32x4 = vbslq_s32( t_u32x4, vmovl_s16( q2_Q10_s16x4 ), vmovl_s16( q1_Q10_s16x4 ) ); + vst1q_s32( psSampleState[ 0 ].Q_Q10, tmp1_s32x4 ); + vst1q_s32( psSampleState[ 1 ].Q_Q10, tmp2_s32x4 ); + } + + { + /* Update states for best quantization */ + int32x4_t exc_Q14_s32x4, LPC_exc_Q14_s32x4, xq_Q14_s32x4, sLF_AR_shp_Q14_s32x4; + + /* Quantized excitation */ + exc_Q14_s32x4 = vshlq_n_s32( tmp1_s32x4, 4 ); + exc_Q14_s32x4 = veorq_s32( exc_Q14_s32x4, sign_s32x4 ); + exc_Q14_s32x4 = vsubq_s32( exc_Q14_s32x4, sign_s32x4 ); + + /* Add predictions */ + LPC_exc_Q14_s32x4 = vaddq_s32( exc_Q14_s32x4, vdupq_n_s32( LTP_pred_Q14 ) ); + xq_Q14_s32x4 = vaddq_s32( LPC_exc_Q14_s32x4, LPC_pred_Q14_s32x4 ); + + /* Update states */ + tmp1_s32x4 = vsubq_s32( xq_Q14_s32x4, vshlq_n_s32( vdupq_n_s32( x_Q10[ i ] ), 4 ) ); + vst1q_s32( psSampleState[ 0 ].Diff_Q14, tmp1_s32x4 ); + sLF_AR_shp_Q14_s32x4 = vsubq_s32( tmp1_s32x4, n_AR_Q14_s32x4 ); + vst1q_s32( psSampleState[ 0 ].sLTP_shp_Q14, vsubq_s32( sLF_AR_shp_Q14_s32x4, n_LF_Q14_s32x4 ) ); + vst1q_s32( psSampleState[ 0 ].LF_AR_Q14, sLF_AR_shp_Q14_s32x4 ); + vst1q_s32( psSampleState[ 0 ].LPC_exc_Q14, LPC_exc_Q14_s32x4 ); + vst1q_s32( psSampleState[ 0 ].xq_Q14, xq_Q14_s32x4 ); + + /* Quantized excitation */ + exc_Q14_s32x4 = vshlq_n_s32( tmp2_s32x4, 4 ); + exc_Q14_s32x4 = veorq_s32( exc_Q14_s32x4, sign_s32x4 ); + exc_Q14_s32x4 = vsubq_s32( exc_Q14_s32x4, sign_s32x4 ); + + /* Add predictions */ + LPC_exc_Q14_s32x4 = vaddq_s32( exc_Q14_s32x4, vdupq_n_s32( LTP_pred_Q14 ) ); + xq_Q14_s32x4 = vaddq_s32( LPC_exc_Q14_s32x4, LPC_pred_Q14_s32x4 ); + + /* Update states */ + tmp1_s32x4 = vsubq_s32( xq_Q14_s32x4, vshlq_n_s32( vdupq_n_s32( x_Q10[ i ] ), 4 ) ); + vst1q_s32( psSampleState[ 1 ].Diff_Q14, tmp1_s32x4 ); + sLF_AR_shp_Q14_s32x4 = vsubq_s32( tmp1_s32x4, n_AR_Q14_s32x4 ); + vst1q_s32( psSampleState[ 1 ].sLTP_shp_Q14, vsubq_s32( sLF_AR_shp_Q14_s32x4, n_LF_Q14_s32x4 ) ); + vst1q_s32( psSampleState[ 1 ].LF_AR_Q14, sLF_AR_shp_Q14_s32x4 ); + vst1q_s32( psSampleState[ 1 ].LPC_exc_Q14, LPC_exc_Q14_s32x4 ); + vst1q_s32( psSampleState[ 1 ].xq_Q14, xq_Q14_s32x4 ); + } + + *smpl_buf_idx = *smpl_buf_idx ? ( *smpl_buf_idx - 1 ) : ( DECISION_DELAY - 1); + last_smple_idx = *smpl_buf_idx + decisionDelay + DECISION_DELAY; + if( last_smple_idx >= DECISION_DELAY ) last_smple_idx -= DECISION_DELAY; + if( last_smple_idx >= DECISION_DELAY ) last_smple_idx -= DECISION_DELAY; + + /* Find winner */ + RDmin_Q10 = psSampleState[ 0 ].RD_Q10[ 0 ]; + Winner_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + if( psSampleState[ 0 ].RD_Q10[ k ] < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ 0 ].RD_Q10[ k ]; + Winner_ind = k; + } + } + + /* Increase RD values of expired states */ + { + uint32x4_t t_u32x4; + Winner_rand_state = psDelDec->RandState[ last_smple_idx ][ Winner_ind ]; + t_u32x4 = vceqq_s32( vld1q_s32( psDelDec->RandState[ last_smple_idx ] ), vdupq_n_s32( Winner_rand_state ) ); + t_u32x4 = vmvnq_u32( t_u32x4 ); + t_u32x4 = vshrq_n_u32( t_u32x4, 5 ); + tmp1_s32x4 = vld1q_s32( psSampleState[ 0 ].RD_Q10 ); + tmp2_s32x4 = vld1q_s32( psSampleState[ 1 ].RD_Q10 ); + tmp1_s32x4 = vaddq_s32( tmp1_s32x4, vreinterpretq_s32_u32( t_u32x4 ) ); + tmp2_s32x4 = vaddq_s32( tmp2_s32x4, vreinterpretq_s32_u32( t_u32x4 ) ); + vst1q_s32( psSampleState[ 0 ].RD_Q10, tmp1_s32x4 ); + vst1q_s32( psSampleState[ 1 ].RD_Q10, tmp2_s32x4 ); + + /* Find worst in first set and best in second set */ + RDmax_Q10 = psSampleState[ 0 ].RD_Q10[ 0 ]; + RDmin_Q10 = psSampleState[ 1 ].RD_Q10[ 0 ]; + RDmax_ind = 0; + RDmin_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + /* find worst in first set */ + if( psSampleState[ 0 ].RD_Q10[ k ] > RDmax_Q10 ) { + RDmax_Q10 = psSampleState[ 0 ].RD_Q10[ k ]; + RDmax_ind = k; + } + /* find best in second set */ + if( psSampleState[ 1 ].RD_Q10[ k ] < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ 1 ].RD_Q10[ k ]; + RDmin_ind = k; + } + } + } + + /* Replace a state if best from second set outperforms worst in first set */ + if( RDmin_Q10 < RDmax_Q10 ) { + opus_int32 (*ptr)[NEON_MAX_DEL_DEC_STATES] = psDelDec->RandState; + const int numOthers = (int)( ( sizeof( NSQ_del_decs_struct ) - sizeof( ( (NSQ_del_decs_struct *)0 )->sLPC_Q14 ) ) + / ( NEON_MAX_DEL_DEC_STATES * sizeof( opus_int32 ) ) ); + /* Only ( predictLPCOrder - 1 ) of sLPC_Q14 buffer need to be updated, though the first several */ + /* useless sLPC_Q14[] will be different comparing with C when predictLPCOrder < NSQ_LPC_BUF_LENGTH. */ + /* Here just update constant ( NSQ_LPC_BUF_LENGTH - 1 ) for simplicity. */ + for( j = i + 1; j < i + NSQ_LPC_BUF_LENGTH; j++ ) { + psDelDec->sLPC_Q14[ j ][ RDmax_ind ] = psDelDec->sLPC_Q14[ j ][ RDmin_ind ]; + } + for( j = 0; j < numOthers; j++ ) { + ptr[ j ][ RDmax_ind ] = ptr[ j ][ RDmin_ind ]; + } + + psSampleState[ 0 ].Q_Q10[ RDmax_ind ] = psSampleState[ 1 ].Q_Q10[ RDmin_ind ]; + psSampleState[ 0 ].RD_Q10[ RDmax_ind ] = psSampleState[ 1 ].RD_Q10[ RDmin_ind ]; + psSampleState[ 0 ].xq_Q14[ RDmax_ind ] = psSampleState[ 1 ].xq_Q14[ RDmin_ind ]; + psSampleState[ 0 ].LF_AR_Q14[ RDmax_ind ] = psSampleState[ 1 ].LF_AR_Q14[ RDmin_ind ]; + psSampleState[ 0 ].Diff_Q14[ RDmax_ind ] = psSampleState[ 1 ].Diff_Q14[ RDmin_ind ]; + psSampleState[ 0 ].sLTP_shp_Q14[ RDmax_ind ] = psSampleState[ 1 ].sLTP_shp_Q14[ RDmin_ind ]; + psSampleState[ 0 ].LPC_exc_Q14[ RDmax_ind ] = psSampleState[ 1 ].LPC_exc_Q14[ RDmin_ind ]; + } + + /* Write samples from winner to output and long-term filter states */ + if( subfr > 0 || i >= decisionDelay ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDelDec->Q_Q10[ last_smple_idx ][ Winner_ind ], 10 ); + xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDelDec->Xq_Q14[ last_smple_idx ][ Winner_ind ], delayedGain_Q10[ last_smple_idx ] ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDelDec->Shape_Q14[ last_smple_idx ][ Winner_ind ]; + sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDelDec->Pred_Q15[ last_smple_idx ][ Winner_ind ]; + } + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Update states */ + vst1q_s32( psDelDec->LF_AR_Q14, vld1q_s32( psSampleState[ 0 ].LF_AR_Q14 ) ); + vst1q_s32( psDelDec->Diff_Q14, vld1q_s32( psSampleState[ 0 ].Diff_Q14 ) ); + vst1q_s32( psDelDec->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ], vld1q_s32( psSampleState[ 0 ].xq_Q14 ) ); + vst1q_s32( psDelDec->Xq_Q14[ *smpl_buf_idx ], vld1q_s32( psSampleState[ 0 ].xq_Q14 ) ); + tmp1_s32x4 = vld1q_s32( psSampleState[ 0 ].Q_Q10 ); + vst1q_s32( psDelDec->Q_Q10[ *smpl_buf_idx ], tmp1_s32x4 ); + vst1q_s32( psDelDec->Pred_Q15[ *smpl_buf_idx ], vshlq_n_s32( vld1q_s32( psSampleState[ 0 ].LPC_exc_Q14 ), 1 ) ); + vst1q_s32( psDelDec->Shape_Q14[ *smpl_buf_idx ], vld1q_s32( psSampleState[ 0 ].sLTP_shp_Q14 ) ); + tmp1_s32x4 = vrshrq_n_s32( tmp1_s32x4, 10 ); + tmp1_s32x4 = vaddq_s32( vld1q_s32( psDelDec->Seed ), tmp1_s32x4 ); + vst1q_s32( psDelDec->Seed, tmp1_s32x4 ); + vst1q_s32( psDelDec->RandState[ *smpl_buf_idx ], tmp1_s32x4 ); + vst1q_s32( psDelDec->RD_Q10, vld1q_s32( psSampleState[ 0 ].RD_Q10 ) ); + delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10; + } + /* Update LPC states */ + silk_memcpy( psDelDec->sLPC_Q14[ 0 ], psDelDec->sLPC_Q14[ length ], NEON_MAX_DEL_DEC_STATES * NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + + RESTORE_STACK; +} + +static OPUS_INLINE void silk_SMULWB_8_neon( + const opus_int16 *a, + const int32x2_t b, + opus_int32 *o +) +{ + const int16x8_t a_s16x8 = vld1q_s16( a ); + int32x4_t o0_s32x4, o1_s32x4; + + o0_s32x4 = vshll_n_s16( vget_low_s16( a_s16x8 ), 15 ); + o1_s32x4 = vshll_n_s16( vget_high_s16( a_s16x8 ), 15 ); + o0_s32x4 = vqdmulhq_lane_s32( o0_s32x4, b, 0 ); + o1_s32x4 = vqdmulhq_lane_s32( o1_s32x4, b, 0 ); + vst1q_s32( o, o0_s32x4 ); + vst1q_s32( o + 4, o1_s32x4 ); +} + +/* Only works when ( b >= -65536 ) && ( b < 65536 ). */ +static OPUS_INLINE void silk_SMULWW_small_b_4_neon( + opus_int32 *a, + const int32x2_t b_s32x2) +{ + int32x4_t o_s32x4; + + o_s32x4 = vld1q_s32( a ); + o_s32x4 = vqdmulhq_lane_s32( o_s32x4, b_s32x2, 0 ); + vst1q_s32( a, o_s32x4 ); +} + +/* Only works when ( b >= -65536 ) && ( b < 65536 ). */ +static OPUS_INLINE void silk_SMULWW_small_b_8_neon( + opus_int32 *a, + const int32x2_t b_s32x2 +) +{ + int32x4_t o0_s32x4, o1_s32x4; + + o0_s32x4 = vld1q_s32( a ); + o1_s32x4 = vld1q_s32( a + 4 ); + o0_s32x4 = vqdmulhq_lane_s32( o0_s32x4, b_s32x2, 0 ); + o1_s32x4 = vqdmulhq_lane_s32( o1_s32x4, b_s32x2, 0 ); + vst1q_s32( a, o0_s32x4 ); + vst1q_s32( a + 4, o1_s32x4 ); +} + +static OPUS_INLINE void silk_SMULWW_4_neon( + opus_int32 *a, + const int32x2_t b_s32x2) +{ + int32x4_t a_s32x4, o_s32x4; + + a_s32x4 = vld1q_s32( a ); + o_s32x4 = vqdmulhq_lane_s32( a_s32x4, b_s32x2, 0 ); + o_s32x4 = vmlaq_lane_s32( o_s32x4, a_s32x4, b_s32x2, 1 ); + vst1q_s32( a, o_s32x4 ); +} + +static OPUS_INLINE void silk_SMULWW_8_neon( + opus_int32 *a, + const int32x2_t b_s32x2 +) +{ + int32x4_t a0_s32x4, a1_s32x4, o0_s32x4, o1_s32x4; + + a0_s32x4 = vld1q_s32( a ); + a1_s32x4 = vld1q_s32( a + 4 ); + o0_s32x4 = vqdmulhq_lane_s32( a0_s32x4, b_s32x2, 0 ); + o1_s32x4 = vqdmulhq_lane_s32( a1_s32x4, b_s32x2, 0 ); + o0_s32x4 = vmlaq_lane_s32( o0_s32x4, a0_s32x4, b_s32x2, 1 ); + o1_s32x4 = vmlaq_lane_s32( o1_s32x4, a1_s32x4, b_s32x2, 1 ); + vst1q_s32( a, o0_s32x4 ); + vst1q_s32( a + 4, o1_s32x4 ); +} + +static OPUS_INLINE void silk_SMULWW_loop_neon( + const opus_int16 *a, + const opus_int32 b, + opus_int32 *o, + const opus_int loop_num +) +{ + opus_int i; + int32x2_t b_s32x2; + + b_s32x2 = vdup_n_s32( b ); + for( i = 0; i < loop_num - 7; i += 8 ) { + silk_SMULWB_8_neon( a + i, b_s32x2, o + i ); + } + for( ; i < loop_num; i++ ) { + o[ i ] = silk_SMULWW( a[ i ], b ); + } +} + +static OPUS_INLINE void silk_nsq_del_dec_scale_states_neon( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_decs_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int16 x16[], /* I Input */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +) +{ + opus_int i, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Scale input */ + inv_gain_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 ); + silk_SMULWW_loop_neon( x16, inv_gain_Q26, x_sc_Q10, psEncC->subfr_length ); + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + silk_SMULWW_loop_neon( sLTP + NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2, inv_gain_Q31, sLTP_Q15 + NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2, lag + LTP_ORDER / 2 ); + } + + /* Adjust for changing gain */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + int32x2_t gain_adj_Q16_s32x2; + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + + /* Scale long-term shaping state */ + if( ( gain_adj_Q16 >= -65536 ) && ( gain_adj_Q16 < 65536 ) ) { + gain_adj_Q16_s32x2 = vdup_n_s32( silk_LSHIFT32( gain_adj_Q16, 15 ) ); + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx - 7; i += 8 ) { + silk_SMULWW_small_b_8_neon( NSQ->sLTP_shp_Q14 + i, gain_adj_Q16_s32x2 ); + } + for( ; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay - 7; i += 8 ) { + silk_SMULWW_small_b_8_neon( sLTP_Q15 + i, gain_adj_Q16_s32x2 ); + } + for( ; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + /* Scale scalar states */ + silk_SMULWW_small_b_4_neon( psDelDec->LF_AR_Q14, gain_adj_Q16_s32x2 ); + silk_SMULWW_small_b_4_neon( psDelDec->Diff_Q14, gain_adj_Q16_s32x2 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + silk_SMULWW_small_b_4_neon( psDelDec->sLPC_Q14[ i ], gain_adj_Q16_s32x2 ); + } + + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + silk_SMULWW_small_b_4_neon( psDelDec->sAR2_Q14[ i ], gain_adj_Q16_s32x2 ); + } + + for( i = 0; i < DECISION_DELAY; i++ ) { + silk_SMULWW_small_b_4_neon( psDelDec->Pred_Q15[ i ], gain_adj_Q16_s32x2 ); + silk_SMULWW_small_b_4_neon( psDelDec->Shape_Q14[ i ], gain_adj_Q16_s32x2 ); + } + } else { + gain_adj_Q16_s32x2 = vdup_n_s32( silk_LSHIFT32( gain_adj_Q16 & 0x0000FFFF, 15 ) ); + gain_adj_Q16_s32x2 = vset_lane_s32( gain_adj_Q16 >> 16, gain_adj_Q16_s32x2, 1 ); + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx - 7; i += 8 ) { + silk_SMULWW_8_neon( NSQ->sLTP_shp_Q14 + i, gain_adj_Q16_s32x2 ); + } + for( ; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay - 7; i += 8 ) { + silk_SMULWW_8_neon( sLTP_Q15 + i, gain_adj_Q16_s32x2 ); + } + for( ; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + /* Scale scalar states */ + silk_SMULWW_4_neon( psDelDec->LF_AR_Q14, gain_adj_Q16_s32x2 ); + silk_SMULWW_4_neon( psDelDec->Diff_Q14, gain_adj_Q16_s32x2 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + silk_SMULWW_4_neon( psDelDec->sLPC_Q14[ i ], gain_adj_Q16_s32x2 ); + } + + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + silk_SMULWW_4_neon( psDelDec->sAR2_Q14[ i ], gain_adj_Q16_s32x2 ); + } + + for( i = 0; i < DECISION_DELAY; i++ ) { + silk_SMULWW_4_neon( psDelDec->Pred_Q15[ i ], gain_adj_Q16_s32x2 ); + silk_SMULWW_4_neon( psDelDec->Shape_Q14[ i ], gain_adj_Q16_s32x2 ); + } + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/NSQ_neon.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/NSQ_neon.c new file mode 100644 index 000000000..964252997 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/NSQ_neon.c @@ -0,0 +1,112 @@ +/*********************************************************************** +Copyright (C) 2014 Vidyo +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main.h" +#include "stack_alloc.h" +#include "NSQ.h" +#include "celt/cpu_support.h" +#include "celt/arm/armcpu.h" + +opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *buf32, const opus_int32 *coef32, opus_int order) +{ + int32x4_t coef0 = vld1q_s32(coef32); + int32x4_t coef1 = vld1q_s32(coef32 + 4); + int32x4_t coef2 = vld1q_s32(coef32 + 8); + int32x4_t coef3 = vld1q_s32(coef32 + 12); + + int32x4_t a0 = vld1q_s32(buf32 - 15); + int32x4_t a1 = vld1q_s32(buf32 - 11); + int32x4_t a2 = vld1q_s32(buf32 - 7); + int32x4_t a3 = vld1q_s32(buf32 - 3); + + int32x4_t b0 = vqdmulhq_s32(coef0, a0); + int32x4_t b1 = vqdmulhq_s32(coef1, a1); + int32x4_t b2 = vqdmulhq_s32(coef2, a2); + int32x4_t b3 = vqdmulhq_s32(coef3, a3); + + int32x4_t c0 = vaddq_s32(b0, b1); + int32x4_t c1 = vaddq_s32(b2, b3); + + int32x4_t d = vaddq_s32(c0, c1); + + int64x2_t e = vpaddlq_s32(d); + + int64x1_t f = vadd_s64(vget_low_s64(e), vget_high_s64(e)); + + opus_int32 out = vget_lane_s32(vreinterpret_s32_s64(f), 0); + + out += silk_RSHIFT( order, 1 ); + + return out; +} + + +opus_int32 silk_NSQ_noise_shape_feedback_loop_neon(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order) +{ + opus_int32 out; + if (order == 8) + { + int32x4_t a00 = vdupq_n_s32(data0[0]); + int32x4_t a01 = vld1q_s32(data1); /* data1[0] ... [3] */ + + int32x4_t a0 = vextq_s32 (a00, a01, 3); /* data0[0] data1[0] ...[2] */ + int32x4_t a1 = vld1q_s32(data1 + 3); /* data1[3] ... [6] */ + + /*TODO: Convert these once in advance instead of once per sample, like + silk_noise_shape_quantizer_short_prediction_neon() does.*/ + int16x8_t coef16 = vld1q_s16(coef); + int32x4_t coef0 = vmovl_s16(vget_low_s16(coef16)); + int32x4_t coef1 = vmovl_s16(vget_high_s16(coef16)); + + /*This is not bit-exact with the C version, since we do not drop the + lower 16 bits of each multiply, but wait until the end to truncate + precision. This is an encoder-specific calculation (and unlike + silk_noise_shape_quantizer_short_prediction_neon(), is not meant to + simulate what the decoder will do). We still could use vqdmulhq_s32() + like silk_noise_shape_quantizer_short_prediction_neon() and save + half the multiplies, but the speed difference is not large, since we + then need two extra adds.*/ + int64x2_t b0 = vmull_s32(vget_low_s32(a0), vget_low_s32(coef0)); + int64x2_t b1 = vmlal_s32(b0, vget_high_s32(a0), vget_high_s32(coef0)); + int64x2_t b2 = vmlal_s32(b1, vget_low_s32(a1), vget_low_s32(coef1)); + int64x2_t b3 = vmlal_s32(b2, vget_high_s32(a1), vget_high_s32(coef1)); + + int64x1_t c = vadd_s64(vget_low_s64(b3), vget_high_s64(b3)); + int64x1_t cS = vrshr_n_s64(c, 15); + int32x2_t d = vreinterpret_s32_s64(cS); + + out = vget_lane_s32(d, 0); + vst1q_s32(data1, a0); + vst1q_s32(data1 + 4, a1); + return out; + } + return silk_NSQ_noise_shape_feedback_loop_c(data0, data1, coef, order); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/NSQ_neon.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/NSQ_neon.h new file mode 100644 index 000000000..b31d9442d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/NSQ_neon.h @@ -0,0 +1,114 @@ +/*********************************************************************** +Copyright (C) 2014 Vidyo +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ +#ifndef SILK_NSQ_NEON_H +#define SILK_NSQ_NEON_H + +#include "cpu_support.h" +#include "SigProc_FIX.h" + +#undef silk_short_prediction_create_arch_coef +/* For vectorized calc, reverse a_Q12 coefs, convert to 32-bit, and shift for vqdmulhq_s32. */ +static OPUS_INLINE void silk_short_prediction_create_arch_coef_neon(opus_int32 *out, const opus_int16 *in, opus_int order) +{ + out[15] = silk_LSHIFT32(in[0], 15); + out[14] = silk_LSHIFT32(in[1], 15); + out[13] = silk_LSHIFT32(in[2], 15); + out[12] = silk_LSHIFT32(in[3], 15); + out[11] = silk_LSHIFT32(in[4], 15); + out[10] = silk_LSHIFT32(in[5], 15); + out[9] = silk_LSHIFT32(in[6], 15); + out[8] = silk_LSHIFT32(in[7], 15); + out[7] = silk_LSHIFT32(in[8], 15); + out[6] = silk_LSHIFT32(in[9], 15); + + if (order == 16) + { + out[5] = silk_LSHIFT32(in[10], 15); + out[4] = silk_LSHIFT32(in[11], 15); + out[3] = silk_LSHIFT32(in[12], 15); + out[2] = silk_LSHIFT32(in[13], 15); + out[1] = silk_LSHIFT32(in[14], 15); + out[0] = silk_LSHIFT32(in[15], 15); + } + else + { + out[5] = 0; + out[4] = 0; + out[3] = 0; + out[2] = 0; + out[1] = 0; + out[0] = 0; + } +} + +#if defined(OPUS_ARM_PRESUME_NEON_INTR) + +#define silk_short_prediction_create_arch_coef(out, in, order) \ + (silk_short_prediction_create_arch_coef_neon(out, in, order)) + +#elif defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + +#define silk_short_prediction_create_arch_coef(out, in, order) \ + do { if (arch == OPUS_ARCH_ARM_NEON) { silk_short_prediction_create_arch_coef_neon(out, in, order); } } while (0) + +#endif + +opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *buf32, const opus_int32 *coef32, opus_int order); + +opus_int32 silk_NSQ_noise_shape_feedback_loop_neon(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order); + +#if defined(OPUS_ARM_PRESUME_NEON_INTR) +#undef silk_noise_shape_quantizer_short_prediction +#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) \ + ((void)arch,silk_noise_shape_quantizer_short_prediction_neon(in, coefRev, order)) + +#undef silk_NSQ_noise_shape_feedback_loop +#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) ((void)arch,silk_NSQ_noise_shape_feedback_loop_neon(data0, data1, coef, order)) + +#elif defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + +/* silk_noise_shape_quantizer_short_prediction implementations take different parameters based on arch + (coef vs. coefRev) so can't use the usual IMPL table implementation */ +#undef silk_noise_shape_quantizer_short_prediction +#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) \ + (arch == OPUS_ARCH_ARM_NEON ? \ + silk_noise_shape_quantizer_short_prediction_neon(in, coefRev, order) : \ + silk_noise_shape_quantizer_short_prediction_c(in, coef, order)) + +extern opus_int32 + (*const SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[OPUS_ARCHMASK+1])( + const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, + opus_int order); + +#undef silk_NSQ_noise_shape_feedback_loop +#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) \ + (SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[(arch)&OPUS_ARCHMASK](data0, data1, \ + coef, order)) + +#endif + +#endif /* SILK_NSQ_NEON_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/SigProc_FIX_armv4.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/SigProc_FIX_armv4.h new file mode 100644 index 000000000..ff62b1e5d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/SigProc_FIX_armv4.h @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (C) 2013 Xiph.Org Foundation and contributors +Copyright (c) 2013 Parrot +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FIX_ARMv4_H +#define SILK_SIGPROC_FIX_ARMv4_H + +#undef silk_MLA +static OPUS_INLINE opus_int32 silk_MLA_armv4(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + opus_int32 res; + __asm__( + "#silk_MLA\n\t" + "mla %0, %1, %2, %3\n\t" + : "=&r"(res) + : "r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_MLA(a, b, c) (silk_MLA_armv4(a, b, c)) + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/SigProc_FIX_armv5e.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/SigProc_FIX_armv5e.h new file mode 100644 index 000000000..617a09cab --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/SigProc_FIX_armv5e.h @@ -0,0 +1,61 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Copyright (c) 2013 Parrot +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FIX_ARMv5E_H +#define SILK_SIGPROC_FIX_ARMv5E_H + +#undef silk_SMULTT +static OPUS_INLINE opus_int32 silk_SMULTT_armv5e(opus_int32 a, opus_int32 b) +{ + opus_int32 res; + __asm__( + "#silk_SMULTT\n\t" + "smultt %0, %1, %2\n\t" + : "=r"(res) + : "%r"(a), "r"(b) + ); + return res; +} +#define silk_SMULTT(a, b) (silk_SMULTT_armv5e(a, b)) + +#undef silk_SMLATT +static OPUS_INLINE opus_int32 silk_SMLATT_armv5e(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + opus_int32 res; + __asm__( + "#silk_SMLATT\n\t" + "smlatt %0, %1, %2, %3\n\t" + : "=r"(res) + : "%r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_SMLATT(a, b, c) (silk_SMLATT_armv5e(a, b, c)) + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/arm_silk_map.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/arm_silk_map.c new file mode 100644 index 000000000..0b9bfec2c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/arm_silk_map.c @@ -0,0 +1,123 @@ +/*********************************************************************** +Copyright (C) 2014 Vidyo +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "main_FIX.h" +#include "NSQ.h" +#include "SigProc_FIX.h" + +#if defined(OPUS_HAVE_RTCD) + +# if (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && \ + !defined(OPUS_ARM_PRESUME_NEON_INTR)) + +void (*const SILK_BIQUAD_ALT_STRIDE2_IMPL[OPUS_ARCHMASK + 1])( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +) = { + silk_biquad_alt_stride2_c, /* ARMv4 */ + silk_biquad_alt_stride2_c, /* EDSP */ + silk_biquad_alt_stride2_c, /* Media */ + silk_biquad_alt_stride2_neon, /* Neon */ +}; + +opus_int32 (*const SILK_LPC_INVERSE_PRED_GAIN_IMPL[OPUS_ARCHMASK + 1])( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +) = { + silk_LPC_inverse_pred_gain_c, /* ARMv4 */ + silk_LPC_inverse_pred_gain_c, /* EDSP */ + silk_LPC_inverse_pred_gain_c, /* Media */ + silk_LPC_inverse_pred_gain_neon, /* Neon */ +}; + +void (*const SILK_NSQ_DEL_DEC_IMPL[OPUS_ARCHMASK + 1])( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) = { + silk_NSQ_del_dec_c, /* ARMv4 */ + silk_NSQ_del_dec_c, /* EDSP */ + silk_NSQ_del_dec_c, /* Media */ + silk_NSQ_del_dec_neon, /* Neon */ +}; + +/*There is no table for silk_noise_shape_quantizer_short_prediction because the + NEON version takes different parameters than the C version. + Instead RTCD is done via if statements at the call sites. + See NSQ_neon.h for details.*/ + +opus_int32 + (*const SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[OPUS_ARCHMASK+1])( + const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, + opus_int order) = { + silk_NSQ_noise_shape_feedback_loop_c, /* ARMv4 */ + silk_NSQ_noise_shape_feedback_loop_c, /* EDSP */ + silk_NSQ_noise_shape_feedback_loop_c, /* Media */ + silk_NSQ_noise_shape_feedback_loop_neon, /* NEON */ +}; + +# endif + +# if defined(FIXED_POINT) && \ + defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR) + +void (*const SILK_WARPED_AUTOCORRELATION_FIX_IMPL[OPUS_ARCHMASK + 1])( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) = { + silk_warped_autocorrelation_FIX_c, /* ARMv4 */ + silk_warped_autocorrelation_FIX_c, /* EDSP */ + silk_warped_autocorrelation_FIX_c, /* Media */ + silk_warped_autocorrelation_FIX_neon, /* Neon */ +}; + +# endif + +#endif /* OPUS_HAVE_RTCD */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/biquad_alt_arm.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/biquad_alt_arm.h new file mode 100644 index 000000000..66ea9f43d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/biquad_alt_arm.h @@ -0,0 +1,68 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_BIQUAD_ALT_ARM_H +# define SILK_BIQUAD_ALT_ARM_H + +# include "celt/arm/armcpu.h" + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +void silk_biquad_alt_stride2_neon( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +); + +# if !defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_PRESUME_NEON) +# define OVERRIDE_silk_biquad_alt_stride2 (1) +# define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((void)(arch), PRESUME_NEON(silk_biquad_alt_stride2)(in, B_Q28, A_Q28, S, out, len)) +# endif +# endif + +# if !defined(OVERRIDE_silk_biquad_alt_stride2) +/*Is run-time CPU detection enabled on this platform?*/ +# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern void (*const SILK_BIQUAD_ALT_STRIDE2_IMPL[OPUS_ARCHMASK+1])( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ + ); +# define OVERRIDE_silk_biquad_alt_stride2 (1) +# define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((*SILK_BIQUAD_ALT_STRIDE2_IMPL[(arch)&OPUS_ARCHMASK])(in, B_Q28, A_Q28, S, out, len)) +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_silk_biquad_alt_stride2 (1) +# define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((void)(arch), silk_biquad_alt_stride2_neon(in, B_Q28, A_Q28, S, out, len)) +# endif +# endif + +#endif /* end SILK_BIQUAD_ALT_ARM_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/biquad_alt_neon_intr.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/biquad_alt_neon_intr.c new file mode 100644 index 000000000..971573318 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/biquad_alt_neon_intr.c @@ -0,0 +1,156 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifdef OPUS_CHECK_ASM +# include +# include "stack_alloc.h" +#endif +#include "SigProc_FIX.h" + +static inline void silk_biquad_alt_stride2_kernel( const int32x4_t A_L_s32x4, const int32x4_t A_U_s32x4, const int32x4_t B_Q28_s32x4, const int32x2_t t_s32x2, const int32x4_t in_s32x4, int32x4_t *S_s32x4, int32x2_t *out32_Q14_s32x2 ) +{ + int32x4_t t_s32x4, out32_Q14_s32x4; + + *out32_Q14_s32x2 = vadd_s32( vget_low_s32( *S_s32x4 ), t_s32x2 ); /* silk_SMLAWB( S{0,1}, B_Q28[ 0 ], in{0,1} ) */ + *S_s32x4 = vcombine_s32( vget_high_s32( *S_s32x4 ), vdup_n_s32( 0 ) ); /* S{0,1} = S{2,3}; S{2,3} = 0; */ + *out32_Q14_s32x2 = vshl_n_s32( *out32_Q14_s32x2, 2 ); /* out32_Q14_{0,1} = silk_LSHIFT( silk_SMLAWB( S{0,1}, B_Q28[ 0 ], in{0,1} ), 2 ); */ + out32_Q14_s32x4 = vcombine_s32( *out32_Q14_s32x2, *out32_Q14_s32x2 ); /* out32_Q14_{0,1,0,1} */ + t_s32x4 = vqdmulhq_s32( out32_Q14_s32x4, A_L_s32x4 ); /* silk_SMULWB( out32_Q14_{0,1,0,1}, A{0,0,1,1}_L_Q28 ) */ + *S_s32x4 = vrsraq_n_s32( *S_s32x4, t_s32x4, 14 ); /* S{0,1} = S{2,3} + silk_RSHIFT_ROUND(); S{2,3} = silk_RSHIFT_ROUND(); */ + t_s32x4 = vqdmulhq_s32( out32_Q14_s32x4, A_U_s32x4 ); /* silk_SMULWB( out32_Q14_{0,1,0,1}, A{0,0,1,1}_U_Q28 ) */ + *S_s32x4 = vaddq_s32( *S_s32x4, t_s32x4 ); /* S0 = silk_SMLAWB( S{0,1,2,3}, out32_Q14_{0,1,0,1}, A{0,0,1,1}_U_Q28 ); */ + t_s32x4 = vqdmulhq_s32( in_s32x4, B_Q28_s32x4 ); /* silk_SMULWB( B_Q28[ {1,1,2,2} ], in{0,1,0,1} ) */ + *S_s32x4 = vaddq_s32( *S_s32x4, t_s32x4 ); /* S0 = silk_SMLAWB( S0, B_Q28[ {1,1,2,2} ], in{0,1,0,1} ); */ +} + +void silk_biquad_alt_stride2_neon( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k = 0; + const int32x2_t offset_s32x2 = vdup_n_s32( (1<<14) - 1 ); + const int32x4_t offset_s32x4 = vcombine_s32( offset_s32x2, offset_s32x2 ); + int16x4_t in_s16x4 = vdup_n_s16( 0 ); + int16x4_t out_s16x4; + int32x2_t A_Q28_s32x2, A_L_s32x2, A_U_s32x2, B_Q28_s32x2, t_s32x2; + int32x4_t A_L_s32x4, A_U_s32x4, B_Q28_s32x4, S_s32x4, out32_Q14_s32x4; + int32x2x2_t t0_s32x2x2, t1_s32x2x2, t2_s32x2x2, S_s32x2x2; + +#ifdef OPUS_CHECK_ASM + opus_int32 S_c[ 4 ]; + VARDECL( opus_int16, out_c ); + SAVE_STACK; + ALLOC( out_c, 2 * len, opus_int16 ); + + silk_memcpy( &S_c, S, sizeof( S_c ) ); + silk_biquad_alt_stride2_c( in, B_Q28, A_Q28, S_c, out_c, len ); +#endif + + /* Negate A_Q28 values and split in two parts */ + A_Q28_s32x2 = vld1_s32( A_Q28 ); + A_Q28_s32x2 = vneg_s32( A_Q28_s32x2 ); + A_L_s32x2 = vshl_n_s32( A_Q28_s32x2, 18 ); /* ( -A_Q28[] & 0x00003FFF ) << 18 */ + A_L_s32x2 = vreinterpret_s32_u32( vshr_n_u32( vreinterpret_u32_s32( A_L_s32x2 ), 3 ) ); /* ( -A_Q28[] & 0x00003FFF ) << 15 */ + A_U_s32x2 = vshr_n_s32( A_Q28_s32x2, 14 ); /* silk_RSHIFT( -A_Q28[], 14 ) */ + A_U_s32x2 = vshl_n_s32( A_U_s32x2, 16 ); /* silk_RSHIFT( -A_Q28[], 14 ) << 16 (Clip two leading bits to conform to C function.) */ + A_U_s32x2 = vshr_n_s32( A_U_s32x2, 1 ); /* silk_RSHIFT( -A_Q28[], 14 ) << 15 */ + + B_Q28_s32x2 = vld1_s32( B_Q28 ); + t_s32x2 = vld1_s32( B_Q28 + 1 ); + t0_s32x2x2 = vzip_s32( A_L_s32x2, A_L_s32x2 ); + t1_s32x2x2 = vzip_s32( A_U_s32x2, A_U_s32x2 ); + t2_s32x2x2 = vzip_s32( t_s32x2, t_s32x2 ); + A_L_s32x4 = vcombine_s32( t0_s32x2x2.val[ 0 ], t0_s32x2x2.val[ 1 ] ); /* A{0,0,1,1}_L_Q28 */ + A_U_s32x4 = vcombine_s32( t1_s32x2x2.val[ 0 ], t1_s32x2x2.val[ 1 ] ); /* A{0,0,1,1}_U_Q28 */ + B_Q28_s32x4 = vcombine_s32( t2_s32x2x2.val[ 0 ], t2_s32x2x2.val[ 1 ] ); /* B_Q28[ {1,1,2,2} ] */ + S_s32x4 = vld1q_s32( S ); /* S0 = S[ 0 ]; S3 = S[ 3 ]; */ + S_s32x2x2 = vtrn_s32( vget_low_s32( S_s32x4 ), vget_high_s32( S_s32x4 ) ); /* S2 = S[ 1 ]; S1 = S[ 2 ]; */ + S_s32x4 = vcombine_s32( S_s32x2x2.val[ 0 ], S_s32x2x2.val[ 1 ] ); + + for( ; k < len - 1; k += 2 ) { + int32x4_t in_s32x4[ 2 ], t_s32x4; + int32x2_t out32_Q14_s32x2[ 2 ]; + + /* S[ 2 * i + 0 ], S[ 2 * i + 1 ], S[ 2 * i + 2 ], S[ 2 * i + 3 ]: Q12 */ + in_s16x4 = vld1_s16( &in[ 2 * k ] ); /* in{0,1,2,3} = in[ 2 * k + {0,1,2,3} ]; */ + in_s32x4[ 0 ] = vshll_n_s16( in_s16x4, 15 ); /* in{0,1,2,3} << 15 */ + t_s32x4 = vqdmulhq_lane_s32( in_s32x4[ 0 ], B_Q28_s32x2, 0 ); /* silk_SMULWB( B_Q28[ 0 ], in{0,1,2,3} ) */ + in_s32x4[ 1 ] = vcombine_s32( vget_high_s32( in_s32x4[ 0 ] ), vget_high_s32( in_s32x4[ 0 ] ) ); /* in{2,3,2,3} << 15 */ + in_s32x4[ 0 ] = vcombine_s32( vget_low_s32 ( in_s32x4[ 0 ] ), vget_low_s32 ( in_s32x4[ 0 ] ) ); /* in{0,1,0,1} << 15 */ + silk_biquad_alt_stride2_kernel( A_L_s32x4, A_U_s32x4, B_Q28_s32x4, vget_low_s32 ( t_s32x4 ), in_s32x4[ 0 ], &S_s32x4, &out32_Q14_s32x2[ 0 ] ); + silk_biquad_alt_stride2_kernel( A_L_s32x4, A_U_s32x4, B_Q28_s32x4, vget_high_s32( t_s32x4 ), in_s32x4[ 1 ], &S_s32x4, &out32_Q14_s32x2[ 1 ] ); + + /* Scale back to Q0 and saturate */ + out32_Q14_s32x4 = vcombine_s32( out32_Q14_s32x2[ 0 ], out32_Q14_s32x2[ 1 ] ); /* out32_Q14_{0,1,2,3} */ + out32_Q14_s32x4 = vaddq_s32( out32_Q14_s32x4, offset_s32x4 ); /* out32_Q14_{0,1,2,3} + (1<<14) - 1 */ + out_s16x4 = vqshrn_n_s32( out32_Q14_s32x4, 14 ); /* (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_{0,1,2,3} + (1<<14) - 1, 14 ) ) */ + vst1_s16( &out[ 2 * k ], out_s16x4 ); /* out[ 2 * k + {0,1,2,3} ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_{0,1,2,3} + (1<<14) - 1, 14 ) ); */ + } + + /* Process leftover. */ + if( k < len ) { + int32x4_t in_s32x4; + int32x2_t out32_Q14_s32x2; + + /* S[ 2 * i + 0 ], S[ 2 * i + 1 ]: Q12 */ + in_s16x4 = vld1_lane_s16( &in[ 2 * k + 0 ], in_s16x4, 0 ); /* in{0,1} = in[ 2 * k + {0,1} ]; */ + in_s16x4 = vld1_lane_s16( &in[ 2 * k + 1 ], in_s16x4, 1 ); /* in{0,1} = in[ 2 * k + {0,1} ]; */ + in_s32x4 = vshll_n_s16( in_s16x4, 15 ); /* in{0,1} << 15 */ + t_s32x2 = vqdmulh_lane_s32( vget_low_s32( in_s32x4 ), B_Q28_s32x2, 0 ); /* silk_SMULWB( B_Q28[ 0 ], in{0,1} ) */ + in_s32x4 = vcombine_s32( vget_low_s32( in_s32x4 ), vget_low_s32( in_s32x4 ) ); /* in{0,1,0,1} << 15 */ + silk_biquad_alt_stride2_kernel( A_L_s32x4, A_U_s32x4, B_Q28_s32x4, t_s32x2, in_s32x4, &S_s32x4, &out32_Q14_s32x2 ); + + /* Scale back to Q0 and saturate */ + out32_Q14_s32x2 = vadd_s32( out32_Q14_s32x2, offset_s32x2 ); /* out32_Q14_{0,1} + (1<<14) - 1 */ + out32_Q14_s32x4 = vcombine_s32( out32_Q14_s32x2, out32_Q14_s32x2 ); /* out32_Q14_{0,1,0,1} + (1<<14) - 1 */ + out_s16x4 = vqshrn_n_s32( out32_Q14_s32x4, 14 ); /* (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_{0,1,0,1} + (1<<14) - 1, 14 ) ) */ + vst1_lane_s16( &out[ 2 * k + 0 ], out_s16x4, 0 ); /* out[ 2 * k + 0 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_0 + (1<<14) - 1, 14 ) ); */ + vst1_lane_s16( &out[ 2 * k + 1 ], out_s16x4, 1 ); /* out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_1 + (1<<14) - 1, 14 ) ); */ + } + + vst1q_lane_s32( &S[ 0 ], S_s32x4, 0 ); /* S[ 0 ] = S0; */ + vst1q_lane_s32( &S[ 1 ], S_s32x4, 2 ); /* S[ 1 ] = S2; */ + vst1q_lane_s32( &S[ 2 ], S_s32x4, 1 ); /* S[ 2 ] = S1; */ + vst1q_lane_s32( &S[ 3 ], S_s32x4, 3 ); /* S[ 3 ] = S3; */ + +#ifdef OPUS_CHECK_ASM + silk_assert( !memcmp( S_c, S, sizeof( S_c ) ) ); + silk_assert( !memcmp( out_c, out, 2 * len * sizeof( opus_int16 ) ) ); + RESTORE_STACK; +#endif +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/macros_arm64.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/macros_arm64.h new file mode 100644 index 000000000..ed030413c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/macros_arm64.h @@ -0,0 +1,39 @@ +/*********************************************************************** +Copyright (C) 2015 Vidyo +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_MACROS_ARM64_H +#define SILK_MACROS_ARM64_H + +#include + +#undef silk_ADD_SAT32 +#define silk_ADD_SAT32(a, b) (vqadds_s32((a), (b))) + +#undef silk_SUB_SAT32 +#define silk_SUB_SAT32(a, b) (vqsubs_s32((a), (b))) + +#endif /* SILK_MACROS_ARM64_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/macros_armv4.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/macros_armv4.h new file mode 100644 index 000000000..877eb18dd --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/macros_armv4.h @@ -0,0 +1,110 @@ +/*********************************************************************** +Copyright (C) 2013 Xiph.Org Foundation and contributors. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_MACROS_ARMv4_H +#define SILK_MACROS_ARMv4_H + +/* This macro only avoids the undefined behaviour from a left shift of + a negative value. It should only be used in macros that can't include + SigProc_FIX.h. In other cases, use silk_LSHIFT32(). */ +#define SAFE_SHL(a,b) ((opus_int32)((opus_uint32)(a) << (b))) + +/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */ +#undef silk_SMULWB +static OPUS_INLINE opus_int32 silk_SMULWB_armv4(opus_int32 a, opus_int16 b) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#silk_SMULWB\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(a), "r"(SAFE_SHL(b,16)) + ); + return rd_hi; +} +#define silk_SMULWB(a, b) (silk_SMULWB_armv4(a, b)) + +/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */ +#undef silk_SMLAWB +#define silk_SMLAWB(a, b, c) ((a) + silk_SMULWB(b, c)) + +/* (a32 * (b32 >> 16)) >> 16 */ +#undef silk_SMULWT +static OPUS_INLINE opus_int32 silk_SMULWT_armv4(opus_int32 a, opus_int32 b) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#silk_SMULWT\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(a), "r"(b&~0xFFFF) + ); + return rd_hi; +} +#define silk_SMULWT(a, b) (silk_SMULWT_armv4(a, b)) + +/* a32 + (b32 * (c32 >> 16)) >> 16 */ +#undef silk_SMLAWT +#define silk_SMLAWT(a, b, c) ((a) + silk_SMULWT(b, c)) + +/* (a32 * b32) >> 16 */ +#undef silk_SMULWW +static OPUS_INLINE opus_int32 silk_SMULWW_armv4(opus_int32 a, opus_int32 b) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#silk_SMULWW\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(a), "r"(b) + ); + return SAFE_SHL(rd_hi,16)+(rd_lo>>16); +} +#define silk_SMULWW(a, b) (silk_SMULWW_armv4(a, b)) + +#undef silk_SMLAWW +static OPUS_INLINE opus_int32 silk_SMLAWW_armv4(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#silk_SMLAWW\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(b), "r"(c) + ); + return a+SAFE_SHL(rd_hi,16)+(rd_lo>>16); +} +#define silk_SMLAWW(a, b, c) (silk_SMLAWW_armv4(a, b, c)) + +#undef SAFE_SHL + +#endif /* SILK_MACROS_ARMv4_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/macros_armv5e.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/macros_armv5e.h new file mode 100644 index 000000000..b14ec65dd --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/arm/macros_armv5e.h @@ -0,0 +1,220 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Copyright (c) 2013 Parrot +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_MACROS_ARMv5E_H +#define SILK_MACROS_ARMv5E_H + +/* This macro only avoids the undefined behaviour from a left shift of + a negative value. It should only be used in macros that can't include + SigProc_FIX.h. In other cases, use silk_LSHIFT32(). */ +#define SAFE_SHL(a,b) ((opus_int32)((opus_uint32)(a) << (b))) + +/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */ +#undef silk_SMULWB +static OPUS_INLINE opus_int32 silk_SMULWB_armv5e(opus_int32 a, opus_int16 b) +{ + int res; + __asm__( + "#silk_SMULWB\n\t" + "smulwb %0, %1, %2\n\t" + : "=r"(res) + : "r"(a), "r"(b) + ); + return res; +} +#define silk_SMULWB(a, b) (silk_SMULWB_armv5e(a, b)) + +/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */ +#undef silk_SMLAWB +static OPUS_INLINE opus_int32 silk_SMLAWB_armv5e(opus_int32 a, opus_int32 b, + opus_int16 c) +{ + int res; + __asm__( + "#silk_SMLAWB\n\t" + "smlawb %0, %1, %2, %3\n\t" + : "=r"(res) + : "r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_SMLAWB(a, b, c) (silk_SMLAWB_armv5e(a, b, c)) + +/* (a32 * (b32 >> 16)) >> 16 */ +#undef silk_SMULWT +static OPUS_INLINE opus_int32 silk_SMULWT_armv5e(opus_int32 a, opus_int32 b) +{ + int res; + __asm__( + "#silk_SMULWT\n\t" + "smulwt %0, %1, %2\n\t" + : "=r"(res) + : "r"(a), "r"(b) + ); + return res; +} +#define silk_SMULWT(a, b) (silk_SMULWT_armv5e(a, b)) + +/* a32 + (b32 * (c32 >> 16)) >> 16 */ +#undef silk_SMLAWT +static OPUS_INLINE opus_int32 silk_SMLAWT_armv5e(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + int res; + __asm__( + "#silk_SMLAWT\n\t" + "smlawt %0, %1, %2, %3\n\t" + : "=r"(res) + : "r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_SMLAWT(a, b, c) (silk_SMLAWT_armv5e(a, b, c)) + +/* (opus_int32)((opus_int16)(a3))) * (opus_int32)((opus_int16)(b32)) output have to be 32bit int */ +#undef silk_SMULBB +static OPUS_INLINE opus_int32 silk_SMULBB_armv5e(opus_int32 a, opus_int32 b) +{ + int res; + __asm__( + "#silk_SMULBB\n\t" + "smulbb %0, %1, %2\n\t" + : "=r"(res) + : "%r"(a), "r"(b) + ); + return res; +} +#define silk_SMULBB(a, b) (silk_SMULBB_armv5e(a, b)) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (opus_int32)((opus_int16)(c32)) output have to be 32bit int */ +#undef silk_SMLABB +static OPUS_INLINE opus_int32 silk_SMLABB_armv5e(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + int res; + __asm__( + "#silk_SMLABB\n\t" + "smlabb %0, %1, %2, %3\n\t" + : "=r"(res) + : "%r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_SMLABB(a, b, c) (silk_SMLABB_armv5e(a, b, c)) + +/* (opus_int32)((opus_int16)(a32)) * (b32 >> 16) */ +#undef silk_SMULBT +static OPUS_INLINE opus_int32 silk_SMULBT_armv5e(opus_int32 a, opus_int32 b) +{ + int res; + __asm__( + "#silk_SMULBT\n\t" + "smulbt %0, %1, %2\n\t" + : "=r"(res) + : "r"(a), "r"(b) + ); + return res; +} +#define silk_SMULBT(a, b) (silk_SMULBT_armv5e(a, b)) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (c32 >> 16) */ +#undef silk_SMLABT +static OPUS_INLINE opus_int32 silk_SMLABT_armv5e(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + int res; + __asm__( + "#silk_SMLABT\n\t" + "smlabt %0, %1, %2, %3\n\t" + : "=r"(res) + : "r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_SMLABT(a, b, c) (silk_SMLABT_armv5e(a, b, c)) + +/* add/subtract with output saturated */ +#undef silk_ADD_SAT32 +static OPUS_INLINE opus_int32 silk_ADD_SAT32_armv5e(opus_int32 a, opus_int32 b) +{ + int res; + __asm__( + "#silk_ADD_SAT32\n\t" + "qadd %0, %1, %2\n\t" + : "=r"(res) + : "%r"(a), "r"(b) + ); + return res; +} +#define silk_ADD_SAT32(a, b) (silk_ADD_SAT32_armv5e(a, b)) + +#undef silk_SUB_SAT32 +static OPUS_INLINE opus_int32 silk_SUB_SAT32_armv5e(opus_int32 a, opus_int32 b) +{ + int res; + __asm__( + "#silk_SUB_SAT32\n\t" + "qsub %0, %1, %2\n\t" + : "=r"(res) + : "r"(a), "r"(b) + ); + return res; +} +#define silk_SUB_SAT32(a, b) (silk_SUB_SAT32_armv5e(a, b)) + +#undef silk_CLZ16 +static OPUS_INLINE opus_int32 silk_CLZ16_armv5(opus_int16 in16) +{ + int res; + __asm__( + "#silk_CLZ16\n\t" + "clz %0, %1;\n" + : "=r"(res) + : "r"(SAFE_SHL(in16,16)|0x8000) + ); + return res; +} +#define silk_CLZ16(in16) (silk_CLZ16_armv5(in16)) + +#undef silk_CLZ32 +static OPUS_INLINE opus_int32 silk_CLZ32_armv5(opus_int32 in32) +{ + int res; + __asm__( + "#silk_CLZ32\n\t" + "clz %0, %1\n\t" + : "=r"(res) + : "r"(in32) + ); + return res; +} +#define silk_CLZ32(in32) (silk_CLZ32_armv5(in32)) + +#undef SAFE_SHL + +#endif /* SILK_MACROS_ARMv5E_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/biquad_alt.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/biquad_alt.c new file mode 100644 index 000000000..54566a43c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/biquad_alt.c @@ -0,0 +1,121 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +/* * + * silk_biquad_alt.c * + * * + * Second order ARMA filter * + * Can handle slowly varying filter coefficients * + * */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Second order ARMA filter, alternative implementation */ +void silk_biquad_alt_stride1( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k; + opus_int32 inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14; + + /* Negate A_Q28 values and split in two parts */ + A0_L_Q28 = ( -A_Q28[ 0 ] ) & 0x00003FFF; /* lower part */ + A0_U_Q28 = silk_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */ + A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */ + A1_U_Q28 = silk_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ]: Q12 */ + inval = in[ k ]; + out32_Q14 = silk_LSHIFT( silk_SMLAWB( S[ 0 ], B_Q28[ 0 ], inval ), 2 ); + + S[ 0 ] = S[1] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A0_L_Q28 ), 14 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], out32_Q14, A0_U_Q28 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], B_Q28[ 1 ], inval); + + S[ 1 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A1_L_Q28 ), 14 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], out32_Q14, A1_U_Q28 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], inval ); + + /* Scale back to Q0 and saturate */ + out[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14 + (1<<14) - 1, 14 ) ); + } +} + +void silk_biquad_alt_stride2_c( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k; + opus_int32 A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14[ 2 ]; + + /* Negate A_Q28 values and split in two parts */ + A0_L_Q28 = ( -A_Q28[ 0 ] ) & 0x00003FFF; /* lower part */ + A0_U_Q28 = silk_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */ + A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */ + A1_U_Q28 = silk_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ], S[ 2 ], S[ 3 ]: Q12 */ + out32_Q14[ 0 ] = silk_LSHIFT( silk_SMLAWB( S[ 0 ], B_Q28[ 0 ], in[ 2 * k + 0 ] ), 2 ); + out32_Q14[ 1 ] = silk_LSHIFT( silk_SMLAWB( S[ 2 ], B_Q28[ 0 ], in[ 2 * k + 1 ] ), 2 ); + + S[ 0 ] = S[ 1 ] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 0 ], A0_L_Q28 ), 14 ); + S[ 2 ] = S[ 3 ] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 1 ], A0_L_Q28 ), 14 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], out32_Q14[ 0 ], A0_U_Q28 ); + S[ 2 ] = silk_SMLAWB( S[ 2 ], out32_Q14[ 1 ], A0_U_Q28 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], B_Q28[ 1 ], in[ 2 * k + 0 ] ); + S[ 2 ] = silk_SMLAWB( S[ 2 ], B_Q28[ 1 ], in[ 2 * k + 1 ] ); + + S[ 1 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 0 ], A1_L_Q28 ), 14 ); + S[ 3 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 1 ], A1_L_Q28 ), 14 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], out32_Q14[ 0 ], A1_U_Q28 ); + S[ 3 ] = silk_SMLAWB( S[ 3 ], out32_Q14[ 1 ], A1_U_Q28 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], in[ 2 * k + 0 ] ); + S[ 3 ] = silk_SMLAWB( S[ 3 ], B_Q28[ 2 ], in[ 2 * k + 1 ] ); + + /* Scale back to Q0 and saturate */ + out[ 2 * k + 0 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14[ 0 ] + (1<<14) - 1, 14 ) ); + out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14[ 1 ] + (1<<14) - 1, 14 ) ); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/bwexpander.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/bwexpander.c new file mode 100644 index 000000000..afa97907e --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/bwexpander.c @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander( + opus_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */ +) +{ + opus_int i; + opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536; + + /* NB: Dont use silk_SMULWB, instead of silk_RSHIFT_ROUND( silk_MUL(), 16 ), below. */ + /* Bias in silk_SMULWB can lead to unstable filters */ + for( i = 0; i < d - 1; i++ ) { + ar[ i ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ i ] ), 16 ); + chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 ); + } + ar[ d - 1 ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ d - 1 ] ), 16 ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/bwexpander_32.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/bwexpander_32.c new file mode 100644 index 000000000..0f32b9df1 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/bwexpander_32.c @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Chirp (bandwidth expand) LP AR filter. + This logic is reused in _celt_lpc(). Any bug fixes should also be applied there. */ +void silk_bwexpander_32( + opus_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor in Q16 */ +) +{ + opus_int i; + opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536; + + for( i = 0; i < d - 1; i++ ) { + ar[ i ] = silk_SMULWW( chirp_Q16, ar[ i ] ); + chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 ); + } + ar[ d - 1 ] = silk_SMULWW( chirp_Q16, ar[ d - 1 ] ); +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/check_control_input.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/check_control_input.c new file mode 100644 index 000000000..739fb01f1 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/check_control_input.c @@ -0,0 +1,106 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "control.h" +#include "errors.h" + +/* Check encoder control struct */ +opus_int check_control_input( + silk_EncControlStruct *encControl /* I Control structure */ +) +{ + celt_assert( encControl != NULL ); + + if( ( ( encControl->API_sampleRate != 8000 ) && + ( encControl->API_sampleRate != 12000 ) && + ( encControl->API_sampleRate != 16000 ) && + ( encControl->API_sampleRate != 24000 ) && + ( encControl->API_sampleRate != 32000 ) && + ( encControl->API_sampleRate != 44100 ) && + ( encControl->API_sampleRate != 48000 ) ) || + ( ( encControl->desiredInternalSampleRate != 8000 ) && + ( encControl->desiredInternalSampleRate != 12000 ) && + ( encControl->desiredInternalSampleRate != 16000 ) ) || + ( ( encControl->maxInternalSampleRate != 8000 ) && + ( encControl->maxInternalSampleRate != 12000 ) && + ( encControl->maxInternalSampleRate != 16000 ) ) || + ( ( encControl->minInternalSampleRate != 8000 ) && + ( encControl->minInternalSampleRate != 12000 ) && + ( encControl->minInternalSampleRate != 16000 ) ) || + ( encControl->minInternalSampleRate > encControl->desiredInternalSampleRate ) || + ( encControl->maxInternalSampleRate < encControl->desiredInternalSampleRate ) || + ( encControl->minInternalSampleRate > encControl->maxInternalSampleRate ) ) { + celt_assert( 0 ); + return SILK_ENC_FS_NOT_SUPPORTED; + } + if( encControl->payloadSize_ms != 10 && + encControl->payloadSize_ms != 20 && + encControl->payloadSize_ms != 40 && + encControl->payloadSize_ms != 60 ) { + celt_assert( 0 ); + return SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; + } + if( encControl->packetLossPercentage < 0 || encControl->packetLossPercentage > 100 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_LOSS_RATE; + } + if( encControl->useDTX < 0 || encControl->useDTX > 1 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_DTX_SETTING; + } + if( encControl->useCBR < 0 || encControl->useCBR > 1 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_CBR_SETTING; + } + if( encControl->useInBandFEC < 0 || encControl->useInBandFEC > 1 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_INBAND_FEC_SETTING; + } + if( encControl->nChannelsAPI < 1 || encControl->nChannelsAPI > ENCODER_NUM_CHANNELS ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->nChannelsInternal < 1 || encControl->nChannelsInternal > ENCODER_NUM_CHANNELS ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->nChannelsInternal > encControl->nChannelsAPI ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->complexity < 0 || encControl->complexity > 10 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_COMPLEXITY_SETTING; + } + + return SILK_NO_ERROR; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/code_signs.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/code_signs.c new file mode 100644 index 000000000..dfd1dca9a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/code_signs.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/*#define silk_enc_map(a) ((a) > 0 ? 1 : 0)*/ +/*#define silk_dec_map(a) ((a) > 0 ? 1 : -1)*/ +/* shifting avoids if-statement */ +#define silk_enc_map(a) ( silk_RSHIFT( (a), 15 ) + 1 ) +#define silk_dec_map(a) ( silk_LSHIFT( (a), 1 ) - 1 ) + +/* Encodes signs of excitation */ +void silk_encode_signs( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + const opus_int8 pulses[], /* I pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +) +{ + opus_int i, j, p; + opus_uint8 icdf[ 2 ]; + const opus_int8 *q_ptr; + const opus_uint8 *icdf_ptr; + + icdf[ 1 ] = 0; + q_ptr = pulses; + i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) ); + icdf_ptr = &silk_sign_iCDF[ i ]; + length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH ); + for( i = 0; i < length; i++ ) { + p = sum_pulses[ i ]; + if( p > 0 ) { + icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ]; + for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) { + if( q_ptr[ j ] != 0 ) { + ec_enc_icdf( psRangeEnc, silk_enc_map( q_ptr[ j ]), icdf, 8 ); + } + } + } + q_ptr += SHELL_CODEC_FRAME_LENGTH; + } +} + +/* Decodes signs of excitation */ +void silk_decode_signs( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pulses[], /* I/O pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +) +{ + opus_int i, j, p; + opus_uint8 icdf[ 2 ]; + opus_int16 *q_ptr; + const opus_uint8 *icdf_ptr; + + icdf[ 1 ] = 0; + q_ptr = pulses; + i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) ); + icdf_ptr = &silk_sign_iCDF[ i ]; + length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH ); + for( i = 0; i < length; i++ ) { + p = sum_pulses[ i ]; + if( p > 0 ) { + icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ]; + for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) { + if( q_ptr[ j ] > 0 ) { + /* attach sign */ +#if 0 + /* conditional implementation */ + if( ec_dec_icdf( psRangeDec, icdf, 8 ) == 0 ) { + q_ptr[ j ] = -q_ptr[ j ]; + } +#else + /* implementation with shift, subtraction, multiplication */ + q_ptr[ j ] *= silk_dec_map( ec_dec_icdf( psRangeDec, icdf, 8 ) ); +#endif + } + } + } + q_ptr += SHELL_CODEC_FRAME_LENGTH; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/control.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/control.h new file mode 100644 index 000000000..b76ec33cd --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/control.h @@ -0,0 +1,150 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_CONTROL_H +#define SILK_CONTROL_H + +#include "typedef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Decoder API flags */ +#define FLAG_DECODE_NORMAL 0 +#define FLAG_PACKET_LOST 1 +#define FLAG_DECODE_LBRR 2 + +/***********************************************/ +/* Structure for controlling encoder operation */ +/***********************************************/ +typedef struct { + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsAPI; + + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsInternal; + + /* I: Input signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */ + opus_int32 API_sampleRate; + + /* I: Maximum internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 maxInternalSampleRate; + + /* I: Minimum internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 minInternalSampleRate; + + /* I: Soft request for internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 desiredInternalSampleRate; + + /* I: Number of samples per packet in milliseconds; 10/20/40/60 */ + opus_int payloadSize_ms; + + /* I: Bitrate during active speech in bits/second; internally limited */ + opus_int32 bitRate; + + /* I: Uplink packet loss in percent (0-100) */ + opus_int packetLossPercentage; + + /* I: Complexity mode; 0 is lowest, 10 is highest complexity */ + opus_int complexity; + + /* I: Flag to enable in-band Forward Error Correction (FEC); 0/1 */ + opus_int useInBandFEC; + + /* I: Flag to actually code in-band Forward Error Correction (FEC) in the current packet; 0/1 */ + opus_int LBRR_coded; + + /* I: Flag to enable discontinuous transmission (DTX); 0/1 */ + opus_int useDTX; + + /* I: Flag to use constant bitrate */ + opus_int useCBR; + + /* I: Maximum number of bits allowed for the frame */ + opus_int maxBits; + + /* I: Causes a smooth downmix to mono */ + opus_int toMono; + + /* I: Opus encoder is allowing us to switch bandwidth */ + opus_int opusCanSwitch; + + /* I: Make frames as independent as possible (but still use LPC) */ + opus_int reducedDependency; + + /* O: Internal sampling rate used, in Hertz; 8000/12000/16000 */ + opus_int32 internalSampleRate; + + /* O: Flag that bandwidth switching is allowed (because low voice activity) */ + opus_int allowBandwidthSwitch; + + /* O: Flag that SILK runs in WB mode without variable LP filter (use for switching between WB/SWB/FB) */ + opus_int inWBmodeWithoutVariableLP; + + /* O: Stereo width */ + opus_int stereoWidth_Q14; + + /* O: Tells the Opus encoder we're ready to switch */ + opus_int switchReady; + + /* O: SILK Signal type */ + opus_int signalType; + + /* O: SILK offset (dithering) */ + opus_int offset; +} silk_EncControlStruct; + +/**************************************************************************/ +/* Structure for controlling decoder operation and reading decoder status */ +/**************************************************************************/ +typedef struct { + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsAPI; + + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsInternal; + + /* I: Output signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */ + opus_int32 API_sampleRate; + + /* I: Internal sampling rate used, in Hertz; 8000/12000/16000 */ + opus_int32 internalSampleRate; + + /* I: Number of samples per packet in milliseconds; 10/20/40/60 */ + opus_int payloadSize_ms; + + /* O: Pitch lag of previous frame (0 if unvoiced), measured in samples at 48 kHz */ + opus_int prevPitchLag; +} silk_DecControlStruct; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/control_SNR.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/control_SNR.c new file mode 100644 index 000000000..9a6db2754 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/control_SNR.c @@ -0,0 +1,113 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "tuning_parameters.h" + +/* These tables hold SNR values divided by 21 (so they fit in 8 bits) + for different target bitrates spaced at 400 bps interval. The first + 10 values are omitted (0-4 kb/s) because they're all zeros. + These tables were obtained by running different SNRs through the + encoder and measuring the active bitrate. */ +static const unsigned char silk_TargetRate_NB_21[117 - 10] = { + 0, 15, 39, 52, 61, 68, + 74, 79, 84, 88, 92, 95, 99,102,105,108,111,114,117,119,122,124, + 126,129,131,133,135,137,139,142,143,145,147,149,151,153,155,157, + 158,160,162,163,165,167,168,170,171,173,174,176,177,179,180,182, + 183,185,186,187,189,190,192,193,194,196,197,199,200,201,203,204, + 205,207,208,209,211,212,213,215,216,217,219,220,221,223,224,225, + 227,228,230,231,232,234,235,236,238,239,241,242,243,245,246,248, + 249,250,252,253,255 +}; + +static const unsigned char silk_TargetRate_MB_21[165 - 10] = { + 0, 0, 28, 43, 52, 59, + 65, 70, 74, 78, 81, 85, 87, 90, 93, 95, 98,100,102,105,107,109, + 111,113,115,116,118,120,122,123,125,127,128,130,131,133,134,136, + 137,138,140,141,143,144,145,147,148,149,151,152,153,154,156,157, + 158,159,160,162,163,164,165,166,167,168,169,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,188,189,190, + 191,192,193,194,195,196,197,198,199,200,201,202,203,203,204,205, + 206,207,208,209,210,211,212,213,214,214,215,216,217,218,219,220, + 221,222,223,224,224,225,226,227,228,229,230,231,232,233,234,235, + 236,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250, + 251,252,253,254,255 +}; + +static const unsigned char silk_TargetRate_WB_21[201 - 10] = { + 0, 0, 0, 8, 29, 41, + 49, 56, 62, 66, 70, 74, 77, 80, 83, 86, 88, 91, 93, 95, 97, 99, + 101,103,105,107,108,110,112,113,115,116,118,119,121,122,123,125, + 126,127,129,130,131,132,134,135,136,137,138,140,141,142,143,144, + 145,146,147,148,149,150,151,152,153,154,156,157,158,159,159,160, + 161,162,163,164,165,166,167,168,169,170,171,171,172,173,174,175, + 176,177,177,178,179,180,181,181,182,183,184,185,185,186,187,188, + 189,189,190,191,192,192,193,194,195,195,196,197,198,198,199,200, + 200,201,202,203,203,204,205,206,206,207,208,209,209,210,211,211, + 212,213,214,214,215,216,216,217,218,219,219,220,221,221,222,223, + 224,224,225,226,226,227,228,229,229,230,231,232,232,233,234,234, + 235,236,237,237,238,239,240,240,241,242,243,243,244,245,246,246, + 247,248,249,249,250,251,252,253,255 +}; + +/* Control SNR of redidual quantizer */ +opus_int silk_control_SNR( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + opus_int32 TargetRate_bps /* I Target max bitrate (bps) */ +) +{ + int id; + int bound; + const unsigned char *snr_table; + + psEncC->TargetRate_bps = TargetRate_bps; + if( psEncC->nb_subfr == 2 ) { + TargetRate_bps -= 2000 + psEncC->fs_kHz/16; + } + if( psEncC->fs_kHz == 8 ) { + bound = sizeof(silk_TargetRate_NB_21); + snr_table = silk_TargetRate_NB_21; + } else if( psEncC->fs_kHz == 12 ) { + bound = sizeof(silk_TargetRate_MB_21); + snr_table = silk_TargetRate_MB_21; + } else { + bound = sizeof(silk_TargetRate_WB_21); + snr_table = silk_TargetRate_WB_21; + } + id = (TargetRate_bps+200)/400; + id = silk_min(id - 10, bound-1); + if( id <= 0 ) { + psEncC->SNR_dB_Q7 = 0; + } else { + psEncC->SNR_dB_Q7 = snr_table[id]*21; + } + return SILK_NO_ERROR; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/control_audio_bandwidth.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/control_audio_bandwidth.c new file mode 100644 index 000000000..f6d22d839 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/control_audio_bandwidth.c @@ -0,0 +1,132 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "tuning_parameters.h" + +/* Control internal sampling rate */ +opus_int silk_control_audio_bandwidth( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl /* I Control structure */ +) +{ + opus_int fs_kHz; + opus_int orig_kHz; + opus_int32 fs_Hz; + + orig_kHz = psEncC->fs_kHz; + /* Handle a bandwidth-switching reset where we need to be aware what the last sampling rate was. */ + if( orig_kHz == 0 ) { + orig_kHz = psEncC->sLP.saved_fs_kHz; + } + fs_kHz = orig_kHz; + fs_Hz = silk_SMULBB( fs_kHz, 1000 ); + if( fs_Hz == 0 ) { + /* Encoder has just been initialized */ + fs_Hz = silk_min( psEncC->desiredInternal_fs_Hz, psEncC->API_fs_Hz ); + fs_kHz = silk_DIV32_16( fs_Hz, 1000 ); + } else if( fs_Hz > psEncC->API_fs_Hz || fs_Hz > psEncC->maxInternal_fs_Hz || fs_Hz < psEncC->minInternal_fs_Hz ) { + /* Make sure internal rate is not higher than external rate or maximum allowed, or lower than minimum allowed */ + fs_Hz = psEncC->API_fs_Hz; + fs_Hz = silk_min( fs_Hz, psEncC->maxInternal_fs_Hz ); + fs_Hz = silk_max( fs_Hz, psEncC->minInternal_fs_Hz ); + fs_kHz = silk_DIV32_16( fs_Hz, 1000 ); + } else { + /* State machine for the internal sampling rate switching */ + if( psEncC->sLP.transition_frame_no >= TRANSITION_FRAMES ) { + /* Stop transition phase */ + psEncC->sLP.mode = 0; + } + if( psEncC->allow_bandwidth_switch || encControl->opusCanSwitch ) { + /* Check if we should switch down */ + if( silk_SMULBB( orig_kHz, 1000 ) > psEncC->desiredInternal_fs_Hz ) + { + /* Switch down */ + if( psEncC->sLP.mode == 0 ) { + /* New transition */ + psEncC->sLP.transition_frame_no = TRANSITION_FRAMES; + + /* Reset transition filter state */ + silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) ); + } + if( encControl->opusCanSwitch ) { + /* Stop transition phase */ + psEncC->sLP.mode = 0; + + /* Switch to a lower sample frequency */ + fs_kHz = orig_kHz == 16 ? 12 : 8; + } else { + if( psEncC->sLP.transition_frame_no <= 0 ) { + encControl->switchReady = 1; + /* Make room for redundancy */ + encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 ); + } else { + /* Direction: down (at double speed) */ + psEncC->sLP.mode = -2; + } + } + } + else + /* Check if we should switch up */ + if( silk_SMULBB( orig_kHz, 1000 ) < psEncC->desiredInternal_fs_Hz ) + { + /* Switch up */ + if( encControl->opusCanSwitch ) { + /* Switch to a higher sample frequency */ + fs_kHz = orig_kHz == 8 ? 12 : 16; + + /* New transition */ + psEncC->sLP.transition_frame_no = 0; + + /* Reset transition filter state */ + silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) ); + + /* Direction: up */ + psEncC->sLP.mode = 1; + } else { + if( psEncC->sLP.mode == 0 ) { + encControl->switchReady = 1; + /* Make room for redundancy */ + encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 ); + } else { + /* Direction: up */ + psEncC->sLP.mode = 1; + } + } + } else { + if (psEncC->sLP.mode<0) + psEncC->sLP.mode = 1; + } + } + } + + return fs_kHz; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/control_codec.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/control_codec.c new file mode 100644 index 000000000..52aa8fded --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/control_codec.c @@ -0,0 +1,423 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef FIXED_POINT +#include "main_FIX.h" +#define silk_encoder_state_Fxx silk_encoder_state_FIX +#else +#include "main_FLP.h" +#define silk_encoder_state_Fxx silk_encoder_state_FLP +#endif +#include "stack_alloc.h" +#include "tuning_parameters.h" +#include "pitch_est_defines.h" + +static opus_int silk_setup_resamplers( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz /* I */ +); + +static opus_int silk_setup_fs( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz, /* I */ + opus_int PacketSize_ms /* I */ +); + +static opus_int silk_setup_complexity( + silk_encoder_state *psEncC, /* I/O */ + opus_int Complexity /* I */ +); + +static OPUS_INLINE opus_int silk_setup_LBRR( + silk_encoder_state *psEncC, /* I/O */ + const silk_EncControlStruct *encControl /* I */ +); + + +/* Control encoder */ +opus_int silk_control_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +) +{ + opus_int fs_kHz, ret = 0; + + psEnc->sCmn.useDTX = encControl->useDTX; + psEnc->sCmn.useCBR = encControl->useCBR; + psEnc->sCmn.API_fs_Hz = encControl->API_sampleRate; + psEnc->sCmn.maxInternal_fs_Hz = encControl->maxInternalSampleRate; + psEnc->sCmn.minInternal_fs_Hz = encControl->minInternalSampleRate; + psEnc->sCmn.desiredInternal_fs_Hz = encControl->desiredInternalSampleRate; + psEnc->sCmn.useInBandFEC = encControl->useInBandFEC; + psEnc->sCmn.nChannelsAPI = encControl->nChannelsAPI; + psEnc->sCmn.nChannelsInternal = encControl->nChannelsInternal; + psEnc->sCmn.allow_bandwidth_switch = allow_bw_switch; + psEnc->sCmn.channelNb = channelNb; + + if( psEnc->sCmn.controlled_since_last_payload != 0 && psEnc->sCmn.prefillFlag == 0 ) { + if( psEnc->sCmn.API_fs_Hz != psEnc->sCmn.prev_API_fs_Hz && psEnc->sCmn.fs_kHz > 0 ) { + /* Change in API sampling rate in the middle of encoding a packet */ + ret += silk_setup_resamplers( psEnc, psEnc->sCmn.fs_kHz ); + } + return ret; + } + + /* Beyond this point we know that there are no previously coded frames in the payload buffer */ + + /********************************************/ + /* Determine internal sampling rate */ + /********************************************/ + fs_kHz = silk_control_audio_bandwidth( &psEnc->sCmn, encControl ); + if( force_fs_kHz ) { + fs_kHz = force_fs_kHz; + } + /********************************************/ + /* Prepare resampler and buffered data */ + /********************************************/ + ret += silk_setup_resamplers( psEnc, fs_kHz ); + + /********************************************/ + /* Set internal sampling frequency */ + /********************************************/ + ret += silk_setup_fs( psEnc, fs_kHz, encControl->payloadSize_ms ); + + /********************************************/ + /* Set encoding complexity */ + /********************************************/ + ret += silk_setup_complexity( &psEnc->sCmn, encControl->complexity ); + + /********************************************/ + /* Set packet loss rate measured by farend */ + /********************************************/ + psEnc->sCmn.PacketLoss_perc = encControl->packetLossPercentage; + + /********************************************/ + /* Set LBRR usage */ + /********************************************/ + ret += silk_setup_LBRR( &psEnc->sCmn, encControl ); + + psEnc->sCmn.controlled_since_last_payload = 1; + + return ret; +} + +static opus_int silk_setup_resamplers( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz /* I */ +) +{ + opus_int ret = SILK_NO_ERROR; + SAVE_STACK; + + if( psEnc->sCmn.fs_kHz != fs_kHz || psEnc->sCmn.prev_API_fs_Hz != psEnc->sCmn.API_fs_Hz ) + { + if( psEnc->sCmn.fs_kHz == 0 ) { + /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */ + ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, fs_kHz * 1000, 1 ); + } else { + VARDECL( opus_int16, x_buf_API_fs_Hz ); + VARDECL( silk_resampler_state_struct, temp_resampler_state ); +#ifdef FIXED_POINT + opus_int16 *x_bufFIX = psEnc->x_buf; +#else + VARDECL( opus_int16, x_bufFIX ); + opus_int32 new_buf_samples; +#endif + opus_int32 api_buf_samples; + opus_int32 old_buf_samples; + opus_int32 buf_length_ms; + + buf_length_ms = silk_LSHIFT( psEnc->sCmn.nb_subfr * 5, 1 ) + LA_SHAPE_MS; + old_buf_samples = buf_length_ms * psEnc->sCmn.fs_kHz; + +#ifndef FIXED_POINT + new_buf_samples = buf_length_ms * fs_kHz; + ALLOC( x_bufFIX, silk_max( old_buf_samples, new_buf_samples ), + opus_int16 ); + silk_float2short_array( x_bufFIX, psEnc->x_buf, old_buf_samples ); +#endif + + /* Initialize resampler for temporary resampling of x_buf data to API_fs_Hz */ + ALLOC( temp_resampler_state, 1, silk_resampler_state_struct ); + ret += silk_resampler_init( temp_resampler_state, silk_SMULBB( psEnc->sCmn.fs_kHz, 1000 ), psEnc->sCmn.API_fs_Hz, 0 ); + + /* Calculate number of samples to temporarily upsample */ + api_buf_samples = buf_length_ms * silk_DIV32_16( psEnc->sCmn.API_fs_Hz, 1000 ); + + /* Temporary resampling of x_buf data to API_fs_Hz */ + ALLOC( x_buf_API_fs_Hz, api_buf_samples, opus_int16 ); + ret += silk_resampler( temp_resampler_state, x_buf_API_fs_Hz, x_bufFIX, old_buf_samples ); + + /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */ + ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, silk_SMULBB( fs_kHz, 1000 ), 1 ); + + /* Correct resampler state by resampling buffered data from API_fs_Hz to fs_kHz */ + ret += silk_resampler( &psEnc->sCmn.resampler_state, x_bufFIX, x_buf_API_fs_Hz, api_buf_samples ); + +#ifndef FIXED_POINT + silk_short2float_array( psEnc->x_buf, x_bufFIX, new_buf_samples); +#endif + } + } + + psEnc->sCmn.prev_API_fs_Hz = psEnc->sCmn.API_fs_Hz; + + RESTORE_STACK; + return ret; +} + +static opus_int silk_setup_fs( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz, /* I */ + opus_int PacketSize_ms /* I */ +) +{ + opus_int ret = SILK_NO_ERROR; + + /* Set packet size */ + if( PacketSize_ms != psEnc->sCmn.PacketSize_ms ) { + if( ( PacketSize_ms != 10 ) && + ( PacketSize_ms != 20 ) && + ( PacketSize_ms != 40 ) && + ( PacketSize_ms != 60 ) ) { + ret = SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; + } + if( PacketSize_ms <= 10 ) { + psEnc->sCmn.nFramesPerPacket = 1; + psEnc->sCmn.nb_subfr = PacketSize_ms == 10 ? 2 : 1; + psEnc->sCmn.frame_length = silk_SMULBB( PacketSize_ms, fs_kHz ); + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz ); + if( psEnc->sCmn.fs_kHz == 8 ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } else { + psEnc->sCmn.nFramesPerPacket = silk_DIV32_16( PacketSize_ms, MAX_FRAME_LENGTH_MS ); + psEnc->sCmn.nb_subfr = MAX_NB_SUBFR; + psEnc->sCmn.frame_length = silk_SMULBB( 20, fs_kHz ); + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz ); + if( psEnc->sCmn.fs_kHz == 8 ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF; + } + } + psEnc->sCmn.PacketSize_ms = PacketSize_ms; + psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */ + } + + /* Set internal sampling frequency */ + celt_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 ); + celt_assert( psEnc->sCmn.nb_subfr == 2 || psEnc->sCmn.nb_subfr == 4 ); + if( psEnc->sCmn.fs_kHz != fs_kHz ) { + /* reset part of the state */ + silk_memset( &psEnc->sShape, 0, sizeof( psEnc->sShape ) ); + silk_memset( &psEnc->sCmn.sNSQ, 0, sizeof( psEnc->sCmn.sNSQ ) ); + silk_memset( psEnc->sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); + silk_memset( &psEnc->sCmn.sLP.In_LP_State, 0, sizeof( psEnc->sCmn.sLP.In_LP_State ) ); + psEnc->sCmn.inputBufIx = 0; + psEnc->sCmn.nFramesEncoded = 0; + psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */ + + /* Initialize non-zero parameters */ + psEnc->sCmn.prevLag = 100; + psEnc->sCmn.first_frame_after_reset = 1; + psEnc->sShape.LastGainIndex = 10; + psEnc->sCmn.sNSQ.lagPrev = 100; + psEnc->sCmn.sNSQ.prev_gain_Q16 = 65536; + psEnc->sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY; + + psEnc->sCmn.fs_kHz = fs_kHz; + if( psEnc->sCmn.fs_kHz == 8 ) { + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } + } else { + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } + if( psEnc->sCmn.fs_kHz == 8 || psEnc->sCmn.fs_kHz == 12 ) { + psEnc->sCmn.predictLPCOrder = MIN_LPC_ORDER; + psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_NB_MB; + } else { + psEnc->sCmn.predictLPCOrder = MAX_LPC_ORDER; + psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_WB; + } + psEnc->sCmn.subfr_length = SUB_FRAME_LENGTH_MS * fs_kHz; + psEnc->sCmn.frame_length = silk_SMULBB( psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr ); + psEnc->sCmn.ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz ); + psEnc->sCmn.la_pitch = silk_SMULBB( LA_PITCH_MS, fs_kHz ); + psEnc->sCmn.max_pitch_lag = silk_SMULBB( 18, fs_kHz ); + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz ); + } else { + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz ); + } + if( psEnc->sCmn.fs_kHz == 16 ) { + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform8_iCDF; + } else if( psEnc->sCmn.fs_kHz == 12 ) { + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform6_iCDF; + } else { + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform4_iCDF; + } + } + + /* Check that settings are valid */ + celt_assert( ( psEnc->sCmn.subfr_length * psEnc->sCmn.nb_subfr ) == psEnc->sCmn.frame_length ); + + return ret; +} + +static opus_int silk_setup_complexity( + silk_encoder_state *psEncC, /* I/O */ + opus_int Complexity /* I */ +) +{ + opus_int ret = 0; + + /* Set encoding complexity */ + celt_assert( Complexity >= 0 && Complexity <= 10 ); + if( Complexity < 1 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 16 ); + psEncC->pitchEstimationLPCOrder = 6; + psEncC->shapingLPCOrder = 12; + psEncC->la_shape = 3 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 1; + psEncC->useInterpolatedNLSFs = 0; + psEncC->NLSF_MSVQ_Survivors = 2; + psEncC->warping_Q16 = 0; + } else if( Complexity < 2 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.76, 16 ); + psEncC->pitchEstimationLPCOrder = 8; + psEncC->shapingLPCOrder = 14; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 1; + psEncC->useInterpolatedNLSFs = 0; + psEncC->NLSF_MSVQ_Survivors = 3; + psEncC->warping_Q16 = 0; + } else if( Complexity < 3 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 16 ); + psEncC->pitchEstimationLPCOrder = 6; + psEncC->shapingLPCOrder = 12; + psEncC->la_shape = 3 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 2; + psEncC->useInterpolatedNLSFs = 0; + psEncC->NLSF_MSVQ_Survivors = 2; + psEncC->warping_Q16 = 0; + } else if( Complexity < 4 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.76, 16 ); + psEncC->pitchEstimationLPCOrder = 8; + psEncC->shapingLPCOrder = 14; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 2; + psEncC->useInterpolatedNLSFs = 0; + psEncC->NLSF_MSVQ_Survivors = 4; + psEncC->warping_Q16 = 0; + } else if( Complexity < 6 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.74, 16 ); + psEncC->pitchEstimationLPCOrder = 10; + psEncC->shapingLPCOrder = 16; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 2; + psEncC->useInterpolatedNLSFs = 1; + psEncC->NLSF_MSVQ_Survivors = 6; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } else if( Complexity < 8 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.72, 16 ); + psEncC->pitchEstimationLPCOrder = 12; + psEncC->shapingLPCOrder = 20; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 3; + psEncC->useInterpolatedNLSFs = 1; + psEncC->NLSF_MSVQ_Survivors = 8; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } else { + psEncC->pitchEstimationComplexity = SILK_PE_MAX_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.7, 16 ); + psEncC->pitchEstimationLPCOrder = 16; + psEncC->shapingLPCOrder = 24; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = MAX_DEL_DEC_STATES; + psEncC->useInterpolatedNLSFs = 1; + psEncC->NLSF_MSVQ_Survivors = 16; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } + + /* Do not allow higher pitch estimation LPC order than predict LPC order */ + psEncC->pitchEstimationLPCOrder = silk_min_int( psEncC->pitchEstimationLPCOrder, psEncC->predictLPCOrder ); + psEncC->shapeWinLength = SUB_FRAME_LENGTH_MS * psEncC->fs_kHz + 2 * psEncC->la_shape; + psEncC->Complexity = Complexity; + + celt_assert( psEncC->pitchEstimationLPCOrder <= MAX_FIND_PITCH_LPC_ORDER ); + celt_assert( psEncC->shapingLPCOrder <= MAX_SHAPE_LPC_ORDER ); + celt_assert( psEncC->nStatesDelayedDecision <= MAX_DEL_DEC_STATES ); + celt_assert( psEncC->warping_Q16 <= 32767 ); + celt_assert( psEncC->la_shape <= LA_SHAPE_MAX ); + celt_assert( psEncC->shapeWinLength <= SHAPE_LPC_WIN_MAX ); + + return ret; +} + +static OPUS_INLINE opus_int silk_setup_LBRR( + silk_encoder_state *psEncC, /* I/O */ + const silk_EncControlStruct *encControl /* I */ +) +{ + opus_int LBRR_in_previous_packet, ret = SILK_NO_ERROR; + + LBRR_in_previous_packet = psEncC->LBRR_enabled; + psEncC->LBRR_enabled = encControl->LBRR_coded; + if( psEncC->LBRR_enabled ) { + /* Set gain increase for coding LBRR excitation */ + if( LBRR_in_previous_packet == 0 ) { + /* Previous packet did not have LBRR, and was therefore coded at a higher bitrate */ + psEncC->LBRR_GainIncreases = 7; + } else { + psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( (opus_int32)psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 ); + } + } + + return ret; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/debug.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/debug.c new file mode 100644 index 000000000..eb0c36ef1 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/debug.c @@ -0,0 +1,172 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "debug.h" + +#if SILK_DEBUG || SILK_TIC_TOC +#include "SigProc_FIX.h" +#endif + +#if SILK_TIC_TOC + +#if (defined(_WIN32) || defined(_WINCE)) +#include /* timer */ +#else /* Linux or Mac*/ +#include +#endif + +#ifdef _WIN32 +unsigned long silk_GetHighResolutionTime(void) /* O time in usec*/ +{ + /* Returns a time counter in microsec */ + /* the resolution is platform dependent */ + /* but is typically 1.62 us resolution */ + LARGE_INTEGER lpPerformanceCount; + LARGE_INTEGER lpFrequency; + QueryPerformanceCounter(&lpPerformanceCount); + QueryPerformanceFrequency(&lpFrequency); + return (unsigned long)((1000000*(lpPerformanceCount.QuadPart)) / lpFrequency.QuadPart); +} +#else /* Linux or Mac*/ +unsigned long GetHighResolutionTime(void) /* O time in usec*/ +{ + struct timeval tv; + gettimeofday(&tv, 0); + return((tv.tv_sec*1000000)+(tv.tv_usec)); +} +#endif + +int silk_Timer_nTimers = 0; +int silk_Timer_depth_ctr = 0; +char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN]; +#ifdef _WIN32 +LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX]; +#else +unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX]; +#endif +unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX]; + +#ifdef _WIN32 +void silk_TimerSave(char *file_name) +{ + if( silk_Timer_nTimers > 0 ) + { + int k; + FILE *fp; + LARGE_INTEGER lpFrequency; + LARGE_INTEGER lpPerformanceCount1, lpPerformanceCount2; + int del = 0x7FFFFFFF; + double avg, sum_avg; + /* estimate overhead of calling performance counters */ + for( k = 0; k < 1000; k++ ) { + QueryPerformanceCounter(&lpPerformanceCount1); + QueryPerformanceCounter(&lpPerformanceCount2); + lpPerformanceCount2.QuadPart -= lpPerformanceCount1.QuadPart; + if( (int)lpPerformanceCount2.LowPart < del ) + del = lpPerformanceCount2.LowPart; + } + QueryPerformanceFrequency(&lpFrequency); + /* print results to file */ + sum_avg = 0.0f; + for( k = 0; k < silk_Timer_nTimers; k++ ) { + if (silk_Timer_depth[k] == 0) { + sum_avg += (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart * silk_Timer_cnt[k]; + } + } + fp = fopen(file_name, "w"); + fprintf(fp, " min avg %% max count\n"); + for( k = 0; k < silk_Timer_nTimers; k++ ) { + if (silk_Timer_depth[k] == 0) { + fprintf(fp, "%-28s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 1) { + fprintf(fp, " %-27s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 2) { + fprintf(fp, " %-26s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 3) { + fprintf(fp, " %-25s", silk_Timer_tags[k]); + } else { + fprintf(fp, " %-24s", silk_Timer_tags[k]); + } + avg = (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart; + fprintf(fp, "%8.2f", (1e6 * (silk_max_64(silk_Timer_min[k] - del, 0))) / lpFrequency.QuadPart); + fprintf(fp, "%12.2f %6.2f", avg, 100.0 * avg / sum_avg * silk_Timer_cnt[k]); + fprintf(fp, "%12.2f", (1e6 * (silk_max_64(silk_Timer_max[k] - del, 0))) / lpFrequency.QuadPart); + fprintf(fp, "%10d\n", silk_Timer_cnt[k]); + } + fprintf(fp, " microseconds\n"); + fclose(fp); + } +} +#else +void silk_TimerSave(char *file_name) +{ + if( silk_Timer_nTimers > 0 ) + { + int k; + FILE *fp; + /* print results to file */ + fp = fopen(file_name, "w"); + fprintf(fp, " min avg max count\n"); + for( k = 0; k < silk_Timer_nTimers; k++ ) + { + if (silk_Timer_depth[k] == 0) { + fprintf(fp, "%-28s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 1) { + fprintf(fp, " %-27s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 2) { + fprintf(fp, " %-26s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 3) { + fprintf(fp, " %-25s", silk_Timer_tags[k]); + } else { + fprintf(fp, " %-24s", silk_Timer_tags[k]); + } + fprintf(fp, "%d ", silk_Timer_min[k]); + fprintf(fp, "%f ", (double)silk_Timer_sum[k] / (double)silk_Timer_cnt[k]); + fprintf(fp, "%d ", silk_Timer_max[k]); + fprintf(fp, "%10d\n", silk_Timer_cnt[k]); + } + fprintf(fp, " microseconds\n"); + fclose(fp); + } +} +#endif + +#endif /* SILK_TIC_TOC */ + +#if SILK_DEBUG +FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ]; +int silk_debug_store_count = 0; +#endif /* SILK_DEBUG */ + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/debug.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/debug.h new file mode 100644 index 000000000..36163e478 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/debug.h @@ -0,0 +1,267 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_DEBUG_H +#define SILK_DEBUG_H + +/* Set to 1 to enable DEBUG_STORE_DATA() macros for dumping + * intermediate signals from the codec. + */ +#define SILK_DEBUG 0 + +/* Flag for using timers */ +#define SILK_TIC_TOC 0 + +#if SILK_DEBUG || SILK_TIC_TOC +#include "typedef.h" +#include /* strcpy, strcmp */ +#include /* file writing */ +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if SILK_TIC_TOC + +unsigned long GetHighResolutionTime(void); /* O time in usec*/ + +#if (defined(_WIN32) || defined(_WINCE)) +#include /* timer */ +#else /* Linux or Mac*/ +#include +#endif + +/*********************************/ +/* timer functions for profiling */ +/*********************************/ +/* example: */ +/* */ +/* TIC(LPC) */ +/* do_LPC(in_vec, order, acoef); // do LPC analysis */ +/* TOC(LPC) */ +/* */ +/* and call the following just before exiting (from main) */ +/* */ +/* silk_TimerSave("silk_TimingData.txt"); */ +/* */ +/* results are now in silk_TimingData.txt */ + +void silk_TimerSave(char *file_name); + +/* max number of timers (in different locations) */ +#define silk_NUM_TIMERS_MAX 50 +/* max length of name tags in TIC(..), TOC(..) */ +#define silk_NUM_TIMERS_MAX_TAG_LEN 30 + +extern int silk_Timer_nTimers; +extern int silk_Timer_depth_ctr; +extern char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN]; +#ifdef _WIN32 +extern LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX]; +#else +extern unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX]; +#endif +extern unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX]; + +/* WARNING: TIC()/TOC can measure only up to 0.1 seconds at a time */ +#ifdef _WIN32 +#define TIC(TAG_NAME) { \ + static int init = 0; \ + static int ID = -1; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + if (ID == -1) { \ + ID = silk_Timer_nTimers; \ + silk_Timer_nTimers++; \ + silk_Timer_depth[ID] = silk_Timer_depth_ctr; \ + strcpy(silk_Timer_tags[ID], #TAG_NAME); \ + silk_Timer_cnt[ID] = 0; \ + silk_Timer_sum[ID] = 0; \ + silk_Timer_min[ID] = 0xFFFFFFFF; \ + silk_Timer_max[ID] = 0; \ + } \ + } \ + silk_Timer_depth_ctr++; \ + QueryPerformanceCounter(&silk_Timer_start[ID]); \ +} +#else +#define TIC(TAG_NAME) { \ + static int init = 0; \ + static int ID = -1; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + if (ID == -1) { \ + ID = silk_Timer_nTimers; \ + silk_Timer_nTimers++; \ + silk_Timer_depth[ID] = silk_Timer_depth_ctr; \ + strcpy(silk_Timer_tags[ID], #TAG_NAME); \ + silk_Timer_cnt[ID] = 0; \ + silk_Timer_sum[ID] = 0; \ + silk_Timer_min[ID] = 0xFFFFFFFF; \ + silk_Timer_max[ID] = 0; \ + } \ + } \ + silk_Timer_depth_ctr++; \ + silk_Timer_start[ID] = GetHighResolutionTime(); \ +} +#endif + +#ifdef _WIN32 +#define TOC(TAG_NAME) { \ + LARGE_INTEGER lpPerformanceCount; \ + static int init = 0; \ + static int ID = 0; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + } \ + QueryPerformanceCounter(&lpPerformanceCount); \ + lpPerformanceCount.QuadPart -= silk_Timer_start[ID].QuadPart; \ + if((lpPerformanceCount.QuadPart < 100000000) && \ + (lpPerformanceCount.QuadPart >= 0)) { \ + silk_Timer_cnt[ID]++; \ + silk_Timer_sum[ID] += lpPerformanceCount.QuadPart; \ + if( lpPerformanceCount.QuadPart > silk_Timer_max[ID] ) \ + silk_Timer_max[ID] = lpPerformanceCount.QuadPart; \ + if( lpPerformanceCount.QuadPart < silk_Timer_min[ID] ) \ + silk_Timer_min[ID] = lpPerformanceCount.QuadPart; \ + } \ + silk_Timer_depth_ctr--; \ +} +#else +#define TOC(TAG_NAME) { \ + unsigned long endTime; \ + static int init = 0; \ + static int ID = 0; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + } \ + endTime = GetHighResolutionTime(); \ + endTime -= silk_Timer_start[ID]; \ + if((endTime < 100000000) && \ + (endTime >= 0)) { \ + silk_Timer_cnt[ID]++; \ + silk_Timer_sum[ID] += endTime; \ + if( endTime > silk_Timer_max[ID] ) \ + silk_Timer_max[ID] = endTime; \ + if( endTime < silk_Timer_min[ID] ) \ + silk_Timer_min[ID] = endTime; \ + } \ + silk_Timer_depth_ctr--; \ +} +#endif + +#else /* SILK_TIC_TOC */ + +/* define macros as empty strings */ +#define TIC(TAG_NAME) +#define TOC(TAG_NAME) +#define silk_TimerSave(FILE_NAME) + +#endif /* SILK_TIC_TOC */ + + +#if SILK_DEBUG +/************************************/ +/* write data to file for debugging */ +/************************************/ +/* Example: DEBUG_STORE_DATA(testfile.pcm, &RIN[0], 160*sizeof(opus_int16)); */ + +#define silk_NUM_STORES_MAX 100 +extern FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ]; +extern int silk_debug_store_count; + +/* Faster way of storing the data */ +#define DEBUG_STORE_DATA( FILE_NAME, DATA_PTR, N_BYTES ) { \ + static opus_int init = 0, cnt = 0; \ + static FILE **fp; \ + if (init == 0) { \ + init = 1; \ + cnt = silk_debug_store_count++; \ + silk_debug_store_fp[ cnt ] = fopen(#FILE_NAME, "wb"); \ + } \ + fwrite((DATA_PTR), (N_BYTES), 1, silk_debug_store_fp[ cnt ]); \ +} + +/* Call this at the end of main() */ +#define SILK_DEBUG_STORE_CLOSE_FILES { \ + opus_int i; \ + for( i = 0; i < silk_debug_store_count; i++ ) { \ + fclose( silk_debug_store_fp[ i ] ); \ + } \ +} + +#else /* SILK_DEBUG */ + +/* define macros as empty strings */ +#define DEBUG_STORE_DATA(FILE_NAME, DATA_PTR, N_BYTES) +#define SILK_DEBUG_STORE_CLOSE_FILES + +#endif /* SILK_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_DEBUG_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/dec_API.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/dec_API.c new file mode 100644 index 000000000..7d5ca7fb9 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/dec_API.c @@ -0,0 +1,419 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "API.h" +#include "main.h" +#include "stack_alloc.h" +#include "os_support.h" + +/************************/ +/* Decoder Super Struct */ +/************************/ +typedef struct { + silk_decoder_state channel_state[ DECODER_NUM_CHANNELS ]; + stereo_dec_state sStereo; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int prev_decode_only_middle; +} silk_decoder; + +/*********************/ +/* Decoder functions */ +/*********************/ + +opus_int silk_Get_Decoder_Size( /* O Returns error code */ + opus_int *decSizeBytes /* O Number of bytes in SILK decoder state */ +) +{ + opus_int ret = SILK_NO_ERROR; + + *decSizeBytes = sizeof( silk_decoder ); + + return ret; +} + +/* Reset decoder state */ +opus_int silk_InitDecoder( /* O Returns error code */ + void *decState /* I/O State */ +) +{ + opus_int n, ret = SILK_NO_ERROR; + silk_decoder_state *channel_state = ((silk_decoder *)decState)->channel_state; + + for( n = 0; n < DECODER_NUM_CHANNELS; n++ ) { + ret = silk_init_decoder( &channel_state[ n ] ); + } + silk_memset(&((silk_decoder *)decState)->sStereo, 0, sizeof(((silk_decoder *)decState)->sStereo)); + /* Not strictly needed, but it's cleaner that way */ + ((silk_decoder *)decState)->prev_decode_only_middle = 0; + + return ret; +} + +/* Decode a frame */ +opus_int silk_Decode( /* O Returns error code */ + void* decState, /* I/O State */ + silk_DecControlStruct* decControl, /* I/O Control Structure */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int newPacketFlag, /* I Indicates first decoder call for this packet */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 *samplesOut, /* O Decoded output speech vector */ + opus_int32 *nSamplesOut, /* O Number of samples decoded */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, n, decode_only_middle = 0, ret = SILK_NO_ERROR; + opus_int32 nSamplesOutDec, LBRR_symbol; + opus_int16 *samplesOut1_tmp[ 2 ]; + VARDECL( opus_int16, samplesOut1_tmp_storage1 ); + VARDECL( opus_int16, samplesOut1_tmp_storage2 ); + VARDECL( opus_int16, samplesOut2_tmp ); + opus_int32 MS_pred_Q13[ 2 ] = { 0 }; + opus_int16 *resample_out_ptr; + silk_decoder *psDec = ( silk_decoder * )decState; + silk_decoder_state *channel_state = psDec->channel_state; + opus_int has_side; + opus_int stereo_to_mono; + int delay_stack_alloc; + SAVE_STACK; + + celt_assert( decControl->nChannelsInternal == 1 || decControl->nChannelsInternal == 2 ); + + /**********************************/ + /* Test if first frame in payload */ + /**********************************/ + if( newPacketFlag ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + channel_state[ n ].nFramesDecoded = 0; /* Used to count frames in packet */ + } + } + + /* If Mono -> Stereo transition in bitstream: init state of second channel */ + if( decControl->nChannelsInternal > psDec->nChannelsInternal ) { + ret += silk_init_decoder( &channel_state[ 1 ] ); + } + + stereo_to_mono = decControl->nChannelsInternal == 1 && psDec->nChannelsInternal == 2 && + ( decControl->internalSampleRate == 1000*channel_state[ 0 ].fs_kHz ); + + if( channel_state[ 0 ].nFramesDecoded == 0 ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + opus_int fs_kHz_dec; + if( decControl->payloadSize_ms == 0 ) { + /* Assuming packet loss, use 10 ms */ + channel_state[ n ].nFramesPerPacket = 1; + channel_state[ n ].nb_subfr = 2; + } else if( decControl->payloadSize_ms == 10 ) { + channel_state[ n ].nFramesPerPacket = 1; + channel_state[ n ].nb_subfr = 2; + } else if( decControl->payloadSize_ms == 20 ) { + channel_state[ n ].nFramesPerPacket = 1; + channel_state[ n ].nb_subfr = 4; + } else if( decControl->payloadSize_ms == 40 ) { + channel_state[ n ].nFramesPerPacket = 2; + channel_state[ n ].nb_subfr = 4; + } else if( decControl->payloadSize_ms == 60 ) { + channel_state[ n ].nFramesPerPacket = 3; + channel_state[ n ].nb_subfr = 4; + } else { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_DEC_INVALID_FRAME_SIZE; + } + fs_kHz_dec = ( decControl->internalSampleRate >> 10 ) + 1; + if( fs_kHz_dec != 8 && fs_kHz_dec != 12 && fs_kHz_dec != 16 ) { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_DEC_INVALID_SAMPLING_FREQUENCY; + } + ret += silk_decoder_set_fs( &channel_state[ n ], fs_kHz_dec, decControl->API_sampleRate ); + } + } + + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 && ( psDec->nChannelsAPI == 1 || psDec->nChannelsInternal == 1 ) ) { + silk_memset( psDec->sStereo.pred_prev_Q13, 0, sizeof( psDec->sStereo.pred_prev_Q13 ) ); + silk_memset( psDec->sStereo.sSide, 0, sizeof( psDec->sStereo.sSide ) ); + silk_memcpy( &channel_state[ 1 ].resampler_state, &channel_state[ 0 ].resampler_state, sizeof( silk_resampler_state_struct ) ); + } + psDec->nChannelsAPI = decControl->nChannelsAPI; + psDec->nChannelsInternal = decControl->nChannelsInternal; + + if( decControl->API_sampleRate > (opus_int32)MAX_API_FS_KHZ * 1000 || decControl->API_sampleRate < 8000 ) { + ret = SILK_DEC_INVALID_SAMPLING_FREQUENCY; + RESTORE_STACK; + return( ret ); + } + + if( lostFlag != FLAG_PACKET_LOST && channel_state[ 0 ].nFramesDecoded == 0 ) { + /* First decoder call for this payload */ + /* Decode VAD flags and LBRR flag */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) { + channel_state[ n ].VAD_flags[ i ] = ec_dec_bit_logp(psRangeDec, 1); + } + channel_state[ n ].LBRR_flag = ec_dec_bit_logp(psRangeDec, 1); + } + /* Decode LBRR flags */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + silk_memset( channel_state[ n ].LBRR_flags, 0, sizeof( channel_state[ n ].LBRR_flags ) ); + if( channel_state[ n ].LBRR_flag ) { + if( channel_state[ n ].nFramesPerPacket == 1 ) { + channel_state[ n ].LBRR_flags[ 0 ] = 1; + } else { + LBRR_symbol = ec_dec_icdf( psRangeDec, silk_LBRR_flags_iCDF_ptr[ channel_state[ n ].nFramesPerPacket - 2 ], 8 ) + 1; + for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) { + channel_state[ n ].LBRR_flags[ i ] = silk_RSHIFT( LBRR_symbol, i ) & 1; + } + } + } + } + + if( lostFlag == FLAG_DECODE_NORMAL ) { + /* Regular decoding: skip all LBRR data */ + for( i = 0; i < channel_state[ 0 ].nFramesPerPacket; i++ ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + if( channel_state[ n ].LBRR_flags[ i ] ) { + opus_int16 pulses[ MAX_FRAME_LENGTH ]; + opus_int condCoding; + + if( decControl->nChannelsInternal == 2 && n == 0 ) { + silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 ); + if( channel_state[ 1 ].LBRR_flags[ i ] == 0 ) { + silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle ); + } + } + /* Use conditional coding if previous frame available */ + if( i > 0 && channel_state[ n ].LBRR_flags[ i - 1 ] ) { + condCoding = CODE_CONDITIONALLY; + } else { + condCoding = CODE_INDEPENDENTLY; + } + silk_decode_indices( &channel_state[ n ], psRangeDec, i, 1, condCoding ); + silk_decode_pulses( psRangeDec, pulses, channel_state[ n ].indices.signalType, + channel_state[ n ].indices.quantOffsetType, channel_state[ n ].frame_length ); + } + } + } + } + } + + /* Get MS predictor index */ + if( decControl->nChannelsInternal == 2 ) { + if( lostFlag == FLAG_DECODE_NORMAL || + ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 0 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 1 ) ) + { + silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 ); + /* For LBRR data, decode mid-only flag only if side-channel's LBRR flag is false */ + if( ( lostFlag == FLAG_DECODE_NORMAL && channel_state[ 1 ].VAD_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) || + ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 1 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) ) + { + silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle ); + } else { + decode_only_middle = 0; + } + } else { + for( n = 0; n < 2; n++ ) { + MS_pred_Q13[ n ] = psDec->sStereo.pred_prev_Q13[ n ]; + } + } + } + + /* Reset side channel decoder prediction memory for first frame with side coding */ + if( decControl->nChannelsInternal == 2 && decode_only_middle == 0 && psDec->prev_decode_only_middle == 1 ) { + silk_memset( psDec->channel_state[ 1 ].outBuf, 0, sizeof(psDec->channel_state[ 1 ].outBuf) ); + silk_memset( psDec->channel_state[ 1 ].sLPC_Q14_buf, 0, sizeof(psDec->channel_state[ 1 ].sLPC_Q14_buf) ); + psDec->channel_state[ 1 ].lagPrev = 100; + psDec->channel_state[ 1 ].LastGainIndex = 10; + psDec->channel_state[ 1 ].prevSignalType = TYPE_NO_VOICE_ACTIVITY; + psDec->channel_state[ 1 ].first_frame_after_reset = 1; + } + + /* Check if the temp buffer fits into the output PCM buffer. If it fits, + we can delay allocating the temp buffer until after the SILK peak stack + usage. We need to use a < and not a <= because of the two extra samples. */ + delay_stack_alloc = decControl->internalSampleRate*decControl->nChannelsInternal + < decControl->API_sampleRate*decControl->nChannelsAPI; + ALLOC( samplesOut1_tmp_storage1, delay_stack_alloc ? ALLOC_NONE + : decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2 ), + opus_int16 ); + if ( delay_stack_alloc ) + { + samplesOut1_tmp[ 0 ] = samplesOut; + samplesOut1_tmp[ 1 ] = samplesOut + channel_state[ 0 ].frame_length + 2; + } else { + samplesOut1_tmp[ 0 ] = samplesOut1_tmp_storage1; + samplesOut1_tmp[ 1 ] = samplesOut1_tmp_storage1 + channel_state[ 0 ].frame_length + 2; + } + + if( lostFlag == FLAG_DECODE_NORMAL ) { + has_side = !decode_only_middle; + } else { + has_side = !psDec->prev_decode_only_middle + || (decControl->nChannelsInternal == 2 && lostFlag == FLAG_DECODE_LBRR && channel_state[1].LBRR_flags[ channel_state[1].nFramesDecoded ] == 1 ); + } + /* Call decoder for one frame */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + if( n == 0 || has_side ) { + opus_int FrameIndex; + opus_int condCoding; + + FrameIndex = channel_state[ 0 ].nFramesDecoded - n; + /* Use independent coding if no previous frame available */ + if( FrameIndex <= 0 ) { + condCoding = CODE_INDEPENDENTLY; + } else if( lostFlag == FLAG_DECODE_LBRR ) { + condCoding = channel_state[ n ].LBRR_flags[ FrameIndex - 1 ] ? CODE_CONDITIONALLY : CODE_INDEPENDENTLY; + } else if( n > 0 && psDec->prev_decode_only_middle ) { + /* If we skipped a side frame in this packet, we don't + need LTP scaling; the LTP state is well-defined. */ + condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING; + } else { + condCoding = CODE_CONDITIONALLY; + } + ret += silk_decode_frame( &channel_state[ n ], psRangeDec, &samplesOut1_tmp[ n ][ 2 ], &nSamplesOutDec, lostFlag, condCoding, arch); + } else { + silk_memset( &samplesOut1_tmp[ n ][ 2 ], 0, nSamplesOutDec * sizeof( opus_int16 ) ); + } + channel_state[ n ].nFramesDecoded++; + } + + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 ) { + /* Convert Mid/Side to Left/Right */ + silk_stereo_MS_to_LR( &psDec->sStereo, samplesOut1_tmp[ 0 ], samplesOut1_tmp[ 1 ], MS_pred_Q13, channel_state[ 0 ].fs_kHz, nSamplesOutDec ); + } else { + /* Buffering */ + silk_memcpy( samplesOut1_tmp[ 0 ], psDec->sStereo.sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( psDec->sStereo.sMid, &samplesOut1_tmp[ 0 ][ nSamplesOutDec ], 2 * sizeof( opus_int16 ) ); + } + + /* Number of output samples */ + *nSamplesOut = silk_DIV32( nSamplesOutDec * decControl->API_sampleRate, silk_SMULBB( channel_state[ 0 ].fs_kHz, 1000 ) ); + + /* Set up pointers to temp buffers */ + ALLOC( samplesOut2_tmp, + decControl->nChannelsAPI == 2 ? *nSamplesOut : ALLOC_NONE, opus_int16 ); + if( decControl->nChannelsAPI == 2 ) { + resample_out_ptr = samplesOut2_tmp; + } else { + resample_out_ptr = samplesOut; + } + + ALLOC( samplesOut1_tmp_storage2, delay_stack_alloc + ? decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2 ) + : ALLOC_NONE, + opus_int16 ); + if ( delay_stack_alloc ) { + OPUS_COPY(samplesOut1_tmp_storage2, samplesOut, decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2)); + samplesOut1_tmp[ 0 ] = samplesOut1_tmp_storage2; + samplesOut1_tmp[ 1 ] = samplesOut1_tmp_storage2 + channel_state[ 0 ].frame_length + 2; + } + for( n = 0; n < silk_min( decControl->nChannelsAPI, decControl->nChannelsInternal ); n++ ) { + + /* Resample decoded signal to API_sampleRate */ + ret += silk_resampler( &channel_state[ n ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ n ][ 1 ], nSamplesOutDec ); + + /* Interleave if stereo output and stereo stream */ + if( decControl->nChannelsAPI == 2 ) { + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ n + 2 * i ] = resample_out_ptr[ i ]; + } + } + } + + /* Create two channel output from mono stream */ + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 1 ) { + if ( stereo_to_mono ){ + /* Resample right channel for newly collapsed stereo just in case + we weren't doing collapsing when switching to mono */ + ret += silk_resampler( &channel_state[ 1 ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ 0 ][ 1 ], nSamplesOutDec ); + + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ 1 + 2 * i ] = resample_out_ptr[ i ]; + } + } else { + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ 1 + 2 * i ] = samplesOut[ 0 + 2 * i ]; + } + } + } + + /* Export pitch lag, measured at 48 kHz sampling rate */ + if( channel_state[ 0 ].prevSignalType == TYPE_VOICED ) { + int mult_tab[ 3 ] = { 6, 4, 3 }; + decControl->prevPitchLag = channel_state[ 0 ].lagPrev * mult_tab[ ( channel_state[ 0 ].fs_kHz - 8 ) >> 2 ]; + } else { + decControl->prevPitchLag = 0; + } + + if( lostFlag == FLAG_PACKET_LOST ) { + /* On packet loss, remove the gain clamping to prevent having the energy "bounce back" + if we lose packets when the energy is going down */ + for ( i = 0; i < psDec->nChannelsInternal; i++ ) + psDec->channel_state[ i ].LastGainIndex = 10; + } else { + psDec->prev_decode_only_middle = decode_only_middle; + } + RESTORE_STACK; + return ret; +} + +#if 0 +/* Getting table of contents for a packet */ +opus_int silk_get_TOC( + const opus_uint8 *payload, /* I Payload data */ + const opus_int nBytesIn, /* I Number of input bytes */ + const opus_int nFramesPerPayload, /* I Number of SILK frames per payload */ + silk_TOC_struct *Silk_TOC /* O Type of content */ +) +{ + opus_int i, flags, ret = SILK_NO_ERROR; + + if( nBytesIn < 1 ) { + return -1; + } + if( nFramesPerPayload < 0 || nFramesPerPayload > 3 ) { + return -1; + } + + silk_memset( Silk_TOC, 0, sizeof( *Silk_TOC ) ); + + /* For stereo, extract the flags for the mid channel */ + flags = silk_RSHIFT( payload[ 0 ], 7 - nFramesPerPayload ) & ( silk_LSHIFT( 1, nFramesPerPayload + 1 ) - 1 ); + + Silk_TOC->inbandFECFlag = flags & 1; + for( i = nFramesPerPayload - 1; i >= 0 ; i-- ) { + flags = silk_RSHIFT( flags, 1 ); + Silk_TOC->VADFlags[ i ] = flags & 1; + Silk_TOC->VADFlag |= flags & 1; + } + + return ret; +} +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_core.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_core.c new file mode 100644 index 000000000..1c352a652 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_core.c @@ -0,0 +1,237 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/**********************************************************/ +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +/**********************************************************/ +void silk_decode_core( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I Decoder control */ + opus_int16 xq[], /* O Decoded speech */ + const opus_int16 pulses[ MAX_FRAME_LENGTH ], /* I Pulse signal */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, k, lag = 0, start_idx, sLTP_buf_idx, NLSF_interpolation_flag, signalType; + opus_int16 *A_Q12, *B_Q14, *pxq, A_Q12_tmp[ MAX_LPC_ORDER ]; + VARDECL( opus_int16, sLTP ); + VARDECL( opus_int32, sLTP_Q15 ); + opus_int32 LTP_pred_Q13, LPC_pred_Q10, Gain_Q10, inv_gain_Q31, gain_adj_Q16, rand_seed, offset_Q10; + opus_int32 *pred_lag_ptr, *pexc_Q14, *pres_Q14; + VARDECL( opus_int32, res_Q14 ); + VARDECL( opus_int32, sLPC_Q14 ); + SAVE_STACK; + + silk_assert( psDec->prev_gain_Q16 != 0 ); + + ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 ); + ALLOC( sLTP_Q15, psDec->ltp_mem_length + psDec->frame_length, opus_int32 ); + ALLOC( res_Q14, psDec->subfr_length, opus_int32 ); + ALLOC( sLPC_Q14, psDec->subfr_length + MAX_LPC_ORDER, opus_int32 ); + + offset_Q10 = silk_Quantization_Offsets_Q10[ psDec->indices.signalType >> 1 ][ psDec->indices.quantOffsetType ]; + + if( psDec->indices.NLSFInterpCoef_Q2 < 1 << 2 ) { + NLSF_interpolation_flag = 1; + } else { + NLSF_interpolation_flag = 0; + } + + /* Decode excitation */ + rand_seed = psDec->indices.Seed; + for( i = 0; i < psDec->frame_length; i++ ) { + rand_seed = silk_RAND( rand_seed ); + psDec->exc_Q14[ i ] = silk_LSHIFT( (opus_int32)pulses[ i ], 14 ); + if( psDec->exc_Q14[ i ] > 0 ) { + psDec->exc_Q14[ i ] -= QUANT_LEVEL_ADJUST_Q10 << 4; + } else + if( psDec->exc_Q14[ i ] < 0 ) { + psDec->exc_Q14[ i ] += QUANT_LEVEL_ADJUST_Q10 << 4; + } + psDec->exc_Q14[ i ] += offset_Q10 << 4; + if( rand_seed < 0 ) { + psDec->exc_Q14[ i ] = -psDec->exc_Q14[ i ]; + } + + rand_seed = silk_ADD32_ovflw( rand_seed, pulses[ i ] ); + } + + /* Copy LPC state */ + silk_memcpy( sLPC_Q14, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + pexc_Q14 = psDec->exc_Q14; + pxq = xq; + sLTP_buf_idx = psDec->ltp_mem_length; + /* Loop over subframes */ + for( k = 0; k < psDec->nb_subfr; k++ ) { + pres_Q14 = res_Q14; + A_Q12 = psDecCtrl->PredCoef_Q12[ k >> 1 ]; + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + silk_memcpy( A_Q12_tmp, A_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); + B_Q14 = &psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER ]; + signalType = psDec->indices.signalType; + + Gain_Q10 = silk_RSHIFT( psDecCtrl->Gains_Q16[ k ], 6 ); + inv_gain_Q31 = silk_INVERSE32_varQ( psDecCtrl->Gains_Q16[ k ], 47 ); + + /* Calculate gain adjustment factor */ + if( psDecCtrl->Gains_Q16[ k ] != psDec->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( psDec->prev_gain_Q16, psDecCtrl->Gains_Q16[ k ], 16 ); + + /* Scale short term state */ + for( i = 0; i < MAX_LPC_ORDER; i++ ) { + sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, sLPC_Q14[ i ] ); + } + } else { + gain_adj_Q16 = (opus_int32)1 << 16; + } + + /* Save inv_gain */ + silk_assert( inv_gain_Q31 != 0 ); + psDec->prev_gain_Q16 = psDecCtrl->Gains_Q16[ k ]; + + /* Avoid abrupt transition from voiced PLC to unvoiced normal decoding */ + if( psDec->lossCnt && psDec->prevSignalType == TYPE_VOICED && + psDec->indices.signalType != TYPE_VOICED && k < MAX_NB_SUBFR/2 ) { + + silk_memset( B_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) ); + B_Q14[ LTP_ORDER/2 ] = SILK_FIX_CONST( 0.25, 14 ); + + signalType = TYPE_VOICED; + psDecCtrl->pitchL[ k ] = psDec->lagPrev; + } + + if( signalType == TYPE_VOICED ) { + /* Voiced */ + lag = psDecCtrl->pitchL[ k ]; + + /* Re-whitening */ + if( k == 0 || ( k == 2 && NLSF_interpolation_flag ) ) { + /* Rewhiten with new A coefs */ + start_idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + if( k == 2 ) { + silk_memcpy( &psDec->outBuf[ psDec->ltp_mem_length ], xq, 2 * psDec->subfr_length * sizeof( opus_int16 ) ); + } + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &psDec->outBuf[ start_idx + k * psDec->subfr_length ], + A_Q12, psDec->ltp_mem_length - start_idx, psDec->LPC_order, arch ); + + /* After rewhitening the LTP state is unscaled */ + if( k == 0 ) { + /* Do LTP downscaling to reduce inter-packet dependency */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, psDecCtrl->LTP_scale_Q14 ), 2 ); + } + for( i = 0; i < lag + LTP_ORDER/2; i++ ) { + sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWB( inv_gain_Q31, sLTP[ psDec->ltp_mem_length - i - 1 ] ); + } + } else { + /* Update LTP state when Gain changes */ + if( gain_adj_Q16 != (opus_int32)1 << 16 ) { + for( i = 0; i < lag + LTP_ORDER/2; i++ ) { + sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ sLTP_buf_idx - i - 1 ] ); + } + } + } + } + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Set up pointer */ + pred_lag_ptr = &sLTP_Q15[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q13 = 2; + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); + pred_lag_ptr++; + + /* Generate LPC excitation */ + pres_Q14[ i ] = silk_ADD_LSHIFT32( pexc_Q14[ i ], LTP_pred_Q13, 1 ); + + /* Update states */ + sLTP_Q15[ sLTP_buf_idx ] = silk_LSHIFT( pres_Q14[ i ], 1 ); + sLTP_buf_idx++; + } + } else { + pres_Q14 = pexc_Q14; + } + + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Short-term prediction */ + celt_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12_tmp[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12_tmp[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12_tmp[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12_tmp[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12_tmp[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12_tmp[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12_tmp[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12_tmp[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12_tmp[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12_tmp[ 9 ] ); + if( psDec->LPC_order == 16 ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 11 ], A_Q12_tmp[ 10 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 12 ], A_Q12_tmp[ 11 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 13 ], A_Q12_tmp[ 12 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 14 ], A_Q12_tmp[ 13 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 15 ], A_Q12_tmp[ 14 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12_tmp[ 15 ] ); + } + + /* Add prediction to LPC excitation */ + sLPC_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( pres_Q14[ i ], silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ) ); + + /* Scale with gain */ + pxq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14[ MAX_LPC_ORDER + i ], Gain_Q10 ), 8 ) ); + } + + /* Update LPC filter state */ + silk_memcpy( sLPC_Q14, &sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + pexc_Q14 += psDec->subfr_length; + pxq += psDec->subfr_length; + } + + /* Save LPC state */ + silk_memcpy( psDec->sLPC_Q14_buf, sLPC_Q14, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + RESTORE_STACK; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_frame.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_frame.c new file mode 100644 index 000000000..4f36f854c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_frame.c @@ -0,0 +1,129 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" +#include "PLC.h" + +/****************/ +/* Decode frame */ +/****************/ +opus_int silk_decode_frame( + silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pOut[], /* O Pointer to output speech frame */ + opus_int32 *pN, /* O Pointer to size of output frame */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int condCoding, /* I The type of conditional coding to use */ + int arch /* I Run-time architecture */ +) +{ + VARDECL( silk_decoder_control, psDecCtrl ); + opus_int L, mv_len, ret = 0; + SAVE_STACK; + + L = psDec->frame_length; + ALLOC( psDecCtrl, 1, silk_decoder_control ); + psDecCtrl->LTP_scale_Q14 = 0; + + /* Safety checks */ + celt_assert( L > 0 && L <= MAX_FRAME_LENGTH ); + + if( lostFlag == FLAG_DECODE_NORMAL || + ( lostFlag == FLAG_DECODE_LBRR && psDec->LBRR_flags[ psDec->nFramesDecoded ] == 1 ) ) + { + VARDECL( opus_int16, pulses ); + ALLOC( pulses, (L + SHELL_CODEC_FRAME_LENGTH - 1) & + ~(SHELL_CODEC_FRAME_LENGTH - 1), opus_int16 ); + /*********************************************/ + /* Decode quantization indices of side info */ + /*********************************************/ + silk_decode_indices( psDec, psRangeDec, psDec->nFramesDecoded, lostFlag, condCoding ); + + /*********************************************/ + /* Decode quantization indices of excitation */ + /*********************************************/ + silk_decode_pulses( psRangeDec, pulses, psDec->indices.signalType, + psDec->indices.quantOffsetType, psDec->frame_length ); + + /********************************************/ + /* Decode parameters and pulse signal */ + /********************************************/ + silk_decode_parameters( psDec, psDecCtrl, condCoding ); + + /********************************************************/ + /* Run inverse NSQ */ + /********************************************************/ + silk_decode_core( psDec, psDecCtrl, pOut, pulses, arch ); + + /********************************************************/ + /* Update PLC state */ + /********************************************************/ + silk_PLC( psDec, psDecCtrl, pOut, 0, arch ); + + psDec->lossCnt = 0; + psDec->prevSignalType = psDec->indices.signalType; + celt_assert( psDec->prevSignalType >= 0 && psDec->prevSignalType <= 2 ); + + /* A frame has been decoded without errors */ + psDec->first_frame_after_reset = 0; + } else { + /* Handle packet loss by extrapolation */ + silk_PLC( psDec, psDecCtrl, pOut, 1, arch ); + } + + /*************************/ + /* Update output buffer. */ + /*************************/ + celt_assert( psDec->ltp_mem_length >= psDec->frame_length ); + mv_len = psDec->ltp_mem_length - psDec->frame_length; + silk_memmove( psDec->outBuf, &psDec->outBuf[ psDec->frame_length ], mv_len * sizeof(opus_int16) ); + silk_memcpy( &psDec->outBuf[ mv_len ], pOut, psDec->frame_length * sizeof( opus_int16 ) ); + + /************************************************/ + /* Comfort noise generation / estimation */ + /************************************************/ + silk_CNG( psDec, psDecCtrl, pOut, L ); + + /****************************************************************/ + /* Ensure smooth connection of extrapolated and good frames */ + /****************************************************************/ + silk_PLC_glue_frames( psDec, pOut, L ); + + /* Update some decoder state variables */ + psDec->lagPrev = psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; + + /* Set output frame length */ + *pN = L; + + RESTORE_STACK; + return ret; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_indices.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_indices.c new file mode 100644 index 000000000..0bb4a997a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_indices.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Decode side-information parameters from payload */ +void silk_decode_indices( + silk_decoder_state *psDec, /* I/O State */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int decode_LBRR, /* I Flag indicating LBRR data is being decoded */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, Ix; + opus_int decode_absolute_lagIndex, delta_lagIndex; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + + /*******************************************/ + /* Decode signal type and quantizer offset */ + /*******************************************/ + if( decode_LBRR || psDec->VAD_flags[ FrameIndex ] ) { + Ix = ec_dec_icdf( psRangeDec, silk_type_offset_VAD_iCDF, 8 ) + 2; + } else { + Ix = ec_dec_icdf( psRangeDec, silk_type_offset_no_VAD_iCDF, 8 ); + } + psDec->indices.signalType = (opus_int8)silk_RSHIFT( Ix, 1 ); + psDec->indices.quantOffsetType = (opus_int8)( Ix & 1 ); + + /****************/ + /* Decode gains */ + /****************/ + /* First subframe */ + if( condCoding == CODE_CONDITIONALLY ) { + /* Conditional coding */ + psDec->indices.GainsIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 ); + } else { + /* Independent coding, in two stages: MSB bits followed by 3 LSBs */ + psDec->indices.GainsIndices[ 0 ] = (opus_int8)silk_LSHIFT( ec_dec_icdf( psRangeDec, silk_gain_iCDF[ psDec->indices.signalType ], 8 ), 3 ); + psDec->indices.GainsIndices[ 0 ] += (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform8_iCDF, 8 ); + } + + /* Remaining subframes */ + for( i = 1; i < psDec->nb_subfr; i++ ) { + psDec->indices.GainsIndices[ i ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 ); + } + + /**********************/ + /* Decode LSF Indices */ + /**********************/ + psDec->indices.NLSFIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->CB1_iCDF[ ( psDec->indices.signalType >> 1 ) * psDec->psNLSF_CB->nVectors ], 8 ); + silk_NLSF_unpack( ec_ix, pred_Q8, psDec->psNLSF_CB, psDec->indices.NLSFIndices[ 0 ] ); + celt_assert( psDec->psNLSF_CB->order == psDec->LPC_order ); + for( i = 0; i < psDec->psNLSF_CB->order; i++ ) { + Ix = ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + if( Ix == 0 ) { + Ix -= ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 ); + } else if( Ix == 2 * NLSF_QUANT_MAX_AMPLITUDE ) { + Ix += ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 ); + } + psDec->indices.NLSFIndices[ i+1 ] = (opus_int8)( Ix - NLSF_QUANT_MAX_AMPLITUDE ); + } + + /* Decode LSF interpolation factor */ + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->indices.NLSFInterpCoef_Q2 = (opus_int8)ec_dec_icdf( psRangeDec, silk_NLSF_interpolation_factor_iCDF, 8 ); + } else { + psDec->indices.NLSFInterpCoef_Q2 = 4; + } + + if( psDec->indices.signalType == TYPE_VOICED ) + { + /*********************/ + /* Decode pitch lags */ + /*********************/ + /* Get lag index */ + decode_absolute_lagIndex = 1; + if( condCoding == CODE_CONDITIONALLY && psDec->ec_prevSignalType == TYPE_VOICED ) { + /* Decode Delta index */ + delta_lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_delta_iCDF, 8 ); + if( delta_lagIndex > 0 ) { + delta_lagIndex = delta_lagIndex - 9; + psDec->indices.lagIndex = (opus_int16)( psDec->ec_prevLagIndex + delta_lagIndex ); + decode_absolute_lagIndex = 0; + } + } + if( decode_absolute_lagIndex ) { + /* Absolute decoding */ + psDec->indices.lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_lag_iCDF, 8 ) * silk_RSHIFT( psDec->fs_kHz, 1 ); + psDec->indices.lagIndex += (opus_int16)ec_dec_icdf( psRangeDec, psDec->pitch_lag_low_bits_iCDF, 8 ); + } + psDec->ec_prevLagIndex = psDec->indices.lagIndex; + + /* Get countour index */ + psDec->indices.contourIndex = (opus_int8)ec_dec_icdf( psRangeDec, psDec->pitch_contour_iCDF, 8 ); + + /********************/ + /* Decode LTP gains */ + /********************/ + /* Decode PERIndex value */ + psDec->indices.PERIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_per_index_iCDF, 8 ); + + for( k = 0; k < psDec->nb_subfr; k++ ) { + psDec->indices.LTPIndex[ k ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_gain_iCDF_ptrs[ psDec->indices.PERIndex ], 8 ); + } + + /**********************/ + /* Decode LTP scaling */ + /**********************/ + if( condCoding == CODE_INDEPENDENTLY ) { + psDec->indices.LTP_scaleIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTPscale_iCDF, 8 ); + } else { + psDec->indices.LTP_scaleIndex = 0; + } + } + psDec->ec_prevSignalType = psDec->indices.signalType; + + /***************/ + /* Decode seed */ + /***************/ + psDec->indices.Seed = (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform4_iCDF, 8 ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_parameters.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_parameters.c new file mode 100644 index 000000000..a56a40985 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_parameters.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Decode parameters from payload */ +void silk_decode_parameters( + silk_decoder_state *psDec, /* I/O State */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, Ix; + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], pNLSF0_Q15[ MAX_LPC_ORDER ]; + const opus_int8 *cbk_ptr_Q7; + + /* Dequant Gains */ + silk_gains_dequant( psDecCtrl->Gains_Q16, psDec->indices.GainsIndices, + &psDec->LastGainIndex, condCoding == CODE_CONDITIONALLY, psDec->nb_subfr ); + + /****************/ + /* Decode NLSFs */ + /****************/ + silk_NLSF_decode( pNLSF_Q15, psDec->indices.NLSFIndices, psDec->psNLSF_CB ); + + /* Convert NLSF parameters to AR prediction filter coefficients */ + silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psDec->LPC_order, psDec->arch ); + + /* If just reset, e.g., because internal Fs changed, do not allow interpolation */ + /* improves the case of packet loss in the first frame after a switch */ + if( psDec->first_frame_after_reset == 1 ) { + psDec->indices.NLSFInterpCoef_Q2 = 4; + } + + if( psDec->indices.NLSFInterpCoef_Q2 < 4 ) { + /* Calculation of the interpolated NLSF0 vector from the interpolation factor, */ + /* the previous NLSF1, and the current NLSF1 */ + for( i = 0; i < psDec->LPC_order; i++ ) { + pNLSF0_Q15[ i ] = psDec->prevNLSF_Q15[ i ] + silk_RSHIFT( silk_MUL( psDec->indices.NLSFInterpCoef_Q2, + pNLSF_Q15[ i ] - psDec->prevNLSF_Q15[ i ] ), 2 ); + } + + /* Convert NLSF parameters to AR prediction filter coefficients */ + silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 0 ], pNLSF0_Q15, psDec->LPC_order, psDec->arch ); + } else { + /* Copy LPC coefficients for first half from second half */ + silk_memcpy( psDecCtrl->PredCoef_Q12[ 0 ], psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) ); + } + + silk_memcpy( psDec->prevNLSF_Q15, pNLSF_Q15, psDec->LPC_order * sizeof( opus_int16 ) ); + + /* After a packet loss do BWE of LPC coefs */ + if( psDec->lossCnt ) { + silk_bwexpander( psDecCtrl->PredCoef_Q12[ 0 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 ); + silk_bwexpander( psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 ); + } + + if( psDec->indices.signalType == TYPE_VOICED ) { + /*********************/ + /* Decode pitch lags */ + /*********************/ + + /* Decode pitch values */ + silk_decode_pitch( psDec->indices.lagIndex, psDec->indices.contourIndex, psDecCtrl->pitchL, psDec->fs_kHz, psDec->nb_subfr ); + + /* Decode Codebook Index */ + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ psDec->indices.PERIndex ]; /* set pointer to start of codebook */ + + for( k = 0; k < psDec->nb_subfr; k++ ) { + Ix = psDec->indices.LTPIndex[ k ]; + for( i = 0; i < LTP_ORDER; i++ ) { + psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER + i ] = silk_LSHIFT( cbk_ptr_Q7[ Ix * LTP_ORDER + i ], 7 ); + } + } + + /**********************/ + /* Decode LTP scaling */ + /**********************/ + Ix = psDec->indices.LTP_scaleIndex; + psDecCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ Ix ]; + } else { + silk_memset( psDecCtrl->pitchL, 0, psDec->nb_subfr * sizeof( opus_int ) ); + silk_memset( psDecCtrl->LTPCoef_Q14, 0, LTP_ORDER * psDec->nb_subfr * sizeof( opus_int16 ) ); + psDec->indices.PERIndex = 0; + psDecCtrl->LTP_scale_Q14 = 0; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_pitch.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_pitch.c new file mode 100644 index 000000000..fd1b6bf55 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_pitch.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/*********************************************************** +* Pitch analyser function +********************************************************** */ +#include "SigProc_FIX.h" +#include "pitch_est_defines.h" + +void silk_decode_pitch( + opus_int16 lagIndex, /* I */ + opus_int8 contourIndex, /* O */ + opus_int pitch_lags[], /* O 4 pitch values */ + const opus_int Fs_kHz, /* I sampling frequency (kHz) */ + const opus_int nb_subfr /* I number of sub frames */ +) +{ + opus_int lag, k, min_lag, max_lag, cbk_size; + const opus_int8 *Lag_CB_ptr; + + if( Fs_kHz == 8 ) { + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE2_EXT; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 ); + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE2_10MS; + } + } else { + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 ); + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + } + + min_lag = silk_SMULBB( PE_MIN_LAG_MS, Fs_kHz ); + max_lag = silk_SMULBB( PE_MAX_LAG_MS, Fs_kHz ); + lag = min_lag + lagIndex; + + for( k = 0; k < nb_subfr; k++ ) { + pitch_lags[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, contourIndex, cbk_size ); + pitch_lags[ k ] = silk_LIMIT( pitch_lags[ k ], min_lag, max_lag ); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_pulses.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_pulses.c new file mode 100644 index 000000000..a56d2d307 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decode_pulses.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/*********************************************/ +/* Decode quantization indices of excitation */ +/*********************************************/ +void silk_decode_pulses( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pulses[], /* O Excitation signal */ + const opus_int signalType, /* I Sigtype */ + const opus_int quantOffsetType, /* I quantOffsetType */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int i, j, k, iter, abs_q, nLS, RateLevelIndex; + opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ], nLshifts[ MAX_NB_SHELL_BLOCKS ]; + opus_int16 *pulses_ptr; + const opus_uint8 *cdf_ptr; + + /*********************/ + /* Decode rate level */ + /*********************/ + RateLevelIndex = ec_dec_icdf( psRangeDec, silk_rate_levels_iCDF[ signalType >> 1 ], 8 ); + + /* Calculate number of shell blocks */ + silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH ); + iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH ); + if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) { + celt_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */ + iter++; + } + + /***************************************************/ + /* Sum-Weighted-Pulses Decoding */ + /***************************************************/ + cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ]; + for( i = 0; i < iter; i++ ) { + nLshifts[ i ] = 0; + sum_pulses[ i ] = ec_dec_icdf( psRangeDec, cdf_ptr, 8 ); + + /* LSB indication */ + while( sum_pulses[ i ] == SILK_MAX_PULSES + 1 ) { + nLshifts[ i ]++; + /* When we've already got 10 LSBs, we shift the table to not allow (SILK_MAX_PULSES + 1) */ + sum_pulses[ i ] = ec_dec_icdf( psRangeDec, + silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1] + ( nLshifts[ i ] == 10 ), 8 ); + } + } + + /***************************************************/ + /* Shell decoding */ + /***************************************************/ + for( i = 0; i < iter; i++ ) { + if( sum_pulses[ i ] > 0 ) { + silk_shell_decoder( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], psRangeDec, sum_pulses[ i ] ); + } else { + silk_memset( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof( pulses[0] ) ); + } + } + + /***************************************************/ + /* LSB Decoding */ + /***************************************************/ + for( i = 0; i < iter; i++ ) { + if( nLshifts[ i ] > 0 ) { + nLS = nLshifts[ i ]; + pulses_ptr = &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ]; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_q = pulses_ptr[ k ]; + for( j = 0; j < nLS; j++ ) { + abs_q = silk_LSHIFT( abs_q, 1 ); + abs_q += ec_dec_icdf( psRangeDec, silk_lsb_iCDF, 8 ); + } + pulses_ptr[ k ] = abs_q; + } + /* Mark the number of pulses non-zero for sign decoding. */ + sum_pulses[ i ] |= nLS << 5; + } + } + + /****************************************/ + /* Decode and add signs to pulse signal */ + /****************************************/ + silk_decode_signs( psRangeDec, pulses, frame_length, signalType, quantOffsetType, sum_pulses ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decoder_set_fs.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decoder_set_fs.c new file mode 100644 index 000000000..d9a13d0f0 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/decoder_set_fs.c @@ -0,0 +1,108 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Set decoder sampling rate */ +opus_int silk_decoder_set_fs( + silk_decoder_state *psDec, /* I/O Decoder state pointer */ + opus_int fs_kHz, /* I Sampling frequency (kHz) */ + opus_int32 fs_API_Hz /* I API Sampling frequency (Hz) */ +) +{ + opus_int frame_length, ret = 0; + + celt_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 ); + celt_assert( psDec->nb_subfr == MAX_NB_SUBFR || psDec->nb_subfr == MAX_NB_SUBFR/2 ); + + /* New (sub)frame length */ + psDec->subfr_length = silk_SMULBB( SUB_FRAME_LENGTH_MS, fs_kHz ); + frame_length = silk_SMULBB( psDec->nb_subfr, psDec->subfr_length ); + + /* Initialize resampler when switching internal or external sampling frequency */ + if( psDec->fs_kHz != fs_kHz || psDec->fs_API_hz != fs_API_Hz ) { + /* Initialize the resampler for dec_API.c preparing resampling from fs_kHz to API_fs_Hz */ + ret += silk_resampler_init( &psDec->resampler_state, silk_SMULBB( fs_kHz, 1000 ), fs_API_Hz, 0 ); + + psDec->fs_API_hz = fs_API_Hz; + } + + if( psDec->fs_kHz != fs_kHz || frame_length != psDec->frame_length ) { + if( fs_kHz == 8 ) { + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } + } else { + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->pitch_contour_iCDF = silk_pitch_contour_iCDF; + } else { + psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } + if( psDec->fs_kHz != fs_kHz ) { + psDec->ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz ); + if( fs_kHz == 8 || fs_kHz == 12 ) { + psDec->LPC_order = MIN_LPC_ORDER; + psDec->psNLSF_CB = &silk_NLSF_CB_NB_MB; + } else { + psDec->LPC_order = MAX_LPC_ORDER; + psDec->psNLSF_CB = &silk_NLSF_CB_WB; + } + if( fs_kHz == 16 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform8_iCDF; + } else if( fs_kHz == 12 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform6_iCDF; + } else if( fs_kHz == 8 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform4_iCDF; + } else { + /* unsupported sampling rate */ + celt_assert( 0 ); + } + psDec->first_frame_after_reset = 1; + psDec->lagPrev = 100; + psDec->LastGainIndex = 10; + psDec->prevSignalType = TYPE_NO_VOICE_ACTIVITY; + silk_memset( psDec->outBuf, 0, sizeof(psDec->outBuf)); + silk_memset( psDec->sLPC_Q14_buf, 0, sizeof(psDec->sLPC_Q14_buf) ); + } + + psDec->fs_kHz = fs_kHz; + psDec->frame_length = frame_length; + } + + /* Check that settings are valid */ + celt_assert( psDec->frame_length > 0 && psDec->frame_length <= MAX_FRAME_LENGTH ); + + return ret; +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/define.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/define.h new file mode 100644 index 000000000..491c86f33 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/define.h @@ -0,0 +1,235 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_DEFINE_H +#define SILK_DEFINE_H + +#include "errors.h" +#include "typedef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Max number of encoder channels (1/2) */ +#define ENCODER_NUM_CHANNELS 2 +/* Number of decoder channels (1/2) */ +#define DECODER_NUM_CHANNELS 2 + +#define MAX_FRAMES_PER_PACKET 3 + +/* Limits on bitrate */ +#define MIN_TARGET_RATE_BPS 5000 +#define MAX_TARGET_RATE_BPS 80000 + +/* LBRR thresholds */ +#define LBRR_NB_MIN_RATE_BPS 12000 +#define LBRR_MB_MIN_RATE_BPS 14000 +#define LBRR_WB_MIN_RATE_BPS 16000 + +/* DTX settings */ +#define NB_SPEECH_FRAMES_BEFORE_DTX 10 /* eq 200 ms */ +#define MAX_CONSECUTIVE_DTX 20 /* eq 400 ms */ +#define DTX_ACTIVITY_THRESHOLD 0.1f + +/* VAD decision */ +#define VAD_NO_DECISION -1 +#define VAD_NO_ACTIVITY 0 +#define VAD_ACTIVITY 1 + +/* Maximum sampling frequency */ +#define MAX_FS_KHZ 16 +#define MAX_API_FS_KHZ 48 + +/* Signal types */ +#define TYPE_NO_VOICE_ACTIVITY 0 +#define TYPE_UNVOICED 1 +#define TYPE_VOICED 2 + +/* Conditional coding types */ +#define CODE_INDEPENDENTLY 0 +#define CODE_INDEPENDENTLY_NO_LTP_SCALING 1 +#define CODE_CONDITIONALLY 2 + +/* Settings for stereo processing */ +#define STEREO_QUANT_TAB_SIZE 16 +#define STEREO_QUANT_SUB_STEPS 5 +#define STEREO_INTERP_LEN_MS 8 /* must be even */ +#define STEREO_RATIO_SMOOTH_COEF 0.01 /* smoothing coef for signal norms and stereo width */ + +/* Range of pitch lag estimates */ +#define PITCH_EST_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ +#define PITCH_EST_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ + +/* Maximum number of subframes */ +#define MAX_NB_SUBFR 4 + +/* Number of samples per frame */ +#define LTP_MEM_LENGTH_MS 20 +#define SUB_FRAME_LENGTH_MS 5 +#define MAX_SUB_FRAME_LENGTH ( SUB_FRAME_LENGTH_MS * MAX_FS_KHZ ) +#define MAX_FRAME_LENGTH_MS ( SUB_FRAME_LENGTH_MS * MAX_NB_SUBFR ) +#define MAX_FRAME_LENGTH ( MAX_FRAME_LENGTH_MS * MAX_FS_KHZ ) + +/* Milliseconds of lookahead for pitch analysis */ +#define LA_PITCH_MS 2 +#define LA_PITCH_MAX ( LA_PITCH_MS * MAX_FS_KHZ ) + +/* Order of LPC used in find pitch */ +#define MAX_FIND_PITCH_LPC_ORDER 16 + +/* Length of LPC window used in find pitch */ +#define FIND_PITCH_LPC_WIN_MS ( 20 + (LA_PITCH_MS << 1) ) +#define FIND_PITCH_LPC_WIN_MS_2_SF ( 10 + (LA_PITCH_MS << 1) ) +#define FIND_PITCH_LPC_WIN_MAX ( FIND_PITCH_LPC_WIN_MS * MAX_FS_KHZ ) + +/* Milliseconds of lookahead for noise shape analysis */ +#define LA_SHAPE_MS 5 +#define LA_SHAPE_MAX ( LA_SHAPE_MS * MAX_FS_KHZ ) + +/* Maximum length of LPC window used in noise shape analysis */ +#define SHAPE_LPC_WIN_MAX ( 15 * MAX_FS_KHZ ) + +/* dB level of lowest gain quantization level */ +#define MIN_QGAIN_DB 2 +/* dB level of highest gain quantization level */ +#define MAX_QGAIN_DB 88 +/* Number of gain quantization levels */ +#define N_LEVELS_QGAIN 64 +/* Max increase in gain quantization index */ +#define MAX_DELTA_GAIN_QUANT 36 +/* Max decrease in gain quantization index */ +#define MIN_DELTA_GAIN_QUANT -4 + +/* Quantization offsets (multiples of 4) */ +#define OFFSET_VL_Q10 32 +#define OFFSET_VH_Q10 100 +#define OFFSET_UVL_Q10 100 +#define OFFSET_UVH_Q10 240 + +#define QUANT_LEVEL_ADJUST_Q10 80 + +/* Maximum numbers of iterations used to stabilize an LPC vector */ +#define MAX_LPC_STABILIZE_ITERATIONS 16 +#define MAX_PREDICTION_POWER_GAIN 1e4f +#define MAX_PREDICTION_POWER_GAIN_AFTER_RESET 1e2f + +#define MAX_LPC_ORDER 16 +#define MIN_LPC_ORDER 10 + +/* Find Pred Coef defines */ +#define LTP_ORDER 5 + +/* LTP quantization settings */ +#define NB_LTP_CBKS 3 + +/* Flag to use harmonic noise shaping */ +#define USE_HARM_SHAPING 1 + +/* Max LPC order of noise shaping filters */ +#define MAX_SHAPE_LPC_ORDER 24 + +#define HARM_SHAPE_FIR_TAPS 3 + +/* Maximum number of delayed decision states */ +#define MAX_DEL_DEC_STATES 4 + +#define LTP_BUF_LENGTH 512 +#define LTP_MASK ( LTP_BUF_LENGTH - 1 ) + +#define DECISION_DELAY 40 + +/* Number of subframes for excitation entropy coding */ +#define SHELL_CODEC_FRAME_LENGTH 16 +#define LOG2_SHELL_CODEC_FRAME_LENGTH 4 +#define MAX_NB_SHELL_BLOCKS ( MAX_FRAME_LENGTH / SHELL_CODEC_FRAME_LENGTH ) + +/* Number of rate levels, for entropy coding of excitation */ +#define N_RATE_LEVELS 10 + +/* Maximum sum of pulses per shell coding frame */ +#define SILK_MAX_PULSES 16 + +#define MAX_MATRIX_SIZE MAX_LPC_ORDER /* Max of LPC Order and LTP order */ + +# define NSQ_LPC_BUF_LENGTH MAX_LPC_ORDER + +/***************************/ +/* Voice activity detector */ +/***************************/ +#define VAD_N_BANDS 4 + +#define VAD_INTERNAL_SUBFRAMES_LOG2 2 +#define VAD_INTERNAL_SUBFRAMES ( 1 << VAD_INTERNAL_SUBFRAMES_LOG2 ) + +#define VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 1024 /* Must be < 4096 */ +#define VAD_NOISE_LEVELS_BIAS 50 + +/* Sigmoid settings */ +#define VAD_NEGATIVE_OFFSET_Q5 128 /* sigmoid is 0 at -128 */ +#define VAD_SNR_FACTOR_Q16 45000 + +/* smoothing for SNR measurement */ +#define VAD_SNR_SMOOTH_COEF_Q18 4096 + +/* Size of the piecewise linear cosine approximation table for the LSFs */ +#define LSF_COS_TAB_SZ_FIX 128 + +/******************/ +/* NLSF quantizer */ +/******************/ +#define NLSF_W_Q 2 +#define NLSF_VQ_MAX_VECTORS 32 +#define NLSF_QUANT_MAX_AMPLITUDE 4 +#define NLSF_QUANT_MAX_AMPLITUDE_EXT 10 +#define NLSF_QUANT_LEVEL_ADJ 0.1 +#define NLSF_QUANT_DEL_DEC_STATES_LOG2 2 +#define NLSF_QUANT_DEL_DEC_STATES ( 1 << NLSF_QUANT_DEL_DEC_STATES_LOG2 ) + +/* Transition filtering for mode switching */ +#define TRANSITION_TIME_MS 5120 /* 5120 = 64 * FRAME_LENGTH_MS * ( TRANSITION_INT_NUM - 1 ) = 64*(20*4)*/ +#define TRANSITION_NB 3 /* Hardcoded in tables */ +#define TRANSITION_NA 2 /* Hardcoded in tables */ +#define TRANSITION_INT_NUM 5 /* Hardcoded in tables */ +#define TRANSITION_FRAMES ( TRANSITION_TIME_MS / MAX_FRAME_LENGTH_MS ) +#define TRANSITION_INT_STEPS ( TRANSITION_FRAMES / ( TRANSITION_INT_NUM - 1 ) ) + +/* BWE factors to apply after packet loss */ +#define BWE_AFTER_LOSS_Q16 63570 + +/* Defines for CN generation */ +#define CNG_BUF_MASK_MAX 255 /* 2^floor(log2(MAX_FRAME_LENGTH))-1 */ +#define CNG_GAIN_SMTH_Q16 4634 /* 0.25^(1/4) */ +#define CNG_GAIN_SMTH_THRESHOLD_Q16 46396 /* -3 dB */ +#define CNG_NLSF_SMTH_Q16 16348 /* 0.25 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/enc_API.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/enc_API.c new file mode 100644 index 000000000..55a33f37e --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/enc_API.c @@ -0,0 +1,576 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "define.h" +#include "API.h" +#include "control.h" +#include "typedef.h" +#include "stack_alloc.h" +#include "structs.h" +#include "tuning_parameters.h" +#ifdef FIXED_POINT +#include "main_FIX.h" +#else +#include "main_FLP.h" +#endif + +/***************************************/ +/* Read control structure from encoder */ +/***************************************/ +static opus_int silk_QueryEncoder( /* O Returns error code */ + const void *encState, /* I State */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +); + +/****************************************/ +/* Encoder functions */ +/****************************************/ + +opus_int silk_Get_Encoder_Size( /* O Returns error code */ + opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */ +) +{ + opus_int ret = SILK_NO_ERROR; + + *encSizeBytes = sizeof( silk_encoder ); + + return ret; +} + +/*************************/ +/* Init or Reset encoder */ +/*************************/ +opus_int silk_InitEncoder( /* O Returns error code */ + void *encState, /* I/O State */ + int arch, /* I Run-time architecture */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +) +{ + silk_encoder *psEnc; + opus_int n, ret = SILK_NO_ERROR; + + psEnc = (silk_encoder *)encState; + + /* Reset encoder */ + silk_memset( psEnc, 0, sizeof( silk_encoder ) ); + for( n = 0; n < ENCODER_NUM_CHANNELS; n++ ) { + if( ret += silk_init_encoder( &psEnc->state_Fxx[ n ], arch ) ) { + celt_assert( 0 ); + } + } + + psEnc->nChannelsAPI = 1; + psEnc->nChannelsInternal = 1; + + /* Read control structure */ + if( ret += silk_QueryEncoder( encState, encStatus ) ) { + celt_assert( 0 ); + } + + return ret; +} + +/***************************************/ +/* Read control structure from encoder */ +/***************************************/ +static opus_int silk_QueryEncoder( /* O Returns error code */ + const void *encState, /* I State */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +) +{ + opus_int ret = SILK_NO_ERROR; + silk_encoder_state_Fxx *state_Fxx; + silk_encoder *psEnc = (silk_encoder *)encState; + + state_Fxx = psEnc->state_Fxx; + + encStatus->nChannelsAPI = psEnc->nChannelsAPI; + encStatus->nChannelsInternal = psEnc->nChannelsInternal; + encStatus->API_sampleRate = state_Fxx[ 0 ].sCmn.API_fs_Hz; + encStatus->maxInternalSampleRate = state_Fxx[ 0 ].sCmn.maxInternal_fs_Hz; + encStatus->minInternalSampleRate = state_Fxx[ 0 ].sCmn.minInternal_fs_Hz; + encStatus->desiredInternalSampleRate = state_Fxx[ 0 ].sCmn.desiredInternal_fs_Hz; + encStatus->payloadSize_ms = state_Fxx[ 0 ].sCmn.PacketSize_ms; + encStatus->bitRate = state_Fxx[ 0 ].sCmn.TargetRate_bps; + encStatus->packetLossPercentage = state_Fxx[ 0 ].sCmn.PacketLoss_perc; + encStatus->complexity = state_Fxx[ 0 ].sCmn.Complexity; + encStatus->useInBandFEC = state_Fxx[ 0 ].sCmn.useInBandFEC; + encStatus->useDTX = state_Fxx[ 0 ].sCmn.useDTX; + encStatus->useCBR = state_Fxx[ 0 ].sCmn.useCBR; + encStatus->internalSampleRate = silk_SMULBB( state_Fxx[ 0 ].sCmn.fs_kHz, 1000 ); + encStatus->allowBandwidthSwitch = state_Fxx[ 0 ].sCmn.allow_bandwidth_switch; + encStatus->inWBmodeWithoutVariableLP = state_Fxx[ 0 ].sCmn.fs_kHz == 16 && state_Fxx[ 0 ].sCmn.sLP.mode == 0; + + return ret; +} + + +/**************************/ +/* Encode frame with Silk */ +/**************************/ +/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */ +/* encControl->payloadSize_ms is set to */ +opus_int silk_Encode( /* O Returns error code */ + void *encState, /* I/O State */ + silk_EncControlStruct *encControl, /* I Control status */ + const opus_int16 *samplesIn, /* I Speech sample input vector */ + opus_int nSamplesIn, /* I Number of samples in input vector */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */ + const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */ + opus_int activity /* I Decision of Opus voice activity detector */ +) +{ + opus_int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0, ret = 0; + opus_int nSamplesToBuffer, nSamplesToBufferMax, nBlocksOf10ms; + opus_int nSamplesFromInput = 0, nSamplesFromInputMax; + opus_int speech_act_thr_for_switch_Q8; + opus_int32 TargetRate_bps, MStargetRates_bps[ 2 ], channelRate_bps, LBRR_symbol, sum; + silk_encoder *psEnc = ( silk_encoder * )encState; + VARDECL( opus_int16, buf ); + opus_int transition, curr_block, tot_blocks; + SAVE_STACK; + + if (encControl->reducedDependency) + { + psEnc->state_Fxx[0].sCmn.first_frame_after_reset = 1; + psEnc->state_Fxx[1].sCmn.first_frame_after_reset = 1; + } + psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded = psEnc->state_Fxx[ 1 ].sCmn.nFramesEncoded = 0; + + /* Check values in encoder control structure */ + if( ( ret = check_control_input( encControl ) ) != 0 ) { + celt_assert( 0 ); + RESTORE_STACK; + return ret; + } + + encControl->switchReady = 0; + + if( encControl->nChannelsInternal > psEnc->nChannelsInternal ) { + /* Mono -> Stereo transition: init state of second channel and stereo state */ + ret += silk_init_encoder( &psEnc->state_Fxx[ 1 ], psEnc->state_Fxx[ 0 ].sCmn.arch ); + silk_memset( psEnc->sStereo.pred_prev_Q13, 0, sizeof( psEnc->sStereo.pred_prev_Q13 ) ); + silk_memset( psEnc->sStereo.sSide, 0, sizeof( psEnc->sStereo.sSide ) ); + psEnc->sStereo.mid_side_amp_Q0[ 0 ] = 0; + psEnc->sStereo.mid_side_amp_Q0[ 1 ] = 1; + psEnc->sStereo.mid_side_amp_Q0[ 2 ] = 0; + psEnc->sStereo.mid_side_amp_Q0[ 3 ] = 1; + psEnc->sStereo.width_prev_Q14 = 0; + psEnc->sStereo.smth_width_Q14 = SILK_FIX_CONST( 1, 14 ); + if( psEnc->nChannelsAPI == 2 ) { + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof( silk_resampler_state_struct ) ); + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.In_HP_State, &psEnc->state_Fxx[ 0 ].sCmn.In_HP_State, sizeof( psEnc->state_Fxx[ 1 ].sCmn.In_HP_State ) ); + } + } + + transition = (encControl->payloadSize_ms != psEnc->state_Fxx[ 0 ].sCmn.PacketSize_ms) || (psEnc->nChannelsInternal != encControl->nChannelsInternal); + + psEnc->nChannelsAPI = encControl->nChannelsAPI; + psEnc->nChannelsInternal = encControl->nChannelsInternal; + + nBlocksOf10ms = silk_DIV32( 100 * nSamplesIn, encControl->API_sampleRate ); + tot_blocks = ( nBlocksOf10ms > 1 ) ? nBlocksOf10ms >> 1 : 1; + curr_block = 0; + if( prefillFlag ) { + silk_LP_state save_LP; + /* Only accept input length of 10 ms */ + if( nBlocksOf10ms != 1 ) { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + } + if ( prefillFlag == 2 ) { + save_LP = psEnc->state_Fxx[ 0 ].sCmn.sLP; + /* Save the sampling rate so the bandwidth switching code can keep handling transitions. */ + save_LP.saved_fs_kHz = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz; + } + /* Reset Encoder */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + ret = silk_init_encoder( &psEnc->state_Fxx[ n ], psEnc->state_Fxx[ n ].sCmn.arch ); + /* Restore the variable LP state. */ + if ( prefillFlag == 2 ) { + psEnc->state_Fxx[ n ].sCmn.sLP = save_LP; + } + celt_assert( !ret ); + } + tmp_payloadSize_ms = encControl->payloadSize_ms; + encControl->payloadSize_ms = 10; + tmp_complexity = encControl->complexity; + encControl->complexity = 0; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.prefillFlag = 1; + } + } else { + /* Only accept input lengths that are a multiple of 10 ms */ + if( nBlocksOf10ms * encControl->API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0 ) { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + } + /* Make sure no more than one packet can be produced */ + if( 1000 * (opus_int32)nSamplesIn > encControl->payloadSize_ms * encControl->API_sampleRate ) { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + } + } + + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + /* Force the side channel to the same rate as the mid */ + opus_int force_fs_kHz = (n==1) ? psEnc->state_Fxx[0].sCmn.fs_kHz : 0; + if( ( ret = silk_control_encoder( &psEnc->state_Fxx[ n ], encControl, psEnc->allowBandwidthSwitch, n, force_fs_kHz ) ) != 0 ) { + silk_assert( 0 ); + RESTORE_STACK; + return ret; + } + if( psEnc->state_Fxx[n].sCmn.first_frame_after_reset || transition ) { + for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) { + psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] = 0; + } + } + psEnc->state_Fxx[ n ].sCmn.inDTX = psEnc->state_Fxx[ n ].sCmn.useDTX; + } + celt_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == psEnc->state_Fxx[ 1 ].sCmn.fs_kHz ); + + /* Input buffering/resampling and encoding */ + nSamplesToBufferMax = + 10 * nBlocksOf10ms * psEnc->state_Fxx[ 0 ].sCmn.fs_kHz; + nSamplesFromInputMax = + silk_DIV32_16( nSamplesToBufferMax * + psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz, + psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 ); + ALLOC( buf, nSamplesFromInputMax, opus_int16 ); + while( 1 ) { + nSamplesToBuffer = psEnc->state_Fxx[ 0 ].sCmn.frame_length - psEnc->state_Fxx[ 0 ].sCmn.inputBufIx; + nSamplesToBuffer = silk_min( nSamplesToBuffer, nSamplesToBufferMax ); + nSamplesFromInput = silk_DIV32_16( nSamplesToBuffer * psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz, psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 ); + /* Resample and write to buffer */ + if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 2 ) { + opus_int id = psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded; + for( n = 0; n < nSamplesFromInput; n++ ) { + buf[ n ] = samplesIn[ 2 * n ]; + } + /* Making sure to start both resamplers from the same state when switching from mono to stereo */ + if( psEnc->nPrevChannelsInternal == 1 && id==0 ) { + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof(psEnc->state_Fxx[ 1 ].sCmn.resampler_state)); + } + + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + + nSamplesToBuffer = psEnc->state_Fxx[ 1 ].sCmn.frame_length - psEnc->state_Fxx[ 1 ].sCmn.inputBufIx; + nSamplesToBuffer = silk_min( nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc->state_Fxx[ 1 ].sCmn.fs_kHz ); + for( n = 0; n < nSamplesFromInput; n++ ) { + buf[ n ] = samplesIn[ 2 * n + 1 ]; + } + ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + + psEnc->state_Fxx[ 1 ].sCmn.inputBufIx += nSamplesToBuffer; + } else if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 1 ) { + /* Combine left and right channels before resampling */ + for( n = 0; n < nSamplesFromInput; n++ ) { + sum = samplesIn[ 2 * n ] + samplesIn[ 2 * n + 1 ]; + buf[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 ); + } + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + /* On the first mono frame, average the results for the two resampler states */ + if( psEnc->nPrevChannelsInternal == 2 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 ) { + ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + for( n = 0; n < psEnc->state_Fxx[ 0 ].sCmn.frame_length; n++ ) { + psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] = + silk_RSHIFT(psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] + + psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx+n+2 ], 1); + } + } + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + } else { + celt_assert( encControl->nChannelsAPI == 1 && encControl->nChannelsInternal == 1 ); + silk_memcpy(buf, samplesIn, nSamplesFromInput*sizeof(opus_int16)); + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + } + + samplesIn += nSamplesFromInput * encControl->nChannelsAPI; + nSamplesIn -= nSamplesFromInput; + + /* Default */ + psEnc->allowBandwidthSwitch = 0; + + /* Silk encoder */ + if( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx >= psEnc->state_Fxx[ 0 ].sCmn.frame_length ) { + /* Enough data in input buffer, so encode */ + celt_assert( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx == psEnc->state_Fxx[ 0 ].sCmn.frame_length ); + celt_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inputBufIx == psEnc->state_Fxx[ 1 ].sCmn.frame_length ); + + /* Deal with LBRR data */ + if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 && !prefillFlag ) { + /* Create space at start of payload for VAD and FEC flags */ + opus_uint8 iCDF[ 2 ] = { 0, 0 }; + iCDF[ 0 ] = 256 - silk_RSHIFT( 256, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal ); + ec_enc_icdf( psRangeEnc, 0, iCDF, 8 ); + + /* Encode any LBRR data from previous packet */ + /* Encode LBRR flags */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + LBRR_symbol = 0; + for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) { + LBRR_symbol |= silk_LSHIFT( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ], i ); + } + psEnc->state_Fxx[ n ].sCmn.LBRR_flag = LBRR_symbol > 0 ? 1 : 0; + if( LBRR_symbol && psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket > 1 ) { + ec_enc_icdf( psRangeEnc, LBRR_symbol - 1, silk_LBRR_flags_iCDF_ptr[ psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket - 2 ], 8 ); + } + } + + /* Code LBRR indices and excitation signals */ + for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) { + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + if( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] ) { + opus_int condCoding; + + if( encControl->nChannelsInternal == 2 && n == 0 ) { + silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ i ] ); + /* For LBRR data there's no need to code the mid-only flag if the side-channel LBRR flag is set */ + if( psEnc->state_Fxx[ 1 ].sCmn.LBRR_flags[ i ] == 0 ) { + silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ i ] ); + } + } + /* Use conditional coding if previous frame available */ + if( i > 0 && psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i - 1 ] ) { + condCoding = CODE_CONDITIONALLY; + } else { + condCoding = CODE_INDEPENDENTLY; + } + silk_encode_indices( &psEnc->state_Fxx[ n ].sCmn, psRangeEnc, i, 1, condCoding ); + silk_encode_pulses( psRangeEnc, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].signalType, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].quantOffsetType, + psEnc->state_Fxx[ n ].sCmn.pulses_LBRR[ i ], psEnc->state_Fxx[ n ].sCmn.frame_length ); + } + } + } + + /* Reset LBRR flags */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + silk_memset( psEnc->state_Fxx[ n ].sCmn.LBRR_flags, 0, sizeof( psEnc->state_Fxx[ n ].sCmn.LBRR_flags ) ); + } + + psEnc->nBitsUsedLBRR = ec_tell( psRangeEnc ); + } + + silk_HP_variable_cutoff( psEnc->state_Fxx ); + + /* Total target bits for packet */ + nBits = silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 ); + /* Subtract bits used for LBRR */ + if( !prefillFlag ) { + nBits -= psEnc->nBitsUsedLBRR; + } + /* Divide by number of uncoded frames left in packet */ + nBits = silk_DIV32_16( nBits, psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket ); + /* Convert to bits/second */ + if( encControl->payloadSize_ms == 10 ) { + TargetRate_bps = silk_SMULBB( nBits, 100 ); + } else { + TargetRate_bps = silk_SMULBB( nBits, 50 ); + } + /* Subtract fraction of bits in excess of target in previous frames and packets */ + TargetRate_bps -= silk_DIV32_16( silk_MUL( psEnc->nBitsExceeded, 1000 ), BITRESERVOIR_DECAY_TIME_MS ); + if( !prefillFlag && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded > 0 ) { + /* Compare actual vs target bits so far in this packet */ + opus_int32 bitsBalance = ec_tell( psRangeEnc ) - psEnc->nBitsUsedLBRR - nBits * psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded; + TargetRate_bps -= silk_DIV32_16( silk_MUL( bitsBalance, 1000 ), BITRESERVOIR_DECAY_TIME_MS ); + } + /* Never exceed input bitrate */ + TargetRate_bps = silk_LIMIT( TargetRate_bps, encControl->bitRate, 5000 ); + + /* Convert Left/Right to Mid/Side */ + if( encControl->nChannelsInternal == 2 ) { + silk_stereo_LR_to_MS( &psEnc->sStereo, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ 2 ], &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ 2 ], + psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], &psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], + MStargetRates_bps, TargetRate_bps, psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8, encControl->toMono, + psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, psEnc->state_Fxx[ 0 ].sCmn.frame_length ); + if( psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) { + /* Reset side channel encoder memory for first frame with side coding */ + if( psEnc->prev_decode_only_middle == 1 ) { + silk_memset( &psEnc->state_Fxx[ 1 ].sShape, 0, sizeof( psEnc->state_Fxx[ 1 ].sShape ) ); + silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sNSQ, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sNSQ ) ); + silk_memset( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15 ) ); + silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State ) ); + psEnc->state_Fxx[ 1 ].sCmn.prevLag = 100; + psEnc->state_Fxx[ 1 ].sCmn.sNSQ.lagPrev = 100; + psEnc->state_Fxx[ 1 ].sShape.LastGainIndex = 10; + psEnc->state_Fxx[ 1 ].sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->state_Fxx[ 1 ].sCmn.sNSQ.prev_gain_Q16 = 65536; + psEnc->state_Fxx[ 1 ].sCmn.first_frame_after_reset = 1; + } + silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ], activity ); + } else { + psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] = 0; + } + if( !prefillFlag ) { + silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] ); + if( psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) { + silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] ); + } + } + } else { + /* Buffering */ + silk_memcpy( psEnc->state_Fxx[ 0 ].sCmn.inputBuf, psEnc->sStereo.sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( psEnc->sStereo.sMid, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.frame_length ], 2 * sizeof( opus_int16 ) ); + } + silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ], activity ); + + /* Encode */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + opus_int maxBits, useCBR; + + /* Handling rate constraints */ + maxBits = encControl->maxBits; + if( tot_blocks == 2 && curr_block == 0 ) { + maxBits = maxBits * 3 / 5; + } else if( tot_blocks == 3 ) { + if( curr_block == 0 ) { + maxBits = maxBits * 2 / 5; + } else if( curr_block == 1 ) { + maxBits = maxBits * 3 / 4; + } + } + useCBR = encControl->useCBR && curr_block == tot_blocks - 1; + + if( encControl->nChannelsInternal == 1 ) { + channelRate_bps = TargetRate_bps; + } else { + channelRate_bps = MStargetRates_bps[ n ]; + if( n == 0 && MStargetRates_bps[ 1 ] > 0 ) { + useCBR = 0; + /* Give mid up to 1/2 of the max bits for that frame */ + maxBits -= encControl->maxBits / ( tot_blocks * 2 ); + } + } + + if( channelRate_bps > 0 ) { + opus_int condCoding; + + silk_control_SNR( &psEnc->state_Fxx[ n ].sCmn, channelRate_bps ); + + /* Use independent coding if no previous frame available */ + if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - n <= 0 ) { + condCoding = CODE_INDEPENDENTLY; + } else if( n > 0 && psEnc->prev_decode_only_middle ) { + /* If we skipped a side frame in this packet, we don't + need LTP scaling; the LTP state is well-defined. */ + condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING; + } else { + condCoding = CODE_CONDITIONALLY; + } + if( ( ret = silk_encode_frame_Fxx( &psEnc->state_Fxx[ n ], nBytesOut, psRangeEnc, condCoding, maxBits, useCBR ) ) != 0 ) { + silk_assert( 0 ); + } + } + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.inputBufIx = 0; + psEnc->state_Fxx[ n ].sCmn.nFramesEncoded++; + } + psEnc->prev_decode_only_middle = psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - 1 ]; + + /* Insert VAD and FEC flags at beginning of bitstream */ + if( *nBytesOut > 0 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket) { + flags = 0; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) { + flags = silk_LSHIFT( flags, 1 ); + flags |= psEnc->state_Fxx[ n ].sCmn.VAD_flags[ i ]; + } + flags = silk_LSHIFT( flags, 1 ); + flags |= psEnc->state_Fxx[ n ].sCmn.LBRR_flag; + } + if( !prefillFlag ) { + ec_enc_patch_initial_bits( psRangeEnc, flags, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal ); + } + + /* Return zero bytes if all channels DTXed */ + if( psEnc->state_Fxx[ 0 ].sCmn.inDTX && ( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inDTX ) ) { + *nBytesOut = 0; + } + + psEnc->nBitsExceeded += *nBytesOut * 8; + psEnc->nBitsExceeded -= silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 ); + psEnc->nBitsExceeded = silk_LIMIT( psEnc->nBitsExceeded, 0, 10000 ); + + /* Update flag indicating if bandwidth switching is allowed */ + speech_act_thr_for_switch_Q8 = silk_SMLAWB( SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ), + SILK_FIX_CONST( ( 1 - SPEECH_ACTIVITY_DTX_THRES ) / MAX_BANDWIDTH_SWITCH_DELAY_MS, 16 + 8 ), psEnc->timeSinceSwitchAllowed_ms ); + if( psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8 < speech_act_thr_for_switch_Q8 ) { + psEnc->allowBandwidthSwitch = 1; + psEnc->timeSinceSwitchAllowed_ms = 0; + } else { + psEnc->allowBandwidthSwitch = 0; + psEnc->timeSinceSwitchAllowed_ms += encControl->payloadSize_ms; + } + } + + if( nSamplesIn == 0 ) { + break; + } + } else { + break; + } + curr_block++; + } + + psEnc->nPrevChannelsInternal = encControl->nChannelsInternal; + + encControl->allowBandwidthSwitch = psEnc->allowBandwidthSwitch; + encControl->inWBmodeWithoutVariableLP = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == 16 && psEnc->state_Fxx[ 0 ].sCmn.sLP.mode == 0; + encControl->internalSampleRate = silk_SMULBB( psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, 1000 ); + encControl->stereoWidth_Q14 = encControl->toMono ? 0 : psEnc->sStereo.smth_width_Q14; + if( prefillFlag ) { + encControl->payloadSize_ms = tmp_payloadSize_ms; + encControl->complexity = tmp_complexity; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.prefillFlag = 0; + } + } + + encControl->signalType = psEnc->state_Fxx[0].sCmn.indices.signalType; + encControl->offset = silk_Quantization_Offsets_Q10 + [ psEnc->state_Fxx[0].sCmn.indices.signalType >> 1 ] + [ psEnc->state_Fxx[0].sCmn.indices.quantOffsetType ]; + RESTORE_STACK; + return ret; +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/encode_indices.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/encode_indices.c new file mode 100644 index 000000000..4bcbc3347 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/encode_indices.c @@ -0,0 +1,181 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Encode side-information parameters to payload */ +void silk_encode_indices( + silk_encoder_state *psEncC, /* I/O Encoder state */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, typeOffset; + opus_int encode_absolute_lagIndex, delta_lagIndex; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + const SideInfoIndices *psIndices; + + if( encode_LBRR ) { + psIndices = &psEncC->indices_LBRR[ FrameIndex ]; + } else { + psIndices = &psEncC->indices; + } + + /*******************************************/ + /* Encode signal type and quantizer offset */ + /*******************************************/ + typeOffset = 2 * psIndices->signalType + psIndices->quantOffsetType; + celt_assert( typeOffset >= 0 && typeOffset < 6 ); + celt_assert( encode_LBRR == 0 || typeOffset >= 2 ); + if( encode_LBRR || typeOffset >= 2 ) { + ec_enc_icdf( psRangeEnc, typeOffset - 2, silk_type_offset_VAD_iCDF, 8 ); + } else { + ec_enc_icdf( psRangeEnc, typeOffset, silk_type_offset_no_VAD_iCDF, 8 ); + } + + /****************/ + /* Encode gains */ + /****************/ + /* first subframe */ + if( condCoding == CODE_CONDITIONALLY ) { + /* conditional coding */ + silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ], silk_delta_gain_iCDF, 8 ); + } else { + /* independent coding, in two stages: MSB bits followed by 3 LSBs */ + silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < N_LEVELS_QGAIN ); + ec_enc_icdf( psRangeEnc, silk_RSHIFT( psIndices->GainsIndices[ 0 ], 3 ), silk_gain_iCDF[ psIndices->signalType ], 8 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ] & 7, silk_uniform8_iCDF, 8 ); + } + + /* remaining subframes */ + for( i = 1; i < psEncC->nb_subfr; i++ ) { + silk_assert( psIndices->GainsIndices[ i ] >= 0 && psIndices->GainsIndices[ i ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ i ], silk_delta_gain_iCDF, 8 ); + } + + /****************/ + /* Encode NLSFs */ + /****************/ + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ 0 ], &psEncC->psNLSF_CB->CB1_iCDF[ ( psIndices->signalType >> 1 ) * psEncC->psNLSF_CB->nVectors ], 8 ); + silk_NLSF_unpack( ec_ix, pred_Q8, psEncC->psNLSF_CB, psIndices->NLSFIndices[ 0 ] ); + celt_assert( psEncC->psNLSF_CB->order == psEncC->predictLPCOrder ); + for( i = 0; i < psEncC->psNLSF_CB->order; i++ ) { + if( psIndices->NLSFIndices[ i+1 ] >= NLSF_QUANT_MAX_AMPLITUDE ) { + ec_enc_icdf( psRangeEnc, 2 * NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 ); + } else if( psIndices->NLSFIndices[ i+1 ] <= -NLSF_QUANT_MAX_AMPLITUDE ) { + ec_enc_icdf( psRangeEnc, 0, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + ec_enc_icdf( psRangeEnc, -psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 ); + } else { + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] + NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + } + } + + /* Encode NLSF interpolation factor */ + if( psEncC->nb_subfr == MAX_NB_SUBFR ) { + silk_assert( psIndices->NLSFInterpCoef_Q2 >= 0 && psIndices->NLSFInterpCoef_Q2 < 5 ); + ec_enc_icdf( psRangeEnc, psIndices->NLSFInterpCoef_Q2, silk_NLSF_interpolation_factor_iCDF, 8 ); + } + + if( psIndices->signalType == TYPE_VOICED ) + { + /*********************/ + /* Encode pitch lags */ + /*********************/ + /* lag index */ + encode_absolute_lagIndex = 1; + if( condCoding == CODE_CONDITIONALLY && psEncC->ec_prevSignalType == TYPE_VOICED ) { + /* Delta Encoding */ + delta_lagIndex = psIndices->lagIndex - psEncC->ec_prevLagIndex; + if( delta_lagIndex < -8 || delta_lagIndex > 11 ) { + delta_lagIndex = 0; + } else { + delta_lagIndex = delta_lagIndex + 9; + encode_absolute_lagIndex = 0; /* Only use delta */ + } + silk_assert( delta_lagIndex >= 0 && delta_lagIndex < 21 ); + ec_enc_icdf( psRangeEnc, delta_lagIndex, silk_pitch_delta_iCDF, 8 ); + } + if( encode_absolute_lagIndex ) { + /* Absolute encoding */ + opus_int32 pitch_high_bits, pitch_low_bits; + pitch_high_bits = silk_DIV32_16( psIndices->lagIndex, silk_RSHIFT( psEncC->fs_kHz, 1 ) ); + pitch_low_bits = psIndices->lagIndex - silk_SMULBB( pitch_high_bits, silk_RSHIFT( psEncC->fs_kHz, 1 ) ); + silk_assert( pitch_low_bits < psEncC->fs_kHz / 2 ); + silk_assert( pitch_high_bits < 32 ); + ec_enc_icdf( psRangeEnc, pitch_high_bits, silk_pitch_lag_iCDF, 8 ); + ec_enc_icdf( psRangeEnc, pitch_low_bits, psEncC->pitch_lag_low_bits_iCDF, 8 ); + } + psEncC->ec_prevLagIndex = psIndices->lagIndex; + + /* Countour index */ + silk_assert( psIndices->contourIndex >= 0 ); + silk_assert( ( psIndices->contourIndex < 34 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 4 ) || + ( psIndices->contourIndex < 11 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 4 ) || + ( psIndices->contourIndex < 12 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 2 ) || + ( psIndices->contourIndex < 3 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 2 ) ); + ec_enc_icdf( psRangeEnc, psIndices->contourIndex, psEncC->pitch_contour_iCDF, 8 ); + + /********************/ + /* Encode LTP gains */ + /********************/ + /* PERIndex value */ + silk_assert( psIndices->PERIndex >= 0 && psIndices->PERIndex < 3 ); + ec_enc_icdf( psRangeEnc, psIndices->PERIndex, silk_LTP_per_index_iCDF, 8 ); + + /* Codebook Indices */ + for( k = 0; k < psEncC->nb_subfr; k++ ) { + silk_assert( psIndices->LTPIndex[ k ] >= 0 && psIndices->LTPIndex[ k ] < ( 8 << psIndices->PERIndex ) ); + ec_enc_icdf( psRangeEnc, psIndices->LTPIndex[ k ], silk_LTP_gain_iCDF_ptrs[ psIndices->PERIndex ], 8 ); + } + + /**********************/ + /* Encode LTP scaling */ + /**********************/ + if( condCoding == CODE_INDEPENDENTLY ) { + silk_assert( psIndices->LTP_scaleIndex >= 0 && psIndices->LTP_scaleIndex < 3 ); + ec_enc_icdf( psRangeEnc, psIndices->LTP_scaleIndex, silk_LTPscale_iCDF, 8 ); + } + silk_assert( !condCoding || psIndices->LTP_scaleIndex == 0 ); + } + + psEncC->ec_prevSignalType = psIndices->signalType; + + /***************/ + /* Encode seed */ + /***************/ + silk_assert( psIndices->Seed >= 0 && psIndices->Seed < 4 ); + ec_enc_icdf( psRangeEnc, psIndices->Seed, silk_uniform4_iCDF, 8 ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/encode_pulses.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/encode_pulses.c new file mode 100644 index 000000000..8a1999138 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/encode_pulses.c @@ -0,0 +1,206 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/*********************************************/ +/* Encode quantization indices of excitation */ +/*********************************************/ + +static OPUS_INLINE opus_int combine_and_check( /* return ok */ + opus_int *pulses_comb, /* O */ + const opus_int *pulses_in, /* I */ + opus_int max_pulses, /* I max value for sum of pulses */ + opus_int len /* I number of output values */ +) +{ + opus_int k, sum; + + for( k = 0; k < len; k++ ) { + sum = pulses_in[ 2 * k ] + pulses_in[ 2 * k + 1 ]; + if( sum > max_pulses ) { + return 1; + } + pulses_comb[ k ] = sum; + } + + return 0; +} + +/* Encode quantization indices of excitation */ +void silk_encode_pulses( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I quantOffsetType */ + opus_int8 pulses[], /* I quantization indices */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int i, k, j, iter, bit, nLS, scale_down, RateLevelIndex = 0; + opus_int32 abs_q, minSumBits_Q5, sumBits_Q5; + VARDECL( opus_int, abs_pulses ); + VARDECL( opus_int, sum_pulses ); + VARDECL( opus_int, nRshifts ); + opus_int pulses_comb[ 8 ]; + opus_int *abs_pulses_ptr; + const opus_int8 *pulses_ptr; + const opus_uint8 *cdf_ptr; + const opus_uint8 *nBits_ptr; + SAVE_STACK; + + silk_memset( pulses_comb, 0, 8 * sizeof( opus_int ) ); /* Fixing Valgrind reported problem*/ + + /****************************/ + /* Prepare for shell coding */ + /****************************/ + /* Calculate number of shell blocks */ + silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH ); + iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH ); + if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) { + celt_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */ + iter++; + silk_memset( &pulses[ frame_length ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof(opus_int8)); + } + + /* Take the absolute value of the pulses */ + ALLOC( abs_pulses, iter * SHELL_CODEC_FRAME_LENGTH, opus_int ); + silk_assert( !( SHELL_CODEC_FRAME_LENGTH & 3 ) ); + for( i = 0; i < iter * SHELL_CODEC_FRAME_LENGTH; i+=4 ) { + abs_pulses[i+0] = ( opus_int )silk_abs( pulses[ i + 0 ] ); + abs_pulses[i+1] = ( opus_int )silk_abs( pulses[ i + 1 ] ); + abs_pulses[i+2] = ( opus_int )silk_abs( pulses[ i + 2 ] ); + abs_pulses[i+3] = ( opus_int )silk_abs( pulses[ i + 3 ] ); + } + + /* Calc sum pulses per shell code frame */ + ALLOC( sum_pulses, iter, opus_int ); + ALLOC( nRshifts, iter, opus_int ); + abs_pulses_ptr = abs_pulses; + for( i = 0; i < iter; i++ ) { + nRshifts[ i ] = 0; + + while( 1 ) { + /* 1+1 -> 2 */ + scale_down = combine_and_check( pulses_comb, abs_pulses_ptr, silk_max_pulses_table[ 0 ], 8 ); + /* 2+2 -> 4 */ + scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 1 ], 4 ); + /* 4+4 -> 8 */ + scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 2 ], 2 ); + /* 8+8 -> 16 */ + scale_down += combine_and_check( &sum_pulses[ i ], pulses_comb, silk_max_pulses_table[ 3 ], 1 ); + + if( scale_down ) { + /* We need to downscale the quantization signal */ + nRshifts[ i ]++; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_pulses_ptr[ k ] = silk_RSHIFT( abs_pulses_ptr[ k ], 1 ); + } + } else { + /* Jump out of while(1) loop and go to next shell coding frame */ + break; + } + } + abs_pulses_ptr += SHELL_CODEC_FRAME_LENGTH; + } + + /**************/ + /* Rate level */ + /**************/ + /* find rate level that leads to fewest bits for coding of pulses per block info */ + minSumBits_Q5 = silk_int32_MAX; + for( k = 0; k < N_RATE_LEVELS - 1; k++ ) { + nBits_ptr = silk_pulses_per_block_BITS_Q5[ k ]; + sumBits_Q5 = silk_rate_levels_BITS_Q5[ signalType >> 1 ][ k ]; + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] > 0 ) { + sumBits_Q5 += nBits_ptr[ SILK_MAX_PULSES + 1 ]; + } else { + sumBits_Q5 += nBits_ptr[ sum_pulses[ i ] ]; + } + } + if( sumBits_Q5 < minSumBits_Q5 ) { + minSumBits_Q5 = sumBits_Q5; + RateLevelIndex = k; + } + } + ec_enc_icdf( psRangeEnc, RateLevelIndex, silk_rate_levels_iCDF[ signalType >> 1 ], 8 ); + + /***************************************************/ + /* Sum-Weighted-Pulses Encoding */ + /***************************************************/ + cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ]; + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] == 0 ) { + ec_enc_icdf( psRangeEnc, sum_pulses[ i ], cdf_ptr, 8 ); + } else { + ec_enc_icdf( psRangeEnc, SILK_MAX_PULSES + 1, cdf_ptr, 8 ); + for( k = 0; k < nRshifts[ i ] - 1; k++ ) { + ec_enc_icdf( psRangeEnc, SILK_MAX_PULSES + 1, silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 ); + } + ec_enc_icdf( psRangeEnc, sum_pulses[ i ], silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 ); + } + } + + /******************/ + /* Shell Encoding */ + /******************/ + for( i = 0; i < iter; i++ ) { + if( sum_pulses[ i ] > 0 ) { + silk_shell_encoder( psRangeEnc, &abs_pulses[ i * SHELL_CODEC_FRAME_LENGTH ] ); + } + } + + /****************/ + /* LSB Encoding */ + /****************/ + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] > 0 ) { + pulses_ptr = &pulses[ i * SHELL_CODEC_FRAME_LENGTH ]; + nLS = nRshifts[ i ] - 1; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_q = (opus_int8)silk_abs( pulses_ptr[ k ] ); + for( j = nLS; j > 0; j-- ) { + bit = silk_RSHIFT( abs_q, j ) & 1; + ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 ); + } + bit = abs_q & 1; + ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 ); + } + } + } + + /****************/ + /* Encode signs */ + /****************/ + silk_encode_signs( psRangeEnc, pulses, frame_length, signalType, quantOffsetType, sum_pulses ); + RESTORE_STACK; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/errors.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/errors.h new file mode 100644 index 000000000..45070800f --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/errors.h @@ -0,0 +1,98 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_ERRORS_H +#define SILK_ERRORS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************/ +/* Error messages */ +/******************/ +#define SILK_NO_ERROR 0 + +/**************************/ +/* Encoder error messages */ +/**************************/ + +/* Input length is not a multiple of 10 ms, or length is longer than the packet length */ +#define SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES -101 + +/* Sampling frequency not 8000, 12000 or 16000 Hertz */ +#define SILK_ENC_FS_NOT_SUPPORTED -102 + +/* Packet size not 10, 20, 40, or 60 ms */ +#define SILK_ENC_PACKET_SIZE_NOT_SUPPORTED -103 + +/* Allocated payload buffer too short */ +#define SILK_ENC_PAYLOAD_BUF_TOO_SHORT -104 + +/* Loss rate not between 0 and 100 percent */ +#define SILK_ENC_INVALID_LOSS_RATE -105 + +/* Complexity setting not valid, use 0...10 */ +#define SILK_ENC_INVALID_COMPLEXITY_SETTING -106 + +/* Inband FEC setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_INBAND_FEC_SETTING -107 + +/* DTX setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_DTX_SETTING -108 + +/* CBR setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_CBR_SETTING -109 + +/* Internal encoder error */ +#define SILK_ENC_INTERNAL_ERROR -110 + +/* Internal encoder error */ +#define SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR -111 + +/**************************/ +/* Decoder error messages */ +/**************************/ + +/* Output sampling frequency lower than internal decoded sampling frequency */ +#define SILK_DEC_INVALID_SAMPLING_FREQUENCY -200 + +/* Payload size exceeded the maximum allowed 1024 bytes */ +#define SILK_DEC_PAYLOAD_TOO_LARGE -201 + +/* Payload has bit errors */ +#define SILK_DEC_PAYLOAD_ERROR -202 + +/* Payload has bit errors */ +#define SILK_DEC_INVALID_FRAME_SIZE -203 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/LTP_analysis_filter_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/LTP_analysis_filter_FIX.c new file mode 100644 index 000000000..5574e7069 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/LTP_analysis_filter_FIX.c @@ -0,0 +1,90 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +void silk_LTP_analysis_filter_FIX( + opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */ + const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */ + const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */ +) +{ + const opus_int16 *x_ptr, *x_lag_ptr; + opus_int16 Btmp_Q14[ LTP_ORDER ]; + opus_int16 *LTP_res_ptr; + opus_int k, i; + opus_int32 LTP_est; + + x_ptr = x; + LTP_res_ptr = LTP_res; + for( k = 0; k < nb_subfr; k++ ) { + + x_lag_ptr = x_ptr - pitchL[ k ]; + + Btmp_Q14[ 0 ] = LTPCoef_Q14[ k * LTP_ORDER ]; + Btmp_Q14[ 1 ] = LTPCoef_Q14[ k * LTP_ORDER + 1 ]; + Btmp_Q14[ 2 ] = LTPCoef_Q14[ k * LTP_ORDER + 2 ]; + Btmp_Q14[ 3 ] = LTPCoef_Q14[ k * LTP_ORDER + 3 ]; + Btmp_Q14[ 4 ] = LTPCoef_Q14[ k * LTP_ORDER + 4 ]; + + /* LTP analysis FIR filter */ + for( i = 0; i < subfr_length + pre_length; i++ ) { + LTP_res_ptr[ i ] = x_ptr[ i ]; + + /* Long-term prediction */ + LTP_est = silk_SMULBB( x_lag_ptr[ LTP_ORDER / 2 ], Btmp_Q14[ 0 ] ); + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ 1 ], Btmp_Q14[ 1 ] ); + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ 0 ], Btmp_Q14[ 2 ] ); + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ -1 ], Btmp_Q14[ 3 ] ); + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ -2 ], Btmp_Q14[ 4 ] ); + + LTP_est = silk_RSHIFT_ROUND( LTP_est, 14 ); /* round and -> Q0*/ + + /* Subtract long-term prediction */ + LTP_res_ptr[ i ] = (opus_int16)silk_SAT16( (opus_int32)x_ptr[ i ] - LTP_est ); + + /* Scale residual */ + LTP_res_ptr[ i ] = silk_SMULWB( invGains_Q16[ k ], LTP_res_ptr[ i ] ); + + x_lag_ptr++; + } + + /* Update pointers */ + LTP_res_ptr += subfr_length + pre_length; + x_ptr += subfr_length; + } +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/LTP_scale_ctrl_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/LTP_scale_ctrl_FIX.c new file mode 100644 index 000000000..3dcedef89 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/LTP_scale_ctrl_FIX.c @@ -0,0 +1,53 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int round_loss; + + if( condCoding == CODE_INDEPENDENTLY ) { + /* Only scale if first frame in packet */ + round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket; + psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT( + silk_SMULWB( silk_SMULBB( round_loss, psEncCtrl->LTPredCodGain_Q7 ), SILK_FIX_CONST( 0.1, 9 ) ), 0, 2 ); + } else { + /* Default is minimum scaling */ + psEnc->sCmn.indices.LTP_scaleIndex = 0; + } + psEncCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ]; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/apply_sine_window_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/apply_sine_window_FIX.c new file mode 100644 index 000000000..03e088a6d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/apply_sine_window_FIX.c @@ -0,0 +1,101 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +/* Every other sample is linearly interpolated, for speed. */ +/* Window length must be between 16 and 120 (incl) and a multiple of 4. */ + +/* Matlab code for table: + for k=16:9*4:16+2*9*4, fprintf(' %7.d,', -round(65536*pi ./ (k:4:k+8*4))); fprintf('\n'); end +*/ +static const opus_int16 freq_table_Q16[ 27 ] = { + 12111, 9804, 8235, 7100, 6239, 5565, 5022, 4575, 4202, + 3885, 3612, 3375, 3167, 2984, 2820, 2674, 2542, 2422, + 2313, 2214, 2123, 2038, 1961, 1889, 1822, 1760, 1702, +}; + +void silk_apply_sine_window( + opus_int16 px_win[], /* O Pointer to windowed signal */ + const opus_int16 px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +) +{ + opus_int k, f_Q16, c_Q16; + opus_int32 S0_Q16, S1_Q16; + + celt_assert( win_type == 1 || win_type == 2 ); + + /* Length must be in a range from 16 to 120 and a multiple of 4 */ + celt_assert( length >= 16 && length <= 120 ); + celt_assert( ( length & 3 ) == 0 ); + + /* Frequency */ + k = ( length >> 2 ) - 4; + celt_assert( k >= 0 && k <= 26 ); + f_Q16 = (opus_int)freq_table_Q16[ k ]; + + /* Factor used for cosine approximation */ + c_Q16 = silk_SMULWB( (opus_int32)f_Q16, -f_Q16 ); + silk_assert( c_Q16 >= -32768 ); + + /* initialize state */ + if( win_type == 1 ) { + /* start from 0 */ + S0_Q16 = 0; + /* approximation of sin(f) */ + S1_Q16 = f_Q16 + silk_RSHIFT( length, 3 ); + } else { + /* start from 1 */ + S0_Q16 = ( (opus_int32)1 << 16 ); + /* approximation of cos(f) */ + S1_Q16 = ( (opus_int32)1 << 16 ) + silk_RSHIFT( c_Q16, 1 ) + silk_RSHIFT( length, 4 ); + } + + /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */ + /* 4 samples at a time */ + for( k = 0; k < length; k += 4 ) { + px_win[ k ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k ] ); + px_win[ k + 1 ] = (opus_int16)silk_SMULWB( S1_Q16, px[ k + 1] ); + S0_Q16 = silk_SMULWB( S1_Q16, c_Q16 ) + silk_LSHIFT( S1_Q16, 1 ) - S0_Q16 + 1; + S0_Q16 = silk_min( S0_Q16, ( (opus_int32)1 << 16 ) ); + + px_win[ k + 2 ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k + 2] ); + px_win[ k + 3 ] = (opus_int16)silk_SMULWB( S0_Q16, px[ k + 3 ] ); + S1_Q16 = silk_SMULWB( S0_Q16, c_Q16 ) + silk_LSHIFT( S0_Q16, 1 ) - S1_Q16; + S1_Q16 = silk_min( S1_Q16, ( (opus_int32)1 << 16 ) ); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/arm/warped_autocorrelation_FIX_arm.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/arm/warped_autocorrelation_FIX_arm.h new file mode 100644 index 000000000..1992e4328 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/arm/warped_autocorrelation_FIX_arm.h @@ -0,0 +1,68 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_WARPED_AUTOCORRELATION_FIX_ARM_H +# define SILK_WARPED_AUTOCORRELATION_FIX_ARM_H + +# include "celt/arm/armcpu.h" + +# if defined(FIXED_POINT) + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +void silk_warped_autocorrelation_FIX_neon( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +); + +# if !defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_PRESUME_NEON) +# define OVERRIDE_silk_warped_autocorrelation_FIX (1) +# define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \ + ((void)(arch), PRESUME_NEON(silk_warped_autocorrelation_FIX)(corr, scale, input, warping_Q16, length, order)) +# endif +# endif + +# if !defined(OVERRIDE_silk_warped_autocorrelation_FIX) +/*Is run-time CPU detection enabled on this platform?*/ +# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern void (*const SILK_WARPED_AUTOCORRELATION_FIX_IMPL[OPUS_ARCHMASK+1])(opus_int32*, opus_int*, const opus_int16*, const opus_int, const opus_int, const opus_int); +# define OVERRIDE_silk_warped_autocorrelation_FIX (1) +# define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \ + ((*SILK_WARPED_AUTOCORRELATION_FIX_IMPL[(arch)&OPUS_ARCHMASK])(corr, scale, input, warping_Q16, length, order)) +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_silk_warped_autocorrelation_FIX (1) +# define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \ + ((void)(arch), silk_warped_autocorrelation_FIX_neon(corr, scale, input, warping_Q16, length, order)) +# endif +# endif + +# endif /* end FIXED_POINT */ + +#endif /* end SILK_WARPED_AUTOCORRELATION_FIX_ARM_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c new file mode 100644 index 000000000..6f3be025c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c @@ -0,0 +1,265 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc., Jean-Marc Valin +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifdef OPUS_CHECK_ASM +# include +#endif +#include "stack_alloc.h" +#include "main_FIX.h" + +static OPUS_INLINE void calc_corr( const opus_int32 *const input_QS, opus_int64 *const corr_QC, const opus_int offset, const int32x4_t state_QS_s32x4 ) +{ + int64x2_t corr_QC_s64x2[ 2 ], t_s64x2[ 2 ]; + const int32x4_t input_QS_s32x4 = vld1q_s32( input_QS + offset ); + corr_QC_s64x2[ 0 ] = vld1q_s64( corr_QC + offset + 0 ); + corr_QC_s64x2[ 1 ] = vld1q_s64( corr_QC + offset + 2 ); + t_s64x2[ 0 ] = vmull_s32( vget_low_s32( state_QS_s32x4 ), vget_low_s32( input_QS_s32x4 ) ); + t_s64x2[ 1 ] = vmull_s32( vget_high_s32( state_QS_s32x4 ), vget_high_s32( input_QS_s32x4 ) ); + corr_QC_s64x2[ 0 ] = vsraq_n_s64( corr_QC_s64x2[ 0 ], t_s64x2[ 0 ], 2 * QS - QC ); + corr_QC_s64x2[ 1 ] = vsraq_n_s64( corr_QC_s64x2[ 1 ], t_s64x2[ 1 ], 2 * QS - QC ); + vst1q_s64( corr_QC + offset + 0, corr_QC_s64x2[ 0 ] ); + vst1q_s64( corr_QC + offset + 2, corr_QC_s64x2[ 1 ] ); +} + +static OPUS_INLINE int32x4_t calc_state( const int32x4_t state_QS0_s32x4, const int32x4_t state_QS0_1_s32x4, const int32x4_t state_QS1_1_s32x4, const int32x4_t warping_Q16_s32x4 ) +{ + int32x4_t t_s32x4 = vsubq_s32( state_QS0_s32x4, state_QS0_1_s32x4 ); + t_s32x4 = vqdmulhq_s32( t_s32x4, warping_Q16_s32x4 ); + return vaddq_s32( state_QS1_1_s32x4, t_s32x4 ); +} + +void silk_warped_autocorrelation_FIX_neon( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + if( ( MAX_SHAPE_LPC_ORDER > 24 ) || ( order < 6 ) ) { + silk_warped_autocorrelation_FIX_c( corr, scale, input, warping_Q16, length, order ); + } else { + opus_int n, i, lsh; + opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; /* In reverse order */ + opus_int64 corr_QC_orderT; + int64x2_t lsh_s64x2; + const opus_int orderT = ( order + 3 ) & ~3; + opus_int64 *corr_QCT; + opus_int32 *input_QS; + VARDECL( opus_int32, input_QST ); + VARDECL( opus_int32, state ); + SAVE_STACK; + + /* Order must be even */ + silk_assert( ( order & 1 ) == 0 ); + silk_assert( 2 * QS - QC >= 0 ); + + /* The additional +4 is to ensure a later vld1q_s32 call does not overflow. */ + /* Strictly, only +3 is needed but +4 simplifies initialization using the 4x32 neon load. */ + ALLOC( input_QST, length + 2 * MAX_SHAPE_LPC_ORDER + 4, opus_int32 ); + + input_QS = input_QST; + /* input_QS has zero paddings in the beginning and end. */ + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + + /* Loop over samples */ + for( n = 0; n < length - 7; n += 8, input_QS += 8 ) { + const int16x8_t t0_s16x4 = vld1q_s16( input + n ); + vst1q_s32( input_QS + 0, vshll_n_s16( vget_low_s16( t0_s16x4 ), QS ) ); + vst1q_s32( input_QS + 4, vshll_n_s16( vget_high_s16( t0_s16x4 ), QS ) ); + } + for( ; n < length; n++, input_QS++ ) { + input_QS[ 0 ] = silk_LSHIFT32( (opus_int32)input[ n ], QS ); + } + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS = input_QST + MAX_SHAPE_LPC_ORDER - orderT; + + /* The following loop runs ( length + order ) times, with ( order ) extra epilogues. */ + /* The zero paddings in input_QS guarantee corr_QC's correctness even with the extra epilogues. */ + /* The values of state_QS will be polluted by the extra epilogues, however they are temporary values. */ + + /* Keep the C code here to help understand the intrinsics optimization. */ + /* + { + opus_int32 state_QS[ 2 ][ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + opus_int32 *state_QST[ 3 ]; + state_QST[ 0 ] = state_QS[ 0 ]; + state_QST[ 1 ] = state_QS[ 1 ]; + for( n = 0; n < length + order; n++, input_QS++ ) { + state_QST[ 0 ][ orderT ] = input_QS[ orderT ]; + for( i = 0; i < orderT; i++ ) { + corr_QC[ i ] += silk_RSHIFT64( silk_SMULL( state_QST[ 0 ][ i ], input_QS[ i ] ), 2 * QS - QC ); + state_QST[ 1 ][ i ] = silk_SMLAWB( state_QST[ 1 ][ i + 1 ], state_QST[ 0 ][ i ] - state_QST[ 0 ][ i + 1 ], warping_Q16 ); + } + state_QST[ 2 ] = state_QST[ 0 ]; + state_QST[ 0 ] = state_QST[ 1 ]; + state_QST[ 1 ] = state_QST[ 2 ]; + } + } + */ + + { + const int32x4_t warping_Q16_s32x4 = vdupq_n_s32( warping_Q16 << 15 ); + const opus_int32 *in = input_QS + orderT; + opus_int o = orderT; + int32x4_t state_QS_s32x4[ 3 ][ 2 ]; + + /* The additional +4 is to ensure a later vld1q_s32 call does not overflow. */ + ALLOC( state, length + order + 4, opus_int32 ); + state_QS_s32x4[ 2 ][ 1 ] = vdupq_n_s32( 0 ); + + /* Calculate 8 taps of all inputs in each loop. */ + do { + state_QS_s32x4[ 0 ][ 0 ] = state_QS_s32x4[ 0 ][ 1 ] = + state_QS_s32x4[ 1 ][ 0 ] = state_QS_s32x4[ 1 ][ 1 ] = vdupq_n_s32( 0 ); + n = 0; + do { + calc_corr( input_QS + n, corr_QC, o - 8, state_QS_s32x4[ 0 ][ 0 ] ); + calc_corr( input_QS + n, corr_QC, o - 4, state_QS_s32x4[ 0 ][ 1 ] ); + state_QS_s32x4[ 2 ][ 1 ] = vld1q_s32( in + n ); + vst1q_lane_s32( state + n, state_QS_s32x4[ 0 ][ 0 ], 0 ); + state_QS_s32x4[ 2 ][ 0 ] = vextq_s32( state_QS_s32x4[ 0 ][ 0 ], state_QS_s32x4[ 0 ][ 1 ], 1 ); + state_QS_s32x4[ 2 ][ 1 ] = vextq_s32( state_QS_s32x4[ 0 ][ 1 ], state_QS_s32x4[ 2 ][ 1 ], 1 ); + state_QS_s32x4[ 0 ][ 0 ] = calc_state( state_QS_s32x4[ 0 ][ 0 ], state_QS_s32x4[ 2 ][ 0 ], state_QS_s32x4[ 1 ][ 0 ], warping_Q16_s32x4 ); + state_QS_s32x4[ 0 ][ 1 ] = calc_state( state_QS_s32x4[ 0 ][ 1 ], state_QS_s32x4[ 2 ][ 1 ], state_QS_s32x4[ 1 ][ 1 ], warping_Q16_s32x4 ); + state_QS_s32x4[ 1 ][ 0 ] = state_QS_s32x4[ 2 ][ 0 ]; + state_QS_s32x4[ 1 ][ 1 ] = state_QS_s32x4[ 2 ][ 1 ]; + } while( ++n < ( length + order ) ); + in = state; + o -= 8; + } while( o > 4 ); + + if( o ) { + /* Calculate the last 4 taps of all inputs. */ + opus_int32 *stateT = state; + silk_assert( o == 4 ); + state_QS_s32x4[ 0 ][ 0 ] = state_QS_s32x4[ 1 ][ 0 ] = vdupq_n_s32( 0 ); + n = length + order; + do { + calc_corr( input_QS, corr_QC, 0, state_QS_s32x4[ 0 ][ 0 ] ); + state_QS_s32x4[ 2 ][ 0 ] = vld1q_s32( stateT ); + vst1q_lane_s32( stateT, state_QS_s32x4[ 0 ][ 0 ], 0 ); + state_QS_s32x4[ 2 ][ 0 ] = vextq_s32( state_QS_s32x4[ 0 ][ 0 ], state_QS_s32x4[ 2 ][ 0 ], 1 ); + state_QS_s32x4[ 0 ][ 0 ] = calc_state( state_QS_s32x4[ 0 ][ 0 ], state_QS_s32x4[ 2 ][ 0 ], state_QS_s32x4[ 1 ][ 0 ], warping_Q16_s32x4 ); + state_QS_s32x4[ 1 ][ 0 ] = state_QS_s32x4[ 2 ][ 0 ]; + input_QS++; + stateT++; + } while( --n ); + } + } + + { + const opus_int16 *inputT = input; + int32x4_t t_s32x4; + int64x1_t t_s64x1; + int64x2_t t_s64x2 = vdupq_n_s64( 0 ); + for( n = 0; n <= length - 8; n += 8 ) { + int16x8_t input_s16x8 = vld1q_s16( inputT ); + t_s32x4 = vmull_s16( vget_low_s16( input_s16x8 ), vget_low_s16( input_s16x8 ) ); + t_s32x4 = vmlal_s16( t_s32x4, vget_high_s16( input_s16x8 ), vget_high_s16( input_s16x8 ) ); + t_s64x2 = vaddw_s32( t_s64x2, vget_low_s32( t_s32x4 ) ); + t_s64x2 = vaddw_s32( t_s64x2, vget_high_s32( t_s32x4 ) ); + inputT += 8; + } + t_s64x1 = vadd_s64( vget_low_s64( t_s64x2 ), vget_high_s64( t_s64x2 ) ); + corr_QC_orderT = vget_lane_s64( t_s64x1, 0 ); + for( ; n < length; n++ ) { + corr_QC_orderT += silk_SMULL( input[ n ], input[ n ] ); + } + corr_QC_orderT = silk_LSHIFT64( corr_QC_orderT, QC ); + corr_QC[ orderT ] = corr_QC_orderT; + } + + corr_QCT = corr_QC + orderT - order; + lsh = silk_CLZ64( corr_QC_orderT ) - 35; + lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC ); + *scale = -( QC + lsh ); + silk_assert( *scale >= -30 && *scale <= 12 ); + lsh_s64x2 = vdupq_n_s64( lsh ); + for( i = 0; i <= order - 3; i += 4 ) { + int32x4_t corr_s32x4; + int64x2_t corr_QC0_s64x2, corr_QC1_s64x2; + corr_QC0_s64x2 = vld1q_s64( corr_QCT + i ); + corr_QC1_s64x2 = vld1q_s64( corr_QCT + i + 2 ); + corr_QC0_s64x2 = vshlq_s64( corr_QC0_s64x2, lsh_s64x2 ); + corr_QC1_s64x2 = vshlq_s64( corr_QC1_s64x2, lsh_s64x2 ); + corr_s32x4 = vcombine_s32( vmovn_s64( corr_QC1_s64x2 ), vmovn_s64( corr_QC0_s64x2 ) ); + corr_s32x4 = vrev64q_s32( corr_s32x4 ); + vst1q_s32( corr + order - i - 3, corr_s32x4 ); + } + if( lsh >= 0 ) { + for( ; i < order + 1; i++ ) { + corr[ order - i ] = (opus_int32)silk_CHECK_FIT32( silk_LSHIFT64( corr_QCT[ i ], lsh ) ); + } + } else { + for( ; i < order + 1; i++ ) { + corr[ order - i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr_QCT[ i ], -lsh ) ); + } + } + silk_assert( corr_QCT[ order ] >= 0 ); /* If breaking, decrease QC*/ + RESTORE_STACK; + } + +#ifdef OPUS_CHECK_ASM + { + opus_int32 corr_c[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int scale_c; + silk_warped_autocorrelation_FIX_c( corr_c, &scale_c, input, warping_Q16, length, order ); + silk_assert( !memcmp( corr_c, corr, sizeof( corr_c[ 0 ] ) * ( order + 1 ) ) ); + silk_assert( scale_c == *scale ); + } +#endif +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/autocorr_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/autocorr_FIX.c new file mode 100644 index 000000000..de95c9869 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/autocorr_FIX.c @@ -0,0 +1,48 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "celt_lpc.h" + +/* Compute autocorrelation */ +void silk_autocorr( + opus_int32 *results, /* O Result (length correlationCount) */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *inputData, /* I Input data to correlate */ + const opus_int inputDataSize, /* I Length of input */ + const opus_int correlationCount, /* I Number of correlation taps to compute */ + int arch /* I Run-time architecture */ +) +{ + opus_int corrCount; + corrCount = silk_min_int( inputDataSize, correlationCount ); + *scale = _celt_autocorr(inputData, results, NULL, 0, corrCount-1, inputDataSize, arch); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/burg_modified_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/burg_modified_FIX.c new file mode 100644 index 000000000..274d4b28e --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/burg_modified_FIX.c @@ -0,0 +1,280 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "define.h" +#include "tuning_parameters.h" +#include "pitch.h" + +#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */ + +#define QA 25 +#define N_BITS_HEAD_ROOM 3 +#define MIN_RSHIFTS -16 +#define MAX_RSHIFTS (32 - QA) + +/* Compute reflection coefficients from input signal */ +void silk_burg_modified_c( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +) +{ + opus_int k, n, s, lz, rshifts, reached_max_gain; + opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2; + const opus_int16 *x_ptr; + opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ]; + opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ]; + opus_int32 xcorr[ SILK_MAX_ORDER_LPC ]; + opus_int64 C0_64; + + celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + + /* Compute autocorrelations, added over subframes */ + C0_64 = silk_inner_prod16_aligned_64( x, x, subfr_length*nb_subfr, arch ); + lz = silk_CLZ64(C0_64); + rshifts = 32 + 1 + N_BITS_HEAD_ROOM - lz; + if (rshifts > MAX_RSHIFTS) rshifts = MAX_RSHIFTS; + if (rshifts < MIN_RSHIFTS) rshifts = MIN_RSHIFTS; + + if (rshifts > 0) { + C0 = (opus_int32)silk_RSHIFT64(C0_64, rshifts ); + } else { + C0 = silk_LSHIFT32((opus_int32)C0_64, -rshifts ); + } + + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += (opus_int32)silk_RSHIFT64( + silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n, arch ), rshifts ); + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + int i; + opus_int32 d; + x_ptr = x + s * subfr_length; + celt_pitch_xcorr(x_ptr, x_ptr + 1, xcorr, subfr_length - D, D, arch ); + for( n = 1; n < D + 1; n++ ) { + for ( i = n + subfr_length - D, d = 0; i < subfr_length; i++ ) + d = MAC16_16( d, x_ptr[ i ], x_ptr[ i - n ] ); + xcorr[ n - 1 ] += d; + } + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += silk_LSHIFT32( xcorr[ n - 1 ], -rshifts ); + } + } + } + silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + + invGain_Q30 = (opus_int32)1 << 30; + reached_max_gain = 0; + for( n = 0; n < D; n++ ) { + /* Update first row of correlation matrix (without first element) */ + /* Update last row of correlation matrix (without last element, stored in reversed order) */ + /* Update C * Af */ + /* Update C * flipud(Af) (stored in reversed order) */ + if( rshifts > -2 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], 16 - rshifts ); /* Q(16-rshifts) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); /* Q(16-rshifts) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], QA - 16 ); /* Q(QA-16) */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); /* Q(QA-16) */ + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp_QA = Af_QA[ k ]; + tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); /* Q(QA-16) */ + tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); /* Q(QA-16) */ + } + tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts ); /* Q(16-rshifts) */ + tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts ); /* Q(16-rshifts) */ + for( k = 0; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] ); /* Q( -rshift ) */ + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], -rshifts ); /* Q( -rshifts ) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); /* Q( -rshifts ) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], 17 ); /* Q17 */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 ); /* Q17 */ + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); /* Q17 */ + /* We sometimes have get overflows in the multiplications (even beyond +/- 2^32), + but they cancel each other and the real result seems to always fit in a 32-bit + signed integer. This was determined experimentally, not theoretically (unfortunately). */ + tmp1 = silk_MLA_ovflw( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); /* Q17 */ + tmp2 = silk_MLA_ovflw( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); /* Q17 */ + } + tmp1 = -tmp1; /* Q17 */ + tmp2 = -tmp2; /* Q17 */ + for( k = 0; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1, + silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2, + silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) ); /* Q( -rshift ) */ + } + } + } + + /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ + tmp1 = C_first_row[ n ]; /* Q( -rshifts ) */ + tmp2 = C_last_row[ n ]; /* Q( -rshifts ) */ + num = 0; /* Q( -rshifts ) */ + nrg = silk_ADD32( CAb[ 0 ], CAf[ 0 ] ); /* Q( 1-rshifts ) */ + for( k = 0; k < n; k++ ) { + Atmp_QA = Af_QA[ k ]; + lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1; + lz = silk_min( 32 - QA, lz ); + Atmp1 = silk_LSHIFT32( Atmp_QA, lz ); /* Q( QA + lz ) */ + + tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + num = silk_ADD_LSHIFT32( num, silk_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + nrg = silk_ADD_LSHIFT32( nrg, silk_SMMUL( silk_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ), + Atmp1 ), 32 - QA - lz ); /* Q( 1-rshifts ) */ + } + CAf[ n + 1 ] = tmp1; /* Q( -rshifts ) */ + CAb[ n + 1 ] = tmp2; /* Q( -rshifts ) */ + num = silk_ADD32( num, tmp2 ); /* Q( -rshifts ) */ + num = silk_LSHIFT32( -num, 1 ); /* Q( 1-rshifts ) */ + + /* Calculate the next order reflection (parcor) coefficient */ + if( silk_abs( num ) < nrg ) { + rc_Q31 = silk_DIV32_varQ( num, nrg, 31 ); + } else { + rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN; + } + + /* Update inverse prediction gain */ + tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 ); + tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 ); + if( tmp1 <= minInvGain_Q30 ) { + /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ + tmp2 = ( (opus_int32)1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 ); /* Q30 */ + rc_Q31 = silk_SQRT_APPROX( tmp2 ); /* Q15 */ + if( rc_Q31 > 0 ) { + /* Newton-Raphson iteration */ + rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 ); /* Q15 */ + rc_Q31 = silk_LSHIFT32( rc_Q31, 16 ); /* Q31 */ + if( num < 0 ) { + /* Ensure adjusted reflection coefficients has the original sign */ + rc_Q31 = -rc_Q31; + } + } + invGain_Q30 = minInvGain_Q30; + reached_max_gain = 1; + } else { + invGain_Q30 = tmp1; + } + + /* Update the AR coefficients */ + for( k = 0; k < (n + 1) >> 1; k++ ) { + tmp1 = Af_QA[ k ]; /* QA */ + tmp2 = Af_QA[ n - k - 1 ]; /* QA */ + Af_QA[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* QA */ + Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* QA */ + } + Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA ); /* QA */ + + if( reached_max_gain ) { + /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ + for( k = n + 1; k < D; k++ ) { + Af_QA[ k ] = 0; + } + break; + } + + /* Update C * Af and C * Ab */ + for( k = 0; k <= n + 1; k++ ) { + tmp1 = CAf[ k ]; /* Q( -rshifts ) */ + tmp2 = CAb[ n - k + 1 ]; /* Q( -rshifts ) */ + CAf[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + } + } + + if( reached_max_gain ) { + for( k = 0; k < D; k++ ) { + /* Scale coefficients */ + A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); + } + /* Subtract energy of preceding samples from C0 */ + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16_aligned_64( x_ptr, x_ptr, D, arch ), rshifts ); + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D, arch), -rshifts); + } + } + /* Approximate residual energy */ + *res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 ); + *res_nrg_Q = -rshifts; + } else { + /* Return residual energy */ + nrg = CAf[ 0 ]; /* Q( -rshifts ) */ + tmp1 = (opus_int32)1 << 16; /* Q16 */ + for( k = 0; k < D; k++ ) { + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); /* Q16 */ + nrg = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); /* Q( -rshifts ) */ + tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 ); /* Q16 */ + A_Q16[ k ] = -Atmp1; + } + *res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */ + *res_nrg_Q = -rshifts; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/corrMatrix_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/corrMatrix_FIX.c new file mode 100644 index 000000000..1b4a29c23 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/corrMatrix_FIX.c @@ -0,0 +1,150 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/********************************************************************** + * Correlation Matrix Computations for LS estimate. + **********************************************************************/ + +#include "main_FIX.h" + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int16 *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */ + const opus_int rshifts, /* I Right shifts of correlations */ + int arch /* I Run-time architecture */ +) +{ + opus_int lag, i; + const opus_int16 *ptr1, *ptr2; + opus_int32 inner_prod; + + ptr1 = &x[ order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */ + ptr2 = t; + /* Calculate X'*t */ + if( rshifts > 0 ) { + /* Right shifting used */ + for( lag = 0; lag < order; lag++ ) { + inner_prod = 0; + for( i = 0; i < L; i++ ) { + inner_prod = silk_ADD_RSHIFT32( inner_prod, silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts ); + } + Xt[ lag ] = inner_prod; /* X[:,lag]'*t */ + ptr1--; /* Go to next column of X */ + } + } else { + silk_assert( rshifts == 0 ); + for( lag = 0; lag < order; lag++ ) { + Xt[ lag ] = silk_inner_prod_aligned( ptr1, ptr2, L, arch ); /* X[:,lag]'*t */ + ptr1--; /* Go to next column of X */ + } + } +} + +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */ + opus_int32 *nrg, /* O Energy of x vector */ + opus_int *rshifts, /* O Right shifts of correlations and energy */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, j, lag; + opus_int32 energy; + const opus_int16 *ptr1, *ptr2; + + /* Calculate energy to find shift used to fit in 32 bits */ + silk_sum_sqr_shift( nrg, rshifts, x, L + order - 1 ); + energy = *nrg; + + /* Calculate energy of first column (0) of X: X[:,0]'*X[:,0] */ + /* Remove contribution of first order - 1 samples */ + for( i = 0; i < order - 1; i++ ) { + energy -= silk_RSHIFT32( silk_SMULBB( x[ i ], x[ i ] ), *rshifts ); + } + + /* Calculate energy of remaining columns of X: X[:,j]'*X[:,j] */ + /* Fill out the diagonal of the correlation matrix */ + matrix_ptr( XX, 0, 0, order ) = energy; + silk_assert( energy >= 0 ); + ptr1 = &x[ order - 1 ]; /* First sample of column 0 of X */ + for( j = 1; j < order; j++ ) { + energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr1[ L - j ] ), *rshifts ) ); + energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr1[ -j ] ), *rshifts ) ); + matrix_ptr( XX, j, j, order ) = energy; + silk_assert( energy >= 0 ); + } + + ptr2 = &x[ order - 2 ]; /* First sample of column 1 of X */ + /* Calculate the remaining elements of the correlation matrix */ + if( *rshifts > 0 ) { + /* Right shifting used */ + for( lag = 1; lag < order; lag++ ) { + /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */ + energy = 0; + for( i = 0; i < L; i++ ) { + energy += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), *rshifts ); + } + /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */ + matrix_ptr( XX, lag, 0, order ) = energy; + matrix_ptr( XX, 0, lag, order ) = energy; + for( j = 1; j < ( order - lag ); j++ ) { + energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ), *rshifts ) ); + energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr2[ -j ] ), *rshifts ) ); + matrix_ptr( XX, lag + j, j, order ) = energy; + matrix_ptr( XX, j, lag + j, order ) = energy; + } + ptr2--; /* Update pointer to first sample of next column (lag) in X */ + } + } else { + for( lag = 1; lag < order; lag++ ) { + /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */ + energy = silk_inner_prod_aligned( ptr1, ptr2, L, arch ); + matrix_ptr( XX, lag, 0, order ) = energy; + matrix_ptr( XX, 0, lag, order ) = energy; + /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */ + for( j = 1; j < ( order - lag ); j++ ) { + energy = silk_SUB32( energy, silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ) ); + energy = silk_SMLABB( energy, ptr1[ -j ], ptr2[ -j ] ); + matrix_ptr( XX, lag + j, j, order ) = energy; + matrix_ptr( XX, j, lag + j, order ) = energy; + } + ptr2--;/* Update pointer to first sample of next column (lag) in X */ + } + } +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/encode_frame_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/encode_frame_FIX.c new file mode 100644 index 000000000..a02bf87db --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/encode_frame_FIX.c @@ -0,0 +1,448 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main_FIX.h" +#include "stack_alloc.h" +#include "tuning_parameters.h" + +/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */ +static OPUS_INLINE void silk_LBRR_encode_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */ + const opus_int16 x16[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +); + +void silk_encode_do_VAD_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int activity /* I Decision of Opus voice activity detector */ +) +{ + const opus_int activity_threshold = SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ); + + /****************************/ + /* Voice Activity Detection */ + /****************************/ + silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch ); + /* If Opus VAD is inactive and Silk VAD is active: lower Silk VAD to just under the threshold */ + if( activity == VAD_NO_ACTIVITY && psEnc->sCmn.speech_activity_Q8 >= activity_threshold ) { + psEnc->sCmn.speech_activity_Q8 = activity_threshold - 1; + } + + /**************************************************/ + /* Convert speech activity into VAD and DTX flags */ + /**************************************************/ + if( psEnc->sCmn.speech_activity_Q8 < activity_threshold ) { + psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->sCmn.noSpeechCounter++; + if( psEnc->sCmn.noSpeechCounter <= NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.inDTX = 0; + } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX; + psEnc->sCmn.inDTX = 0; + } + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0; + } else { + psEnc->sCmn.noSpeechCounter = 0; + psEnc->sCmn.inDTX = 0; + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + } +} + +/****************/ +/* Encode frame */ +/****************/ +opus_int silk_encode_frame_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +) +{ + silk_encoder_control_FIX sEncCtrl; + opus_int i, iter, maxIter, found_upper, found_lower, ret = 0; + opus_int16 *x_frame; + ec_enc sRangeEnc_copy, sRangeEnc_copy2; + silk_nsq_state sNSQ_copy, sNSQ_copy2; + opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper; + opus_int32 gainsID, gainsID_lower, gainsID_upper; + opus_int16 gainMult_Q8; + opus_int16 ec_prevLagIndex_copy; + opus_int ec_prevSignalType_copy; + opus_int8 LastGainIndex_copy2; + opus_int gain_lock[ MAX_NB_SUBFR ] = {0}; + opus_int16 best_gain_mult[ MAX_NB_SUBFR ]; + opus_int best_sum[ MAX_NB_SUBFR ]; + SAVE_STACK; + + /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */ + LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0; + + psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3; + + /**************************************************************/ + /* Set up Input Pointers, and insert frame in input buffer */ + /*************************************************************/ + /* start of frame to encode */ + x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length; + + /***************************************/ + /* Ensure smooth bandwidth transitions */ + /***************************************/ + silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); + + /*******************************************/ + /* Copy new frame to front of input buffer */ + /*******************************************/ + silk_memcpy( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length * sizeof( opus_int16 ) ); + + if( !psEnc->sCmn.prefillFlag ) { + VARDECL( opus_int16, res_pitch ); + VARDECL( opus_uint8, ec_buf_copy ); + opus_int16 *res_pitch_frame; + + ALLOC( res_pitch, + psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + + psEnc->sCmn.ltp_mem_length, opus_int16 ); + /* start of pitch LPC residual frame */ + res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length; + + /*****************************************/ + /* Find pitch lags, initial LPC analysis */ + /*****************************************/ + silk_find_pitch_lags_FIX( psEnc, &sEncCtrl, res_pitch, x_frame - psEnc->sCmn.ltp_mem_length, psEnc->sCmn.arch ); + + /************************/ + /* Noise shape analysis */ + /************************/ + silk_noise_shape_analysis_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame, psEnc->sCmn.arch ); + + /***************************************************/ + /* Find linear prediction coefficients (LPC + LTP) */ + /***************************************************/ + silk_find_pred_coefs_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame, condCoding ); + + /****************************************/ + /* Process gains */ + /****************************************/ + silk_process_gains_FIX( psEnc, &sEncCtrl, condCoding ); + + /****************************************/ + /* Low Bitrate Redundant Encoding */ + /****************************************/ + silk_LBRR_encode_FIX( psEnc, &sEncCtrl, x_frame, condCoding ); + + /* Loop over quantizer and entropy coding to control bitrate */ + maxIter = 6; + gainMult_Q8 = SILK_FIX_CONST( 1, 8 ); + found_lower = 0; + found_upper = 0; + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + gainsID_lower = -1; + gainsID_upper = -1; + /* Copy part of the input state */ + silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) ); + silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + seed_copy = psEnc->sCmn.indices.Seed; + ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex; + ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType; + ALLOC( ec_buf_copy, 1275, opus_uint8 ); + for( iter = 0; ; iter++ ) { + if( gainsID == gainsID_lower ) { + nBits = nBits_lower; + } else if( gainsID == gainsID_upper ) { + nBits = nBits_upper; + } else { + /* Restore part of the input state */ + if( iter > 0 ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) ); + psEnc->sCmn.indices.Seed = seed_copy; + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, x_frame, psEnc->sCmn.pulses, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR_Q13, sEncCtrl.HarmShapeGain_Q14, + sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14, + psEnc->sCmn.arch ); + } else { + silk_NSQ( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, x_frame, psEnc->sCmn.pulses, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR_Q13, sEncCtrl.HarmShapeGain_Q14, + sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14, + psEnc->sCmn.arch); + } + + if ( iter == maxIter && !found_lower ) { + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + } + + /****************************************/ + /* Encode Parameters */ + /****************************************/ + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + /****************************************/ + /* Encode Excitation Signal */ + /****************************************/ + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + + /* If we still bust after the last iteration, do some damage control. */ + if ( iter == maxIter && !found_lower && nBits > maxBits ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + + /* Keep gains the same as the last frame. */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + psEnc->sCmn.indices.GainsIndices[ i ] = 4; + } + if (condCoding != CODE_CONDITIONALLY) { + psEnc->sCmn.indices.GainsIndices[ 0 ] = sEncCtrl.lastGainIndexPrev; + } + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + /* Clear all pulses. */ + for ( i = 0; i < psEnc->sCmn.frame_length; i++ ) { + psEnc->sCmn.pulses[ i ] = 0; + } + + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + } + + if( useCBR == 0 && iter == 0 && nBits <= maxBits ) { + break; + } + } + + if( iter == maxIter ) { + if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) { + /* Restore output state from earlier iteration that did meet the bitrate budget */ + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + celt_assert( sRangeEnc_copy2.offs <= 1275 ); + silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) ); + psEnc->sShape.LastGainIndex = LastGainIndex_copy2; + } + break; + } + + if( nBits > maxBits ) { + if( found_lower == 0 && iter >= 2 ) { + /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */ + sEncCtrl.Lambda_Q10 = silk_ADD_RSHIFT32( sEncCtrl.Lambda_Q10, sEncCtrl.Lambda_Q10, 1 ); + found_upper = 0; + gainsID_upper = -1; + } else { + found_upper = 1; + nBits_upper = nBits; + gainMult_upper = gainMult_Q8; + gainsID_upper = gainsID; + } + } else if( nBits < maxBits - 5 ) { + found_lower = 1; + nBits_lower = nBits; + gainMult_lower = gainMult_Q8; + if( gainsID != gainsID_lower ) { + gainsID_lower = gainsID; + /* Copy part of the output state */ + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + celt_assert( psRangeEnc->offs <= 1275 ); + silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs ); + silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + LastGainIndex_copy2 = psEnc->sShape.LastGainIndex; + } + } else { + /* Within 5 bits of budget: close enough */ + break; + } + + if ( !found_lower && nBits > maxBits ) { + int j; + for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + int sum=0; + for ( j = i*psEnc->sCmn.subfr_length; j < (i+1)*psEnc->sCmn.subfr_length; j++ ) { + sum += abs( psEnc->sCmn.pulses[j] ); + } + if ( iter == 0 || (sum < best_sum[i] && !gain_lock[i]) ) { + best_sum[i] = sum; + best_gain_mult[i] = gainMult_Q8; + } else { + gain_lock[i] = 1; + } + } + } + if( ( found_lower & found_upper ) == 0 ) { + /* Adjust gain according to high-rate rate/distortion curve */ + if( nBits > maxBits ) { + if (gainMult_Q8 < 16384) { + gainMult_Q8 *= 2; + } else { + gainMult_Q8 = 32767; + } + } else { + opus_int32 gain_factor_Q16; + gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) ); + gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 ); + } + + } else { + /* Adjust gain by interpolating */ + gainMult_Q8 = gainMult_lower + silk_DIV32_16( silk_MUL( gainMult_upper - gainMult_lower, maxBits - nBits_lower ), nBits_upper - nBits_lower ); + /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */ + if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ); + } else + if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + opus_int16 tmp; + if ( gain_lock[i] ) { + tmp = best_gain_mult[i]; + } else { + tmp = gainMult_Q8; + } + sEncCtrl.Gains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], tmp ), 8 ); + } + + /* Quantize gains */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, sEncCtrl.Gains_Q16, + &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Unique identifier of gains vector */ + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + } + } + + /* Update input buffer */ + silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ], + ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( opus_int16 ) ); + + /* Exit without entropy coding */ + if( psEnc->sCmn.prefillFlag ) { + /* No payload */ + *pnBytesOut = 0; + RESTORE_STACK; + return ret; + } + + /* Parameters needed for next frame */ + psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ]; + psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType; + + /****************************************/ + /* Finalize payload */ + /****************************************/ + psEnc->sCmn.first_frame_after_reset = 0; + /* Payload size */ + *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 ); + + RESTORE_STACK; + return ret; +} + +/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */ +static OPUS_INLINE void silk_LBRR_encode_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */ + const opus_int16 x16[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +) +{ + opus_int32 TempGains_Q16[ MAX_NB_SUBFR ]; + SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ]; + silk_nsq_state sNSQ_LBRR; + + /*******************************************/ + /* Control use of inband LBRR */ + /*******************************************/ + if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) { + psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + + /* Copy noise shaping quantizer state and quantization indices from regular encoding */ + silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) ); + + /* Save original gains */ + silk_memcpy( TempGains_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + + if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) { + /* First frame in packet or previous frame not LBRR coded */ + psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex; + + /* Increase Gains to get target LBRR rate */ + psIndices_LBRR->GainsIndices[ 0 ] = psIndices_LBRR->GainsIndices[ 0 ] + psEnc->sCmn.LBRR_GainIncreases; + psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 ); + } + + /* Decode to get gains in sync with decoder */ + /* Overwrite unquantized gains with quantized gains */ + silk_gains_dequant( psEncCtrl->Gains_Q16, psIndices_LBRR->GainsIndices, + &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, x16, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14, + psEncCtrl->AR_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14, + psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14, psEnc->sCmn.arch ); + } else { + silk_NSQ( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, x16, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14, + psEncCtrl->AR_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14, + psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14, psEnc->sCmn.arch ); + } + + /* Restore original gains */ + silk_memcpy( psEncCtrl->Gains_Q16, TempGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/find_LPC_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/find_LPC_FIX.c new file mode 100644 index 000000000..c762a0f2a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/find_LPC_FIX.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" +#include "tuning_parameters.h" + +/* Finds LPC vector from correlations, and converts to NLSF */ +void silk_find_LPC_FIX( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const opus_int16 x[], /* I Input signal */ + const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */ +) +{ + opus_int k, subfr_length; + opus_int32 a_Q16[ MAX_LPC_ORDER ]; + opus_int isInterpLower, shift; + opus_int32 res_nrg0, res_nrg1; + opus_int rshift0, rshift1; + + /* Used only for LSF interpolation */ + opus_int32 a_tmp_Q16[ MAX_LPC_ORDER ], res_nrg_interp, res_nrg, res_tmp_nrg; + opus_int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q; + opus_int16 a_tmp_Q12[ MAX_LPC_ORDER ]; + opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ]; + SAVE_STACK; + + subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder; + + /* Default: no interpolation */ + psEncC->indices.NLSFInterpCoef_Q2 = 4; + + /* Burg AR analysis for the full frame */ + silk_burg_modified( &res_nrg, &res_nrg_Q, a_Q16, x, minInvGain_Q30, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder, psEncC->arch ); + + if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) { + VARDECL( opus_int16, LPC_res ); + + /* Optimal solution for last 10 ms */ + silk_burg_modified( &res_tmp_nrg, &res_tmp_nrg_Q, a_tmp_Q16, x + 2 * subfr_length, minInvGain_Q30, subfr_length, 2, psEncC->predictLPCOrder, psEncC->arch ); + + /* subtract residual energy here, as that's easier than adding it to the */ + /* residual energy of the first 10 ms in each iteration of the search below */ + shift = res_tmp_nrg_Q - res_nrg_Q; + if( shift >= 0 ) { + if( shift < 32 ) { + res_nrg = res_nrg - silk_RSHIFT( res_tmp_nrg, shift ); + } + } else { + silk_assert( shift > -32 ); + res_nrg = silk_RSHIFT( res_nrg, -shift ) - res_tmp_nrg; + res_nrg_Q = res_tmp_nrg_Q; + } + + /* Convert to NLSFs */ + silk_A2NLSF( NLSF_Q15, a_tmp_Q16, psEncC->predictLPCOrder ); + + ALLOC( LPC_res, 2 * subfr_length, opus_int16 ); + + /* Search over interpolation indices to find the one with lowest residual energy */ + for( k = 3; k >= 0; k-- ) { + /* Interpolate NLSFs for first half */ + silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder ); + + /* Convert to LPC for residual energy evaluation */ + silk_NLSF2A( a_tmp_Q12, NLSF0_Q15, psEncC->predictLPCOrder, psEncC->arch ); + + /* Calculate residual energy with NLSF interpolation */ + silk_LPC_analysis_filter( LPC_res, x, a_tmp_Q12, 2 * subfr_length, psEncC->predictLPCOrder, psEncC->arch ); + + silk_sum_sqr_shift( &res_nrg0, &rshift0, LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder ); + silk_sum_sqr_shift( &res_nrg1, &rshift1, LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder ); + + /* Add subframe energies from first half frame */ + shift = rshift0 - rshift1; + if( shift >= 0 ) { + res_nrg1 = silk_RSHIFT( res_nrg1, shift ); + res_nrg_interp_Q = -rshift0; + } else { + res_nrg0 = silk_RSHIFT( res_nrg0, -shift ); + res_nrg_interp_Q = -rshift1; + } + res_nrg_interp = silk_ADD32( res_nrg0, res_nrg1 ); + + /* Compare with first half energy without NLSF interpolation, or best interpolated value so far */ + shift = res_nrg_interp_Q - res_nrg_Q; + if( shift >= 0 ) { + if( silk_RSHIFT( res_nrg_interp, shift ) < res_nrg ) { + isInterpLower = silk_TRUE; + } else { + isInterpLower = silk_FALSE; + } + } else { + if( -shift < 32 ) { + if( res_nrg_interp < silk_RSHIFT( res_nrg, -shift ) ) { + isInterpLower = silk_TRUE; + } else { + isInterpLower = silk_FALSE; + } + } else { + isInterpLower = silk_FALSE; + } + } + + /* Determine whether current interpolated NLSFs are best so far */ + if( isInterpLower == silk_TRUE ) { + /* Interpolation has lower residual energy */ + res_nrg = res_nrg_interp; + res_nrg_Q = res_nrg_interp_Q; + psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k; + } + } + } + + if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) { + /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ + silk_A2NLSF( NLSF_Q15, a_Q16, psEncC->predictLPCOrder ); + } + + celt_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) ); + RESTORE_STACK; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/find_LTP_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/find_LTP_FIX.c new file mode 100644 index 000000000..62d4afb25 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/find_LTP_FIX.c @@ -0,0 +1,99 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +void silk_find_LTP_FIX( + opus_int32 XXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Correlation matrix */ + opus_int32 xXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER ], /* O Correlation vector */ + const opus_int16 r_ptr[], /* I Residual signal after LPC */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, k, extra_shifts; + opus_int xx_shifts, xX_shifts, XX_shifts; + const opus_int16 *lag_ptr; + opus_int32 *XXLTP_Q17_ptr, *xXLTP_Q17_ptr; + opus_int32 xx, nrg, temp; + + xXLTP_Q17_ptr = xXLTP_Q17; + XXLTP_Q17_ptr = XXLTP_Q17; + for( k = 0; k < nb_subfr; k++ ) { + lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 ); + + silk_sum_sqr_shift( &xx, &xx_shifts, r_ptr, subfr_length + LTP_ORDER ); /* xx in Q( -xx_shifts ) */ + silk_corrMatrix_FIX( lag_ptr, subfr_length, LTP_ORDER, XXLTP_Q17_ptr, &nrg, &XX_shifts, arch ); /* XXLTP_Q17_ptr and nrg in Q( -XX_shifts ) */ + extra_shifts = xx_shifts - XX_shifts; + if( extra_shifts > 0 ) { + /* Shift XX */ + xX_shifts = xx_shifts; + for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { + XXLTP_Q17_ptr[ i ] = silk_RSHIFT32( XXLTP_Q17_ptr[ i ], extra_shifts ); /* Q( -xX_shifts ) */ + } + nrg = silk_RSHIFT32( nrg, extra_shifts ); /* Q( -xX_shifts ) */ + } else if( extra_shifts < 0 ) { + /* Shift xx */ + xX_shifts = XX_shifts; + xx = silk_RSHIFT32( xx, -extra_shifts ); /* Q( -xX_shifts ) */ + } else { + xX_shifts = xx_shifts; + } + silk_corrVector_FIX( lag_ptr, r_ptr, subfr_length, LTP_ORDER, xXLTP_Q17_ptr, xX_shifts, arch ); /* xXLTP_Q17_ptr in Q( -xX_shifts ) */ + + /* At this point all correlations are in Q(-xX_shifts) */ + temp = silk_SMLAWB( 1, nrg, SILK_FIX_CONST( LTP_CORR_INV_MAX, 16 ) ); + temp = silk_max( temp, xx ); +TIC(div) +#if 0 + for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { + XXLTP_Q17_ptr[ i ] = silk_DIV32_varQ( XXLTP_Q17_ptr[ i ], temp, 17 ); + } + for( i = 0; i < LTP_ORDER; i++ ) { + xXLTP_Q17_ptr[ i ] = silk_DIV32_varQ( xXLTP_Q17_ptr[ i ], temp, 17 ); + } +#else + for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { + XXLTP_Q17_ptr[ i ] = (opus_int32)( silk_LSHIFT64( (opus_int64)XXLTP_Q17_ptr[ i ], 17 ) / temp ); + } + for( i = 0; i < LTP_ORDER; i++ ) { + xXLTP_Q17_ptr[ i ] = (opus_int32)( silk_LSHIFT64( (opus_int64)xXLTP_Q17_ptr[ i ], 17 ) / temp ); + } +#endif +TOC(div) + r_ptr += subfr_length; + XXLTP_Q17_ptr += LTP_ORDER * LTP_ORDER; + xXLTP_Q17_ptr += LTP_ORDER; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/find_pitch_lags_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/find_pitch_lags_FIX.c new file mode 100644 index 000000000..6c3379f2b --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/find_pitch_lags_FIX.c @@ -0,0 +1,143 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" +#include "tuning_parameters.h" + +/* Find pitch lags */ +void silk_find_pitch_lags_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int16 res[], /* O residual */ + const opus_int16 x[], /* I Speech signal */ + int arch /* I Run-time architecture */ +) +{ + opus_int buf_len, i, scale; + opus_int32 thrhld_Q13, res_nrg; + const opus_int16 *x_ptr; + VARDECL( opus_int16, Wsig ); + opus_int16 *Wsig_ptr; + opus_int32 auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ]; + opus_int16 rc_Q15[ MAX_FIND_PITCH_LPC_ORDER ]; + opus_int32 A_Q24[ MAX_FIND_PITCH_LPC_ORDER ]; + opus_int16 A_Q12[ MAX_FIND_PITCH_LPC_ORDER ]; + SAVE_STACK; + + /******************************************/ + /* Set up buffer lengths etc based on Fs */ + /******************************************/ + buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length; + + /* Safety check */ + celt_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length ); + + /*************************************/ + /* Estimate LPC AR coefficients */ + /*************************************/ + + /* Calculate windowed signal */ + + ALLOC( Wsig, psEnc->sCmn.pitch_LPC_win_length, opus_int16 ); + + /* First LA_LTP samples */ + x_ptr = x + buf_len - psEnc->sCmn.pitch_LPC_win_length; + Wsig_ptr = Wsig; + silk_apply_sine_window( Wsig_ptr, x_ptr, 1, psEnc->sCmn.la_pitch ); + + /* Middle un - windowed samples */ + Wsig_ptr += psEnc->sCmn.la_pitch; + x_ptr += psEnc->sCmn.la_pitch; + silk_memcpy( Wsig_ptr, x_ptr, ( psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ) ) * sizeof( opus_int16 ) ); + + /* Last LA_LTP samples */ + Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + x_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + silk_apply_sine_window( Wsig_ptr, x_ptr, 2, psEnc->sCmn.la_pitch ); + + /* Calculate autocorrelation sequence */ + silk_autocorr( auto_corr, &scale, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1, arch ); + + /* Add white noise, as fraction of energy */ + auto_corr[ 0 ] = silk_SMLAWB( auto_corr[ 0 ], auto_corr[ 0 ], SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ) + 1; + + /* Calculate the reflection coefficients using schur */ + res_nrg = silk_schur( rc_Q15, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Prediction gain */ + psEncCtrl->predGain_Q16 = silk_DIV32_varQ( auto_corr[ 0 ], silk_max_int( res_nrg, 1 ), 16 ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a( A_Q24, rc_Q15, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Convert From 32 bit Q24 to 16 bit Q12 coefs */ + for( i = 0; i < psEnc->sCmn.pitchEstimationLPCOrder; i++ ) { + A_Q12[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( A_Q24[ i ], 12 ) ); + } + + /* Do BWE */ + silk_bwexpander( A_Q12, psEnc->sCmn.pitchEstimationLPCOrder, SILK_FIX_CONST( FIND_PITCH_BANDWIDTH_EXPANSION, 16 ) ); + + /*****************************************/ + /* LPC analysis filtering */ + /*****************************************/ + silk_LPC_analysis_filter( res, x, A_Q12, buf_len, psEnc->sCmn.pitchEstimationLPCOrder, psEnc->sCmn.arch ); + + if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) { + /* Threshold for pitch estimator */ + thrhld_Q13 = SILK_FIX_CONST( 0.6, 13 ); + thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.004, 13 ), psEnc->sCmn.pitchEstimationLPCOrder ); + thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1, 21 ), psEnc->sCmn.speech_activity_Q8 ); + thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.15, 13 ), silk_RSHIFT( psEnc->sCmn.prevSignalType, 1 ) ); + thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1, 14 ), psEnc->sCmn.input_tilt_Q15 ); + thrhld_Q13 = silk_SAT16( thrhld_Q13 ); + + /*****************************************/ + /* Call pitch estimator */ + /*****************************************/ + if( silk_pitch_analysis_core( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, &psEnc->sCmn.indices.contourIndex, + &psEnc->LTPCorr_Q15, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16, + (opus_int)thrhld_Q13, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr, + psEnc->sCmn.arch) == 0 ) + { + psEnc->sCmn.indices.signalType = TYPE_VOICED; + } else { + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + } + } else { + silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) ); + psEnc->sCmn.indices.lagIndex = 0; + psEnc->sCmn.indices.contourIndex = 0; + psEnc->LTPCorr_Q15 = 0; + } + RESTORE_STACK; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/find_pred_coefs_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/find_pred_coefs_FIX.c new file mode 100644 index 000000000..606d86334 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/find_pred_coefs_FIX.c @@ -0,0 +1,145 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" + +void silk_find_pred_coefs_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + const opus_int16 res_pitch[], /* I Residual from pitch analysis */ + const opus_int16 x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i; + opus_int32 invGains_Q16[ MAX_NB_SUBFR ], local_gains[ MAX_NB_SUBFR ]; + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ]; + const opus_int16 *x_ptr; + opus_int16 *x_pre_ptr; + VARDECL( opus_int16, LPC_in_pre ); + opus_int32 min_gain_Q16, minInvGain_Q30; + SAVE_STACK; + + /* weighting for weighted least squares */ + min_gain_Q16 = silk_int32_MAX >> 6; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + min_gain_Q16 = silk_min( min_gain_Q16, psEncCtrl->Gains_Q16[ i ] ); + } + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + /* Divide to Q16 */ + silk_assert( psEncCtrl->Gains_Q16[ i ] > 0 ); + /* Invert and normalize gains, and ensure that maximum invGains_Q16 is within range of a 16 bit int */ + invGains_Q16[ i ] = silk_DIV32_varQ( min_gain_Q16, psEncCtrl->Gains_Q16[ i ], 16 - 2 ); + + /* Limit inverse */ + invGains_Q16[ i ] = silk_max( invGains_Q16[ i ], 100 ); + + /* Square the inverted gains */ + silk_assert( invGains_Q16[ i ] == silk_SAT16( invGains_Q16[ i ] ) ); + + /* Invert the inverted and normalized gains */ + local_gains[ i ] = silk_DIV32( ( (opus_int32)1 << 16 ), invGains_Q16[ i ] ); + } + + ALLOC( LPC_in_pre, + psEnc->sCmn.nb_subfr * psEnc->sCmn.predictLPCOrder + + psEnc->sCmn.frame_length, opus_int16 ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + VARDECL( opus_int32, xXLTP_Q17 ); + VARDECL( opus_int32, XXLTP_Q17 ); + + /**********/ + /* VOICED */ + /**********/ + celt_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 ); + + ALLOC( xXLTP_Q17, psEnc->sCmn.nb_subfr * LTP_ORDER, opus_int32 ); + ALLOC( XXLTP_Q17, psEnc->sCmn.nb_subfr * LTP_ORDER * LTP_ORDER, opus_int32 ); + + /* LTP analysis */ + silk_find_LTP_FIX( XXLTP_Q17, xXLTP_Q17, res_pitch, + psEncCtrl->pitchL, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.arch ); + + /* Quantize LTP gain parameters */ + silk_quant_LTP_gains( psEncCtrl->LTPCoef_Q14, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex, + &psEnc->sCmn.sum_log_gain_Q7, &psEncCtrl->LTPredCodGain_Q7, XXLTP_Q17, xXLTP_Q17, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.arch ); + + /* Control LTP scaling */ + silk_LTP_scale_ctrl_FIX( psEnc, psEncCtrl, condCoding ); + + /* Create LTP residual */ + silk_LTP_analysis_filter_FIX( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef_Q14, + psEncCtrl->pitchL, invGains_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + + } else { + /************/ + /* UNVOICED */ + /************/ + /* Create signal with prepended subframes, scaled by inverse gains */ + x_ptr = x - psEnc->sCmn.predictLPCOrder; + x_pre_ptr = LPC_in_pre; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + silk_scale_copy_vector16( x_pre_ptr, x_ptr, invGains_Q16[ i ], + psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder ); + x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder; + x_ptr += psEnc->sCmn.subfr_length; + } + + silk_memset( psEncCtrl->LTPCoef_Q14, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( opus_int16 ) ); + psEncCtrl->LTPredCodGain_Q7 = 0; + psEnc->sCmn.sum_log_gain_Q7 = 0; + } + + /* Limit on total predictive coding gain */ + if( psEnc->sCmn.first_frame_after_reset ) { + minInvGain_Q30 = SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET, 30 ); + } else { + minInvGain_Q30 = silk_log2lin( silk_SMLAWB( 16 << 7, (opus_int32)psEncCtrl->LTPredCodGain_Q7, SILK_FIX_CONST( 1.0 / 3, 16 ) ) ); /* Q16 */ + minInvGain_Q30 = silk_DIV32_varQ( minInvGain_Q30, + silk_SMULWW( SILK_FIX_CONST( MAX_PREDICTION_POWER_GAIN, 0 ), + silk_SMLAWB( SILK_FIX_CONST( 0.25, 18 ), SILK_FIX_CONST( 0.75, 18 ), psEncCtrl->coding_quality_Q14 ) ), 14 ); + } + + /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */ + silk_find_LPC_FIX( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain_Q30 ); + + /* Quantize LSFs */ + silk_process_NLSFs( &psEnc->sCmn, psEncCtrl->PredCoef_Q12, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 ); + + /* Calculate residual energy using quantized LPC coefficients */ + silk_residual_energy_FIX( psEncCtrl->ResNrg, psEncCtrl->ResNrgQ, LPC_in_pre, psEncCtrl->PredCoef_Q12, local_gains, + psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder, psEnc->sCmn.arch ); + + /* Copy to prediction struct for use in next frame for interpolation */ + silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); + RESTORE_STACK; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/k2a_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/k2a_FIX.c new file mode 100644 index 000000000..549f6eada --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/k2a_FIX.c @@ -0,0 +1,54 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */ + const opus_int32 order /* I Prediction order */ +) +{ + opus_int k, n; + opus_int32 rc, tmp1, tmp2; + + for( k = 0; k < order; k++ ) { + rc = rc_Q15[ k ]; + for( n = 0; n < (k + 1) >> 1; n++ ) { + tmp1 = A_Q24[ n ]; + tmp2 = A_Q24[ k - n - 1 ]; + A_Q24[ n ] = silk_SMLAWB( tmp1, silk_LSHIFT( tmp2, 1 ), rc ); + A_Q24[ k - n - 1 ] = silk_SMLAWB( tmp2, silk_LSHIFT( tmp1, 1 ), rc ); + } + A_Q24[ k ] = -silk_LSHIFT( (opus_int32)rc_Q15[ k ], 9 ); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/k2a_Q16_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/k2a_Q16_FIX.c new file mode 100644 index 000000000..1595aa621 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/k2a_Q16_FIX.c @@ -0,0 +1,54 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_Q16( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */ + const opus_int32 order /* I Prediction order */ +) +{ + opus_int k, n; + opus_int32 rc, tmp1, tmp2; + + for( k = 0; k < order; k++ ) { + rc = rc_Q16[ k ]; + for( n = 0; n < (k + 1) >> 1; n++ ) { + tmp1 = A_Q24[ n ]; + tmp2 = A_Q24[ k - n - 1 ]; + A_Q24[ n ] = silk_SMLAWW( tmp1, tmp2, rc ); + A_Q24[ k - n - 1 ] = silk_SMLAWW( tmp2, tmp1, rc ); + } + A_Q24[ k ] = -silk_LSHIFT( rc, 8 ); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/main_FIX.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/main_FIX.h new file mode 100644 index 000000000..6d2112e51 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/main_FIX.h @@ -0,0 +1,244 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_MAIN_FIX_H +#define SILK_MAIN_FIX_H + +#include "SigProc_FIX.h" +#include "structs_FIX.h" +#include "control.h" +#include "main.h" +#include "PLC.h" +#include "debug.h" +#include "entenc.h" + +#if ((defined(OPUS_ARM_ASM) && defined(FIXED_POINT)) \ + || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#include "fixed/arm/warped_autocorrelation_FIX_arm.h" +#endif + +#ifndef FORCE_CPP_BUILD +#ifdef __cplusplus +extern "C" +{ +#endif +#endif + +#define silk_encoder_state_Fxx silk_encoder_state_FIX +#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FIX +#define silk_encode_frame_Fxx silk_encode_frame_FIX + +#define QC 10 +#define QS 13 + +/*********************/ +/* Encoder Functions */ +/*********************/ + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +); + +/* Encoder main function */ +void silk_encode_do_VAD_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int activity /* I Decision of Opus voice activity detector */ +); + +/* Encoder main function */ +opus_int silk_encode_frame_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +); + +/* Initializes the Silk encoder state */ +opus_int silk_init_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk FIX encoder state */ + int arch /* I Run-time architecture */ +); + +/* Control the Silk encoder */ +opus_int silk_control_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +); + +/**************************/ +/* Noise shaping analysis */ +/**************************/ +/* Compute noise shaping coefficients and initial gain values */ +void silk_noise_shape_analysis_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */ + int arch /* I Run-time architecture */ +); + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FIX_c( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +); + +#if !defined(OVERRIDE_silk_warped_autocorrelation_FIX) +#define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \ + ((void)(arch), silk_warped_autocorrelation_FIX_c(corr, scale, input, warping_Q16, length, order)) +#endif + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/**********************************************/ +/* Prediction Analysis */ +/**********************************************/ +/* Find pitch lags */ +void silk_find_pitch_lags_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int16 res[], /* O residual */ + const opus_int16 x[], /* I Speech signal */ + int arch /* I Run-time architecture */ +); + +/* Find LPC and LTP coefficients */ +void silk_find_pred_coefs_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + const opus_int16 res_pitch[], /* I Residual from pitch analysis */ + const opus_int16 x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* LPC analysis */ +void silk_find_LPC_FIX( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const opus_int16 x[], /* I Input signal */ + const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */ +); + +/* LTP analysis */ +void silk_find_LTP_FIX( + opus_int32 XXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Correlation matrix */ + opus_int32 xXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER ], /* O Correlation vector */ + const opus_int16 r_lpc[], /* I Residual signal after LPC */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +); + +void silk_LTP_analysis_filter_FIX( + opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */ + const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */ + const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */ +); + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FIX( + opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */ + const opus_int16 x[], /* I Input signal */ + opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int LPC_order, /* I LPC order */ + int arch /* I Run-time architecture */ +); + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +opus_int32 silk_residual_energy16_covar_FIX( + const opus_int16 *c, /* I Prediction vector */ + const opus_int32 *wXX, /* I Correlation matrix */ + const opus_int32 *wXx, /* I Correlation vector */ + opus_int32 wxx, /* I Signal energy */ + opus_int D, /* I Dimension */ + opus_int cQ /* I Q value for c vector 0 - 15 */ +); + +/* Processing of gains */ +void silk_process_gains_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/******************/ +/* Linear Algebra */ +/******************/ +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */ + opus_int32 *nrg, /* O Energy of x vector */ + opus_int *rshifts, /* O Right shifts of correlations */ + int arch /* I Run-time architecture */ +); + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int16 *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */ + const opus_int rshifts, /* I Right shifts of correlations */ + int arch /* I Run-time architecture */ +); + +#ifndef FORCE_CPP_BUILD +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* FORCE_CPP_BUILD */ +#endif /* SILK_MAIN_FIX_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h new file mode 100644 index 000000000..3999b5bd0 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h @@ -0,0 +1,336 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + + +/**************************************************************/ +/* Compute noise shaping coefficients and initial gain values */ +/**************************************************************/ +#define OVERRIDE_silk_noise_shape_analysis_FIX + +void silk_noise_shape_analysis_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */ + int arch /* I Run-time architecture */ +) +{ + silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + opus_int k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0; + opus_int32 SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32; + opus_int32 nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7; + opus_int32 delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8; + opus_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 AR1_Q24[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 AR2_Q24[ MAX_SHAPE_LPC_ORDER ]; + VARDECL( opus_int16, x_windowed ); + const opus_int16 *x_ptr, *pitch_res_ptr; + SAVE_STACK; + + /* Point to start of first LPC analysis block */ + x_ptr = x - psEnc->sCmn.la_shape; + + /****************/ + /* GAIN CONTROL */ + /****************/ + SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7; + + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ] + + psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 ); + + /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */ + psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 - + SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 ); + + /* Reduce coding SNR during low speech activity */ + if( psEnc->sCmn.useCBR == 0 ) { + b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8; + b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 ); + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), /* Q11*/ + silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); /* Q12*/ + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 ); + } else { + /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMLAWB( SILK_FIX_CONST( 6.0, 9 ), -SILK_FIX_CONST( 0.4, 18 ), psEnc->sCmn.SNR_dB_Q7 ), + SILK_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 ); + } + + /*************************/ + /* SPARSENESS PROCESSING */ + /*************************/ + /* Set quantizer offset */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Initially set to 0; may be overruled in process_gains(..) */ + psEnc->sCmn.indices.quantOffsetType = 0; + psEncCtrl->sparseness_Q8 = 0; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = silk_LSHIFT( psEnc->sCmn.fs_kHz, 1 ); + energy_variation_Q7 = 0; + log_energy_prev_Q7 = 0; + pitch_res_ptr = pitch_res; + for( k = 0; k < silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; k++ ) { + silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples ); + nrg += silk_RSHIFT( nSamples, scale ); /* Q(-scale)*/ + + log_energy_Q7 = silk_lin2log( nrg ); + if( k > 0 ) { + energy_variation_Q7 += silk_abs( log_energy_Q7 - log_energy_prev_Q7 ); + } + log_energy_prev_Q7 = log_energy_Q7; + pitch_res_ptr += nSamples; + } + + psEncCtrl->sparseness_Q8 = silk_RSHIFT( silk_sigm_Q15( silk_SMULWB( energy_variation_Q7 - + SILK_FIX_CONST( 5.0, 7 ), SILK_FIX_CONST( 0.1, 16 ) ) ), 7 ); + + /* Set quantization offset depending on sparseness measure */ + if( psEncCtrl->sparseness_Q8 > SILK_FIX_CONST( SPARSENESS_THRESHOLD_QNT_OFFSET, 8 ) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + + /* Increase coding SNR for sparse signals */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( SPARSE_SNR_INCR_dB, 15 ), psEncCtrl->sparseness_Q8 - SILK_FIX_CONST( 0.5, 8 ) ); + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength_Q16 = silk_SMULWB( psEncCtrl->predGain_Q16, SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ); + BWExp1_Q16 = BWExp2_Q16 = silk_DIV32_varQ( SILK_FIX_CONST( BANDWIDTH_EXPANSION, 16 ), + silk_SMLAWW( SILK_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 ); + delta_Q16 = silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - silk_SMULBB( 3, psEncCtrl->coding_quality_Q14 ), + SILK_FIX_CONST( LOW_RATE_BANDWIDTH_EXPANSION_DELTA, 16 ) ); + BWExp1_Q16 = silk_SUB32( BWExp1_Q16, delta_Q16 ); + BWExp2_Q16 = silk_ADD32( BWExp2_Q16, delta_Q16 ); + /* BWExp1 will be applied after BWExp2, so make it relative */ + BWExp1_Q16 = silk_DIV32_16( silk_LSHIFT( BWExp1_Q16, 14 ), silk_RSHIFT( BWExp2_Q16, 2 ) ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ + warping_Q16 = silk_SMLAWB( psEnc->sCmn.warping_Q16, (opus_int32)psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( 0.01, 18 ) ); + } else { + warping_Q16 = 0; + } + + /********************************************/ + /* Compute noise shaping AR coefs and gains */ + /********************************************/ + ALLOC( x_windowed, psEnc->sCmn.shapeWinLength, opus_int16 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Apply window: sine slope followed by flat part followed by cosine slope */ + opus_int shift, slope_part, flat_part; + flat_part = psEnc->sCmn.fs_kHz * 3; + slope_part = silk_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 ); + + silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(opus_int16) ); + shift += flat_part; + silk_apply_sine_window( x_windowed + shift, x_ptr + shift, 2, slope_part ); + + /* Update pointer: next LPC analysis block */ + x_ptr += psEnc->sCmn.subfr_length; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Calculate warped auto correlation */ + silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder, arch ); + } else { + /* Calculate regular auto correlation */ + silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1, arch ); + } + + /* Add white noise, as a fraction of energy */ + auto_corr[0] = silk_ADD32( auto_corr[0], silk_max_32( silk_SMULWB( silk_RSHIFT( auto_corr[ 0 ], 4 ), + SILK_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) ); + + /* Calculate the reflection coefficients using schur */ + nrg = silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder ); + silk_assert( nrg >= 0 ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a_Q16( AR2_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder ); + + Qnrg = -scale; /* range: -12...30*/ + silk_assert( Qnrg >= -12 ); + silk_assert( Qnrg <= 30 ); + + /* Make sure that Qnrg is an even number */ + if( Qnrg & 1 ) { + Qnrg -= 1; + nrg >>= 1; + } + + tmp32 = silk_SQRT_APPROX( nrg ); + Qnrg >>= 1; /* range: -6...15*/ + + psEncCtrl->Gains_Q16[ k ] = (silk_LSHIFT32( silk_LIMIT( (tmp32), silk_RSHIFT32( silk_int32_MIN, (16 - Qnrg) ), \ + silk_RSHIFT32( silk_int32_MAX, (16 - Qnrg) ) ), (16 - Qnrg) )); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Adjust gain for warping */ + gain_mult_Q16 = warped_gain( AR2_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder ); + silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); + if ( silk_SMULWW( silk_RSHIFT_ROUND( psEncCtrl->Gains_Q16[ k ], 1 ), gain_mult_Q16 ) >= ( silk_int32_MAX >> 1 ) ) { + psEncCtrl->Gains_Q16[ k ] = silk_int32_MAX; + } else { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + } + } + + /* Bandwidth expansion for synthesis filter shaping */ + silk_bwexpander_32( AR2_Q24, psEnc->sCmn.shapingLPCOrder, BWExp2_Q16 ); + + /* Compute noise shaping filter coefficients */ + silk_memcpy( AR1_Q24, AR2_Q24, psEnc->sCmn.shapingLPCOrder * sizeof( opus_int32 ) ); + + /* Bandwidth expansion for analysis filter shaping */ + silk_assert( BWExp1_Q16 <= SILK_FIX_CONST( 1.0, 16 ) ); + silk_bwexpander_32( AR1_Q24, psEnc->sCmn.shapingLPCOrder, BWExp1_Q16 ); + + /* Ratio of prediction gains, in energy domain */ + pre_nrg_Q30 = silk_LPC_inverse_pred_gain_Q24( AR2_Q24, psEnc->sCmn.shapingLPCOrder, arch ); + nrg = silk_LPC_inverse_pred_gain_Q24( AR1_Q24, psEnc->sCmn.shapingLPCOrder, arch ); + + /*psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ) = 0.3f + 0.7f * pre_nrg / nrg;*/ + pre_nrg_Q30 = silk_LSHIFT32( silk_SMULWB( pre_nrg_Q30, SILK_FIX_CONST( 0.7, 15 ) ), 1 ); + psEncCtrl->GainsPre_Q14[ k ] = ( opus_int ) SILK_FIX_CONST( 0.3, 14 ) + silk_DIV32_varQ( pre_nrg_Q30, nrg, 14 ); + + /* Convert to monic warped prediction coefficients and limit absolute values */ + limit_warped_coefs( AR2_Q24, AR1_Q24, warping_Q16, SILK_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder ); + + /* Convert from Q24 to Q13 and store in int16 */ + for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) { + psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR1_Q24[ i ], 11 ) ); + psEncCtrl->AR2_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR2_Q24[ i ], 11 ) ); + } + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity and put lower limit on gains */ + gain_mult_Q16 = silk_log2lin( -silk_SMLAWB( -SILK_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SILK_FIX_CONST( 0.16, 16 ) ) ); + gain_add_Q16 = silk_log2lin( silk_SMLAWB( SILK_FIX_CONST( 16.0, 7 ), SILK_FIX_CONST( MIN_QGAIN_DB, 7 ), SILK_FIX_CONST( 0.16, 16 ) ) ); + silk_assert( gain_mult_Q16 > 0 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); + psEncCtrl->Gains_Q16[ k ] = silk_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 ); + } + + gain_mult_Q16 = SILK_FIX_CONST( 1.0, 16 ) + silk_RSHIFT_ROUND( silk_MLA( SILK_FIX_CONST( INPUT_TILT, 26 ), + psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ), 10 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->GainsPre_Q14[ k ] = silk_SMULWB( gain_mult_Q16, psEncCtrl->GainsPre_Q14[ k ] ); + } + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength_Q16 = silk_MUL( SILK_FIX_CONST( LOW_FREQ_SHAPING, 4 ), silk_SMLAWB( SILK_FIX_CONST( 1.0, 12 ), + SILK_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13 ), psEnc->sCmn.input_quality_bands_Q15[ 0 ] - SILK_FIX_CONST( 1.0, 15 ) ) ); + strength_Q16 = silk_RSHIFT( silk_MUL( strength_Q16, psEnc->sCmn.speech_activity_Q8 ), 8 ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */ + /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/ + opus_int fs_kHz_inv = silk_DIV32_16( SILK_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + b_Q14 = fs_kHz_inv + silk_DIV32_16( SILK_FIX_CONST( 3.0, 14 ), psEncCtrl->pitchL[ k ] ); + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ k ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - silk_SMULWB( strength_Q16, b_Q14 ), 16 ); + psEncCtrl->LF_shp_Q14[ k ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + } + silk_assert( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SILK_FIX_CONST( 0.5, 24 ) ); /* Guarantees that second argument to SMULWB() is within range of an opus_int16*/ + Tilt_Q16 = - SILK_FIX_CONST( HP_NOISE_COEF, 16 ) - + silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - SILK_FIX_CONST( HP_NOISE_COEF, 16 ), + silk_SMULWB( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->sCmn.speech_activity_Q8 ) ); + } else { + b_Q14 = silk_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); /* 1.3_Q0 = 21299_Q14*/ + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ 0 ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - + silk_SMULWB( strength_Q16, silk_SMULWB( SILK_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 ); + psEncCtrl->LF_shp_Q14[ 0 ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ]; + } + Tilt_Q16 = -SILK_FIX_CONST( HP_NOISE_COEF, 16 ); + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + /* Control boosting of harmonic frequencies */ + HarmBoost_Q16 = silk_SMULWB( silk_SMULWB( SILK_FIX_CONST( 1.0, 17 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 3 ), + psEnc->LTPCorr_Q15 ), SILK_FIX_CONST( LOW_RATE_HARMONIC_BOOST, 16 ) ); + + /* More harmonic boost for noisy input signals */ + HarmBoost_Q16 = silk_SMLAWB( HarmBoost_Q16, + SILK_FIX_CONST( 1.0, 16 ) - silk_LSHIFT( psEncCtrl->input_quality_Q14, 2 ), SILK_FIX_CONST( LOW_INPUT_QUALITY_HARMONIC_BOOST, 16 ) ); + + if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain_Q16 = silk_SMLAWB( SILK_FIX_CONST( HARMONIC_SHAPING, 16 ), + SILK_FIX_CONST( 1.0, 16 ) - silk_SMULWB( SILK_FIX_CONST( 1.0, 18 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ), + psEncCtrl->input_quality_Q14 ), SILK_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain_Q16 = silk_SMULWB( silk_LSHIFT( HarmShapeGain_Q16, 1 ), + silk_SQRT_APPROX( silk_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) ); + } else { + HarmShapeGain_Q16 = 0; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < MAX_NB_SUBFR; k++ ) { + psShapeSt->HarmBoost_smth_Q16 = + silk_SMLAWB( psShapeSt->HarmBoost_smth_Q16, HarmBoost_Q16 - psShapeSt->HarmBoost_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->HarmShapeGain_smth_Q16 = + silk_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->Tilt_smth_Q16 = + silk_SMLAWB( psShapeSt->Tilt_smth_Q16, Tilt_Q16 - psShapeSt->Tilt_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + + psEncCtrl->HarmBoost_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmBoost_smth_Q16, 2 ); + psEncCtrl->HarmShapeGain_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 ); + psEncCtrl->Tilt_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16, 2 ); + } + RESTORE_STACK; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/mips/prefilter_FIX_mipsr1.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/mips/prefilter_FIX_mipsr1.h new file mode 100644 index 000000000..21b256885 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/mips/prefilter_FIX_mipsr1.h @@ -0,0 +1,184 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ +#ifndef __PREFILTER_FIX_MIPSR1_H__ +#define __PREFILTER_FIX_MIPSR1_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" +#include "tuning_parameters.h" + +#define OVERRIDE_silk_warped_LPC_analysis_filter_FIX +void silk_warped_LPC_analysis_filter_FIX( + opus_int32 state[], /* I/O State [order + 1] */ + opus_int32 res_Q2[], /* O Residual signal [length] */ + const opus_int16 coef_Q13[], /* I Coefficients [order] */ + const opus_int16 input[], /* I Input signal [length] */ + const opus_int16 lambda_Q16, /* I Warping factor */ + const opus_int length, /* I Length of input signal */ + const opus_int order, /* I Filter order (even) */ + int arch +) +{ + opus_int n, i; + opus_int32 acc_Q11, acc_Q22, tmp1, tmp2, tmp3, tmp4; + opus_int32 state_cur, state_next; + + (void)arch; + + /* Order must be even */ + /* Length must be even */ + + silk_assert( ( order & 1 ) == 0 ); + silk_assert( ( length & 1 ) == 0 ); + + for( n = 0; n < length; n+=2 ) { + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 ); + state_cur = silk_LSHIFT( input[ n ], 14 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 ); + state_next = tmp2; + acc_Q11 = silk_RSHIFT( order, 1 ); + acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ 0 ] ); + + + /* Output of lowpass section */ + tmp4 = silk_SMLAWB( state_cur, state_next, lambda_Q16 ); + state[ 0 ] = silk_LSHIFT( input[ n+1 ], 14 ); + /* Output of allpass section */ + tmp3 = silk_SMLAWB( state_next, tmp1 - tmp4, lambda_Q16 ); + state[ 1 ] = tmp4; + acc_Q22 = silk_RSHIFT( order, 1 ); + acc_Q22 = silk_SMLAWB( acc_Q22, tmp4, coef_Q13[ 0 ] ); + + /* Loop over allpass sections */ + for( i = 2; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 ); + state_cur = tmp1; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 ); + state_next = tmp2; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] ); + + + /* Output of allpass section */ + tmp4 = silk_SMLAWB( state_cur, state_next - tmp3, lambda_Q16 ); + state[ i ] = tmp3; + acc_Q22 = silk_SMLAWB( acc_Q22, tmp3, coef_Q13[ i - 1 ] ); + /* Output of allpass section */ + tmp3 = silk_SMLAWB( state_next, tmp1 - tmp4, lambda_Q16 ); + state[ i + 1 ] = tmp4; + acc_Q22 = silk_SMLAWB( acc_Q22, tmp4, coef_Q13[ i ] ); + } + acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] ); + res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( acc_Q11, 9 ); + + state[ order ] = tmp3; + acc_Q22 = silk_SMLAWB( acc_Q22, tmp3, coef_Q13[ order - 1 ] ); + res_Q2[ n+1 ] = silk_LSHIFT( (opus_int32)input[ n+1 ], 2 ) - silk_RSHIFT_ROUND( acc_Q22, 9 ); + } +} + + + +/* Prefilter for finding Quantizer input signal */ +#define OVERRIDE_silk_prefilt_FIX +static inline void silk_prefilt_FIX( + silk_prefilter_state_FIX *P, /* I/O state */ + opus_int32 st_res_Q12[], /* I short term residual signal */ + opus_int32 xw_Q3[], /* O prefiltered signal */ + opus_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */ + opus_int Tilt_Q14, /* I Tilt shaping coeficient */ + opus_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients */ + opus_int lag, /* I Lag for harmonic shaping */ + opus_int length /* I Length of signals */ +) +{ + opus_int i, idx, LTP_shp_buf_idx; + opus_int32 n_LTP_Q12, n_Tilt_Q10, n_LF_Q10; + opus_int32 sLF_MA_shp_Q12, sLF_AR_shp_Q12; + opus_int16 *LTP_shp_buf; + + /* To speed up use temp variables instead of using the struct */ + LTP_shp_buf = P->sLTP_shp; + LTP_shp_buf_idx = P->sLTP_shp_buf_idx; + sLF_AR_shp_Q12 = P->sLF_AR_shp_Q12; + sLF_MA_shp_Q12 = P->sLF_MA_shp_Q12; + + if( lag > 0 ) { + for( i = 0; i < length; i++ ) { + /* unrolled loop */ + silk_assert( HARM_SHAPE_FIR_TAPS == 3 ); + idx = lag + LTP_shp_buf_idx; + n_LTP_Q12 = silk_SMULBB( LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + n_LTP_Q12 = silk_SMLABT( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 ) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + n_LTP_Q12 = silk_SMLABB( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + + n_Tilt_Q10 = silk_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 ); + n_LF_Q10 = silk_SMLAWB( silk_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 ); + + sLF_AR_shp_Q12 = silk_SUB32( st_res_Q12[ i ], silk_LSHIFT( n_Tilt_Q10, 2 ) ); + sLF_MA_shp_Q12 = silk_SUB32( sLF_AR_shp_Q12, silk_LSHIFT( n_LF_Q10, 2 ) ); + + LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK; + LTP_shp_buf[ LTP_shp_buf_idx ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) ); + + xw_Q3[i] = silk_RSHIFT_ROUND( silk_SUB32( sLF_MA_shp_Q12, n_LTP_Q12 ), 9 ); + } + } + else + { + for( i = 0; i < length; i++ ) { + + n_LTP_Q12 = 0; + + n_Tilt_Q10 = silk_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 ); + n_LF_Q10 = silk_SMLAWB( silk_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 ); + + sLF_AR_shp_Q12 = silk_SUB32( st_res_Q12[ i ], silk_LSHIFT( n_Tilt_Q10, 2 ) ); + sLF_MA_shp_Q12 = silk_SUB32( sLF_AR_shp_Q12, silk_LSHIFT( n_LF_Q10, 2 ) ); + + LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK; + LTP_shp_buf[ LTP_shp_buf_idx ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) ); + + xw_Q3[i] = silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 9 ); + } + } + + /* Copy temp variable back to state */ + P->sLF_AR_shp_Q12 = sLF_AR_shp_Q12; + P->sLF_MA_shp_Q12 = sLF_MA_shp_Q12; + P->sLTP_shp_buf_idx = LTP_shp_buf_idx; +} + +#endif /* __PREFILTER_FIX_MIPSR1_H__ */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h new file mode 100644 index 000000000..66eb2ed26 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h @@ -0,0 +1,165 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__ +#define __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +#undef QC +#define QC 10 + +#undef QS +#define QS 14 + +/* Autocorrelations for a warped frequency axis */ +#define OVERRIDE_silk_warped_autocorrelation_FIX_c +void silk_warped_autocorrelation_FIX_c( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + opus_int n, i, lsh; + opus_int32 tmp1_QS=0, tmp2_QS=0, tmp3_QS=0, tmp4_QS=0, tmp5_QS=0, tmp6_QS=0, tmp7_QS=0, tmp8_QS=0, start_1=0, start_2=0, start_3=0; + opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + opus_int64 temp64; + + opus_int32 val; + val = 2 * QS - QC; + + /* Order must be even */ + silk_assert( ( order & 1 ) == 0 ); + silk_assert( 2 * QS - QC >= 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n=n+4 ) { + + tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS ); + start_1 = tmp1_QS; + tmp3_QS = silk_LSHIFT32( (opus_int32)input[ n+1], QS ); + start_2 = tmp3_QS; + tmp5_QS = silk_LSHIFT32( (opus_int32)input[ n+2], QS ); + start_3 = tmp5_QS; + tmp7_QS = silk_LSHIFT32( (opus_int32)input[ n+3], QS ); + + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 ); + corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp1_QS, start_1); + + tmp4_QS = silk_SMLAWB( tmp1_QS, tmp2_QS - tmp3_QS, warping_Q16 ); + corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp3_QS, start_2); + + tmp6_QS = silk_SMLAWB( tmp3_QS, tmp4_QS - tmp5_QS, warping_Q16 ); + corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp5_QS, start_3); + + tmp8_QS = silk_SMLAWB( tmp5_QS, tmp6_QS - tmp7_QS, warping_Q16 ); + state_QS[ i ] = tmp7_QS; + corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp7_QS, state_QS[0]); + + /* Output of allpass section */ + tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 ); + corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp2_QS, start_1); + + tmp3_QS = silk_SMLAWB( tmp2_QS, tmp1_QS - tmp4_QS, warping_Q16 ); + corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp4_QS, start_2); + + tmp5_QS = silk_SMLAWB( tmp4_QS, tmp3_QS - tmp6_QS, warping_Q16 ); + corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp6_QS, start_3); + + tmp7_QS = silk_SMLAWB( tmp6_QS, tmp5_QS - tmp8_QS, warping_Q16 ); + state_QS[ i + 1 ] = tmp8_QS; + corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp8_QS, state_QS[ 0 ]); + + } + state_QS[ order ] = tmp7_QS; + + corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp1_QS, start_1); + corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp3_QS, start_2); + corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp5_QS, start_3); + corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp7_QS, state_QS[ 0 ]); + } + + for(;n< length; n++ ) { + + tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS ); + + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + + /* Output of allpass section */ + tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 ); + state_QS[ i ] = tmp1_QS; + corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp1_QS, state_QS[ 0 ]); + + /* Output of allpass section */ + tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 ); + state_QS[ i + 1 ] = tmp2_QS; + corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp2_QS, state_QS[ 0 ]); + } + state_QS[ order ] = tmp1_QS; + corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp1_QS, state_QS[ 0 ]); + } + + temp64 = corr_QC[ 0 ]; + temp64 = __builtin_mips_shilo(temp64, val); + + lsh = silk_CLZ64( temp64 ) - 35; + lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC ); + *scale = -( QC + lsh ); + silk_assert( *scale >= -30 && *scale <= 12 ); + if( lsh >= 0 ) { + for( i = 0; i < order + 1; i++ ) { + temp64 = corr_QC[ i ]; + //temp64 = __builtin_mips_shilo(temp64, val); + temp64 = (val >= 0) ? (temp64 >> val) : (temp64 << -val); + corr[ i ] = (opus_int32)silk_CHECK_FIT32( __builtin_mips_shilo( temp64, -lsh ) ); + } + } else { + for( i = 0; i < order + 1; i++ ) { + temp64 = corr_QC[ i ]; + //temp64 = __builtin_mips_shilo(temp64, val); + temp64 = (val >= 0) ? (temp64 >> val) : (temp64 << -val); + corr[ i ] = (opus_int32)silk_CHECK_FIT32( __builtin_mips_shilo( temp64, -lsh ) ); + } + } + + corr_QC[ 0 ] = __builtin_mips_shilo(corr_QC[ 0 ], val); + + silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/ +} +#endif /* __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__ */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/noise_shape_analysis_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/noise_shape_analysis_FIX.c new file mode 100644 index 000000000..85fea0bf0 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/noise_shape_analysis_FIX.c @@ -0,0 +1,407 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" +#include "tuning_parameters.h" + +/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */ +/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */ +/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */ +/* coefficient in an array of coefficients, for monic filters. */ +static OPUS_INLINE opus_int32 warped_gain( /* gain in Q16*/ + const opus_int32 *coefs_Q24, + opus_int lambda_Q16, + opus_int order +) { + opus_int i; + opus_int32 gain_Q24; + + lambda_Q16 = -lambda_Q16; + gain_Q24 = coefs_Q24[ order - 1 ]; + for( i = order - 2; i >= 0; i-- ) { + gain_Q24 = silk_SMLAWB( coefs_Q24[ i ], gain_Q24, lambda_Q16 ); + } + gain_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), gain_Q24, -lambda_Q16 ); + return silk_INVERSE32_varQ( gain_Q24, 40 ); +} + +/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */ +/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */ +static OPUS_INLINE void limit_warped_coefs( + opus_int32 *coefs_Q24, + opus_int lambda_Q16, + opus_int32 limit_Q24, + opus_int order +) { + opus_int i, iter, ind = 0; + opus_int32 tmp, maxabs_Q24, chirp_Q16, gain_Q16; + opus_int32 nom_Q16, den_Q24; + opus_int32 limit_Q20, maxabs_Q20; + + /* Convert to monic coefficients */ + lambda_Q16 = -lambda_Q16; + for( i = order - 1; i > 0; i-- ) { + coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 ); + } + lambda_Q16 = -lambda_Q16; + nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_Q24[ 0 ], lambda_Q16 ); + gain_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + for( i = 0; i < order; i++ ) { + coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] ); + } + limit_Q20 = silk_RSHIFT(limit_Q24, 4); + for( iter = 0; iter < 10; iter++ ) { + /* Find maximum absolute value */ + maxabs_Q24 = -1; + for( i = 0; i < order; i++ ) { + tmp = silk_abs_int32( coefs_Q24[ i ] ); + if( tmp > maxabs_Q24 ) { + maxabs_Q24 = tmp; + ind = i; + } + } + /* Use Q20 to avoid any overflow when multiplying by (ind + 1) later. */ + maxabs_Q20 = silk_RSHIFT(maxabs_Q24, 4); + if( maxabs_Q20 <= limit_Q20 ) { + /* Coefficients are within range - done */ + return; + } + + /* Convert back to true warped coefficients */ + for( i = 1; i < order; i++ ) { + coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 ); + } + gain_Q16 = silk_INVERSE32_varQ( gain_Q16, 32 ); + for( i = 0; i < order; i++ ) { + coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] ); + } + + /* Apply bandwidth expansion */ + chirp_Q16 = SILK_FIX_CONST( 0.99, 16 ) - silk_DIV32_varQ( + silk_SMULWB( maxabs_Q20 - limit_Q20, silk_SMLABB( SILK_FIX_CONST( 0.8, 10 ), SILK_FIX_CONST( 0.1, 10 ), iter ) ), + silk_MUL( maxabs_Q20, ind + 1 ), 22 ); + silk_bwexpander_32( coefs_Q24, order, chirp_Q16 ); + + /* Convert to monic warped coefficients */ + lambda_Q16 = -lambda_Q16; + for( i = order - 1; i > 0; i-- ) { + coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 ); + } + lambda_Q16 = -lambda_Q16; + nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_Q24[ 0 ], lambda_Q16 ); + gain_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + for( i = 0; i < order; i++ ) { + coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] ); + } + } + silk_assert( 0 ); +} + +/* Disable MIPS version until it's updated. */ +#if 0 && defined(MIPSr1_ASM) +#include "mips/noise_shape_analysis_FIX_mipsr1.h" +#endif + +/**************************************************************/ +/* Compute noise shaping coefficients and initial gain values */ +/**************************************************************/ +#ifndef OVERRIDE_silk_noise_shape_analysis_FIX +void silk_noise_shape_analysis_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */ + int arch /* I Run-time architecture */ +) +{ + silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + opus_int k, i, nSamples, nSegs, Qnrg, b_Q14, warping_Q16, scale = 0; + opus_int32 SNR_adj_dB_Q7, HarmShapeGain_Q16, Tilt_Q16, tmp32; + opus_int32 nrg, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7; + opus_int32 BWExp_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8; + opus_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 AR_Q24[ MAX_SHAPE_LPC_ORDER ]; + VARDECL( opus_int16, x_windowed ); + const opus_int16 *x_ptr, *pitch_res_ptr; + SAVE_STACK; + + /* Point to start of first LPC analysis block */ + x_ptr = x - psEnc->sCmn.la_shape; + + /****************/ + /* GAIN CONTROL */ + /****************/ + SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7; + + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ] + + psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 ); + + /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */ + psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 - + SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 ); + + /* Reduce coding SNR during low speech activity */ + if( psEnc->sCmn.useCBR == 0 ) { + b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8; + b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 ); + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), /* Q11*/ + silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); /* Q12*/ + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 ); + } else { + /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMLAWB( SILK_FIX_CONST( 6.0, 9 ), -SILK_FIX_CONST( 0.4, 18 ), psEnc->sCmn.SNR_dB_Q7 ), + SILK_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 ); + } + + /*************************/ + /* SPARSENESS PROCESSING */ + /*************************/ + /* Set quantizer offset */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Initially set to 0; may be overruled in process_gains(..) */ + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = silk_LSHIFT( psEnc->sCmn.fs_kHz, 1 ); + energy_variation_Q7 = 0; + log_energy_prev_Q7 = 0; + pitch_res_ptr = pitch_res; + nSegs = silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; + for( k = 0; k < nSegs; k++ ) { + silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples ); + nrg += silk_RSHIFT( nSamples, scale ); /* Q(-scale)*/ + + log_energy_Q7 = silk_lin2log( nrg ); + if( k > 0 ) { + energy_variation_Q7 += silk_abs( log_energy_Q7 - log_energy_prev_Q7 ); + } + log_energy_prev_Q7 = log_energy_Q7; + pitch_res_ptr += nSamples; + } + + /* Set quantization offset depending on sparseness measure */ + if( energy_variation_Q7 > SILK_FIX_CONST( ENERGY_VARIATION_THRESHOLD_QNT_OFFSET, 7 ) * (nSegs-1) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength_Q16 = silk_SMULWB( psEncCtrl->predGain_Q16, SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ); + BWExp_Q16 = silk_DIV32_varQ( SILK_FIX_CONST( BANDWIDTH_EXPANSION, 16 ), + silk_SMLAWW( SILK_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ + warping_Q16 = silk_SMLAWB( psEnc->sCmn.warping_Q16, (opus_int32)psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( 0.01, 18 ) ); + } else { + warping_Q16 = 0; + } + + /********************************************/ + /* Compute noise shaping AR coefs and gains */ + /********************************************/ + ALLOC( x_windowed, psEnc->sCmn.shapeWinLength, opus_int16 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Apply window: sine slope followed by flat part followed by cosine slope */ + opus_int shift, slope_part, flat_part; + flat_part = psEnc->sCmn.fs_kHz * 3; + slope_part = silk_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 ); + + silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(opus_int16) ); + shift += flat_part; + silk_apply_sine_window( x_windowed + shift, x_ptr + shift, 2, slope_part ); + + /* Update pointer: next LPC analysis block */ + x_ptr += psEnc->sCmn.subfr_length; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Calculate warped auto correlation */ + silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder, arch ); + } else { + /* Calculate regular auto correlation */ + silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1, arch ); + } + + /* Add white noise, as a fraction of energy */ + auto_corr[0] = silk_ADD32( auto_corr[0], silk_max_32( silk_SMULWB( silk_RSHIFT( auto_corr[ 0 ], 4 ), + SILK_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) ); + + /* Calculate the reflection coefficients using schur */ + nrg = silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder ); + silk_assert( nrg >= 0 ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a_Q16( AR_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder ); + + Qnrg = -scale; /* range: -12...30*/ + silk_assert( Qnrg >= -12 ); + silk_assert( Qnrg <= 30 ); + + /* Make sure that Qnrg is an even number */ + if( Qnrg & 1 ) { + Qnrg -= 1; + nrg >>= 1; + } + + tmp32 = silk_SQRT_APPROX( nrg ); + Qnrg >>= 1; /* range: -6...15*/ + + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( tmp32, 16 - Qnrg ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Adjust gain for warping */ + gain_mult_Q16 = warped_gain( AR_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder ); + silk_assert( psEncCtrl->Gains_Q16[ k ] > 0 ); + if( psEncCtrl->Gains_Q16[ k ] < SILK_FIX_CONST( 0.25, 16 ) ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + } else { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( silk_RSHIFT_ROUND( psEncCtrl->Gains_Q16[ k ], 1 ), gain_mult_Q16 ); + if ( psEncCtrl->Gains_Q16[ k ] >= ( silk_int32_MAX >> 1 ) ) { + psEncCtrl->Gains_Q16[ k ] = silk_int32_MAX; + } else { + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT32( psEncCtrl->Gains_Q16[ k ], 1 ); + } + } + silk_assert( psEncCtrl->Gains_Q16[ k ] > 0 ); + } + + /* Bandwidth expansion */ + silk_bwexpander_32( AR_Q24, psEnc->sCmn.shapingLPCOrder, BWExp_Q16 ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Convert to monic warped prediction coefficients and limit absolute values */ + limit_warped_coefs( AR_Q24, warping_Q16, SILK_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder ); + + /* Convert from Q24 to Q13 and store in int16 */ + for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) { + psEncCtrl->AR_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR_Q24[ i ], 11 ) ); + } + } else { + silk_LPC_fit( &psEncCtrl->AR_Q13[ k * MAX_SHAPE_LPC_ORDER ], AR_Q24, 13, 24, psEnc->sCmn.shapingLPCOrder ); + } + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity and put lower limit on gains */ + gain_mult_Q16 = silk_log2lin( -silk_SMLAWB( -SILK_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SILK_FIX_CONST( 0.16, 16 ) ) ); + gain_add_Q16 = silk_log2lin( silk_SMLAWB( SILK_FIX_CONST( 16.0, 7 ), SILK_FIX_CONST( MIN_QGAIN_DB, 7 ), SILK_FIX_CONST( 0.16, 16 ) ) ); + silk_assert( gain_mult_Q16 > 0 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); + psEncCtrl->Gains_Q16[ k ] = silk_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 ); + } + + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength_Q16 = silk_MUL( SILK_FIX_CONST( LOW_FREQ_SHAPING, 4 ), silk_SMLAWB( SILK_FIX_CONST( 1.0, 12 ), + SILK_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13 ), psEnc->sCmn.input_quality_bands_Q15[ 0 ] - SILK_FIX_CONST( 1.0, 15 ) ) ); + strength_Q16 = silk_RSHIFT( silk_MUL( strength_Q16, psEnc->sCmn.speech_activity_Q8 ), 8 ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */ + /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/ + opus_int fs_kHz_inv = silk_DIV32_16( SILK_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + b_Q14 = fs_kHz_inv + silk_DIV32_16( SILK_FIX_CONST( 3.0, 14 ), psEncCtrl->pitchL[ k ] ); + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ k ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - silk_SMULWB( strength_Q16, b_Q14 ), 16 ); + psEncCtrl->LF_shp_Q14[ k ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + } + silk_assert( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SILK_FIX_CONST( 0.5, 24 ) ); /* Guarantees that second argument to SMULWB() is within range of an opus_int16*/ + Tilt_Q16 = - SILK_FIX_CONST( HP_NOISE_COEF, 16 ) - + silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - SILK_FIX_CONST( HP_NOISE_COEF, 16 ), + silk_SMULWB( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->sCmn.speech_activity_Q8 ) ); + } else { + b_Q14 = silk_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); /* 1.3_Q0 = 21299_Q14*/ + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ 0 ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - + silk_SMULWB( strength_Q16, silk_SMULWB( SILK_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 ); + psEncCtrl->LF_shp_Q14[ 0 ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ]; + } + Tilt_Q16 = -SILK_FIX_CONST( HP_NOISE_COEF, 16 ); + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain_Q16 = silk_SMLAWB( SILK_FIX_CONST( HARMONIC_SHAPING, 16 ), + SILK_FIX_CONST( 1.0, 16 ) - silk_SMULWB( SILK_FIX_CONST( 1.0, 18 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ), + psEncCtrl->input_quality_Q14 ), SILK_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain_Q16 = silk_SMULWB( silk_LSHIFT( HarmShapeGain_Q16, 1 ), + silk_SQRT_APPROX( silk_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) ); + } else { + HarmShapeGain_Q16 = 0; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < MAX_NB_SUBFR; k++ ) { + psShapeSt->HarmShapeGain_smth_Q16 = + silk_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->Tilt_smth_Q16 = + silk_SMLAWB( psShapeSt->Tilt_smth_Q16, Tilt_Q16 - psShapeSt->Tilt_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + + psEncCtrl->HarmShapeGain_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 ); + psEncCtrl->Tilt_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16, 2 ); + } + RESTORE_STACK; +} +#endif /* OVERRIDE_silk_noise_shape_analysis_FIX */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/pitch_analysis_core_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/pitch_analysis_core_FIX.c new file mode 100644 index 000000000..14729046d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/pitch_analysis_core_FIX.c @@ -0,0 +1,721 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/*********************************************************** +* Pitch analyser function +********************************************************** */ +#include "SigProc_FIX.h" +#include "pitch_est_defines.h" +#include "stack_alloc.h" +#include "debug.h" +#include "pitch.h" + +#define SCRATCH_SIZE 22 +#define SF_LENGTH_4KHZ ( PE_SUBFR_LENGTH_MS * 4 ) +#define SF_LENGTH_8KHZ ( PE_SUBFR_LENGTH_MS * 8 ) +#define MIN_LAG_4KHZ ( PE_MIN_LAG_MS * 4 ) +#define MIN_LAG_8KHZ ( PE_MIN_LAG_MS * 8 ) +#define MAX_LAG_4KHZ ( PE_MAX_LAG_MS * 4 ) +#define MAX_LAG_8KHZ ( PE_MAX_LAG_MS * 8 - 1 ) +#define CSTRIDE_4KHZ ( MAX_LAG_4KHZ + 1 - MIN_LAG_4KHZ ) +#define CSTRIDE_8KHZ ( MAX_LAG_8KHZ + 3 - ( MIN_LAG_8KHZ - 2 ) ) +#define D_COMP_MIN ( MIN_LAG_8KHZ - 3 ) +#define D_COMP_MAX ( MAX_LAG_8KHZ + 4 ) +#define D_COMP_STRIDE ( D_COMP_MAX - D_COMP_MIN ) + +typedef opus_int32 silk_pe_stage3_vals[ PE_NB_STAGE3_LAGS ]; + +/************************************************************/ +/* Internally used functions */ +/************************************************************/ +static void silk_P_Ana_calc_corr_st3( + silk_pe_stage3_vals cross_corr_st3[], /* O 3 DIM correlation array */ + const opus_int16 frame[], /* I vector to correlate */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of a 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +); + +static void silk_P_Ana_calc_energy_st3( + silk_pe_stage3_vals energies_st3[], /* O 3 DIM energy array */ + const opus_int16 frame[], /* I vector to calc energy in */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of one 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +); + +/*************************************************************/ +/* FIXED POINT CORE PITCH ANALYSIS FUNCTION */ +/*************************************************************/ +opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const opus_int16 *frame_unscaled, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O 4 pitch lag values */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */ + const opus_int search_thres2_Q13, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I Sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr, /* I number of 5 ms subframes */ + int arch /* I Run-time architecture */ +) +{ + VARDECL( opus_int16, frame_8kHz_buf ); + VARDECL( opus_int16, frame_4kHz ); + VARDECL( opus_int16, frame_scaled ); + opus_int32 filt_state[ 6 ]; + const opus_int16 *frame, *frame_8kHz; + opus_int i, k, d, j; + VARDECL( opus_int16, C ); + VARDECL( opus_int32, xcorr32 ); + const opus_int16 *target_ptr, *basis_ptr; + opus_int32 cross_corr, normalizer, energy, energy_basis, energy_target; + opus_int d_srch[ PE_D_SRCH_LENGTH ], Cmax, length_d_srch, length_d_comp, shift; + VARDECL( opus_int16, d_comp ); + opus_int32 sum, threshold, lag_counter; + opus_int CBimax, CBimax_new, CBimax_old, lag, start_lag, end_lag, lag_new; + opus_int32 CC[ PE_NB_CBKS_STAGE2_EXT ], CCmax, CCmax_b, CCmax_new_b, CCmax_new; + VARDECL( silk_pe_stage3_vals, energies_st3 ); + VARDECL( silk_pe_stage3_vals, cross_corr_st3 ); + opus_int frame_length, frame_length_8kHz, frame_length_4kHz; + opus_int sf_length; + opus_int min_lag; + opus_int max_lag; + opus_int32 contour_bias_Q15, diff; + opus_int nb_cbk_search, cbk_size; + opus_int32 delta_lag_log2_sqr_Q7, lag_log2_Q7, prevLag_log2_Q7, prev_lag_bias_Q13; + const opus_int8 *Lag_CB_ptr; + SAVE_STACK; + + /* Check for valid sampling frequency */ + celt_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 ); + + /* Check for valid complexity setting */ + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + silk_assert( search_thres1_Q16 >= 0 && search_thres1_Q16 <= (1<<16) ); + silk_assert( search_thres2_Q13 >= 0 && search_thres2_Q13 <= (1<<13) ); + + /* Set up frame lengths max / min lag for the sampling frequency */ + frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz; + frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4; + frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8; + sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz; + min_lag = PE_MIN_LAG_MS * Fs_kHz; + max_lag = PE_MAX_LAG_MS * Fs_kHz - 1; + + /* Downscale input if necessary */ + silk_sum_sqr_shift( &energy, &shift, frame_unscaled, frame_length ); + shift += 3 - silk_CLZ32( energy ); /* at least two bits headroom */ + ALLOC( frame_scaled, frame_length, opus_int16 ); + if( shift > 0 ) { + shift = silk_RSHIFT( shift + 1, 1 ); + for( i = 0; i < frame_length; i++ ) { + frame_scaled[ i ] = silk_RSHIFT( frame_unscaled[ i ], shift ); + } + frame = frame_scaled; + } else { + frame = frame_unscaled; + } + + ALLOC( frame_8kHz_buf, ( Fs_kHz == 8 ) ? 1 : frame_length_8kHz, opus_int16 ); + /* Resample from input sampled at Fs_kHz to 8 kHz */ + if( Fs_kHz == 16 ) { + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) ); + silk_resampler_down2( filt_state, frame_8kHz_buf, frame, frame_length ); + frame_8kHz = frame_8kHz_buf; + } else if( Fs_kHz == 12 ) { + silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) ); + silk_resampler_down2_3( filt_state, frame_8kHz_buf, frame, frame_length ); + frame_8kHz = frame_8kHz_buf; + } else { + celt_assert( Fs_kHz == 8 ); + frame_8kHz = frame; + } + + /* Decimate again to 4 kHz */ + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );/* Set state to zero */ + ALLOC( frame_4kHz, frame_length_4kHz, opus_int16 ); + silk_resampler_down2( filt_state, frame_4kHz, frame_8kHz, frame_length_8kHz ); + + /* Low-pass filter */ + for( i = frame_length_4kHz - 1; i > 0; i-- ) { + frame_4kHz[ i ] = silk_ADD_SAT16( frame_4kHz[ i ], frame_4kHz[ i - 1 ] ); + } + + + /****************************************************************************** + * FIRST STAGE, operating in 4 khz + ******************************************************************************/ + ALLOC( C, nb_subfr * CSTRIDE_8KHZ, opus_int16 ); + ALLOC( xcorr32, MAX_LAG_4KHZ-MIN_LAG_4KHZ+1, opus_int32 ); + silk_memset( C, 0, (nb_subfr >> 1) * CSTRIDE_4KHZ * sizeof( opus_int16 ) ); + target_ptr = &frame_4kHz[ silk_LSHIFT( SF_LENGTH_4KHZ, 2 ) ]; + for( k = 0; k < nb_subfr >> 1; k++ ) { + /* Check that we are within range of the array */ + celt_assert( target_ptr >= frame_4kHz ); + celt_assert( target_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz ); + + basis_ptr = target_ptr - MIN_LAG_4KHZ; + + /* Check that we are within range of the array */ + celt_assert( basis_ptr >= frame_4kHz ); + celt_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz ); + + celt_pitch_xcorr( target_ptr, target_ptr - MAX_LAG_4KHZ, xcorr32, SF_LENGTH_8KHZ, MAX_LAG_4KHZ - MIN_LAG_4KHZ + 1, arch ); + + /* Calculate first vector products before loop */ + cross_corr = xcorr32[ MAX_LAG_4KHZ - MIN_LAG_4KHZ ]; + normalizer = silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ, arch ); + normalizer = silk_ADD32( normalizer, silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ, arch ) ); + normalizer = silk_ADD32( normalizer, silk_SMULBB( SF_LENGTH_8KHZ, 4000 ) ); + + matrix_ptr( C, k, 0, CSTRIDE_4KHZ ) = + (opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 ); /* Q13 */ + + /* From now on normalizer is computed recursively */ + for( d = MIN_LAG_4KHZ + 1; d <= MAX_LAG_4KHZ; d++ ) { + basis_ptr--; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_4kHz ); + silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz ); + + cross_corr = xcorr32[ MAX_LAG_4KHZ - d ]; + + /* Add contribution of new sample and remove contribution from oldest sample */ + normalizer = silk_ADD32( normalizer, + silk_SMULBB( basis_ptr[ 0 ], basis_ptr[ 0 ] ) - + silk_SMULBB( basis_ptr[ SF_LENGTH_8KHZ ], basis_ptr[ SF_LENGTH_8KHZ ] ) ); + + matrix_ptr( C, k, d - MIN_LAG_4KHZ, CSTRIDE_4KHZ) = + (opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 ); /* Q13 */ + } + /* Update target pointer */ + target_ptr += SF_LENGTH_8KHZ; + } + + /* Combine two subframes into single correlation measure and apply short-lag bias */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) { + sum = (opus_int32)matrix_ptr( C, 0, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ ) + + (opus_int32)matrix_ptr( C, 1, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ ); /* Q14 */ + sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q14 */ + C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum; /* Q14 */ + } + } else { + /* Only short-lag bias */ + for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) { + sum = silk_LSHIFT( (opus_int32)C[ i - MIN_LAG_4KHZ ], 1 ); /* Q14 */ + sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q14 */ + C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum; /* Q14 */ + } + } + + /* Sort */ + length_d_srch = silk_ADD_LSHIFT32( 4, complexity, 1 ); + celt_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH ); + silk_insertion_sort_decreasing_int16( C, d_srch, CSTRIDE_4KHZ, + length_d_srch ); + + /* Escape if correlation is very low already here */ + Cmax = (opus_int)C[ 0 ]; /* Q14 */ + if( Cmax < SILK_FIX_CONST( 0.2, 14 ) ) { + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) ); + *LTPCorr_Q15 = 0; + *lagIndex = 0; + *contourIndex = 0; + RESTORE_STACK; + return 1; + } + + threshold = silk_SMULWB( search_thres1_Q16, Cmax ); + for( i = 0; i < length_d_srch; i++ ) { + /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */ + if( C[ i ] > threshold ) { + d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + MIN_LAG_4KHZ, 1 ); + } else { + length_d_srch = i; + break; + } + } + celt_assert( length_d_srch > 0 ); + + ALLOC( d_comp, D_COMP_STRIDE, opus_int16 ); + for( i = D_COMP_MIN; i < D_COMP_MAX; i++ ) { + d_comp[ i - D_COMP_MIN ] = 0; + } + for( i = 0; i < length_d_srch; i++ ) { + d_comp[ d_srch[ i ] - D_COMP_MIN ] = 1; + } + + /* Convolution */ + for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) { + d_comp[ i - D_COMP_MIN ] += + d_comp[ i - 1 - D_COMP_MIN ] + d_comp[ i - 2 - D_COMP_MIN ]; + } + + length_d_srch = 0; + for( i = MIN_LAG_8KHZ; i < MAX_LAG_8KHZ + 1; i++ ) { + if( d_comp[ i + 1 - D_COMP_MIN ] > 0 ) { + d_srch[ length_d_srch ] = i; + length_d_srch++; + } + } + + /* Convolution */ + for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) { + d_comp[ i - D_COMP_MIN ] += d_comp[ i - 1 - D_COMP_MIN ] + + d_comp[ i - 2 - D_COMP_MIN ] + d_comp[ i - 3 - D_COMP_MIN ]; + } + + length_d_comp = 0; + for( i = MIN_LAG_8KHZ; i < D_COMP_MAX; i++ ) { + if( d_comp[ i - D_COMP_MIN ] > 0 ) { + d_comp[ length_d_comp ] = i - 2; + length_d_comp++; + } + } + + /********************************************************************************** + ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation + *************************************************************************************/ + + /********************************************************************************* + * Find energy of each subframe projected onto its history, for a range of delays + *********************************************************************************/ + silk_memset( C, 0, nb_subfr * CSTRIDE_8KHZ * sizeof( opus_int16 ) ); + + target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ]; + for( k = 0; k < nb_subfr; k++ ) { + + /* Check that we are within range of the array */ + celt_assert( target_ptr >= frame_8kHz ); + celt_assert( target_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz ); + + energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ, arch ), 1 ); + for( j = 0; j < length_d_comp; j++ ) { + d = d_comp[ j ]; + basis_ptr = target_ptr - d; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_8kHz ); + silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz ); + + cross_corr = silk_inner_prod_aligned( target_ptr, basis_ptr, SF_LENGTH_8KHZ, arch ); + if( cross_corr > 0 ) { + energy_basis = silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ, arch ); + matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) = + (opus_int16)silk_DIV32_varQ( cross_corr, + silk_ADD32( energy_target, + energy_basis ), + 13 + 1 ); /* Q13 */ + } else { + matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) = 0; + } + } + target_ptr += SF_LENGTH_8KHZ; + } + + /* search over lag range and lags codebook */ + /* scale factor for lag codebook, as a function of center lag */ + + CCmax = silk_int32_MIN; + CCmax_b = silk_int32_MIN; + + CBimax = 0; /* To avoid returning undefined lag values */ + lag = -1; /* To check if lag with strong enough correlation has been found */ + + if( prevLag > 0 ) { + if( Fs_kHz == 12 ) { + prevLag = silk_DIV32_16( silk_LSHIFT( prevLag, 1 ), 3 ); + } else if( Fs_kHz == 16 ) { + prevLag = silk_RSHIFT( prevLag, 1 ); + } + prevLag_log2_Q7 = silk_lin2log( (opus_int32)prevLag ); + } else { + prevLag_log2_Q7 = 0; + } + silk_assert( search_thres2_Q13 == silk_SAT16( search_thres2_Q13 ) ); + /* Set up stage 2 codebook based on number of subframes */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + cbk_size = PE_NB_CBKS_STAGE2_EXT; + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) { + /* If input is 8 khz use a larger codebook here because it is last stage */ + nb_cbk_search = PE_NB_CBKS_STAGE2_EXT; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE2; + } + } else { + cbk_size = PE_NB_CBKS_STAGE2_10MS; + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE2_10MS; + } + + for( k = 0; k < length_d_srch; k++ ) { + d = d_srch[ k ]; + for( j = 0; j < nb_cbk_search; j++ ) { + CC[ j ] = 0; + for( i = 0; i < nb_subfr; i++ ) { + opus_int d_subfr; + /* Try all codebooks */ + d_subfr = d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size ); + CC[ j ] = CC[ j ] + + (opus_int32)matrix_ptr( C, i, + d_subfr - ( MIN_LAG_8KHZ - 2 ), + CSTRIDE_8KHZ ); + } + } + /* Find best codebook */ + CCmax_new = silk_int32_MIN; + CBimax_new = 0; + for( i = 0; i < nb_cbk_search; i++ ) { + if( CC[ i ] > CCmax_new ) { + CCmax_new = CC[ i ]; + CBimax_new = i; + } + } + + /* Bias towards shorter lags */ + lag_log2_Q7 = silk_lin2log( d ); /* Q7 */ + silk_assert( lag_log2_Q7 == silk_SAT16( lag_log2_Q7 ) ); + silk_assert( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) ) ); + CCmax_new_b = CCmax_new - silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ), lag_log2_Q7 ), 7 ); /* Q13 */ + + /* Bias towards previous lag */ + silk_assert( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) ) ); + if( prevLag > 0 ) { + delta_lag_log2_sqr_Q7 = lag_log2_Q7 - prevLag_log2_Q7; + silk_assert( delta_lag_log2_sqr_Q7 == silk_SAT16( delta_lag_log2_sqr_Q7 ) ); + delta_lag_log2_sqr_Q7 = silk_RSHIFT( silk_SMULBB( delta_lag_log2_sqr_Q7, delta_lag_log2_sqr_Q7 ), 7 ); + prev_lag_bias_Q13 = silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ), *LTPCorr_Q15 ), 15 ); /* Q13 */ + prev_lag_bias_Q13 = silk_DIV32( silk_MUL( prev_lag_bias_Q13, delta_lag_log2_sqr_Q7 ), delta_lag_log2_sqr_Q7 + SILK_FIX_CONST( 0.5, 7 ) ); + CCmax_new_b -= prev_lag_bias_Q13; /* Q13 */ + } + + if( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */ + CCmax_new > silk_SMULBB( nb_subfr, search_thres2_Q13 ) && /* Correlation needs to be high enough to be voiced */ + silk_CB_lags_stage2[ 0 ][ CBimax_new ] <= MIN_LAG_8KHZ /* Lag must be in range */ + ) { + CCmax_b = CCmax_new_b; + CCmax = CCmax_new; + lag = d; + CBimax = CBimax_new; + } + } + + if( lag == -1 ) { + /* No suitable candidate found */ + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) ); + *LTPCorr_Q15 = 0; + *lagIndex = 0; + *contourIndex = 0; + RESTORE_STACK; + return 1; + } + + /* Output normalized correlation */ + *LTPCorr_Q15 = (opus_int)silk_LSHIFT( silk_DIV32_16( CCmax, nb_subfr ), 2 ); + silk_assert( *LTPCorr_Q15 >= 0 ); + + if( Fs_kHz > 8 ) { + /* Search in original signal */ + + CBimax_old = CBimax; + /* Compensate for decimation */ + silk_assert( lag == silk_SAT16( lag ) ); + if( Fs_kHz == 12 ) { + lag = silk_RSHIFT( silk_SMULBB( lag, 3 ), 1 ); + } else if( Fs_kHz == 16 ) { + lag = silk_LSHIFT( lag, 1 ); + } else { + lag = silk_SMULBB( lag, 3 ); + } + + lag = silk_LIMIT_int( lag, min_lag, max_lag ); + start_lag = silk_max_int( lag - 2, min_lag ); + end_lag = silk_min_int( lag + 2, max_lag ); + lag_new = lag; /* to avoid undefined lag */ + CBimax = 0; /* to avoid undefined lag */ + + CCmax = silk_int32_MIN; + /* pitch lags according to second stage */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + 2 * silk_CB_lags_stage2[ k ][ CBimax_old ]; + } + + /* Set up codebook parameters according to complexity setting and frame length */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + } + + /* Calculate the correlations and energies needed in stage 3 */ + ALLOC( energies_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals ); + ALLOC( cross_corr_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals ); + silk_P_Ana_calc_corr_st3( cross_corr_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch ); + silk_P_Ana_calc_energy_st3( energies_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch ); + + lag_counter = 0; + silk_assert( lag == silk_SAT16( lag ) ); + contour_bias_Q15 = silk_DIV32_16( SILK_FIX_CONST( PE_FLATCONTOUR_BIAS, 15 ), lag ); + + target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * Fs_kHz ]; + energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, nb_subfr * sf_length, arch ), 1 ); + for( d = start_lag; d <= end_lag; d++ ) { + for( j = 0; j < nb_cbk_search; j++ ) { + cross_corr = 0; + energy = energy_target; + for( k = 0; k < nb_subfr; k++ ) { + cross_corr = silk_ADD32( cross_corr, + matrix_ptr( cross_corr_st3, k, j, + nb_cbk_search )[ lag_counter ] ); + energy = silk_ADD32( energy, + matrix_ptr( energies_st3, k, j, + nb_cbk_search )[ lag_counter ] ); + silk_assert( energy >= 0 ); + } + if( cross_corr > 0 ) { + CCmax_new = silk_DIV32_varQ( cross_corr, energy, 13 + 1 ); /* Q13 */ + /* Reduce depending on flatness of contour */ + diff = silk_int16_MAX - silk_MUL( contour_bias_Q15, j ); /* Q15 */ + silk_assert( diff == silk_SAT16( diff ) ); + CCmax_new = silk_SMULWB( CCmax_new, diff ); /* Q14 */ + } else { + CCmax_new = 0; + } + + if( CCmax_new > CCmax && ( d + silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag ) { + CCmax = CCmax_new; + lag_new = d; + CBimax = j; + } + } + lag_counter++; + } + + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz ); + } + *lagIndex = (opus_int16)( lag_new - min_lag); + *contourIndex = (opus_int8)CBimax; + } else { /* Fs_kHz == 8 */ + /* Save Lags */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], MIN_LAG_8KHZ, PE_MAX_LAG_MS * 8 ); + } + *lagIndex = (opus_int16)( lag - MIN_LAG_8KHZ ); + *contourIndex = (opus_int8)CBimax; + } + celt_assert( *lagIndex >= 0 ); + /* return as voiced */ + RESTORE_STACK; + return 0; +} + +/*********************************************************************** + * Calculates the correlations used in stage 3 search. In order to cover + * the whole lag codebook for all the searched offset lags (lag +- 2), + * the following correlations are needed in each sub frame: + * + * sf1: lag range [-8,...,7] total 16 correlations + * sf2: lag range [-4,...,4] total 9 correlations + * sf3: lag range [-3,....4] total 8 correltions + * sf4: lag range [-6,....8] total 15 correlations + * + * In total 48 correlations. The direct implementation computed in worst + * case 4*12*5 = 240 correlations, but more likely around 120. + ***********************************************************************/ +static void silk_P_Ana_calc_corr_st3( + silk_pe_stage3_vals cross_corr_st3[], /* O 3 DIM correlation array */ + const opus_int16 frame[], /* I vector to correlate */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of a 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +) +{ + const opus_int16 *target_ptr; + opus_int i, j, k, lag_counter, lag_low, lag_high; + opus_int nb_cbk_search, delta, idx, cbk_size; + VARDECL( opus_int32, scratch_mem ); + VARDECL( opus_int32, xcorr32 ); + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + SAVE_STACK; + + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 ); + ALLOC( xcorr32, SCRATCH_SIZE, opus_int32 ); + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */ + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the correlations for each subframe */ + lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 ); + celt_assert(lag_high-lag_low+1 <= SCRATCH_SIZE); + celt_pitch_xcorr( target_ptr, target_ptr - start_lag - lag_high, xcorr32, sf_length, lag_high - lag_low + 1, arch ); + for( j = lag_low; j <= lag_high; j++ ) { + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = xcorr32[ lag_high - j ]; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + matrix_ptr( cross_corr_st3, k, i, nb_cbk_search )[ j ] = + scratch_mem[ idx + j ]; + } + } + target_ptr += sf_length; + } + RESTORE_STACK; +} + +/********************************************************************/ +/* Calculate the energies for first two subframes. The energies are */ +/* calculated recursively. */ +/********************************************************************/ +static void silk_P_Ana_calc_energy_st3( + silk_pe_stage3_vals energies_st3[], /* O 3 DIM energy array */ + const opus_int16 frame[], /* I vector to calc energy in */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of one 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +) +{ + const opus_int16 *target_ptr, *basis_ptr; + opus_int32 energy; + opus_int k, i, j, lag_counter; + opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff; + VARDECL( opus_int32, scratch_mem ); + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + SAVE_STACK; + + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 ); + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the energy for first lag */ + basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) ); + energy = silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length, arch ); + silk_assert( energy >= 0 ); + scratch_mem[ lag_counter ] = energy; + lag_counter++; + + lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 ); + for( i = 1; i < lag_diff; i++ ) { + /* remove part outside new window */ + energy -= silk_SMULBB( basis_ptr[ sf_length - i ], basis_ptr[ sf_length - i ] ); + silk_assert( energy >= 0 ); + + /* add part that comes into window */ + energy = silk_ADD_SAT32( energy, silk_SMULBB( basis_ptr[ -i ], basis_ptr[ -i ] ) ); + silk_assert( energy >= 0 ); + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = energy; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] = + scratch_mem[ idx + j ]; + silk_assert( + matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] >= 0 ); + } + } + target_ptr += sf_length; + } + RESTORE_STACK; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/process_gains_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/process_gains_FIX.c new file mode 100644 index 000000000..05aba3178 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/process_gains_FIX.c @@ -0,0 +1,117 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/* Processing of gains */ +void silk_process_gains_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + opus_int k; + opus_int32 s_Q16, InvMaxSqrVal_Q16, gain, gain_squared, ResNrg, ResNrgPart, quant_offset_Q10; + + /* Gain reduction when LTP coding gain is high */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /*s = -0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); */ + s_Q16 = -silk_sigm_Q15( silk_RSHIFT_ROUND( psEncCtrl->LTPredCodGain_Q7 - SILK_FIX_CONST( 12.0, 7 ), 4 ) ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMLAWB( psEncCtrl->Gains_Q16[ k ], psEncCtrl->Gains_Q16[ k ], s_Q16 ); + } + } + + /* Limit the quantized signal */ + /* InvMaxSqrVal = pow( 2.0f, 0.33f * ( 21.0f - SNR_dB ) ) / subfr_length; */ + InvMaxSqrVal_Q16 = silk_DIV32_16( silk_log2lin( + silk_SMULWB( SILK_FIX_CONST( 21 + 16 / 0.33, 7 ) - psEnc->sCmn.SNR_dB_Q7, SILK_FIX_CONST( 0.33, 16 ) ) ), psEnc->sCmn.subfr_length ); + + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Soft limit on ratio residual energy and squared gains */ + ResNrg = psEncCtrl->ResNrg[ k ]; + ResNrgPart = silk_SMULWW( ResNrg, InvMaxSqrVal_Q16 ); + if( psEncCtrl->ResNrgQ[ k ] > 0 ) { + ResNrgPart = silk_RSHIFT_ROUND( ResNrgPart, psEncCtrl->ResNrgQ[ k ] ); + } else { + if( ResNrgPart >= silk_RSHIFT( silk_int32_MAX, -psEncCtrl->ResNrgQ[ k ] ) ) { + ResNrgPart = silk_int32_MAX; + } else { + ResNrgPart = silk_LSHIFT( ResNrgPart, -psEncCtrl->ResNrgQ[ k ] ); + } + } + gain = psEncCtrl->Gains_Q16[ k ]; + gain_squared = silk_ADD_SAT32( ResNrgPart, silk_SMMUL( gain, gain ) ); + if( gain_squared < silk_int16_MAX ) { + /* recalculate with higher precision */ + gain_squared = silk_SMLAWW( silk_LSHIFT( ResNrgPart, 16 ), gain, gain ); + silk_assert( gain_squared > 0 ); + gain = silk_SQRT_APPROX( gain_squared ); /* Q8 */ + gain = silk_min( gain, silk_int32_MAX >> 8 ); + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 8 ); /* Q16 */ + } else { + gain = silk_SQRT_APPROX( gain_squared ); /* Q0 */ + gain = silk_min( gain, silk_int32_MAX >> 16 ); + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 16 ); /* Q16 */ + } + } + + /* Save unquantized gains and gain Index */ + silk_memcpy( psEncCtrl->GainsUnq_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex; + + /* Quantize gains */ + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, psEncCtrl->Gains_Q16, + &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + if( psEncCtrl->LTPredCodGain_Q7 + silk_RSHIFT( psEnc->sCmn.input_tilt_Q15, 8 ) > SILK_FIX_CONST( 1.0, 7 ) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /* Quantizer boundary adjustment */ + quant_offset_Q10 = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ]; + psEncCtrl->Lambda_Q10 = SILK_FIX_CONST( LAMBDA_OFFSET, 10 ) + + silk_SMULBB( SILK_FIX_CONST( LAMBDA_DELAYED_DECISIONS, 10 ), psEnc->sCmn.nStatesDelayedDecision ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_SPEECH_ACT, 18 ), psEnc->sCmn.speech_activity_Q8 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_INPUT_QUALITY, 12 ), psEncCtrl->input_quality_Q14 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_CODING_QUALITY, 12 ), psEncCtrl->coding_quality_Q14 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_QUANT_OFFSET, 16 ), quant_offset_Q10 ); + + silk_assert( psEncCtrl->Lambda_Q10 > 0 ); + silk_assert( psEncCtrl->Lambda_Q10 < SILK_FIX_CONST( 2, 10 ) ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/regularize_correlations_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/regularize_correlations_FIX.c new file mode 100644 index 000000000..a2836b05f --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/regularize_correlations_FIX.c @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Add noise to matrix diagonal */ +void silk_regularize_correlations_FIX( + opus_int32 *XX, /* I/O Correlation matrices */ + opus_int32 *xx, /* I/O Correlation values */ + opus_int32 noise, /* I Noise to add */ + opus_int D /* I Dimension of XX */ +) +{ + opus_int i; + for( i = 0; i < D; i++ ) { + matrix_ptr( &XX[ 0 ], i, i, D ) = silk_ADD32( matrix_ptr( &XX[ 0 ], i, i, D ), noise ); + } + xx[ 0 ] += noise; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/residual_energy16_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/residual_energy16_FIX.c new file mode 100644 index 000000000..7f130f3d3 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/residual_energy16_FIX.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +opus_int32 silk_residual_energy16_covar_FIX( + const opus_int16 *c, /* I Prediction vector */ + const opus_int32 *wXX, /* I Correlation matrix */ + const opus_int32 *wXx, /* I Correlation vector */ + opus_int32 wxx, /* I Signal energy */ + opus_int D, /* I Dimension */ + opus_int cQ /* I Q value for c vector 0 - 15 */ +) +{ + opus_int i, j, lshifts, Qxtra; + opus_int32 c_max, w_max, tmp, tmp2, nrg; + opus_int cn[ MAX_MATRIX_SIZE ]; + const opus_int32 *pRow; + + /* Safety checks */ + celt_assert( D >= 0 ); + celt_assert( D <= 16 ); + celt_assert( cQ > 0 ); + celt_assert( cQ < 16 ); + + lshifts = 16 - cQ; + Qxtra = lshifts; + + c_max = 0; + for( i = 0; i < D; i++ ) { + c_max = silk_max_32( c_max, silk_abs( (opus_int32)c[ i ] ) ); + } + Qxtra = silk_min_int( Qxtra, silk_CLZ32( c_max ) - 17 ); + + w_max = silk_max_32( wXX[ 0 ], wXX[ D * D - 1 ] ); + Qxtra = silk_min_int( Qxtra, silk_CLZ32( silk_MUL( D, silk_RSHIFT( silk_SMULWB( w_max, c_max ), 4 ) ) ) - 5 ); + Qxtra = silk_max_int( Qxtra, 0 ); + for( i = 0; i < D; i++ ) { + cn[ i ] = silk_LSHIFT( ( opus_int )c[ i ], Qxtra ); + silk_assert( silk_abs(cn[i]) <= ( silk_int16_MAX + 1 ) ); /* Check that silk_SMLAWB can be used */ + } + lshifts -= Qxtra; + + /* Compute wxx - 2 * wXx * c */ + tmp = 0; + for( i = 0; i < D; i++ ) { + tmp = silk_SMLAWB( tmp, wXx[ i ], cn[ i ] ); + } + nrg = silk_RSHIFT( wxx, 1 + lshifts ) - tmp; /* Q: -lshifts - 1 */ + + /* Add c' * wXX * c, assuming wXX is symmetric */ + tmp2 = 0; + for( i = 0; i < D; i++ ) { + tmp = 0; + pRow = &wXX[ i * D ]; + for( j = i + 1; j < D; j++ ) { + tmp = silk_SMLAWB( tmp, pRow[ j ], cn[ j ] ); + } + tmp = silk_SMLAWB( tmp, silk_RSHIFT( pRow[ i ], 1 ), cn[ i ] ); + tmp2 = silk_SMLAWB( tmp2, tmp, cn[ i ] ); + } + nrg = silk_ADD_LSHIFT32( nrg, tmp2, lshifts ); /* Q: -lshifts - 1 */ + + /* Keep one bit free always, because we add them for LSF interpolation */ + if( nrg < 1 ) { + nrg = 1; + } else if( nrg > silk_RSHIFT( silk_int32_MAX, lshifts + 2 ) ) { + nrg = silk_int32_MAX >> 1; + } else { + nrg = silk_LSHIFT( nrg, lshifts + 1 ); /* Q0 */ + } + return nrg; + +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/residual_energy_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/residual_energy_FIX.c new file mode 100644 index 000000000..6c7cade9a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/residual_energy_FIX.c @@ -0,0 +1,98 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FIX( + opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */ + const opus_int16 x[], /* I Input signal */ + opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int LPC_order, /* I LPC order */ + int arch /* I Run-time architecture */ +) +{ + opus_int offset, i, j, rshift, lz1, lz2; + opus_int16 *LPC_res_ptr; + VARDECL( opus_int16, LPC_res ); + const opus_int16 *x_ptr; + opus_int32 tmp32; + SAVE_STACK; + + x_ptr = x; + offset = LPC_order + subfr_length; + + /* Filter input to create the LPC residual for each frame half, and measure subframe energies */ + ALLOC( LPC_res, ( MAX_NB_SUBFR >> 1 ) * offset, opus_int16 ); + celt_assert( ( nb_subfr >> 1 ) * ( MAX_NB_SUBFR >> 1 ) == nb_subfr ); + for( i = 0; i < nb_subfr >> 1; i++ ) { + /* Calculate half frame LPC residual signal including preceding samples */ + silk_LPC_analysis_filter( LPC_res, x_ptr, a_Q12[ i ], ( MAX_NB_SUBFR >> 1 ) * offset, LPC_order, arch ); + + /* Point to first subframe of the just calculated LPC residual signal */ + LPC_res_ptr = LPC_res + LPC_order; + for( j = 0; j < ( MAX_NB_SUBFR >> 1 ); j++ ) { + /* Measure subframe energy */ + silk_sum_sqr_shift( &nrgs[ i * ( MAX_NB_SUBFR >> 1 ) + j ], &rshift, LPC_res_ptr, subfr_length ); + + /* Set Q values for the measured energy */ + nrgsQ[ i * ( MAX_NB_SUBFR >> 1 ) + j ] = -rshift; + + /* Move to next subframe */ + LPC_res_ptr += offset; + } + /* Move to next frame half */ + x_ptr += ( MAX_NB_SUBFR >> 1 ) * offset; + } + + /* Apply the squared subframe gains */ + for( i = 0; i < nb_subfr; i++ ) { + /* Fully upscale gains and energies */ + lz1 = silk_CLZ32( nrgs[ i ] ) - 1; + lz2 = silk_CLZ32( gains[ i ] ) - 1; + + tmp32 = silk_LSHIFT32( gains[ i ], lz2 ); + + /* Find squared gains */ + tmp32 = silk_SMMUL( tmp32, tmp32 ); /* Q( 2 * lz2 - 32 )*/ + + /* Scale energies */ + nrgs[ i ] = silk_SMMUL( tmp32, silk_LSHIFT32( nrgs[ i ], lz1 ) ); /* Q( nrgsQ[ i ] + lz1 + 2 * lz2 - 32 - 32 )*/ + nrgsQ[ i ] += lz1 + 2 * lz2 - 32 - 32; + } + RESTORE_STACK; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/schur64_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/schur64_FIX.c new file mode 100644 index 000000000..4b7e19ea5 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/schur64_FIX.c @@ -0,0 +1,93 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Slower than schur(), but more accurate. */ +/* Uses SMULL(), available on armv4 */ +opus_int32 silk_schur64( /* O returns residual energy */ + opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */ + const opus_int32 c[], /* I Correlations [order+1] */ + opus_int32 order /* I Prediction order */ +) +{ + opus_int k, n; + opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; + opus_int32 Ctmp1_Q30, Ctmp2_Q30, rc_tmp_Q31; + + celt_assert( order >= 0 && order <= SILK_MAX_ORDER_LPC ); + + /* Check for invalid input */ + if( c[ 0 ] <= 0 ) { + silk_memset( rc_Q16, 0, order * sizeof( opus_int32 ) ); + return 0; + } + + k = 0; + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ]; + } while( ++k <= order ); + + for( k = 0; k < order; k++ ) { + /* Check that we won't be getting an unstable rc, otherwise stop here. */ + if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) { + if ( C[ k + 1 ][ 0 ] > 0 ) { + rc_Q16[ k ] = -SILK_FIX_CONST( .99f, 16 ); + } else { + rc_Q16[ k ] = SILK_FIX_CONST( .99f, 16 ); + } + k++; + break; + } + + /* Get reflection coefficient: divide two Q30 values and get result in Q31 */ + rc_tmp_Q31 = silk_DIV32_varQ( -C[ k + 1 ][ 0 ], C[ 0 ][ 1 ], 31 ); + + /* Save the output */ + rc_Q16[ k ] = silk_RSHIFT_ROUND( rc_tmp_Q31, 15 ); + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1_Q30 = C[ n + k + 1 ][ 0 ]; + Ctmp2_Q30 = C[ n ][ 1 ]; + + /* Multiply and add the highest int32 */ + C[ n + k + 1 ][ 0 ] = Ctmp1_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp2_Q30, 1 ), rc_tmp_Q31 ); + C[ n ][ 1 ] = Ctmp2_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp1_Q30, 1 ), rc_tmp_Q31 ); + } + } + + for(; k < order; k++ ) { + rc_Q16[ k ] = 0; + } + + return silk_max_32( 1, C[ 0 ][ 1 ] ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/schur_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/schur_FIX.c new file mode 100644 index 000000000..2840f6b1a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/schur_FIX.c @@ -0,0 +1,107 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Faster than schur64(), but much less accurate. */ +/* uses SMLAWB(), requiring armv5E and higher. */ +opus_int32 silk_schur( /* O Returns residual energy */ + opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */ + const opus_int32 *c, /* I correlations [order+1] */ + const opus_int32 order /* I prediction order */ +) +{ + opus_int k, n, lz; + opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; + opus_int32 Ctmp1, Ctmp2, rc_tmp_Q15; + + celt_assert( order >= 0 && order <= SILK_MAX_ORDER_LPC ); + + /* Get number of leading zeros */ + lz = silk_CLZ32( c[ 0 ] ); + + /* Copy correlations and adjust level to Q30 */ + k = 0; + if( lz < 2 ) { + /* lz must be 1, so shift one to the right */ + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = silk_RSHIFT( c[ k ], 1 ); + } while( ++k <= order ); + } else if( lz > 2 ) { + /* Shift to the left */ + lz -= 2; + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = silk_LSHIFT( c[ k ], lz ); + } while( ++k <= order ); + } else { + /* No need to shift */ + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ]; + } while( ++k <= order ); + } + + for( k = 0; k < order; k++ ) { + /* Check that we won't be getting an unstable rc, otherwise stop here. */ + if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) { + if ( C[ k + 1 ][ 0 ] > 0 ) { + rc_Q15[ k ] = -SILK_FIX_CONST( .99f, 15 ); + } else { + rc_Q15[ k ] = SILK_FIX_CONST( .99f, 15 ); + } + k++; + break; + } + + /* Get reflection coefficient */ + rc_tmp_Q15 = -silk_DIV32_16( C[ k + 1 ][ 0 ], silk_max_32( silk_RSHIFT( C[ 0 ][ 1 ], 15 ), 1 ) ); + + /* Clip (shouldn't happen for properly conditioned inputs) */ + rc_tmp_Q15 = silk_SAT16( rc_tmp_Q15 ); + + /* Store */ + rc_Q15[ k ] = (opus_int16)rc_tmp_Q15; + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1 = C[ n + k + 1 ][ 0 ]; + Ctmp2 = C[ n ][ 1 ]; + C[ n + k + 1 ][ 0 ] = silk_SMLAWB( Ctmp1, silk_LSHIFT( Ctmp2, 1 ), rc_tmp_Q15 ); + C[ n ][ 1 ] = silk_SMLAWB( Ctmp2, silk_LSHIFT( Ctmp1, 1 ), rc_tmp_Q15 ); + } + } + + for(; k < order; k++ ) { + rc_Q15[ k ] = 0; + } + + /* return residual energy */ + return silk_max_32( 1, C[ 0 ][ 1 ] ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/structs_FIX.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/structs_FIX.h new file mode 100644 index 000000000..2774a97b2 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/structs_FIX.h @@ -0,0 +1,116 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_STRUCTS_FIX_H +#define SILK_STRUCTS_FIX_H + +#include "typedef.h" +#include "main.h" +#include "structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************/ +/* Noise shaping analysis state */ +/********************************/ +typedef struct { + opus_int8 LastGainIndex; + opus_int32 HarmBoost_smth_Q16; + opus_int32 HarmShapeGain_smth_Q16; + opus_int32 Tilt_smth_Q16; +} silk_shape_state_FIX; + +/********************************/ +/* Encoder state FIX */ +/********************************/ +typedef struct { + silk_encoder_state sCmn; /* Common struct, shared with floating-point code */ + silk_shape_state_FIX sShape; /* Shape state */ + + /* Buffer for find pitch and noise shape analysis */ + silk_DWORD_ALIGN opus_int16 x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */ + opus_int LTPCorr_Q15; /* Normalized correlation from pitch lag estimator */ + opus_int32 resNrgSmth; +} silk_encoder_state_FIX; + +/************************/ +/* Encoder control FIX */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; + opus_int pitchL[ MAX_NB_SUBFR ]; + + /* Noise shaping parameters */ + /* Testing */ + silk_DWORD_ALIGN opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */ + opus_int Tilt_Q14[ MAX_NB_SUBFR ]; + opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ]; + opus_int Lambda_Q10; + opus_int input_quality_Q14; + opus_int coding_quality_Q14; + + /* measures */ + opus_int32 predGain_Q16; + opus_int LTPredCodGain_Q7; + opus_int32 ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */ + opus_int ResNrgQ[ MAX_NB_SUBFR ]; /* Q domain for the residual energy > 0 */ + + /* Parameters for CBR mode */ + opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ]; + opus_int8 lastGainIndexPrev; +} silk_encoder_control_FIX; + +/************************/ +/* Encoder Super Struct */ +/************************/ +typedef struct { + silk_encoder_state_FIX state_Fxx[ ENCODER_NUM_CHANNELS ]; + stereo_enc_state sStereo; + opus_int32 nBitsUsedLBRR; + opus_int32 nBitsExceeded; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int nPrevChannelsInternal; + opus_int timeSinceSwitchAllowed_ms; + opus_int allowBandwidthSwitch; + opus_int prev_decode_only_middle; +} silk_encoder; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/vector_ops_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/vector_ops_FIX.c new file mode 100644 index 000000000..d94980014 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/vector_ops_FIX.c @@ -0,0 +1,102 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "pitch.h" + +/* Copy and multiply a vector by a constant */ +void silk_scale_copy_vector16( + opus_int16 *data_out, + const opus_int16 *data_in, + opus_int32 gain_Q16, /* I Gain in Q16 */ + const opus_int dataSize /* I Length */ +) +{ + opus_int i; + opus_int32 tmp32; + + for( i = 0; i < dataSize; i++ ) { + tmp32 = silk_SMULWB( gain_Q16, data_in[ i ] ); + data_out[ i ] = (opus_int16)silk_CHECK_FIT16( tmp32 ); + } +} + +/* Multiply a vector by a constant */ +void silk_scale_vector32_Q26_lshift_18( + opus_int32 *data1, /* I/O Q0/Q18 */ + opus_int32 gain_Q26, /* I Q26 */ + opus_int dataSize /* I length */ +) +{ + opus_int i; + + for( i = 0; i < dataSize; i++ ) { + data1[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( silk_SMULL( data1[ i ], gain_Q26 ), 8 ) ); /* OUTPUT: Q18 */ + } +} + +/* sum = for(i=0;i6, memory access can be reduced by half. */ +opus_int32 silk_inner_prod_aligned( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int len, /* I vector lengths */ + int arch /* I Run-time architecture */ +) +{ +#ifdef FIXED_POINT + return celt_inner_prod(inVec1, inVec2, len, arch); +#else + opus_int i; + opus_int32 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_SMLABB( sum, inVec1[ i ], inVec2[ i ] ); + } + return sum; +#endif +} + +opus_int64 silk_inner_prod16_aligned_64_c( + const opus_int16 *inVec1, /* I input vector 1 */ + const opus_int16 *inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i; + opus_int64 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_SMLALBB( sum, inVec1[ i ], inVec2[ i ] ); + } + return sum; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/warped_autocorrelation_FIX.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/warped_autocorrelation_FIX.c new file mode 100644 index 000000000..5c79553bc --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/warped_autocorrelation_FIX.c @@ -0,0 +1,92 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +#if defined(MIPSr1_ASM) +#include "mips/warped_autocorrelation_FIX_mipsr1.h" +#endif + + +/* Autocorrelations for a warped frequency axis */ +#ifndef OVERRIDE_silk_warped_autocorrelation_FIX_c +void silk_warped_autocorrelation_FIX_c( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + opus_int n, i, lsh; + opus_int32 tmp1_QS, tmp2_QS; + opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + + /* Order must be even */ + celt_assert( ( order & 1 ) == 0 ); + silk_assert( 2 * QS - QC >= 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n++ ) { + tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS ); + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 ); + state_QS[ i ] = tmp1_QS; + corr_QC[ i ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); + /* Output of allpass section */ + tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 ); + state_QS[ i + 1 ] = tmp2_QS; + corr_QC[ i + 1 ] += silk_RSHIFT64( silk_SMULL( tmp2_QS, state_QS[ 0 ] ), 2 * QS - QC ); + } + state_QS[ order ] = tmp1_QS; + corr_QC[ order ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); + } + + lsh = silk_CLZ64( corr_QC[ 0 ] ) - 35; + lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC ); + *scale = -( QC + lsh ); + silk_assert( *scale >= -30 && *scale <= 12 ); + if( lsh >= 0 ) { + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_LSHIFT64( corr_QC[ i ], lsh ) ); + } + } else { + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr_QC[ i ], -lsh ) ); + } + } + silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/ +} +#endif /* OVERRIDE_silk_warped_autocorrelation_FIX_c */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/x86/burg_modified_FIX_sse4_1.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/x86/burg_modified_FIX_sse4_1.c new file mode 100644 index 000000000..bbb1ce0fc --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/x86/burg_modified_FIX_sse4_1.c @@ -0,0 +1,377 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "SigProc_FIX.h" +#include "define.h" +#include "tuning_parameters.h" +#include "pitch.h" +#include "celt/x86/x86cpu.h" + +#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */ + +#define QA 25 +#define N_BITS_HEAD_ROOM 2 +#define MIN_RSHIFTS -16 +#define MAX_RSHIFTS (32 - QA) + +/* Compute reflection coefficients from input signal */ +void silk_burg_modified_sse4_1( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +) +{ + opus_int k, n, s, lz, rshifts, rshifts_extra, reached_max_gain; + opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2; + const opus_int16 *x_ptr; + opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ]; + opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ]; + opus_int32 xcorr[ SILK_MAX_ORDER_LPC ]; + + __m128i FIRST_3210, LAST_3210, ATMP_3210, TMP1_3210, TMP2_3210, T1_3210, T2_3210, PTR_3210, SUBFR_3210, X1_3210, X2_3210; + __m128i CONST1 = _mm_set1_epi32(1); + + celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + + /* Compute autocorrelations, added over subframes */ + silk_sum_sqr_shift( &C0, &rshifts, x, nb_subfr * subfr_length ); + if( rshifts > MAX_RSHIFTS ) { + C0 = silk_LSHIFT32( C0, rshifts - MAX_RSHIFTS ); + silk_assert( C0 > 0 ); + rshifts = MAX_RSHIFTS; + } else { + lz = silk_CLZ32( C0 ) - 1; + rshifts_extra = N_BITS_HEAD_ROOM - lz; + if( rshifts_extra > 0 ) { + rshifts_extra = silk_min( rshifts_extra, MAX_RSHIFTS - rshifts ); + C0 = silk_RSHIFT32( C0, rshifts_extra ); + } else { + rshifts_extra = silk_max( rshifts_extra, MIN_RSHIFTS - rshifts ); + C0 = silk_LSHIFT32( C0, -rshifts_extra ); + } + rshifts += rshifts_extra; + } + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += (opus_int32)silk_RSHIFT64( + silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n, arch ), rshifts ); + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + int i; + opus_int32 d; + x_ptr = x + s * subfr_length; + celt_pitch_xcorr(x_ptr, x_ptr + 1, xcorr, subfr_length - D, D, arch ); + for( n = 1; n < D + 1; n++ ) { + for ( i = n + subfr_length - D, d = 0; i < subfr_length; i++ ) + d = MAC16_16( d, x_ptr[ i ], x_ptr[ i - n ] ); + xcorr[ n - 1 ] += d; + } + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += silk_LSHIFT32( xcorr[ n - 1 ], -rshifts ); + } + } + } + silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + + invGain_Q30 = (opus_int32)1 << 30; + reached_max_gain = 0; + for( n = 0; n < D; n++ ) { + /* Update first row of correlation matrix (without first element) */ + /* Update last row of correlation matrix (without last element, stored in reversed order) */ + /* Update C * Af */ + /* Update C * flipud(Af) (stored in reversed order) */ + if( rshifts > -2 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], 16 - rshifts ); /* Q(16-rshifts) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); /* Q(16-rshifts) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], QA - 16 ); /* Q(QA-16) */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); /* Q(QA-16) */ + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp_QA = Af_QA[ k ]; + tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); /* Q(QA-16) */ + tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); /* Q(QA-16) */ + } + tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts ); /* Q(16-rshifts) */ + tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts ); /* Q(16-rshifts) */ + for( k = 0; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] ); /* Q( -rshift ) */ + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], -rshifts ); /* Q( -rshifts ) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); /* Q( -rshifts ) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], 17 ); /* Q17 */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 ); /* Q17 */ + + X1_3210 = _mm_set1_epi32( x1 ); + X2_3210 = _mm_set1_epi32( x2 ); + TMP1_3210 = _mm_setzero_si128(); + TMP2_3210 = _mm_setzero_si128(); + for( k = 0; k < n - 3; k += 4 ) { + PTR_3210 = OP_CVTEPI16_EPI32_M64( &x_ptr[ n - k - 1 - 3 ] ); + SUBFR_3210 = OP_CVTEPI16_EPI32_M64( &x_ptr[ subfr_length - n + k ] ); + FIRST_3210 = _mm_loadu_si128( (__m128i *)&C_first_row[ k ] ); + PTR_3210 = _mm_shuffle_epi32( PTR_3210, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + LAST_3210 = _mm_loadu_si128( (__m128i *)&C_last_row[ k ] ); + ATMP_3210 = _mm_loadu_si128( (__m128i *)&Af_QA[ k ] ); + + T1_3210 = _mm_mullo_epi32( PTR_3210, X1_3210 ); + T2_3210 = _mm_mullo_epi32( SUBFR_3210, X2_3210 ); + + ATMP_3210 = _mm_srai_epi32( ATMP_3210, 7 ); + ATMP_3210 = _mm_add_epi32( ATMP_3210, CONST1 ); + ATMP_3210 = _mm_srai_epi32( ATMP_3210, 1 ); + + FIRST_3210 = _mm_add_epi32( FIRST_3210, T1_3210 ); + LAST_3210 = _mm_add_epi32( LAST_3210, T2_3210 ); + + PTR_3210 = _mm_mullo_epi32( ATMP_3210, PTR_3210 ); + SUBFR_3210 = _mm_mullo_epi32( ATMP_3210, SUBFR_3210 ); + + _mm_storeu_si128( (__m128i *)&C_first_row[ k ], FIRST_3210 ); + _mm_storeu_si128( (__m128i *)&C_last_row[ k ], LAST_3210 ); + + TMP1_3210 = _mm_add_epi32( TMP1_3210, PTR_3210 ); + TMP2_3210 = _mm_add_epi32( TMP2_3210, SUBFR_3210 ); + } + + TMP1_3210 = _mm_add_epi32( TMP1_3210, _mm_unpackhi_epi64(TMP1_3210, TMP1_3210 ) ); + TMP2_3210 = _mm_add_epi32( TMP2_3210, _mm_unpackhi_epi64(TMP2_3210, TMP2_3210 ) ); + TMP1_3210 = _mm_add_epi32( TMP1_3210, _mm_shufflelo_epi16(TMP1_3210, 0x0E ) ); + TMP2_3210 = _mm_add_epi32( TMP2_3210, _mm_shufflelo_epi16(TMP2_3210, 0x0E ) ); + + tmp1 += _mm_cvtsi128_si32( TMP1_3210 ); + tmp2 += _mm_cvtsi128_si32( TMP2_3210 ); + + for( ; k < n; k++ ) { + C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); /* Q17 */ + tmp1 = silk_MLA( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); /* Q17 */ + tmp2 = silk_MLA( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); /* Q17 */ + } + + tmp1 = -tmp1; /* Q17 */ + tmp2 = -tmp2; /* Q17 */ + + { + __m128i xmm_tmp1, xmm_tmp2; + __m128i xmm_x_ptr_n_k_x2x0, xmm_x_ptr_n_k_x3x1; + __m128i xmm_x_ptr_sub_x2x0, xmm_x_ptr_sub_x3x1; + + xmm_tmp1 = _mm_set1_epi32( tmp1 ); + xmm_tmp2 = _mm_set1_epi32( tmp2 ); + + for( k = 0; k <= n - 3; k += 4 ) { + xmm_x_ptr_n_k_x2x0 = OP_CVTEPI16_EPI32_M64( &x_ptr[ n - k - 3 ] ); + xmm_x_ptr_sub_x2x0 = OP_CVTEPI16_EPI32_M64( &x_ptr[ subfr_length - n + k - 1 ] ); + + xmm_x_ptr_n_k_x2x0 = _mm_shuffle_epi32( xmm_x_ptr_n_k_x2x0, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + + xmm_x_ptr_n_k_x2x0 = _mm_slli_epi32( xmm_x_ptr_n_k_x2x0, -rshifts - 1 ); + xmm_x_ptr_sub_x2x0 = _mm_slli_epi32( xmm_x_ptr_sub_x2x0, -rshifts - 1 ); + + /* equal shift right 4 bytes, xmm_x_ptr_n_k_x3x1 = _mm_srli_si128(xmm_x_ptr_n_k_x2x0, 4)*/ + xmm_x_ptr_n_k_x3x1 = _mm_shuffle_epi32( xmm_x_ptr_n_k_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + xmm_x_ptr_sub_x3x1 = _mm_shuffle_epi32( xmm_x_ptr_sub_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_x_ptr_n_k_x2x0 = _mm_mul_epi32( xmm_x_ptr_n_k_x2x0, xmm_tmp1 ); + xmm_x_ptr_n_k_x3x1 = _mm_mul_epi32( xmm_x_ptr_n_k_x3x1, xmm_tmp1 ); + xmm_x_ptr_sub_x2x0 = _mm_mul_epi32( xmm_x_ptr_sub_x2x0, xmm_tmp2 ); + xmm_x_ptr_sub_x3x1 = _mm_mul_epi32( xmm_x_ptr_sub_x3x1, xmm_tmp2 ); + + xmm_x_ptr_n_k_x2x0 = _mm_srli_epi64( xmm_x_ptr_n_k_x2x0, 16 ); + xmm_x_ptr_n_k_x3x1 = _mm_slli_epi64( xmm_x_ptr_n_k_x3x1, 16 ); + xmm_x_ptr_sub_x2x0 = _mm_srli_epi64( xmm_x_ptr_sub_x2x0, 16 ); + xmm_x_ptr_sub_x3x1 = _mm_slli_epi64( xmm_x_ptr_sub_x3x1, 16 ); + + xmm_x_ptr_n_k_x2x0 = _mm_blend_epi16( xmm_x_ptr_n_k_x2x0, xmm_x_ptr_n_k_x3x1, 0xCC ); + xmm_x_ptr_sub_x2x0 = _mm_blend_epi16( xmm_x_ptr_sub_x2x0, xmm_x_ptr_sub_x3x1, 0xCC ); + + X1_3210 = _mm_loadu_si128( (__m128i *)&CAf[ k ] ); + PTR_3210 = _mm_loadu_si128( (__m128i *)&CAb[ k ] ); + + X1_3210 = _mm_add_epi32( X1_3210, xmm_x_ptr_n_k_x2x0 ); + PTR_3210 = _mm_add_epi32( PTR_3210, xmm_x_ptr_sub_x2x0 ); + + _mm_storeu_si128( (__m128i *)&CAf[ k ], X1_3210 ); + _mm_storeu_si128( (__m128i *)&CAb[ k ], PTR_3210 ); + } + + for( ; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1, + silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2, + silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) ); /* Q( -rshift ) */ + } + } + } + } + + /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ + tmp1 = C_first_row[ n ]; /* Q( -rshifts ) */ + tmp2 = C_last_row[ n ]; /* Q( -rshifts ) */ + num = 0; /* Q( -rshifts ) */ + nrg = silk_ADD32( CAb[ 0 ], CAf[ 0 ] ); /* Q( 1-rshifts ) */ + for( k = 0; k < n; k++ ) { + Atmp_QA = Af_QA[ k ]; + lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1; + lz = silk_min( 32 - QA, lz ); + Atmp1 = silk_LSHIFT32( Atmp_QA, lz ); /* Q( QA + lz ) */ + + tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + num = silk_ADD_LSHIFT32( num, silk_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + nrg = silk_ADD_LSHIFT32( nrg, silk_SMMUL( silk_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ), + Atmp1 ), 32 - QA - lz ); /* Q( 1-rshifts ) */ + } + CAf[ n + 1 ] = tmp1; /* Q( -rshifts ) */ + CAb[ n + 1 ] = tmp2; /* Q( -rshifts ) */ + num = silk_ADD32( num, tmp2 ); /* Q( -rshifts ) */ + num = silk_LSHIFT32( -num, 1 ); /* Q( 1-rshifts ) */ + + /* Calculate the next order reflection (parcor) coefficient */ + if( silk_abs( num ) < nrg ) { + rc_Q31 = silk_DIV32_varQ( num, nrg, 31 ); + } else { + rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN; + } + + /* Update inverse prediction gain */ + tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 ); + tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 ); + if( tmp1 <= minInvGain_Q30 ) { + /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ + tmp2 = ( (opus_int32)1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 ); /* Q30 */ + rc_Q31 = silk_SQRT_APPROX( tmp2 ); /* Q15 */ + if( rc_Q31 > 0 ) { + /* Newton-Raphson iteration */ + rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 ); /* Q15 */ + rc_Q31 = silk_LSHIFT32( rc_Q31, 16 ); /* Q31 */ + if( num < 0 ) { + /* Ensure adjusted reflection coefficients has the original sign */ + rc_Q31 = -rc_Q31; + } + } + invGain_Q30 = minInvGain_Q30; + reached_max_gain = 1; + } else { + invGain_Q30 = tmp1; + } + + /* Update the AR coefficients */ + for( k = 0; k < (n + 1) >> 1; k++ ) { + tmp1 = Af_QA[ k ]; /* QA */ + tmp2 = Af_QA[ n - k - 1 ]; /* QA */ + Af_QA[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* QA */ + Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* QA */ + } + Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA ); /* QA */ + + if( reached_max_gain ) { + /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ + for( k = n + 1; k < D; k++ ) { + Af_QA[ k ] = 0; + } + break; + } + + /* Update C * Af and C * Ab */ + for( k = 0; k <= n + 1; k++ ) { + tmp1 = CAf[ k ]; /* Q( -rshifts ) */ + tmp2 = CAb[ n - k + 1 ]; /* Q( -rshifts ) */ + CAf[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + } + } + + if( reached_max_gain ) { + for( k = 0; k < D; k++ ) { + /* Scale coefficients */ + A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); + } + /* Subtract energy of preceding samples from C0 */ + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16_aligned_64( x_ptr, x_ptr, D, arch ), rshifts ); + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D, arch ), -rshifts ); + } + } + /* Approximate residual energy */ + *res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 ); + *res_nrg_Q = -rshifts; + } else { + /* Return residual energy */ + nrg = CAf[ 0 ]; /* Q( -rshifts ) */ + tmp1 = (opus_int32)1 << 16; /* Q16 */ + for( k = 0; k < D; k++ ) { + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); /* Q16 */ + nrg = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); /* Q( -rshifts ) */ + tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 ); /* Q16 */ + A_Q16[ k ] = -Atmp1; + } + *res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */ + *res_nrg_Q = -rshifts; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/x86/prefilter_FIX_sse.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/x86/prefilter_FIX_sse.c new file mode 100644 index 000000000..555432cd9 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/x86/prefilter_FIX_sse.c @@ -0,0 +1,160 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "main.h" +#include "celt/x86/x86cpu.h" + +void silk_warped_LPC_analysis_filter_FIX_sse4_1( + opus_int32 state[], /* I/O State [order + 1] */ + opus_int32 res_Q2[], /* O Residual signal [length] */ + const opus_int16 coef_Q13[], /* I Coefficients [order] */ + const opus_int16 input[], /* I Input signal [length] */ + const opus_int16 lambda_Q16, /* I Warping factor */ + const opus_int length, /* I Length of input signal */ + const opus_int order /* I Filter order (even) */ +) +{ + opus_int n, i; + opus_int32 acc_Q11, tmp1, tmp2; + + /* Order must be even */ + celt_assert( ( order & 1 ) == 0 ); + + if (order == 10) + { + if (0 == lambda_Q16) + { + __m128i coef_Q13_3210, coef_Q13_7654; + __m128i coef_Q13_0123, coef_Q13_4567; + __m128i state_0123, state_4567; + __m128i xmm_product1, xmm_product2; + __m128i xmm_tempa, xmm_tempb; + + register opus_int32 sum; + register opus_int32 state_8, state_9, state_a; + register opus_int64 coef_Q13_8, coef_Q13_9; + + celt_assert( length > 0 ); + + coef_Q13_3210 = OP_CVTEPI16_EPI32_M64( &coef_Q13[ 0 ] ); + coef_Q13_7654 = OP_CVTEPI16_EPI32_M64( &coef_Q13[ 4 ] ); + + coef_Q13_0123 = _mm_shuffle_epi32( coef_Q13_3210, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + coef_Q13_4567 = _mm_shuffle_epi32( coef_Q13_7654, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + + coef_Q13_8 = (opus_int64) coef_Q13[ 8 ]; + coef_Q13_9 = (opus_int64) coef_Q13[ 9 ]; + + state_0123 = _mm_loadu_si128( (__m128i *)(&state[ 0 ] ) ); + state_4567 = _mm_loadu_si128( (__m128i *)(&state[ 4 ] ) ); + + state_0123 = _mm_shuffle_epi32( state_0123, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + state_4567 = _mm_shuffle_epi32( state_4567, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + + state_8 = state[ 8 ]; + state_9 = state[ 9 ]; + state_a = 0; + + for( n = 0; n < length; n++ ) + { + xmm_product1 = _mm_mul_epi32( coef_Q13_0123, state_0123 ); /* 64-bit multiply, only 2 pairs */ + xmm_product2 = _mm_mul_epi32( coef_Q13_4567, state_4567 ); + + xmm_tempa = _mm_shuffle_epi32( state_0123, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + xmm_tempb = _mm_shuffle_epi32( state_4567, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + + xmm_product1 = _mm_srli_epi64( xmm_product1, 16 ); /* >> 16, zero extending works */ + xmm_product2 = _mm_srli_epi64( xmm_product2, 16 ); + + xmm_tempa = _mm_mul_epi32( coef_Q13_3210, xmm_tempa ); + xmm_tempb = _mm_mul_epi32( coef_Q13_7654, xmm_tempb ); + + xmm_tempa = _mm_srli_epi64( xmm_tempa, 16 ); + xmm_tempb = _mm_srli_epi64( xmm_tempb, 16 ); + + xmm_tempa = _mm_add_epi32( xmm_tempa, xmm_product1 ); + xmm_tempb = _mm_add_epi32( xmm_tempb, xmm_product2 ); + xmm_tempa = _mm_add_epi32( xmm_tempa, xmm_tempb ); + + sum = (opus_int32)((coef_Q13_8 * state_8) >> 16); + sum += (opus_int32)((coef_Q13_9 * state_9) >> 16); + + xmm_tempa = _mm_add_epi32( xmm_tempa, _mm_shuffle_epi32( xmm_tempa, _MM_SHUFFLE( 0, 0, 0, 2 ) ) ); + sum += _mm_cvtsi128_si32( xmm_tempa); + res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( ( 5 + sum ), 9); + + /* move right */ + state_a = state_9; + state_9 = state_8; + state_8 = _mm_cvtsi128_si32( state_4567 ); + state_4567 = _mm_alignr_epi8( state_0123, state_4567, 4 ); + + state_0123 = _mm_alignr_epi8( _mm_cvtsi32_si128( silk_LSHIFT( input[ n ], 14 ) ), state_0123, 4 ); + } + + _mm_storeu_si128( (__m128i *)( &state[ 0 ] ), _mm_shuffle_epi32( state_0123, _MM_SHUFFLE( 0, 1, 2, 3 ) ) ); + _mm_storeu_si128( (__m128i *)( &state[ 4 ] ), _mm_shuffle_epi32( state_4567, _MM_SHUFFLE( 0, 1, 2, 3 ) ) ); + state[ 8 ] = state_8; + state[ 9 ] = state_9; + state[ 10 ] = state_a; + + return; + } + } + + for( n = 0; n < length; n++ ) { + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 ); + state[ 0 ] = silk_LSHIFT( input[ n ], 14 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 ); + state[ 1 ] = tmp2; + acc_Q11 = silk_RSHIFT( order, 1 ); + acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( i = 2; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 ); + state[ i ] = tmp1; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 ); + state[ i + 1 ] = tmp2; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] ); + } + state[ order ] = tmp1; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] ); + res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( acc_Q11, 9 ); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/x86/vector_ops_FIX_sse4_1.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/x86/vector_ops_FIX_sse4_1.c new file mode 100644 index 000000000..c1e90564d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/fixed/x86/vector_ops_FIX_sse4_1.c @@ -0,0 +1,88 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "main.h" + +#include "SigProc_FIX.h" +#include "pitch.h" + +opus_int64 silk_inner_prod16_aligned_64_sse4_1( + const opus_int16 *inVec1, /* I input vector 1 */ + const opus_int16 *inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i, dataSize8; + opus_int64 sum; + + __m128i xmm_tempa; + __m128i inVec1_76543210, acc1; + __m128i inVec2_76543210, acc2; + + sum = 0; + dataSize8 = len & ~7; + + acc1 = _mm_setzero_si128(); + acc2 = _mm_setzero_si128(); + + for( i = 0; i < dataSize8; i += 8 ) { + inVec1_76543210 = _mm_loadu_si128( (__m128i *)(&inVec1[i + 0] ) ); + inVec2_76543210 = _mm_loadu_si128( (__m128i *)(&inVec2[i + 0] ) ); + + /* only when all 4 operands are -32768 (0x8000), this results in wrap around */ + inVec1_76543210 = _mm_madd_epi16( inVec1_76543210, inVec2_76543210 ); + + xmm_tempa = _mm_cvtepi32_epi64( inVec1_76543210 ); + /* equal shift right 8 bytes */ + inVec1_76543210 = _mm_shuffle_epi32( inVec1_76543210, _MM_SHUFFLE( 0, 0, 3, 2 ) ); + inVec1_76543210 = _mm_cvtepi32_epi64( inVec1_76543210 ); + + acc1 = _mm_add_epi64( acc1, xmm_tempa ); + acc2 = _mm_add_epi64( acc2, inVec1_76543210 ); + } + + acc1 = _mm_add_epi64( acc1, acc2 ); + + /* equal shift right 8 bytes */ + acc2 = _mm_shuffle_epi32( acc1, _MM_SHUFFLE( 0, 0, 3, 2 ) ); + acc1 = _mm_add_epi64( acc1, acc2 ); + + _mm_storel_epi64( (__m128i *)&sum, acc1 ); + + for( ; i < len; i++ ) { + sum = silk_SMLABB( sum, inVec1[ i ], inVec2[ i ] ); + } + + return sum; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/LPC_analysis_filter_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/LPC_analysis_filter_FLP.c new file mode 100644 index 000000000..0e1a1fed0 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/LPC_analysis_filter_FLP.c @@ -0,0 +1,249 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main_FLP.h" + +/************************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first Order output samples are set to zero */ +/************************************************/ + +/* 16th order LPC analysis filter, does not write first 16 samples */ +static OPUS_INLINE void silk_LPC_analysis_filter16_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 16; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ] + + s_ptr[ -8 ] * PredCoef[ 8 ] + + s_ptr[ -9 ] * PredCoef[ 9 ] + + s_ptr[ -10 ] * PredCoef[ 10 ] + + s_ptr[ -11 ] * PredCoef[ 11 ] + + s_ptr[ -12 ] * PredCoef[ 12 ] + + s_ptr[ -13 ] * PredCoef[ 13 ] + + s_ptr[ -14 ] * PredCoef[ 14 ] + + s_ptr[ -15 ] * PredCoef[ 15 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 12th order LPC analysis filter, does not write first 12 samples */ +static OPUS_INLINE void silk_LPC_analysis_filter12_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 12; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ] + + s_ptr[ -8 ] * PredCoef[ 8 ] + + s_ptr[ -9 ] * PredCoef[ 9 ] + + s_ptr[ -10 ] * PredCoef[ 10 ] + + s_ptr[ -11 ] * PredCoef[ 11 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 10th order LPC analysis filter, does not write first 10 samples */ +static OPUS_INLINE void silk_LPC_analysis_filter10_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 10; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ] + + s_ptr[ -8 ] * PredCoef[ 8 ] + + s_ptr[ -9 ] * PredCoef[ 9 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 8th order LPC analysis filter, does not write first 8 samples */ +static OPUS_INLINE void silk_LPC_analysis_filter8_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 8; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 6th order LPC analysis filter, does not write first 6 samples */ +static OPUS_INLINE void silk_LPC_analysis_filter6_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 6; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/************************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first Order output samples are set to zero */ +/************************************************/ +void silk_LPC_analysis_filter_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length, /* I Length of input signal */ + const opus_int Order /* I LPC order */ +) +{ + celt_assert( Order <= length ); + + switch( Order ) { + case 6: + silk_LPC_analysis_filter6_FLP( r_LPC, PredCoef, s, length ); + break; + + case 8: + silk_LPC_analysis_filter8_FLP( r_LPC, PredCoef, s, length ); + break; + + case 10: + silk_LPC_analysis_filter10_FLP( r_LPC, PredCoef, s, length ); + break; + + case 12: + silk_LPC_analysis_filter12_FLP( r_LPC, PredCoef, s, length ); + break; + + case 16: + silk_LPC_analysis_filter16_FLP( r_LPC, PredCoef, s, length ); + break; + + default: + celt_assert( 0 ); + break; + } + + /* Set first Order output samples to zero */ + silk_memset( r_LPC, 0, Order * sizeof( silk_float ) ); +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/LPC_inv_pred_gain_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/LPC_inv_pred_gain_FLP.c new file mode 100644 index 000000000..2be2122d6 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/LPC_inv_pred_gain_FLP.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "SigProc_FLP.h" +#include "define.h" + +/* compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +/* this code is based on silk_a2k_FLP() */ +silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */ + const silk_float *A, /* I prediction coefficients [order] */ + opus_int32 order /* I prediction order */ +) +{ + opus_int k, n; + double invGain, rc, rc_mult1, rc_mult2, tmp1, tmp2; + silk_float Atmp[ SILK_MAX_ORDER_LPC ]; + + silk_memcpy( Atmp, A, order * sizeof(silk_float) ); + + invGain = 1.0; + for( k = order - 1; k > 0; k-- ) { + rc = -Atmp[ k ]; + rc_mult1 = 1.0f - rc * rc; + invGain *= rc_mult1; + if( invGain * MAX_PREDICTION_POWER_GAIN < 1.0f ) { + return 0.0f; + } + rc_mult2 = 1.0f / rc_mult1; + for( n = 0; n < (k + 1) >> 1; n++ ) { + tmp1 = Atmp[ n ]; + tmp2 = Atmp[ k - n - 1 ]; + Atmp[ n ] = (silk_float)( ( tmp1 - tmp2 * rc ) * rc_mult2 ); + Atmp[ k - n - 1 ] = (silk_float)( ( tmp2 - tmp1 * rc ) * rc_mult2 ); + } + } + rc = -Atmp[ 0 ]; + rc_mult1 = 1.0f - rc * rc; + invGain *= rc_mult1; + if( invGain * MAX_PREDICTION_POWER_GAIN < 1.0f ) { + return 0.0f; + } + return (silk_float)invGain; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/LTP_analysis_filter_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/LTP_analysis_filter_FLP.c new file mode 100644 index 000000000..849b7c1c5 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/LTP_analysis_filter_FLP.c @@ -0,0 +1,75 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +void silk_LTP_analysis_filter_FLP( + silk_float *LTP_res, /* O LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */ + const silk_float *x, /* I Input signal, with preceding samples */ + const silk_float B[ LTP_ORDER * MAX_NB_SUBFR ], /* I LTP coefficients for each subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const silk_float invGains[ MAX_NB_SUBFR ], /* I Inverse quantization gains */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int pre_length /* I Preceding samples for each subframe */ +) +{ + const silk_float *x_ptr, *x_lag_ptr; + silk_float Btmp[ LTP_ORDER ]; + silk_float *LTP_res_ptr; + silk_float inv_gain; + opus_int k, i, j; + + x_ptr = x; + LTP_res_ptr = LTP_res; + for( k = 0; k < nb_subfr; k++ ) { + x_lag_ptr = x_ptr - pitchL[ k ]; + inv_gain = invGains[ k ]; + for( i = 0; i < LTP_ORDER; i++ ) { + Btmp[ i ] = B[ k * LTP_ORDER + i ]; + } + + /* LTP analysis FIR filter */ + for( i = 0; i < subfr_length + pre_length; i++ ) { + LTP_res_ptr[ i ] = x_ptr[ i ]; + /* Subtract long-term prediction */ + for( j = 0; j < LTP_ORDER; j++ ) { + LTP_res_ptr[ i ] -= Btmp[ j ] * x_lag_ptr[ LTP_ORDER / 2 - j ]; + } + LTP_res_ptr[ i ] *= inv_gain; + x_lag_ptr++; + } + + /* Update pointers */ + LTP_res_ptr += subfr_length + pre_length; + x_ptr += subfr_length; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/LTP_scale_ctrl_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/LTP_scale_ctrl_FLP.c new file mode 100644 index 000000000..8dbe29d0f --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/LTP_scale_ctrl_FLP.c @@ -0,0 +1,52 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +void silk_LTP_scale_ctrl_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int round_loss; + + if( condCoding == CODE_INDEPENDENTLY ) { + /* Only scale if first frame in packet */ + round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket; + psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT( round_loss * psEncCtrl->LTPredCodGain * 0.1f, 0.0f, 2.0f ); + } else { + /* Default is minimum scaling */ + psEnc->sCmn.indices.LTP_scaleIndex = 0; + } + + psEncCtrl->LTP_scale = (silk_float)silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ] / 16384.0f; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/SigProc_FLP.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/SigProc_FLP.h new file mode 100644 index 000000000..953de8b09 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/SigProc_FLP.h @@ -0,0 +1,197 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FLP_H +#define SILK_SIGPROC_FLP_H + +#include "SigProc_FIX.h" +#include "float_cast.h" +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************/ +/* SIGNAL PROCESSING FUNCTIONS */ +/********************************************************************/ + +/* Chirp (bw expand) LP AR filter */ +void silk_bwexpander_FLP( + silk_float *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I length of ar */ + const silk_float chirp /* I chirp factor (typically in range (0..1) ) */ +); + +/* compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +/* this code is based on silk_FLP_a2k() */ +silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */ + const silk_float *A, /* I prediction coefficients [order] */ + opus_int32 order /* I prediction order */ +); + +silk_float silk_schur_FLP( /* O returns residual energy */ + silk_float refl_coef[], /* O reflection coefficients (length order) */ + const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */ + opus_int order /* I order */ +); + +void silk_k2a_FLP( + silk_float *A, /* O prediction coefficients [order] */ + const silk_float *rc, /* I reflection coefficients [order] */ + opus_int32 order /* I prediction order */ +); + +/* compute autocorrelation */ +void silk_autocorrelation_FLP( + silk_float *results, /* O result (length correlationCount) */ + const silk_float *inputData, /* I input data to correlate */ + opus_int inputDataSize, /* I length of input */ + opus_int correlationCount /* I number of correlation taps to compute */ +); + +opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const silk_float *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O Pitch lag values [nb_subfr] */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + silk_float *LTPCorr, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const silk_float search_thres1, /* I First stage threshold for lag candidates 0 - 1 */ + const silk_float search_thres2, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr, /* I Number of 5 ms subframes */ + int arch /* I Run-time architecture */ +); + +void silk_insertion_sort_decreasing_FLP( + silk_float *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +/* Compute reflection coefficients from input signal */ +silk_float silk_burg_modified_FLP( /* O returns residual energy */ + silk_float A[], /* O prediction coefficients (length order) */ + const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */ + const silk_float minInvGain, /* I minimum inverse prediction gain */ + const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I number of subframes stacked in x */ + const opus_int D /* I order */ +); + +/* multiply a vector by a constant */ +void silk_scale_vector_FLP( + silk_float *data1, + silk_float gain, + opus_int dataSize +); + +/* copy and multiply a vector by a constant */ +void silk_scale_copy_vector_FLP( + silk_float *data_out, + const silk_float *data_in, + silk_float gain, + opus_int dataSize +); + +/* inner product of two silk_float arrays, with result as double */ +double silk_inner_product_FLP( + const silk_float *data1, + const silk_float *data2, + opus_int dataSize +); + +/* sum of squares of a silk_float array, with result as double */ +double silk_energy_FLP( + const silk_float *data, + opus_int dataSize +); + +/********************************************************************/ +/* MACROS */ +/********************************************************************/ + +#define PI (3.1415926536f) + +#define silk_min_float( a, b ) (((a) < (b)) ? (a) : (b)) +#define silk_max_float( a, b ) (((a) > (b)) ? (a) : (b)) +#define silk_abs_float( a ) ((silk_float)fabs(a)) + +/* sigmoid function */ +static OPUS_INLINE silk_float silk_sigmoid( silk_float x ) +{ + return (silk_float)(1.0 / (1.0 + exp(-x))); +} + +/* floating-point to integer conversion (rounding) */ +static OPUS_INLINE opus_int32 silk_float2int( silk_float x ) +{ + return (opus_int32)float2int( x ); +} + +/* floating-point to integer conversion (rounding) */ +static OPUS_INLINE void silk_float2short_array( + opus_int16 *out, + const silk_float *in, + opus_int32 length +) +{ + opus_int32 k; + for( k = length - 1; k >= 0; k-- ) { + out[k] = silk_SAT16( (opus_int32)float2int( in[k] ) ); + } +} + +/* integer to floating-point conversion */ +static OPUS_INLINE void silk_short2float_array( + silk_float *out, + const opus_int16 *in, + opus_int32 length +) +{ + opus_int32 k; + for( k = length - 1; k >= 0; k-- ) { + out[k] = (silk_float)in[k]; + } +} + +/* using log2() helps the fixed-point conversion */ +static OPUS_INLINE silk_float silk_log2( double x ) +{ + return ( silk_float )( 3.32192809488736 * log10( x ) ); +} + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_SIGPROC_FLP_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/apply_sine_window_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/apply_sine_window_FLP.c new file mode 100644 index 000000000..e49e71799 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/apply_sine_window_FLP.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Apply sine window to signal vector */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +void silk_apply_sine_window_FLP( + silk_float px_win[], /* O Pointer to windowed signal */ + const silk_float px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +) +{ + opus_int k; + silk_float freq, c, S0, S1; + + celt_assert( win_type == 1 || win_type == 2 ); + + /* Length must be multiple of 4 */ + celt_assert( ( length & 3 ) == 0 ); + + freq = PI / ( length + 1 ); + + /* Approximation of 2 * cos(f) */ + c = 2.0f - freq * freq; + + /* Initialize state */ + if( win_type < 2 ) { + /* Start from 0 */ + S0 = 0.0f; + /* Approximation of sin(f) */ + S1 = freq; + } else { + /* Start from 1 */ + S0 = 1.0f; + /* Approximation of cos(f) */ + S1 = 0.5f * c; + } + + /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */ + /* 4 samples at a time */ + for( k = 0; k < length; k += 4 ) { + px_win[ k + 0 ] = px[ k + 0 ] * 0.5f * ( S0 + S1 ); + px_win[ k + 1 ] = px[ k + 1 ] * S1; + S0 = c * S1 - S0; + px_win[ k + 2 ] = px[ k + 2 ] * 0.5f * ( S1 + S0 ); + px_win[ k + 3 ] = px[ k + 3 ] * S0; + S1 = c * S0 - S1; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/autocorrelation_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/autocorrelation_FLP.c new file mode 100644 index 000000000..8b8a9e659 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/autocorrelation_FLP.c @@ -0,0 +1,52 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "typedef.h" +#include "SigProc_FLP.h" + +/* compute autocorrelation */ +void silk_autocorrelation_FLP( + silk_float *results, /* O result (length correlationCount) */ + const silk_float *inputData, /* I input data to correlate */ + opus_int inputDataSize, /* I length of input */ + opus_int correlationCount /* I number of correlation taps to compute */ +) +{ + opus_int i; + + if( correlationCount > inputDataSize ) { + correlationCount = inputDataSize; + } + + for( i = 0; i < correlationCount; i++ ) { + results[ i ] = (silk_float)silk_inner_product_FLP( inputData, inputData + i, inputDataSize - i ); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/burg_modified_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/burg_modified_FLP.c new file mode 100644 index 000000000..756b76a35 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/burg_modified_FLP.c @@ -0,0 +1,186 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" +#include "tuning_parameters.h" +#include "define.h" + +#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384*/ + +/* Compute reflection coefficients from input signal */ +silk_float silk_burg_modified_FLP( /* O returns residual energy */ + silk_float A[], /* O prediction coefficients (length order) */ + const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */ + const silk_float minInvGain, /* I minimum inverse prediction gain */ + const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I number of subframes stacked in x */ + const opus_int D /* I order */ +) +{ + opus_int k, n, s, reached_max_gain; + double C0, invGain, num, nrg_f, nrg_b, rc, Atmp, tmp1, tmp2; + const silk_float *x_ptr; + double C_first_row[ SILK_MAX_ORDER_LPC ], C_last_row[ SILK_MAX_ORDER_LPC ]; + double CAf[ SILK_MAX_ORDER_LPC + 1 ], CAb[ SILK_MAX_ORDER_LPC + 1 ]; + double Af[ SILK_MAX_ORDER_LPC ]; + + celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + + /* Compute autocorrelations, added over subframes */ + C0 = silk_energy_FLP( x, nb_subfr * subfr_length ); + silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( double ) ); + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += silk_inner_product_FLP( x_ptr, x_ptr + n, subfr_length - n ); + } + } + silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( double ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + FIND_LPC_COND_FAC * C0 + 1e-9f; + invGain = 1.0f; + reached_max_gain = 0; + for( n = 0; n < D; n++ ) { + /* Update first row of correlation matrix (without first element) */ + /* Update last row of correlation matrix (without last element, stored in reversed order) */ + /* Update C * Af */ + /* Update C * flipud(Af) (stored in reversed order) */ + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + tmp1 = x_ptr[ n ]; + tmp2 = x_ptr[ subfr_length - n - 1 ]; + for( k = 0; k < n; k++ ) { + C_first_row[ k ] -= x_ptr[ n ] * x_ptr[ n - k - 1 ]; + C_last_row[ k ] -= x_ptr[ subfr_length - n - 1 ] * x_ptr[ subfr_length - n + k ]; + Atmp = Af[ k ]; + tmp1 += x_ptr[ n - k - 1 ] * Atmp; + tmp2 += x_ptr[ subfr_length - n + k ] * Atmp; + } + for( k = 0; k <= n; k++ ) { + CAf[ k ] -= tmp1 * x_ptr[ n - k ]; + CAb[ k ] -= tmp2 * x_ptr[ subfr_length - n + k - 1 ]; + } + } + tmp1 = C_first_row[ n ]; + tmp2 = C_last_row[ n ]; + for( k = 0; k < n; k++ ) { + Atmp = Af[ k ]; + tmp1 += C_last_row[ n - k - 1 ] * Atmp; + tmp2 += C_first_row[ n - k - 1 ] * Atmp; + } + CAf[ n + 1 ] = tmp1; + CAb[ n + 1 ] = tmp2; + + /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ + num = CAb[ n + 1 ]; + nrg_b = CAb[ 0 ]; + nrg_f = CAf[ 0 ]; + for( k = 0; k < n; k++ ) { + Atmp = Af[ k ]; + num += CAb[ n - k ] * Atmp; + nrg_b += CAb[ k + 1 ] * Atmp; + nrg_f += CAf[ k + 1 ] * Atmp; + } + silk_assert( nrg_f > 0.0 ); + silk_assert( nrg_b > 0.0 ); + + /* Calculate the next order reflection (parcor) coefficient */ + rc = -2.0 * num / ( nrg_f + nrg_b ); + silk_assert( rc > -1.0 && rc < 1.0 ); + + /* Update inverse prediction gain */ + tmp1 = invGain * ( 1.0 - rc * rc ); + if( tmp1 <= minInvGain ) { + /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ + rc = sqrt( 1.0 - minInvGain / invGain ); + if( num > 0 ) { + /* Ensure adjusted reflection coefficients has the original sign */ + rc = -rc; + } + invGain = minInvGain; + reached_max_gain = 1; + } else { + invGain = tmp1; + } + + /* Update the AR coefficients */ + for( k = 0; k < (n + 1) >> 1; k++ ) { + tmp1 = Af[ k ]; + tmp2 = Af[ n - k - 1 ]; + Af[ k ] = tmp1 + rc * tmp2; + Af[ n - k - 1 ] = tmp2 + rc * tmp1; + } + Af[ n ] = rc; + + if( reached_max_gain ) { + /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ + for( k = n + 1; k < D; k++ ) { + Af[ k ] = 0.0; + } + break; + } + + /* Update C * Af and C * Ab */ + for( k = 0; k <= n + 1; k++ ) { + tmp1 = CAf[ k ]; + CAf[ k ] += rc * CAb[ n - k + 1 ]; + CAb[ n - k + 1 ] += rc * tmp1; + } + } + + if( reached_max_gain ) { + /* Convert to silk_float */ + for( k = 0; k < D; k++ ) { + A[ k ] = (silk_float)( -Af[ k ] ); + } + /* Subtract energy of preceding samples from C0 */ + for( s = 0; s < nb_subfr; s++ ) { + C0 -= silk_energy_FLP( x + s * subfr_length, D ); + } + /* Approximate residual energy */ + nrg_f = C0 * invGain; + } else { + /* Compute residual energy and store coefficients as silk_float */ + nrg_f = CAf[ 0 ]; + tmp1 = 1.0; + for( k = 0; k < D; k++ ) { + Atmp = Af[ k ]; + nrg_f += CAf[ k + 1 ] * Atmp; + tmp1 += Atmp * Atmp; + A[ k ] = (silk_float)(-Atmp); + } + nrg_f -= FIND_LPC_COND_FAC * C0 * tmp1; + } + + /* Return residual energy */ + return (silk_float)nrg_f; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/bwexpander_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/bwexpander_FLP.c new file mode 100644 index 000000000..d55a4d79a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/bwexpander_FLP.c @@ -0,0 +1,49 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* Chirp (bw expand) LP AR filter */ +void silk_bwexpander_FLP( + silk_float *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I length of ar */ + const silk_float chirp /* I chirp factor (typically in range (0..1) ) */ +) +{ + opus_int i; + silk_float cfac = chirp; + + for( i = 0; i < d - 1; i++ ) { + ar[ i ] *= cfac; + cfac *= chirp; + } + ar[ d - 1 ] *= cfac; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/corrMatrix_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/corrMatrix_FLP.c new file mode 100644 index 000000000..eae6a1cfc --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/corrMatrix_FLP.c @@ -0,0 +1,93 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/********************************************************************** + * Correlation matrix computations for LS estimate. + **********************************************************************/ + +#include "main_FLP.h" + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FLP( + const silk_float *x, /* I x vector [L+order-1] used to create X */ + const silk_float *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vecors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *Xt /* O X'*t correlation vector [order] */ +) +{ + opus_int lag; + const silk_float *ptr1; + + ptr1 = &x[ Order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */ + for( lag = 0; lag < Order; lag++ ) { + /* Calculate X[:,lag]'*t */ + Xt[ lag ] = (silk_float)silk_inner_product_FLP( ptr1, t, L ); + ptr1--; /* Next column of X */ + } +} + +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FLP( + const silk_float *x, /* I x vector [ L+order-1 ] used to create X */ + const opus_int L, /* I Length of vectors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *XX /* O X'*X correlation matrix [order x order] */ +) +{ + opus_int j, lag; + double energy; + const silk_float *ptr1, *ptr2; + + ptr1 = &x[ Order - 1 ]; /* First sample of column 0 of X */ + energy = silk_energy_FLP( ptr1, L ); /* X[:,0]'*X[:,0] */ + matrix_ptr( XX, 0, 0, Order ) = ( silk_float )energy; + for( j = 1; j < Order; j++ ) { + /* Calculate X[:,j]'*X[:,j] */ + energy += ptr1[ -j ] * ptr1[ -j ] - ptr1[ L - j ] * ptr1[ L - j ]; + matrix_ptr( XX, j, j, Order ) = ( silk_float )energy; + } + + ptr2 = &x[ Order - 2 ]; /* First sample of column 1 of X */ + for( lag = 1; lag < Order; lag++ ) { + /* Calculate X[:,0]'*X[:,lag] */ + energy = silk_inner_product_FLP( ptr1, ptr2, L ); + matrix_ptr( XX, lag, 0, Order ) = ( silk_float )energy; + matrix_ptr( XX, 0, lag, Order ) = ( silk_float )energy; + /* Calculate X[:,j]'*X[:,j + lag] */ + for( j = 1; j < ( Order - lag ); j++ ) { + energy += ptr1[ -j ] * ptr2[ -j ] - ptr1[ L - j ] * ptr2[ L - j ]; + matrix_ptr( XX, lag + j, j, Order ) = ( silk_float )energy; + matrix_ptr( XX, j, lag + j, Order ) = ( silk_float )energy; + } + ptr2--; /* Next column of X */ + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/encode_frame_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/encode_frame_FLP.c new file mode 100644 index 000000000..b029c3f5c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/encode_frame_FLP.c @@ -0,0 +1,435 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */ +static OPUS_INLINE void silk_LBRR_encode_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float xfw[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +); + +void silk_encode_do_VAD_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int activity /* I Decision of Opus voice activity detector */ +) +{ + const opus_int activity_threshold = SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ); + + /****************************/ + /* Voice Activity Detection */ + /****************************/ + silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch ); + /* If Opus VAD is inactive and Silk VAD is active: lower Silk VAD to just under the threshold */ + if( activity == VAD_NO_ACTIVITY && psEnc->sCmn.speech_activity_Q8 >= activity_threshold ) { + psEnc->sCmn.speech_activity_Q8 = activity_threshold - 1; + } + + /**************************************************/ + /* Convert speech activity into VAD and DTX flags */ + /**************************************************/ + if( psEnc->sCmn.speech_activity_Q8 < activity_threshold ) { + psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->sCmn.noSpeechCounter++; + if( psEnc->sCmn.noSpeechCounter <= NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.inDTX = 0; + } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX; + psEnc->sCmn.inDTX = 0; + } + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0; + } else { + psEnc->sCmn.noSpeechCounter = 0; + psEnc->sCmn.inDTX = 0; + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + } +} + +/****************/ +/* Encode frame */ +/****************/ +opus_int silk_encode_frame_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int32 *pnBytesOut, /* O Number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +) +{ + silk_encoder_control_FLP sEncCtrl; + opus_int i, iter, maxIter, found_upper, found_lower, ret = 0; + silk_float *x_frame, *res_pitch_frame; + silk_float res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ]; + ec_enc sRangeEnc_copy, sRangeEnc_copy2; + silk_nsq_state sNSQ_copy, sNSQ_copy2; + opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper; + opus_int32 gainsID, gainsID_lower, gainsID_upper; + opus_int16 gainMult_Q8; + opus_int16 ec_prevLagIndex_copy; + opus_int ec_prevSignalType_copy; + opus_int8 LastGainIndex_copy2; + opus_int32 pGains_Q16[ MAX_NB_SUBFR ]; + opus_uint8 ec_buf_copy[ 1275 ]; + opus_int gain_lock[ MAX_NB_SUBFR ] = {0}; + opus_int16 best_gain_mult[ MAX_NB_SUBFR ]; + opus_int best_sum[ MAX_NB_SUBFR ]; + + /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */ + LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0; + + psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3; + + /**************************************************************/ + /* Set up Input Pointers, and insert frame in input buffer */ + /**************************************************************/ + /* pointers aligned with start of frame to encode */ + x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length; /* start of frame to encode */ + res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length; /* start of pitch LPC residual frame */ + + /***************************************/ + /* Ensure smooth bandwidth transitions */ + /***************************************/ + silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); + + /*******************************************/ + /* Copy new frame to front of input buffer */ + /*******************************************/ + silk_short2float_array( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); + + /* Add tiny signal to avoid high CPU load from denormalized floating point numbers */ + for( i = 0; i < 8; i++ ) { + x_frame[ LA_SHAPE_MS * psEnc->sCmn.fs_kHz + i * ( psEnc->sCmn.frame_length >> 3 ) ] += ( 1 - ( i & 2 ) ) * 1e-6f; + } + + if( !psEnc->sCmn.prefillFlag ) { + /*****************************************/ + /* Find pitch lags, initial LPC analysis */ + /*****************************************/ + silk_find_pitch_lags_FLP( psEnc, &sEncCtrl, res_pitch, x_frame, psEnc->sCmn.arch ); + + /************************/ + /* Noise shape analysis */ + /************************/ + silk_noise_shape_analysis_FLP( psEnc, &sEncCtrl, res_pitch_frame, x_frame ); + + /***************************************************/ + /* Find linear prediction coefficients (LPC + LTP) */ + /***************************************************/ + silk_find_pred_coefs_FLP( psEnc, &sEncCtrl, res_pitch_frame, x_frame, condCoding ); + + /****************************************/ + /* Process gains */ + /****************************************/ + silk_process_gains_FLP( psEnc, &sEncCtrl, condCoding ); + + /****************************************/ + /* Low Bitrate Redundant Encoding */ + /****************************************/ + silk_LBRR_encode_FLP( psEnc, &sEncCtrl, x_frame, condCoding ); + + /* Loop over quantizer and entroy coding to control bitrate */ + maxIter = 6; + gainMult_Q8 = SILK_FIX_CONST( 1, 8 ); + found_lower = 0; + found_upper = 0; + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + gainsID_lower = -1; + gainsID_upper = -1; + /* Copy part of the input state */ + silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) ); + silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + seed_copy = psEnc->sCmn.indices.Seed; + ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex; + ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType; + for( iter = 0; ; iter++ ) { + if( gainsID == gainsID_lower ) { + nBits = nBits_lower; + } else if( gainsID == gainsID_upper ) { + nBits = nBits_upper; + } else { + /* Restore part of the input state */ + if( iter > 0 ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) ); + psEnc->sCmn.indices.Seed = seed_copy; + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + silk_NSQ_wrapper_FLP( psEnc, &sEncCtrl, &psEnc->sCmn.indices, &psEnc->sCmn.sNSQ, psEnc->sCmn.pulses, x_frame ); + + if ( iter == maxIter && !found_lower ) { + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + } + + /****************************************/ + /* Encode Parameters */ + /****************************************/ + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + /****************************************/ + /* Encode Excitation Signal */ + /****************************************/ + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + + /* If we still bust after the last iteration, do some damage control. */ + if ( iter == maxIter && !found_lower && nBits > maxBits ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + + /* Keep gains the same as the last frame. */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + psEnc->sCmn.indices.GainsIndices[ i ] = 4; + } + if (condCoding != CODE_CONDITIONALLY) { + psEnc->sCmn.indices.GainsIndices[ 0 ] = sEncCtrl.lastGainIndexPrev; + } + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + /* Clear all pulses. */ + for ( i = 0; i < psEnc->sCmn.frame_length; i++ ) { + psEnc->sCmn.pulses[ i ] = 0; + } + + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + } + + if( useCBR == 0 && iter == 0 && nBits <= maxBits ) { + break; + } + } + + if( iter == maxIter ) { + if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) { + /* Restore output state from earlier iteration that did meet the bitrate budget */ + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + celt_assert( sRangeEnc_copy2.offs <= 1275 ); + silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) ); + psEnc->sShape.LastGainIndex = LastGainIndex_copy2; + } + break; + } + + if( nBits > maxBits ) { + if( found_lower == 0 && iter >= 2 ) { + /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */ + sEncCtrl.Lambda = silk_max_float(sEncCtrl.Lambda*1.5f, 1.5f); + /* Reducing dithering can help us hit the target. */ + psEnc->sCmn.indices.quantOffsetType = 0; + found_upper = 0; + gainsID_upper = -1; + } else { + found_upper = 1; + nBits_upper = nBits; + gainMult_upper = gainMult_Q8; + gainsID_upper = gainsID; + } + } else if( nBits < maxBits - 5 ) { + found_lower = 1; + nBits_lower = nBits; + gainMult_lower = gainMult_Q8; + if( gainsID != gainsID_lower ) { + gainsID_lower = gainsID; + /* Copy part of the output state */ + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + celt_assert( psRangeEnc->offs <= 1275 ); + silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs ); + silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + LastGainIndex_copy2 = psEnc->sShape.LastGainIndex; + } + } else { + /* Within 5 bits of budget: close enough */ + break; + } + + if ( !found_lower && nBits > maxBits ) { + int j; + for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + int sum=0; + for ( j = i*psEnc->sCmn.subfr_length; j < (i+1)*psEnc->sCmn.subfr_length; j++ ) { + sum += abs( psEnc->sCmn.pulses[j] ); + } + if ( iter == 0 || (sum < best_sum[i] && !gain_lock[i]) ) { + best_sum[i] = sum; + best_gain_mult[i] = gainMult_Q8; + } else { + gain_lock[i] = 1; + } + } + } + if( ( found_lower & found_upper ) == 0 ) { + /* Adjust gain according to high-rate rate/distortion curve */ + if( nBits > maxBits ) { + if (gainMult_Q8 < 16384) { + gainMult_Q8 *= 2; + } else { + gainMult_Q8 = 32767; + } + } else { + opus_int32 gain_factor_Q16; + gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) ); + gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 ); + } + } else { + /* Adjust gain by interpolating */ + gainMult_Q8 = gainMult_lower + ( ( gainMult_upper - gainMult_lower ) * ( maxBits - nBits_lower ) ) / ( nBits_upper - nBits_lower ); + /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */ + if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ); + } else + if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + opus_int16 tmp; + if ( gain_lock[i] ) { + tmp = best_gain_mult[i]; + } else { + tmp = gainMult_Q8; + } + pGains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], tmp ), 8 ); + } + + /* Quantize gains */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16, + &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Unique identifier of gains vector */ + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + sEncCtrl.Gains[ i ] = pGains_Q16[ i ] / 65536.0f; + } + } + } + + /* Update input buffer */ + silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ], + ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( silk_float ) ); + + /* Exit without entropy coding */ + if( psEnc->sCmn.prefillFlag ) { + /* No payload */ + *pnBytesOut = 0; + return ret; + } + + /* Parameters needed for next frame */ + psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ]; + psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType; + + /****************************************/ + /* Finalize payload */ + /****************************************/ + psEnc->sCmn.first_frame_after_reset = 0; + /* Payload size */ + *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 ); + + return ret; +} + +/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */ +static OPUS_INLINE void silk_LBRR_encode_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float xfw[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +) +{ + opus_int k; + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + silk_float TempGains[ MAX_NB_SUBFR ]; + SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ]; + silk_nsq_state sNSQ_LBRR; + + /*******************************************/ + /* Control use of inband LBRR */ + /*******************************************/ + if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) { + psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + + /* Copy noise shaping quantizer state and quantization indices from regular encoding */ + silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) ); + + /* Save original gains */ + silk_memcpy( TempGains, psEncCtrl->Gains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) ); + + if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) { + /* First frame in packet or previous frame not LBRR coded */ + psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex; + + /* Increase Gains to get target LBRR rate */ + psIndices_LBRR->GainsIndices[ 0 ] += psEnc->sCmn.LBRR_GainIncreases; + psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 ); + } + + /* Decode to get gains in sync with decoder */ + silk_gains_dequant( Gains_Q16, psIndices_LBRR->GainsIndices, + &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] = Gains_Q16[ k ] * ( 1.0f / 65536.0f ); + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + silk_NSQ_wrapper_FLP( psEnc, psEncCtrl, psIndices_LBRR, &sNSQ_LBRR, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], xfw ); + + /* Restore original gains */ + silk_memcpy( psEncCtrl->Gains, TempGains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) ); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/energy_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/energy_FLP.c new file mode 100644 index 000000000..7bc7173c9 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/energy_FLP.c @@ -0,0 +1,59 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* sum of squares of a silk_float array, with result as double */ +double silk_energy_FLP( + const silk_float *data, + opus_int dataSize +) +{ + opus_int i; + double result; + + /* 4x unrolled loop */ + result = 0.0; + for( i = 0; i < dataSize - 3; i += 4 ) { + result += data[ i + 0 ] * (double)data[ i + 0 ] + + data[ i + 1 ] * (double)data[ i + 1 ] + + data[ i + 2 ] * (double)data[ i + 2 ] + + data[ i + 3 ] * (double)data[ i + 3 ]; + } + + /* add any remaining products */ + for( ; i < dataSize; i++ ) { + result += data[ i ] * (double)data[ i ]; + } + + silk_assert( result >= 0.0 ); + return result; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/find_LPC_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/find_LPC_FLP.c new file mode 100644 index 000000000..fa3ffe7f8 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/find_LPC_FLP.c @@ -0,0 +1,104 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "define.h" +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* LPC analysis */ +void silk_find_LPC_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const silk_float x[], /* I Input signal */ + const silk_float minInvGain /* I Inverse of max prediction gain */ +) +{ + opus_int k, subfr_length; + silk_float a[ MAX_LPC_ORDER ]; + + /* Used only for NLSF interpolation */ + silk_float res_nrg, res_nrg_2nd, res_nrg_interp; + opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ]; + silk_float a_tmp[ MAX_LPC_ORDER ]; + silk_float LPC_res[ MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ]; + + subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder; + + /* Default: No interpolation */ + psEncC->indices.NLSFInterpCoef_Q2 = 4; + + /* Burg AR analysis for the full frame */ + res_nrg = silk_burg_modified_FLP( a, x, minInvGain, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder ); + + if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) { + /* Optimal solution for last 10 ms; subtract residual energy here, as that's easier than */ + /* adding it to the residual energy of the first 10 ms in each iteration of the search below */ + res_nrg -= silk_burg_modified_FLP( a_tmp, x + ( MAX_NB_SUBFR / 2 ) * subfr_length, minInvGain, subfr_length, MAX_NB_SUBFR / 2, psEncC->predictLPCOrder ); + + /* Convert to NLSFs */ + silk_A2NLSF_FLP( NLSF_Q15, a_tmp, psEncC->predictLPCOrder ); + + /* Search over interpolation indices to find the one with lowest residual energy */ + res_nrg_2nd = silk_float_MAX; + for( k = 3; k >= 0; k-- ) { + /* Interpolate NLSFs for first half */ + silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder ); + + /* Convert to LPC for residual energy evaluation */ + silk_NLSF2A_FLP( a_tmp, NLSF0_Q15, psEncC->predictLPCOrder, psEncC->arch ); + + /* Calculate residual energy with LSF interpolation */ + silk_LPC_analysis_filter_FLP( LPC_res, a_tmp, x, 2 * subfr_length, psEncC->predictLPCOrder ); + res_nrg_interp = (silk_float)( + silk_energy_FLP( LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder ) + + silk_energy_FLP( LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder ) ); + + /* Determine whether current interpolated NLSFs are best so far */ + if( res_nrg_interp < res_nrg ) { + /* Interpolation has lower residual energy */ + res_nrg = res_nrg_interp; + psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k; + } else if( res_nrg_interp > res_nrg_2nd ) { + /* No reason to continue iterating - residual energies will continue to climb */ + break; + } + res_nrg_2nd = res_nrg_interp; + } + } + + if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) { + /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ + silk_A2NLSF_FLP( NLSF_Q15, a, psEncC->predictLPCOrder ); + } + + celt_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || + ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/find_LTP_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/find_LTP_FLP.c new file mode 100644 index 000000000..f97064930 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/find_LTP_FLP.c @@ -0,0 +1,64 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +void silk_find_LTP_FLP( + silk_float XX[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + silk_float xX[ MAX_NB_SUBFR * LTP_ORDER ], /* O Weight for LTP quantization */ + const silk_float r_ptr[], /* I LPC residual */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k; + silk_float *xX_ptr, *XX_ptr; + const silk_float *lag_ptr; + silk_float xx, temp; + + xX_ptr = xX; + XX_ptr = XX; + for( k = 0; k < nb_subfr; k++ ) { + lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 ); + silk_corrMatrix_FLP( lag_ptr, subfr_length, LTP_ORDER, XX_ptr ); + silk_corrVector_FLP( lag_ptr, r_ptr, subfr_length, LTP_ORDER, xX_ptr ); + xx = ( silk_float )silk_energy_FLP( r_ptr, subfr_length + LTP_ORDER ); + temp = 1.0f / silk_max( xx, LTP_CORR_INV_MAX * 0.5f * ( XX_ptr[ 0 ] + XX_ptr[ 24 ] ) + 1.0f ); + silk_scale_vector_FLP( XX_ptr, temp, LTP_ORDER * LTP_ORDER ); + silk_scale_vector_FLP( xX_ptr, temp, LTP_ORDER ); + + r_ptr += subfr_length; + XX_ptr += LTP_ORDER * LTP_ORDER; + xX_ptr += LTP_ORDER; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/find_pitch_lags_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/find_pitch_lags_FLP.c new file mode 100644 index 000000000..dedbcd283 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/find_pitch_lags_FLP.c @@ -0,0 +1,132 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main_FLP.h" +#include "tuning_parameters.h" + +void silk_find_pitch_lags_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + silk_float res[], /* O Residual */ + const silk_float x[], /* I Speech signal */ + int arch /* I Run-time architecture */ +) +{ + opus_int buf_len; + silk_float thrhld, res_nrg; + const silk_float *x_buf_ptr, *x_buf; + silk_float auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ]; + silk_float A[ MAX_FIND_PITCH_LPC_ORDER ]; + silk_float refl_coef[ MAX_FIND_PITCH_LPC_ORDER ]; + silk_float Wsig[ FIND_PITCH_LPC_WIN_MAX ]; + silk_float *Wsig_ptr; + + /******************************************/ + /* Set up buffer lengths etc based on Fs */ + /******************************************/ + buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length; + + /* Safety check */ + celt_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length ); + + x_buf = x - psEnc->sCmn.ltp_mem_length; + + /******************************************/ + /* Estimate LPC AR coeficients */ + /******************************************/ + + /* Calculate windowed signal */ + + /* First LA_LTP samples */ + x_buf_ptr = x_buf + buf_len - psEnc->sCmn.pitch_LPC_win_length; + Wsig_ptr = Wsig; + silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 1, psEnc->sCmn.la_pitch ); + + /* Middle non-windowed samples */ + Wsig_ptr += psEnc->sCmn.la_pitch; + x_buf_ptr += psEnc->sCmn.la_pitch; + silk_memcpy( Wsig_ptr, x_buf_ptr, ( psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ) ) * sizeof( silk_float ) ); + + /* Last LA_LTP samples */ + Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ); + x_buf_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ); + silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch ); + + /* Calculate autocorrelation sequence */ + silk_autocorrelation_FLP( auto_corr, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1 ); + + /* Add white noise, as a fraction of the energy */ + auto_corr[ 0 ] += auto_corr[ 0 ] * FIND_PITCH_WHITE_NOISE_FRACTION + 1; + + /* Calculate the reflection coefficients using Schur */ + res_nrg = silk_schur_FLP( refl_coef, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Prediction gain */ + psEncCtrl->predGain = auto_corr[ 0 ] / silk_max_float( res_nrg, 1.0f ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a_FLP( A, refl_coef, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Bandwidth expansion */ + silk_bwexpander_FLP( A, psEnc->sCmn.pitchEstimationLPCOrder, FIND_PITCH_BANDWIDTH_EXPANSION ); + + /*****************************************/ + /* LPC analysis filtering */ + /*****************************************/ + silk_LPC_analysis_filter_FLP( res, A, x_buf, buf_len, psEnc->sCmn.pitchEstimationLPCOrder ); + + if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) { + /* Threshold for pitch estimator */ + thrhld = 0.6f; + thrhld -= 0.004f * psEnc->sCmn.pitchEstimationLPCOrder; + thrhld -= 0.1f * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + thrhld -= 0.15f * (psEnc->sCmn.prevSignalType >> 1); + thrhld -= 0.1f * psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f ); + + /*****************************************/ + /* Call Pitch estimator */ + /*****************************************/ + if( silk_pitch_analysis_core_FLP( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, + &psEnc->sCmn.indices.contourIndex, &psEnc->LTPCorr, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16 / 65536.0f, + thrhld, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr, arch ) == 0 ) + { + psEnc->sCmn.indices.signalType = TYPE_VOICED; + } else { + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + } + } else { + silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) ); + psEnc->sCmn.indices.lagIndex = 0; + psEnc->sCmn.indices.contourIndex = 0; + psEnc->LTPCorr = 0; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/find_pred_coefs_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/find_pred_coefs_FLP.c new file mode 100644 index 000000000..dcf7c5202 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/find_pred_coefs_FLP.c @@ -0,0 +1,116 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Find LPC and LTP coefficients */ +void silk_find_pred_coefs_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float res_pitch[], /* I Residual from pitch analysis */ + const silk_float x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i; + silk_float XXLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ]; + silk_float xXLTP[ MAX_NB_SUBFR * LTP_ORDER ]; + silk_float invGains[ MAX_NB_SUBFR ]; + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ]; + const silk_float *x_ptr; + silk_float *x_pre_ptr, LPC_in_pre[ MAX_NB_SUBFR * MAX_LPC_ORDER + MAX_FRAME_LENGTH ]; + silk_float minInvGain; + + /* Weighting for weighted least squares */ + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + silk_assert( psEncCtrl->Gains[ i ] > 0.0f ); + invGains[ i ] = 1.0f / psEncCtrl->Gains[ i ]; + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /**********/ + /* VOICED */ + /**********/ + celt_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 ); + + /* LTP analysis */ + silk_find_LTP_FLP( XXLTP, xXLTP, res_pitch, psEncCtrl->pitchL, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr ); + + /* Quantize LTP gain parameters */ + silk_quant_LTP_gains_FLP( psEncCtrl->LTPCoef, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex, + &psEnc->sCmn.sum_log_gain_Q7, &psEncCtrl->LTPredCodGain, XXLTP, xXLTP, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.arch ); + + /* Control LTP scaling */ + silk_LTP_scale_ctrl_FLP( psEnc, psEncCtrl, condCoding ); + + /* Create LTP residual */ + silk_LTP_analysis_filter_FLP( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef, + psEncCtrl->pitchL, invGains, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + } else { + /************/ + /* UNVOICED */ + /************/ + /* Create signal with prepended subframes, scaled by inverse gains */ + x_ptr = x - psEnc->sCmn.predictLPCOrder; + x_pre_ptr = LPC_in_pre; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + silk_scale_copy_vector_FLP( x_pre_ptr, x_ptr, invGains[ i ], + psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder ); + x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder; + x_ptr += psEnc->sCmn.subfr_length; + } + silk_memset( psEncCtrl->LTPCoef, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( silk_float ) ); + psEncCtrl->LTPredCodGain = 0.0f; + psEnc->sCmn.sum_log_gain_Q7 = 0; + } + + /* Limit on total predictive coding gain */ + if( psEnc->sCmn.first_frame_after_reset ) { + minInvGain = 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET; + } else { + minInvGain = (silk_float)pow( 2, psEncCtrl->LTPredCodGain / 3 ) / MAX_PREDICTION_POWER_GAIN; + minInvGain /= 0.25f + 0.75f * psEncCtrl->coding_quality; + } + + /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */ + silk_find_LPC_FLP( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain ); + + /* Quantize LSFs */ + silk_process_NLSFs_FLP( &psEnc->sCmn, psEncCtrl->PredCoef, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 ); + + /* Calculate residual energy using quantized LPC coefficients */ + silk_residual_energy_FLP( psEncCtrl->ResNrg, LPC_in_pre, psEncCtrl->PredCoef, psEncCtrl->Gains, + psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + + /* Copy to prediction struct for use in next frame for interpolation */ + silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/inner_product_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/inner_product_FLP.c new file mode 100644 index 000000000..cdd39d24c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/inner_product_FLP.c @@ -0,0 +1,59 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* inner product of two silk_float arrays, with result as double */ +double silk_inner_product_FLP( + const silk_float *data1, + const silk_float *data2, + opus_int dataSize +) +{ + opus_int i; + double result; + + /* 4x unrolled loop */ + result = 0.0; + for( i = 0; i < dataSize - 3; i += 4 ) { + result += data1[ i + 0 ] * (double)data2[ i + 0 ] + + data1[ i + 1 ] * (double)data2[ i + 1 ] + + data1[ i + 2 ] * (double)data2[ i + 2 ] + + data1[ i + 3 ] * (double)data2[ i + 3 ]; + } + + /* add any remaining products */ + for( ; i < dataSize; i++ ) { + result += data1[ i ] * (double)data2[ i ]; + } + + return result; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/k2a_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/k2a_FLP.c new file mode 100644 index 000000000..1448008db --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/k2a_FLP.c @@ -0,0 +1,54 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_FLP( + silk_float *A, /* O prediction coefficients [order] */ + const silk_float *rc, /* I reflection coefficients [order] */ + opus_int32 order /* I prediction order */ +) +{ + opus_int k, n; + silk_float rck, tmp1, tmp2; + + for( k = 0; k < order; k++ ) { + rck = rc[ k ]; + for( n = 0; n < (k + 1) >> 1; n++ ) { + tmp1 = A[ n ]; + tmp2 = A[ k - n - 1 ]; + A[ n ] = tmp1 + tmp2 * rck; + A[ k - n - 1 ] = tmp2 + tmp1 * rck; + } + A[ k ] = -rck; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/main_FLP.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/main_FLP.h new file mode 100644 index 000000000..5dc0ccf4a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/main_FLP.h @@ -0,0 +1,286 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_MAIN_FLP_H +#define SILK_MAIN_FLP_H + +#include "SigProc_FLP.h" +#include "SigProc_FIX.h" +#include "structs_FLP.h" +#include "main.h" +#include "define.h" +#include "debug.h" +#include "entenc.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define silk_encoder_state_Fxx silk_encoder_state_FLP +#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FLP +#define silk_encode_frame_Fxx silk_encode_frame_FLP + +/*********************/ +/* Encoder Functions */ +/*********************/ + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +); + +/* Encoder main function */ +void silk_encode_do_VAD_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int activity /* I Decision of Opus voice activity detector */ +); + +/* Encoder main function */ +opus_int silk_encode_frame_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int32 *pnBytesOut, /* O Number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +); + +/* Initializes the Silk encoder state */ +opus_int silk_init_encoder( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + int arch /* I Run-tim architecture */ +); + +/* Control the Silk encoder */ +opus_int silk_control_encoder( + silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +); + +/**************************/ +/* Noise shaping analysis */ +/**************************/ +/* Compute noise shaping coefficients and initial gain values */ +void silk_noise_shape_analysis_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float *pitch_res, /* I LPC residual from pitch analysis */ + const silk_float *x /* I Input signal [frame_length + la_shape] */ +); + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FLP( + silk_float *corr, /* O Result [order + 1] */ + const silk_float *input, /* I Input data to correlate */ + const silk_float warping, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +); + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/**********************************************/ +/* Prediction Analysis */ +/**********************************************/ +/* Find pitch lags */ +void silk_find_pitch_lags_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + silk_float res[], /* O Residual */ + const silk_float x[], /* I Speech signal */ + int arch /* I Run-time architecture */ +); + +/* Find LPC and LTP coefficients */ +void silk_find_pred_coefs_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float res_pitch[], /* I Residual from pitch analysis */ + const silk_float x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* LPC analysis */ +void silk_find_LPC_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const silk_float x[], /* I Input signal */ + const silk_float minInvGain /* I Prediction gain from LTP (dB) */ +); + +/* LTP analysis */ +void silk_find_LTP_FLP( + silk_float XX[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + silk_float xX[ MAX_NB_SUBFR * LTP_ORDER ], /* O Weight for LTP quantization */ + const silk_float r_ptr[], /* I LPC residual */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr /* I number of subframes */ +); + +void silk_LTP_analysis_filter_FLP( + silk_float *LTP_res, /* O LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */ + const silk_float *x, /* I Input signal, with preceding samples */ + const silk_float B[ LTP_ORDER * MAX_NB_SUBFR ], /* I LTP coefficients for each subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const silk_float invGains[ MAX_NB_SUBFR ], /* I Inverse quantization gains */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int pre_length /* I Preceding samples for each subframe */ +); + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FLP( + silk_float nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + const silk_float x[], /* I Input signal */ + silk_float a[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const silk_float gains[], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int LPC_order /* I LPC order */ +); + +/* 16th order LPC analysis filter */ +void silk_LPC_analysis_filter_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length, /* I Length of input signal */ + const opus_int Order /* I LPC order */ +); + +/* LTP tap quantizer */ +void silk_quant_LTP_gains_FLP( + silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook index */ + opus_int8 *periodicity_index, /* O Periodicity index */ + opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */ + silk_float *pred_gain_dB, /* O LTP prediction gain */ + const silk_float XX[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Correlation matrix */ + const silk_float xX[ MAX_NB_SUBFR * LTP_ORDER ], /* I Correlation vector */ + const opus_int subfr_len, /* I Number of samples per subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +); + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +silk_float silk_residual_energy_covar_FLP( /* O Weighted residual energy */ + const silk_float *c, /* I Filter coefficients */ + silk_float *wXX, /* I/O Weighted correlation matrix, reg. out */ + const silk_float *wXx, /* I Weighted correlation vector */ + const silk_float wxx, /* I Weighted correlation value */ + const opus_int D /* I Dimension */ +); + +/* Processing of gains */ +void silk_process_gains_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/******************/ +/* Linear Algebra */ +/******************/ +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FLP( + const silk_float *x, /* I x vector [ L+order-1 ] used to create X */ + const opus_int L, /* I Length of vectors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *XX /* O X'*X correlation matrix [order x order] */ +); + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FLP( + const silk_float *x, /* I x vector [L+order-1] used to create X */ + const silk_float *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vecors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *Xt /* O X'*t correlation vector [order] */ +); + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +void silk_apply_sine_window_FLP( + silk_float px_win[], /* O Pointer to windowed signal */ + const silk_float px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +); + +/* Wrapper functions. Call flp / fix code */ + +/* Convert AR filter coefficients to NLSF parameters */ +void silk_A2NLSF_FLP( + opus_int16 *NLSF_Q15, /* O NLSF vector [ LPC_order ] */ + const silk_float *pAR, /* I LPC coefficients [ LPC_order ] */ + const opus_int LPC_order /* I LPC order */ +); + +/* Convert NLSF parameters to AR prediction filter coefficients */ +void silk_NLSF2A_FLP( + silk_float *pAR, /* O LPC coefficients [ LPC_order ] */ + const opus_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */ + const opus_int LPC_order, /* I LPC order */ + int arch /* I Run-time architecture */ +); + +/* Limit, stabilize, and quantize NLSFs */ +void silk_process_NLSFs_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSF_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +); + +/* Floating-point Silk NSQ wrapper */ +void silk_NSQ_wrapper_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SideInfoIndices *psIndices, /* I/O Quantization indices */ + silk_nsq_state *psNSQ, /* I/O Noise Shaping Quantzation state */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const silk_float x[] /* I Prefiltered input signal */ +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/noise_shape_analysis_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/noise_shape_analysis_FLP.c new file mode 100644 index 000000000..cb3d8a50b --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/noise_shape_analysis_FLP.c @@ -0,0 +1,350 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */ +/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */ +/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */ +/* coefficient in an array of coefficients, for monic filters. */ +static OPUS_INLINE silk_float warped_gain( + const silk_float *coefs, + silk_float lambda, + opus_int order +) { + opus_int i; + silk_float gain; + + lambda = -lambda; + gain = coefs[ order - 1 ]; + for( i = order - 2; i >= 0; i-- ) { + gain = lambda * gain + coefs[ i ]; + } + return (silk_float)( 1.0f / ( 1.0f - lambda * gain ) ); +} + +/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */ +/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */ +static OPUS_INLINE void warped_true2monic_coefs( + silk_float *coefs, + silk_float lambda, + silk_float limit, + opus_int order +) { + opus_int i, iter, ind = 0; + silk_float tmp, maxabs, chirp, gain; + + /* Convert to monic coefficients */ + for( i = order - 1; i > 0; i-- ) { + coefs[ i - 1 ] -= lambda * coefs[ i ]; + } + gain = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs[ 0 ] ); + for( i = 0; i < order; i++ ) { + coefs[ i ] *= gain; + } + + /* Limit */ + for( iter = 0; iter < 10; iter++ ) { + /* Find maximum absolute value */ + maxabs = -1.0f; + for( i = 0; i < order; i++ ) { + tmp = silk_abs_float( coefs[ i ] ); + if( tmp > maxabs ) { + maxabs = tmp; + ind = i; + } + } + if( maxabs <= limit ) { + /* Coefficients are within range - done */ + return; + } + + /* Convert back to true warped coefficients */ + for( i = 1; i < order; i++ ) { + coefs[ i - 1 ] += lambda * coefs[ i ]; + } + gain = 1.0f / gain; + for( i = 0; i < order; i++ ) { + coefs[ i ] *= gain; + } + + /* Apply bandwidth expansion */ + chirp = 0.99f - ( 0.8f + 0.1f * iter ) * ( maxabs - limit ) / ( maxabs * ( ind + 1 ) ); + silk_bwexpander_FLP( coefs, order, chirp ); + + /* Convert to monic warped coefficients */ + for( i = order - 1; i > 0; i-- ) { + coefs[ i - 1 ] -= lambda * coefs[ i ]; + } + gain = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs[ 0 ] ); + for( i = 0; i < order; i++ ) { + coefs[ i ] *= gain; + } + } + silk_assert( 0 ); +} + +static OPUS_INLINE void limit_coefs( + silk_float *coefs, + silk_float limit, + opus_int order +) { + opus_int i, iter, ind = 0; + silk_float tmp, maxabs, chirp; + + for( iter = 0; iter < 10; iter++ ) { + /* Find maximum absolute value */ + maxabs = -1.0f; + for( i = 0; i < order; i++ ) { + tmp = silk_abs_float( coefs[ i ] ); + if( tmp > maxabs ) { + maxabs = tmp; + ind = i; + } + } + if( maxabs <= limit ) { + /* Coefficients are within range - done */ + return; + } + + /* Apply bandwidth expansion */ + chirp = 0.99f - ( 0.8f + 0.1f * iter ) * ( maxabs - limit ) / ( maxabs * ( ind + 1 ) ); + silk_bwexpander_FLP( coefs, order, chirp ); + } + silk_assert( 0 ); +} + +/* Compute noise shaping coefficients and initial gain values */ +void silk_noise_shape_analysis_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float *pitch_res, /* I LPC residual from pitch analysis */ + const silk_float *x /* I Input signal [frame_length + la_shape] */ +) +{ + silk_shape_state_FLP *psShapeSt = &psEnc->sShape; + opus_int k, nSamples, nSegs; + silk_float SNR_adj_dB, HarmShapeGain, Tilt; + silk_float nrg, log_energy, log_energy_prev, energy_variation; + silk_float BWExp, gain_mult, gain_add, strength, b, warping; + silk_float x_windowed[ SHAPE_LPC_WIN_MAX ]; + silk_float auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + silk_float rc[ MAX_SHAPE_LPC_ORDER + 1 ]; + const silk_float *x_ptr, *pitch_res_ptr; + + /* Point to start of first LPC analysis block */ + x_ptr = x - psEnc->sCmn.la_shape; + + /****************/ + /* GAIN CONTROL */ + /****************/ + SNR_adj_dB = psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ); + + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality = 0.5f * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] + psEnc->sCmn.input_quality_bands_Q15[ 1 ] ) * ( 1.0f / 32768.0f ); + + /* Coding quality level, between 0.0 and 1.0 */ + psEncCtrl->coding_quality = silk_sigmoid( 0.25f * ( SNR_adj_dB - 20.0f ) ); + + if( psEnc->sCmn.useCBR == 0 ) { + /* Reduce coding SNR during low speech activity */ + b = 1.0f - psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + SNR_adj_dB -= BG_SNR_DECR_dB * psEncCtrl->coding_quality * ( 0.5f + 0.5f * psEncCtrl->input_quality ) * b * b; + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB += HARM_SNR_INCR_dB * psEnc->LTPCorr; + } else { + /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ + SNR_adj_dB += ( -0.4f * psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) + 6.0f ) * ( 1.0f - psEncCtrl->input_quality ); + } + + /*************************/ + /* SPARSENESS PROCESSING */ + /*************************/ + /* Set quantizer offset */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Initially set to 0; may be overruled in process_gains(..) */ + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = 2 * psEnc->sCmn.fs_kHz; + energy_variation = 0.0f; + log_energy_prev = 0.0f; + pitch_res_ptr = pitch_res; + nSegs = silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; + for( k = 0; k < nSegs; k++ ) { + nrg = ( silk_float )nSamples + ( silk_float )silk_energy_FLP( pitch_res_ptr, nSamples ); + log_energy = silk_log2( nrg ); + if( k > 0 ) { + energy_variation += silk_abs_float( log_energy - log_energy_prev ); + } + log_energy_prev = log_energy; + pitch_res_ptr += nSamples; + } + + /* Set quantization offset depending on sparseness measure */ + if( energy_variation > ENERGY_VARIATION_THRESHOLD_QNT_OFFSET * (nSegs-1) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength = FIND_PITCH_WHITE_NOISE_FRACTION * psEncCtrl->predGain; /* between 0.0 and 1.0 */ + BWExp = BANDWIDTH_EXPANSION / ( 1.0f + strength * strength ); + + /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ + warping = (silk_float)psEnc->sCmn.warping_Q16 / 65536.0f + 0.01f * psEncCtrl->coding_quality; + + /********************************************/ + /* Compute noise shaping AR coefs and gains */ + /********************************************/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Apply window: sine slope followed by flat part followed by cosine slope */ + opus_int shift, slope_part, flat_part; + flat_part = psEnc->sCmn.fs_kHz * 3; + slope_part = ( psEnc->sCmn.shapeWinLength - flat_part ) / 2; + + silk_apply_sine_window_FLP( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(silk_float) ); + shift += flat_part; + silk_apply_sine_window_FLP( x_windowed + shift, x_ptr + shift, 2, slope_part ); + + /* Update pointer: next LPC analysis block */ + x_ptr += psEnc->sCmn.subfr_length; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Calculate warped auto correlation */ + silk_warped_autocorrelation_FLP( auto_corr, x_windowed, warping, + psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder ); + } else { + /* Calculate regular auto correlation */ + silk_autocorrelation_FLP( auto_corr, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1 ); + } + + /* Add white noise, as a fraction of energy */ + auto_corr[ 0 ] += auto_corr[ 0 ] * SHAPE_WHITE_NOISE_FRACTION + 1.0f; + + /* Convert correlations to prediction coefficients, and compute residual energy */ + nrg = silk_schur_FLP( rc, auto_corr, psEnc->sCmn.shapingLPCOrder ); + silk_k2a_FLP( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], rc, psEnc->sCmn.shapingLPCOrder ); + psEncCtrl->Gains[ k ] = ( silk_float )sqrt( nrg ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Adjust gain for warping */ + psEncCtrl->Gains[ k ] *= warped_gain( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], warping, psEnc->sCmn.shapingLPCOrder ); + } + + /* Bandwidth expansion for synthesis filter shaping */ + silk_bwexpander_FLP( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Convert to monic warped prediction coefficients and limit absolute values */ + warped_true2monic_coefs( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], warping, 3.999f, psEnc->sCmn.shapingLPCOrder ); + } else { + /* Limit absolute values */ + limit_coefs( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], 3.999f, psEnc->sCmn.shapingLPCOrder ); + } + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity */ + gain_mult = (silk_float)pow( 2.0f, -0.16f * SNR_adj_dB ); + gain_add = (silk_float)pow( 2.0f, 0.16f * MIN_QGAIN_DB ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] *= gain_mult; + psEncCtrl->Gains[ k ] += gain_add; + } + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength = LOW_FREQ_SHAPING * ( 1.0f + LOW_QUALITY_LOW_FREQ_SHAPING_DECR * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] * ( 1.0f / 32768.0f ) - 1.0f ) ); + strength *= psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */ + /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + b = 0.2f / psEnc->sCmn.fs_kHz + 3.0f / psEncCtrl->pitchL[ k ]; + psEncCtrl->LF_MA_shp[ k ] = -1.0f + b; + psEncCtrl->LF_AR_shp[ k ] = 1.0f - b - b * strength; + } + Tilt = - HP_NOISE_COEF - + (1 - HP_NOISE_COEF) * HARM_HP_NOISE_COEF * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + } else { + b = 1.3f / psEnc->sCmn.fs_kHz; + psEncCtrl->LF_MA_shp[ 0 ] = -1.0f + b; + psEncCtrl->LF_AR_shp[ 0 ] = 1.0f - b - b * strength * 0.6f; + for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->LF_MA_shp[ k ] = psEncCtrl->LF_MA_shp[ 0 ]; + psEncCtrl->LF_AR_shp[ k ] = psEncCtrl->LF_AR_shp[ 0 ]; + } + Tilt = -HP_NOISE_COEF; + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Harmonic noise shaping */ + HarmShapeGain = HARMONIC_SHAPING; + + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain += HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING * + ( 1.0f - ( 1.0f - psEncCtrl->coding_quality ) * psEncCtrl->input_quality ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain *= ( silk_float )sqrt( psEnc->LTPCorr ); + } else { + HarmShapeGain = 0.0f; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psShapeSt->HarmShapeGain_smth += SUBFR_SMTH_COEF * ( HarmShapeGain - psShapeSt->HarmShapeGain_smth ); + psEncCtrl->HarmShapeGain[ k ] = psShapeSt->HarmShapeGain_smth; + psShapeSt->Tilt_smth += SUBFR_SMTH_COEF * ( Tilt - psShapeSt->Tilt_smth ); + psEncCtrl->Tilt[ k ] = psShapeSt->Tilt_smth; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/pitch_analysis_core_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/pitch_analysis_core_FLP.c new file mode 100644 index 000000000..f351bc371 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/pitch_analysis_core_FLP.c @@ -0,0 +1,630 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/***************************************************************************** +* Pitch analyser function +******************************************************************************/ +#include "SigProc_FLP.h" +#include "SigProc_FIX.h" +#include "pitch_est_defines.h" +#include "pitch.h" + +#define SCRATCH_SIZE 22 + +/************************************************************/ +/* Internally used functions */ +/************************************************************/ +static void silk_P_Ana_calc_corr_st3( + silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +); + +static void silk_P_Ana_calc_energy_st3( + silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +); + +/************************************************************/ +/* CORE PITCH ANALYSIS FUNCTION */ +/************************************************************/ +opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const silk_float *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O Pitch lag values [nb_subfr] */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + silk_float *LTPCorr, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const silk_float search_thres1, /* I First stage threshold for lag candidates 0 - 1 */ + const silk_float search_thres2, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr, /* I Number of 5 ms subframes */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, k, d, j; + silk_float frame_8kHz[ PE_MAX_FRAME_LENGTH_MS * 8 ]; + silk_float frame_4kHz[ PE_MAX_FRAME_LENGTH_MS * 4 ]; + opus_int16 frame_8_FIX[ PE_MAX_FRAME_LENGTH_MS * 8 ]; + opus_int16 frame_4_FIX[ PE_MAX_FRAME_LENGTH_MS * 4 ]; + opus_int32 filt_state[ 6 ]; + silk_float threshold, contour_bias; + silk_float C[ PE_MAX_NB_SUBFR][ (PE_MAX_LAG >> 1) + 5 ]; + opus_val32 xcorr[ PE_MAX_LAG_MS * 4 - PE_MIN_LAG_MS * 4 + 1 ]; + silk_float CC[ PE_NB_CBKS_STAGE2_EXT ]; + const silk_float *target_ptr, *basis_ptr; + double cross_corr, normalizer, energy, energy_tmp; + opus_int d_srch[ PE_D_SRCH_LENGTH ]; + opus_int16 d_comp[ (PE_MAX_LAG >> 1) + 5 ]; + opus_int length_d_srch, length_d_comp; + silk_float Cmax, CCmax, CCmax_b, CCmax_new_b, CCmax_new; + opus_int CBimax, CBimax_new, lag, start_lag, end_lag, lag_new; + opus_int cbk_size; + silk_float lag_log2, prevLag_log2, delta_lag_log2_sqr; + silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ]; + silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ]; + opus_int lag_counter; + opus_int frame_length, frame_length_8kHz, frame_length_4kHz; + opus_int sf_length, sf_length_8kHz, sf_length_4kHz; + opus_int min_lag, min_lag_8kHz, min_lag_4kHz; + opus_int max_lag, max_lag_8kHz, max_lag_4kHz; + opus_int nb_cbk_search; + const opus_int8 *Lag_CB_ptr; + + /* Check for valid sampling frequency */ + celt_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 ); + + /* Check for valid complexity setting */ + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + silk_assert( search_thres1 >= 0.0f && search_thres1 <= 1.0f ); + silk_assert( search_thres2 >= 0.0f && search_thres2 <= 1.0f ); + + /* Set up frame lengths max / min lag for the sampling frequency */ + frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz; + frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4; + frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8; + sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz; + sf_length_4kHz = PE_SUBFR_LENGTH_MS * 4; + sf_length_8kHz = PE_SUBFR_LENGTH_MS * 8; + min_lag = PE_MIN_LAG_MS * Fs_kHz; + min_lag_4kHz = PE_MIN_LAG_MS * 4; + min_lag_8kHz = PE_MIN_LAG_MS * 8; + max_lag = PE_MAX_LAG_MS * Fs_kHz - 1; + max_lag_4kHz = PE_MAX_LAG_MS * 4; + max_lag_8kHz = PE_MAX_LAG_MS * 8 - 1; + + /* Resample from input sampled at Fs_kHz to 8 kHz */ + if( Fs_kHz == 16 ) { + /* Resample to 16 -> 8 khz */ + opus_int16 frame_16_FIX[ 16 * PE_MAX_FRAME_LENGTH_MS ]; + silk_float2short_array( frame_16_FIX, frame, frame_length ); + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) ); + silk_resampler_down2( filt_state, frame_8_FIX, frame_16_FIX, frame_length ); + silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz ); + } else if( Fs_kHz == 12 ) { + /* Resample to 12 -> 8 khz */ + opus_int16 frame_12_FIX[ 12 * PE_MAX_FRAME_LENGTH_MS ]; + silk_float2short_array( frame_12_FIX, frame, frame_length ); + silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) ); + silk_resampler_down2_3( filt_state, frame_8_FIX, frame_12_FIX, frame_length ); + silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz ); + } else { + celt_assert( Fs_kHz == 8 ); + silk_float2short_array( frame_8_FIX, frame, frame_length_8kHz ); + } + + /* Decimate again to 4 kHz */ + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) ); + silk_resampler_down2( filt_state, frame_4_FIX, frame_8_FIX, frame_length_8kHz ); + silk_short2float_array( frame_4kHz, frame_4_FIX, frame_length_4kHz ); + + /* Low-pass filter */ + for( i = frame_length_4kHz - 1; i > 0; i-- ) { + frame_4kHz[ i ] = silk_ADD_SAT16( frame_4kHz[ i ], frame_4kHz[ i - 1 ] ); + } + + /****************************************************************************** + * FIRST STAGE, operating in 4 khz + ******************************************************************************/ + silk_memset(C, 0, sizeof(silk_float) * nb_subfr * ((PE_MAX_LAG >> 1) + 5)); + target_ptr = &frame_4kHz[ silk_LSHIFT( sf_length_4kHz, 2 ) ]; + for( k = 0; k < nb_subfr >> 1; k++ ) { + /* Check that we are within range of the array */ + celt_assert( target_ptr >= frame_4kHz ); + celt_assert( target_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + basis_ptr = target_ptr - min_lag_4kHz; + + /* Check that we are within range of the array */ + celt_assert( basis_ptr >= frame_4kHz ); + celt_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + celt_pitch_xcorr( target_ptr, target_ptr-max_lag_4kHz, xcorr, sf_length_8kHz, max_lag_4kHz - min_lag_4kHz + 1, arch ); + + /* Calculate first vector products before loop */ + cross_corr = xcorr[ max_lag_4kHz - min_lag_4kHz ]; + normalizer = silk_energy_FLP( target_ptr, sf_length_8kHz ) + + silk_energy_FLP( basis_ptr, sf_length_8kHz ) + + sf_length_8kHz * 4000.0f; + + C[ 0 ][ min_lag_4kHz ] += (silk_float)( 2 * cross_corr / normalizer ); + + /* From now on normalizer is computed recursively */ + for( d = min_lag_4kHz + 1; d <= max_lag_4kHz; d++ ) { + basis_ptr--; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_4kHz ); + silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + cross_corr = xcorr[ max_lag_4kHz - d ]; + + /* Add contribution of new sample and remove contribution from oldest sample */ + normalizer += + basis_ptr[ 0 ] * (double)basis_ptr[ 0 ] - + basis_ptr[ sf_length_8kHz ] * (double)basis_ptr[ sf_length_8kHz ]; + C[ 0 ][ d ] += (silk_float)( 2 * cross_corr / normalizer ); + } + /* Update target pointer */ + target_ptr += sf_length_8kHz; + } + + /* Apply short-lag bias */ + for( i = max_lag_4kHz; i >= min_lag_4kHz; i-- ) { + C[ 0 ][ i ] -= C[ 0 ][ i ] * i / 4096.0f; + } + + /* Sort */ + length_d_srch = 4 + 2 * complexity; + celt_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH ); + silk_insertion_sort_decreasing_FLP( &C[ 0 ][ min_lag_4kHz ], d_srch, max_lag_4kHz - min_lag_4kHz + 1, length_d_srch ); + + /* Escape if correlation is very low already here */ + Cmax = C[ 0 ][ min_lag_4kHz ]; + if( Cmax < 0.2f ) { + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) ); + *LTPCorr = 0.0f; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + threshold = search_thres1 * Cmax; + for( i = 0; i < length_d_srch; i++ ) { + /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */ + if( C[ 0 ][ min_lag_4kHz + i ] > threshold ) { + d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + min_lag_4kHz, 1 ); + } else { + length_d_srch = i; + break; + } + } + celt_assert( length_d_srch > 0 ); + + for( i = min_lag_8kHz - 5; i < max_lag_8kHz + 5; i++ ) { + d_comp[ i ] = 0; + } + for( i = 0; i < length_d_srch; i++ ) { + d_comp[ d_srch[ i ] ] = 1; + } + + /* Convolution */ + for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) { + d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ]; + } + + length_d_srch = 0; + for( i = min_lag_8kHz; i < max_lag_8kHz + 1; i++ ) { + if( d_comp[ i + 1 ] > 0 ) { + d_srch[ length_d_srch ] = i; + length_d_srch++; + } + } + + /* Convolution */ + for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) { + d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ] + d_comp[ i - 3 ]; + } + + length_d_comp = 0; + for( i = min_lag_8kHz; i < max_lag_8kHz + 4; i++ ) { + if( d_comp[ i ] > 0 ) { + d_comp[ length_d_comp ] = (opus_int16)( i - 2 ); + length_d_comp++; + } + } + + /********************************************************************************** + ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation + *************************************************************************************/ + /********************************************************************************* + * Find energy of each subframe projected onto its history, for a range of delays + *********************************************************************************/ + silk_memset( C, 0, PE_MAX_NB_SUBFR*((PE_MAX_LAG >> 1) + 5) * sizeof(silk_float)); + + if( Fs_kHz == 8 ) { + target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * 8 ]; + } else { + target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ]; + } + for( k = 0; k < nb_subfr; k++ ) { + energy_tmp = silk_energy_FLP( target_ptr, sf_length_8kHz ) + 1.0; + for( j = 0; j < length_d_comp; j++ ) { + d = d_comp[ j ]; + basis_ptr = target_ptr - d; + cross_corr = silk_inner_product_FLP( basis_ptr, target_ptr, sf_length_8kHz ); + if( cross_corr > 0.0f ) { + energy = silk_energy_FLP( basis_ptr, sf_length_8kHz ); + C[ k ][ d ] = (silk_float)( 2 * cross_corr / ( energy + energy_tmp ) ); + } else { + C[ k ][ d ] = 0.0f; + } + } + target_ptr += sf_length_8kHz; + } + + /* search over lag range and lags codebook */ + /* scale factor for lag codebook, as a function of center lag */ + + CCmax = 0.0f; /* This value doesn't matter */ + CCmax_b = -1000.0f; + + CBimax = 0; /* To avoid returning undefined lag values */ + lag = -1; /* To check if lag with strong enough correlation has been found */ + + if( prevLag > 0 ) { + if( Fs_kHz == 12 ) { + prevLag = silk_LSHIFT( prevLag, 1 ) / 3; + } else if( Fs_kHz == 16 ) { + prevLag = silk_RSHIFT( prevLag, 1 ); + } + prevLag_log2 = silk_log2( (silk_float)prevLag ); + } else { + prevLag_log2 = 0; + } + + /* Set up stage 2 codebook based on number of subframes */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + cbk_size = PE_NB_CBKS_STAGE2_EXT; + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) { + /* If input is 8 khz use a larger codebook here because it is last stage */ + nb_cbk_search = PE_NB_CBKS_STAGE2_EXT; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE2; + } + } else { + cbk_size = PE_NB_CBKS_STAGE2_10MS; + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE2_10MS; + } + + for( k = 0; k < length_d_srch; k++ ) { + d = d_srch[ k ]; + for( j = 0; j < nb_cbk_search; j++ ) { + CC[j] = 0.0f; + for( i = 0; i < nb_subfr; i++ ) { + /* Try all codebooks */ + CC[ j ] += C[ i ][ d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size )]; + } + } + /* Find best codebook */ + CCmax_new = -1000.0f; + CBimax_new = 0; + for( i = 0; i < nb_cbk_search; i++ ) { + if( CC[ i ] > CCmax_new ) { + CCmax_new = CC[ i ]; + CBimax_new = i; + } + } + + /* Bias towards shorter lags */ + lag_log2 = silk_log2( (silk_float)d ); + CCmax_new_b = CCmax_new - PE_SHORTLAG_BIAS * nb_subfr * lag_log2; + + /* Bias towards previous lag */ + if( prevLag > 0 ) { + delta_lag_log2_sqr = lag_log2 - prevLag_log2; + delta_lag_log2_sqr *= delta_lag_log2_sqr; + CCmax_new_b -= PE_PREVLAG_BIAS * nb_subfr * (*LTPCorr) * delta_lag_log2_sqr / ( delta_lag_log2_sqr + 0.5f ); + } + + if( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */ + CCmax_new > nb_subfr * search_thres2 /* Correlation needs to be high enough to be voiced */ + ) { + CCmax_b = CCmax_new_b; + CCmax = CCmax_new; + lag = d; + CBimax = CBimax_new; + } + } + + if( lag == -1 ) { + /* No suitable candidate found */ + silk_memset( pitch_out, 0, PE_MAX_NB_SUBFR * sizeof(opus_int) ); + *LTPCorr = 0.0f; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + /* Output normalized correlation */ + *LTPCorr = (silk_float)( CCmax / nb_subfr ); + silk_assert( *LTPCorr >= 0.0f ); + + if( Fs_kHz > 8 ) { + /* Search in original signal */ + + /* Compensate for decimation */ + silk_assert( lag == silk_SAT16( lag ) ); + if( Fs_kHz == 12 ) { + lag = silk_RSHIFT_ROUND( silk_SMULBB( lag, 3 ), 1 ); + } else { /* Fs_kHz == 16 */ + lag = silk_LSHIFT( lag, 1 ); + } + + lag = silk_LIMIT_int( lag, min_lag, max_lag ); + start_lag = silk_max_int( lag - 2, min_lag ); + end_lag = silk_min_int( lag + 2, max_lag ); + lag_new = lag; /* to avoid undefined lag */ + CBimax = 0; /* to avoid undefined lag */ + + CCmax = -1000.0f; + + /* Calculate the correlations and energies needed in stage 3 */ + silk_P_Ana_calc_corr_st3( cross_corr_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch ); + silk_P_Ana_calc_energy_st3( energies_st3, frame, start_lag, sf_length, nb_subfr, complexity ); + + lag_counter = 0; + silk_assert( lag == silk_SAT16( lag ) ); + contour_bias = PE_FLATCONTOUR_BIAS / lag; + + /* Set up cbk parameters according to complexity setting and frame length */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + } + + target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * Fs_kHz ]; + energy_tmp = silk_energy_FLP( target_ptr, nb_subfr * sf_length ) + 1.0; + for( d = start_lag; d <= end_lag; d++ ) { + for( j = 0; j < nb_cbk_search; j++ ) { + cross_corr = 0.0; + energy = energy_tmp; + for( k = 0; k < nb_subfr; k++ ) { + cross_corr += cross_corr_st3[ k ][ j ][ lag_counter ]; + energy += energies_st3[ k ][ j ][ lag_counter ]; + } + if( cross_corr > 0.0 ) { + CCmax_new = (silk_float)( 2 * cross_corr / energy ); + /* Reduce depending on flatness of contour */ + CCmax_new *= 1.0f - contour_bias * j; + } else { + CCmax_new = 0.0f; + } + + if( CCmax_new > CCmax && ( d + (opus_int)silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag ) { + CCmax = CCmax_new; + lag_new = d; + CBimax = j; + } + } + lag_counter++; + } + + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz ); + } + *lagIndex = (opus_int16)( lag_new - min_lag ); + *contourIndex = (opus_int8)CBimax; + } else { /* Fs_kHz == 8 */ + /* Save Lags */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag_8kHz, PE_MAX_LAG_MS * 8 ); + } + *lagIndex = (opus_int16)( lag - min_lag_8kHz ); + *contourIndex = (opus_int8)CBimax; + } + celt_assert( *lagIndex >= 0 ); + /* return as voiced */ + return 0; +} + +/*********************************************************************** + * Calculates the correlations used in stage 3 search. In order to cover + * the whole lag codebook for all the searched offset lags (lag +- 2), + * the following correlations are needed in each sub frame: + * + * sf1: lag range [-8,...,7] total 16 correlations + * sf2: lag range [-4,...,4] total 9 correlations + * sf3: lag range [-3,....4] total 8 correltions + * sf4: lag range [-6,....8] total 15 correlations + * + * In total 48 correlations. The direct implementation computed in worst + * case 4*12*5 = 240 correlations, but more likely around 120. + ***********************************************************************/ +static void silk_P_Ana_calc_corr_st3( + silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +) +{ + const silk_float *target_ptr; + opus_int i, j, k, lag_counter, lag_low, lag_high; + opus_int nb_cbk_search, delta, idx, cbk_size; + silk_float scratch_mem[ SCRATCH_SIZE ]; + opus_val32 xcorr[ SCRATCH_SIZE ]; + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */ + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the correlations for each subframe */ + lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 ); + silk_assert(lag_high-lag_low+1 <= SCRATCH_SIZE); + celt_pitch_xcorr( target_ptr, target_ptr - start_lag - lag_high, xcorr, sf_length, lag_high - lag_low + 1, arch ); + for( j = lag_low; j <= lag_high; j++ ) { + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = xcorr[ lag_high - j ]; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + cross_corr_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + } + } + target_ptr += sf_length; + } +} + +/********************************************************************/ +/* Calculate the energies for first two subframes. The energies are */ +/* calculated recursively. */ +/********************************************************************/ +static void silk_P_Ana_calc_energy_st3( + silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +) +{ + const silk_float *target_ptr, *basis_ptr; + double energy; + opus_int k, i, j, lag_counter; + opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff; + silk_float scratch_mem[ SCRATCH_SIZE ]; + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the energy for first lag */ + basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) ); + energy = silk_energy_FLP( basis_ptr, sf_length ) + 1e-3; + silk_assert( energy >= 0.0 ); + scratch_mem[lag_counter] = (silk_float)energy; + lag_counter++; + + lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 ); + for( i = 1; i < lag_diff; i++ ) { + /* remove part outside new window */ + energy -= basis_ptr[sf_length - i] * (double)basis_ptr[sf_length - i]; + silk_assert( energy >= 0.0 ); + + /* add part that comes into window */ + energy += basis_ptr[ -i ] * (double)basis_ptr[ -i ]; + silk_assert( energy >= 0.0 ); + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[lag_counter] = (silk_float)energy; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + energies_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + silk_assert( energies_st3[ k ][ i ][ j ] >= 0.0f ); + } + } + target_ptr += sf_length; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/process_gains_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/process_gains_FLP.c new file mode 100644 index 000000000..c0da0dae4 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/process_gains_FLP.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* Processing of gains */ +void silk_process_gains_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + silk_shape_state_FLP *psShapeSt = &psEnc->sShape; + opus_int k; + opus_int32 pGains_Q16[ MAX_NB_SUBFR ]; + silk_float s, InvMaxSqrVal, gain, quant_offset; + + /* Gain reduction when LTP coding gain is high */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + s = 1.0f - 0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] *= s; + } + } + + /* Limit the quantized signal */ + InvMaxSqrVal = ( silk_float )( pow( 2.0f, 0.33f * ( 21.0f - psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) ) ) / psEnc->sCmn.subfr_length ); + + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Soft limit on ratio residual energy and squared gains */ + gain = psEncCtrl->Gains[ k ]; + gain = ( silk_float )sqrt( gain * gain + psEncCtrl->ResNrg[ k ] * InvMaxSqrVal ); + psEncCtrl->Gains[ k ] = silk_min_float( gain, 32767.0f ); + } + + /* Prepare gains for noise shaping quantization */ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + pGains_Q16[ k ] = (opus_int32)( psEncCtrl->Gains[ k ] * 65536.0f ); + } + + /* Save unquantized gains and gain Index */ + silk_memcpy( psEncCtrl->GainsUnq_Q16, pGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex; + + /* Quantize gains */ + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16, + &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] = pGains_Q16[ k ] / 65536.0f; + } + + /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + if( psEncCtrl->LTPredCodGain + psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f ) > 1.0f ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /* Quantizer boundary adjustment */ + quant_offset = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ] / 1024.0f; + psEncCtrl->Lambda = LAMBDA_OFFSET + + LAMBDA_DELAYED_DECISIONS * psEnc->sCmn.nStatesDelayedDecision + + LAMBDA_SPEECH_ACT * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ) + + LAMBDA_INPUT_QUALITY * psEncCtrl->input_quality + + LAMBDA_CODING_QUALITY * psEncCtrl->coding_quality + + LAMBDA_QUANT_OFFSET * quant_offset; + + silk_assert( psEncCtrl->Lambda > 0.0f ); + silk_assert( psEncCtrl->Lambda < 2.0f ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/regularize_correlations_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/regularize_correlations_FLP.c new file mode 100644 index 000000000..df4612604 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/regularize_correlations_FLP.c @@ -0,0 +1,48 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Add noise to matrix diagonal */ +void silk_regularize_correlations_FLP( + silk_float *XX, /* I/O Correlation matrices */ + silk_float *xx, /* I/O Correlation values */ + const silk_float noise, /* I Noise energy to add */ + const opus_int D /* I Dimension of XX */ +) +{ + opus_int i; + + for( i = 0; i < D; i++ ) { + matrix_ptr( &XX[ 0 ], i, i, D ) += noise; + } + xx[ 0 ] += noise; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/residual_energy_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/residual_energy_FLP.c new file mode 100644 index 000000000..1bd07b33a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/residual_energy_FLP.c @@ -0,0 +1,117 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +#define MAX_ITERATIONS_RESIDUAL_NRG 10 +#define REGULARIZATION_FACTOR 1e-8f + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +silk_float silk_residual_energy_covar_FLP( /* O Weighted residual energy */ + const silk_float *c, /* I Filter coefficients */ + silk_float *wXX, /* I/O Weighted correlation matrix, reg. out */ + const silk_float *wXx, /* I Weighted correlation vector */ + const silk_float wxx, /* I Weighted correlation value */ + const opus_int D /* I Dimension */ +) +{ + opus_int i, j, k; + silk_float tmp, nrg = 0.0f, regularization; + + /* Safety checks */ + celt_assert( D >= 0 ); + + regularization = REGULARIZATION_FACTOR * ( wXX[ 0 ] + wXX[ D * D - 1 ] ); + for( k = 0; k < MAX_ITERATIONS_RESIDUAL_NRG; k++ ) { + nrg = wxx; + + tmp = 0.0f; + for( i = 0; i < D; i++ ) { + tmp += wXx[ i ] * c[ i ]; + } + nrg -= 2.0f * tmp; + + /* compute c' * wXX * c, assuming wXX is symmetric */ + for( i = 0; i < D; i++ ) { + tmp = 0.0f; + for( j = i + 1; j < D; j++ ) { + tmp += matrix_c_ptr( wXX, i, j, D ) * c[ j ]; + } + nrg += c[ i ] * ( 2.0f * tmp + matrix_c_ptr( wXX, i, i, D ) * c[ i ] ); + } + if( nrg > 0 ) { + break; + } else { + /* Add white noise */ + for( i = 0; i < D; i++ ) { + matrix_c_ptr( wXX, i, i, D ) += regularization; + } + /* Increase noise for next run */ + regularization *= 2.0f; + } + } + if( k == MAX_ITERATIONS_RESIDUAL_NRG ) { + silk_assert( nrg == 0 ); + nrg = 1.0f; + } + + return nrg; +} + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FLP( + silk_float nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + const silk_float x[], /* I Input signal */ + silk_float a[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const silk_float gains[], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int LPC_order /* I LPC order */ +) +{ + opus_int shift; + silk_float *LPC_res_ptr, LPC_res[ ( MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ) / 2 ]; + + LPC_res_ptr = LPC_res + LPC_order; + shift = LPC_order + subfr_length; + + /* Filter input to create the LPC residual for each frame half, and measure subframe energies */ + silk_LPC_analysis_filter_FLP( LPC_res, a[ 0 ], x + 0 * shift, 2 * shift, LPC_order ); + nrgs[ 0 ] = ( silk_float )( gains[ 0 ] * gains[ 0 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) ); + nrgs[ 1 ] = ( silk_float )( gains[ 1 ] * gains[ 1 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) ); + + if( nb_subfr == MAX_NB_SUBFR ) { + silk_LPC_analysis_filter_FLP( LPC_res, a[ 1 ], x + 2 * shift, 2 * shift, LPC_order ); + nrgs[ 2 ] = ( silk_float )( gains[ 2 ] * gains[ 2 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) ); + nrgs[ 3 ] = ( silk_float )( gains[ 3 ] * gains[ 3 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) ); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/scale_copy_vector_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/scale_copy_vector_FLP.c new file mode 100644 index 000000000..20db32b3b --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/scale_copy_vector_FLP.c @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* copy and multiply a vector by a constant */ +void silk_scale_copy_vector_FLP( + silk_float *data_out, + const silk_float *data_in, + silk_float gain, + opus_int dataSize +) +{ + opus_int i, dataSize4; + + /* 4x unrolled loop */ + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + data_out[ i + 0 ] = gain * data_in[ i + 0 ]; + data_out[ i + 1 ] = gain * data_in[ i + 1 ]; + data_out[ i + 2 ] = gain * data_in[ i + 2 ]; + data_out[ i + 3 ] = gain * data_in[ i + 3 ]; + } + + /* any remaining elements */ + for( ; i < dataSize; i++ ) { + data_out[ i ] = gain * data_in[ i ]; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/scale_vector_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/scale_vector_FLP.c new file mode 100644 index 000000000..108fdcbed --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/scale_vector_FLP.c @@ -0,0 +1,56 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* multiply a vector by a constant */ +void silk_scale_vector_FLP( + silk_float *data1, + silk_float gain, + opus_int dataSize +) +{ + opus_int i, dataSize4; + + /* 4x unrolled loop */ + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + data1[ i + 0 ] *= gain; + data1[ i + 1 ] *= gain; + data1[ i + 2 ] *= gain; + data1[ i + 3 ] *= gain; + } + + /* any remaining elements */ + for( ; i < dataSize; i++ ) { + data1[ i ] *= gain; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/schur_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/schur_FLP.c new file mode 100644 index 000000000..8526c748d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/schur_FLP.c @@ -0,0 +1,70 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +silk_float silk_schur_FLP( /* O returns residual energy */ + silk_float refl_coef[], /* O reflection coefficients (length order) */ + const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */ + opus_int order /* I order */ +) +{ + opus_int k, n; + double C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; + double Ctmp1, Ctmp2, rc_tmp; + + celt_assert( order >= 0 && order <= SILK_MAX_ORDER_LPC ); + + /* Copy correlations */ + k = 0; + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = auto_corr[ k ]; + } while( ++k <= order ); + + for( k = 0; k < order; k++ ) { + /* Get reflection coefficient */ + rc_tmp = -C[ k + 1 ][ 0 ] / silk_max_float( C[ 0 ][ 1 ], 1e-9f ); + + /* Save the output */ + refl_coef[ k ] = (silk_float)rc_tmp; + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1 = C[ n + k + 1 ][ 0 ]; + Ctmp2 = C[ n ][ 1 ]; + C[ n + k + 1 ][ 0 ] = Ctmp1 + Ctmp2 * rc_tmp; + C[ n ][ 1 ] = Ctmp2 + Ctmp1 * rc_tmp; + } + } + + /* Return residual energy */ + return (silk_float)C[ 0 ][ 1 ]; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/sort_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/sort_FLP.c new file mode 100644 index 000000000..0e18f3195 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/sort_FLP.c @@ -0,0 +1,83 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Insertion sort (fast for already almost sorted arrays): */ +/* Best case: O(n) for an already sorted array */ +/* Worst case: O(n^2) for an inversely sorted array */ + +#include "typedef.h" +#include "SigProc_FLP.h" + +void silk_insertion_sort_decreasing_FLP( + silk_float *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + silk_float value; + opus_int i, j; + + /* Safety checks */ + celt_assert( K > 0 ); + celt_assert( L > 0 ); + celt_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ i ] = i; + } + + /* Sort vector elements by value, decreasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value > a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/structs_FLP.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/structs_FLP.h new file mode 100644 index 000000000..3150b386e --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/structs_FLP.h @@ -0,0 +1,112 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_STRUCTS_FLP_H +#define SILK_STRUCTS_FLP_H + +#include "typedef.h" +#include "main.h" +#include "structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************/ +/* Noise shaping analysis state */ +/********************************/ +typedef struct { + opus_int8 LastGainIndex; + silk_float HarmShapeGain_smth; + silk_float Tilt_smth; +} silk_shape_state_FLP; + +/********************************/ +/* Encoder state FLP */ +/********************************/ +typedef struct { + silk_encoder_state sCmn; /* Common struct, shared with fixed-point code */ + silk_shape_state_FLP sShape; /* Noise shaping state */ + + /* Buffer for find pitch and noise shape analysis */ + silk_float x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */ + silk_float LTPCorr; /* Normalized correlation from pitch lag estimator */ +} silk_encoder_state_FLP; + +/************************/ +/* Encoder control FLP */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + silk_float Gains[ MAX_NB_SUBFR ]; + silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ]; /* holds interpolated and final coefficients */ + silk_float LTPCoef[LTP_ORDER * MAX_NB_SUBFR]; + silk_float LTP_scale; + opus_int pitchL[ MAX_NB_SUBFR ]; + + /* Noise shaping parameters */ + silk_float AR[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + silk_float LF_MA_shp[ MAX_NB_SUBFR ]; + silk_float LF_AR_shp[ MAX_NB_SUBFR ]; + silk_float Tilt[ MAX_NB_SUBFR ]; + silk_float HarmShapeGain[ MAX_NB_SUBFR ]; + silk_float Lambda; + silk_float input_quality; + silk_float coding_quality; + + /* Measures */ + silk_float predGain; + silk_float LTPredCodGain; + silk_float ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */ + + /* Parameters for CBR mode */ + opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ]; + opus_int8 lastGainIndexPrev; +} silk_encoder_control_FLP; + +/************************/ +/* Encoder Super Struct */ +/************************/ +typedef struct { + silk_encoder_state_FLP state_Fxx[ ENCODER_NUM_CHANNELS ]; + stereo_enc_state sStereo; + opus_int32 nBitsUsedLBRR; + opus_int32 nBitsExceeded; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int nPrevChannelsInternal; + opus_int timeSinceSwitchAllowed_ms; + opus_int allowBandwidthSwitch; + opus_int prev_decode_only_middle; +} silk_encoder; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/warped_autocorrelation_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/warped_autocorrelation_FLP.c new file mode 100644 index 000000000..09186e73d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/warped_autocorrelation_FLP.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FLP( + silk_float *corr, /* O Result [order + 1] */ + const silk_float *input, /* I Input data to correlate */ + const silk_float warping, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + opus_int n, i; + double tmp1, tmp2; + double state[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + double C[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + + /* Order must be even */ + celt_assert( ( order & 1 ) == 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n++ ) { + tmp1 = input[ n ]; + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = state[ i ] + warping * ( state[ i + 1 ] - tmp1 ); + state[ i ] = tmp1; + C[ i ] += state[ 0 ] * tmp1; + /* Output of allpass section */ + tmp1 = state[ i + 1 ] + warping * ( state[ i + 2 ] - tmp2 ); + state[ i + 1 ] = tmp2; + C[ i + 1 ] += state[ 0 ] * tmp2; + } + state[ order ] = tmp1; + C[ order ] += state[ 0 ] * tmp1; + } + + /* Copy correlations in silk_float output format */ + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = ( silk_float )C[ i ]; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/wrappers_FLP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/wrappers_FLP.c new file mode 100644 index 000000000..ad90b874a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/float/wrappers_FLP.c @@ -0,0 +1,207 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Wrappers. Calls flp / fix code */ + +/* Convert AR filter coefficients to NLSF parameters */ +void silk_A2NLSF_FLP( + opus_int16 *NLSF_Q15, /* O NLSF vector [ LPC_order ] */ + const silk_float *pAR, /* I LPC coefficients [ LPC_order ] */ + const opus_int LPC_order /* I LPC order */ +) +{ + opus_int i; + opus_int32 a_fix_Q16[ MAX_LPC_ORDER ]; + + for( i = 0; i < LPC_order; i++ ) { + a_fix_Q16[ i ] = silk_float2int( pAR[ i ] * 65536.0f ); + } + + silk_A2NLSF( NLSF_Q15, a_fix_Q16, LPC_order ); +} + +/* Convert LSF parameters to AR prediction filter coefficients */ +void silk_NLSF2A_FLP( + silk_float *pAR, /* O LPC coefficients [ LPC_order ] */ + const opus_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */ + const opus_int LPC_order, /* I LPC order */ + int arch /* I Run-time architecture */ +) +{ + opus_int i; + opus_int16 a_fix_Q12[ MAX_LPC_ORDER ]; + + silk_NLSF2A( a_fix_Q12, NLSF_Q15, LPC_order, arch ); + + for( i = 0; i < LPC_order; i++ ) { + pAR[ i ] = ( silk_float )a_fix_Q12[ i ] * ( 1.0f / 4096.0f ); + } +} + +/******************************************/ +/* Floating-point NLSF processing wrapper */ +/******************************************/ +void silk_process_NLSFs_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSF_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +) +{ + opus_int i, j; + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + + silk_process_NLSFs( psEncC, PredCoef_Q12, NLSF_Q15, prev_NLSF_Q15); + + for( j = 0; j < 2; j++ ) { + for( i = 0; i < psEncC->predictLPCOrder; i++ ) { + PredCoef[ j ][ i ] = ( silk_float )PredCoef_Q12[ j ][ i ] * ( 1.0f / 4096.0f ); + } + } +} + +/****************************************/ +/* Floating-point Silk NSQ wrapper */ +/****************************************/ +void silk_NSQ_wrapper_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SideInfoIndices *psIndices, /* I/O Quantization indices */ + silk_nsq_state *psNSQ, /* I/O Noise Shaping Quantzation state */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const silk_float x[] /* I Prefiltered input signal */ +) +{ + opus_int i, j; + opus_int16 x16[ MAX_FRAME_LENGTH ]; + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; + + /* Noise shaping parameters */ + opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */ + opus_int Lambda_Q10; + opus_int Tilt_Q14[ MAX_NB_SUBFR ]; + opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ]; + + /* Convert control struct to fix control struct */ + /* Noise shape parameters */ + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + for( j = 0; j < psEnc->sCmn.shapingLPCOrder; j++ ) { + AR_Q13[ i * MAX_SHAPE_LPC_ORDER + j ] = silk_float2int( psEncCtrl->AR[ i * MAX_SHAPE_LPC_ORDER + j ] * 8192.0f ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + LF_shp_Q14[ i ] = silk_LSHIFT32( silk_float2int( psEncCtrl->LF_AR_shp[ i ] * 16384.0f ), 16 ) | + (opus_uint16)silk_float2int( psEncCtrl->LF_MA_shp[ i ] * 16384.0f ); + Tilt_Q14[ i ] = (opus_int)silk_float2int( psEncCtrl->Tilt[ i ] * 16384.0f ); + HarmShapeGain_Q14[ i ] = (opus_int)silk_float2int( psEncCtrl->HarmShapeGain[ i ] * 16384.0f ); + } + Lambda_Q10 = ( opus_int )silk_float2int( psEncCtrl->Lambda * 1024.0f ); + + /* prediction and coding parameters */ + for( i = 0; i < psEnc->sCmn.nb_subfr * LTP_ORDER; i++ ) { + LTPCoef_Q14[ i ] = (opus_int16)silk_float2int( psEncCtrl->LTPCoef[ i ] * 16384.0f ); + } + + for( j = 0; j < 2; j++ ) { + for( i = 0; i < psEnc->sCmn.predictLPCOrder; i++ ) { + PredCoef_Q12[ j ][ i ] = (opus_int16)silk_float2int( psEncCtrl->PredCoef[ j ][ i ] * 4096.0f ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + Gains_Q16[ i ] = silk_float2int( psEncCtrl->Gains[ i ] * 65536.0f ); + silk_assert( Gains_Q16[ i ] > 0 ); + } + + if( psIndices->signalType == TYPE_VOICED ) { + LTP_scale_Q14 = silk_LTPScales_table_Q14[ psIndices->LTP_scaleIndex ]; + } else { + LTP_scale_Q14 = 0; + } + + /* Convert input to fix */ + for( i = 0; i < psEnc->sCmn.frame_length; i++ ) { + x16[ i ] = silk_float2int( x[ i ] ); + } + + /* Call NSQ */ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, psNSQ, psIndices, x16, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14, + AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14, psEnc->sCmn.arch ); + } else { + silk_NSQ( &psEnc->sCmn, psNSQ, psIndices, x16, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14, + AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14, psEnc->sCmn.arch ); + } +} + +/***********************************************/ +/* Floating-point Silk LTP quantiation wrapper */ +/***********************************************/ +void silk_quant_LTP_gains_FLP( + silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook index */ + opus_int8 *periodicity_index, /* O Periodicity index */ + opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */ + silk_float *pred_gain_dB, /* O LTP prediction gain */ + const silk_float XX[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Correlation matrix */ + const silk_float xX[ MAX_NB_SUBFR * LTP_ORDER ], /* I Correlation vector */ + const opus_int subfr_len, /* I Number of samples per subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, pred_gain_dB_Q7; + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ]; + opus_int32 XX_Q17[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ]; + opus_int32 xX_Q17[ MAX_NB_SUBFR * LTP_ORDER ]; + + for( i = 0; i < nb_subfr * LTP_ORDER * LTP_ORDER; i++ ) { + XX_Q17[ i ] = (opus_int32)silk_float2int( XX[ i ] * 131072.0f ); + } + for( i = 0; i < nb_subfr * LTP_ORDER; i++ ) { + xX_Q17[ i ] = (opus_int32)silk_float2int( xX[ i ] * 131072.0f ); + } + + silk_quant_LTP_gains( B_Q14, cbk_index, periodicity_index, sum_log_gain_Q7, &pred_gain_dB_Q7, XX_Q17, xX_Q17, subfr_len, nb_subfr, arch ); + + for( i = 0; i < nb_subfr * LTP_ORDER; i++ ) { + B[ i ] = (silk_float)B_Q14[ i ] * ( 1.0f / 16384.0f ); + } + + *pred_gain_dB = (silk_float)pred_gain_dB_Q7 * ( 1.0f / 128.0f ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/gain_quant.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/gain_quant.c new file mode 100644 index 000000000..ee65245aa --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/gain_quant.c @@ -0,0 +1,142 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +#define OFFSET ( ( MIN_QGAIN_DB * 128 ) / 6 + 16 * 128 ) +#define SCALE_Q16 ( ( 65536 * ( N_LEVELS_QGAIN - 1 ) ) / ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) ) +#define INV_SCALE_Q16 ( ( 65536 * ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) ) / ( N_LEVELS_QGAIN - 1 ) ) + +/* Gain scalar quantization with hysteresis, uniform on log scale */ +void silk_gains_quant( + opus_int8 ind[ MAX_NB_SUBFR ], /* O gain indices */ + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* I/O gains (quantized out) */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k, double_step_size_threshold; + + for( k = 0; k < nb_subfr; k++ ) { + /* Convert to log scale, scale, floor() */ + ind[ k ] = silk_SMULWB( SCALE_Q16, silk_lin2log( gain_Q16[ k ] ) - OFFSET ); + + /* Round towards previous quantized gain (hysteresis) */ + if( ind[ k ] < *prev_ind ) { + ind[ k ]++; + } + ind[ k ] = silk_LIMIT_int( ind[ k ], 0, N_LEVELS_QGAIN - 1 ); + + /* Compute delta indices and limit */ + if( k == 0 && conditional == 0 ) { + /* Full index */ + ind[ k ] = silk_LIMIT_int( ind[ k ], *prev_ind + MIN_DELTA_GAIN_QUANT, N_LEVELS_QGAIN - 1 ); + *prev_ind = ind[ k ]; + } else { + /* Delta index */ + ind[ k ] = ind[ k ] - *prev_ind; + + /* Double the quantization step size for large gain increases, so that the max gain level can be reached */ + double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind; + if( ind[ k ] > double_step_size_threshold ) { + ind[ k ] = double_step_size_threshold + silk_RSHIFT( ind[ k ] - double_step_size_threshold + 1, 1 ); + } + + ind[ k ] = silk_LIMIT_int( ind[ k ], MIN_DELTA_GAIN_QUANT, MAX_DELTA_GAIN_QUANT ); + + /* Accumulate deltas */ + if( ind[ k ] > double_step_size_threshold ) { + *prev_ind += silk_LSHIFT( ind[ k ], 1 ) - double_step_size_threshold; + *prev_ind = silk_min_int( *prev_ind, N_LEVELS_QGAIN - 1 ); + } else { + *prev_ind += ind[ k ]; + } + + /* Shift to make non-negative */ + ind[ k ] -= MIN_DELTA_GAIN_QUANT; + } + + /* Scale and convert to linear scale */ + gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */ + } +} + +/* Gains scalar dequantization, uniform on log scale */ +void silk_gains_dequant( + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k, ind_tmp, double_step_size_threshold; + + for( k = 0; k < nb_subfr; k++ ) { + if( k == 0 && conditional == 0 ) { + /* Gain index is not allowed to go down more than 16 steps (~21.8 dB) */ + *prev_ind = silk_max_int( ind[ k ], *prev_ind - 16 ); + } else { + /* Delta index */ + ind_tmp = ind[ k ] + MIN_DELTA_GAIN_QUANT; + + /* Accumulate deltas */ + double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind; + if( ind_tmp > double_step_size_threshold ) { + *prev_ind += silk_LSHIFT( ind_tmp, 1 ) - double_step_size_threshold; + } else { + *prev_ind += ind_tmp; + } + } + *prev_ind = silk_LIMIT_int( *prev_ind, 0, N_LEVELS_QGAIN - 1 ); + + /* Scale and convert to linear scale */ + gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */ + } +} + +/* Compute unique identifier of gain indices vector */ +opus_int32 silk_gains_ID( /* O returns unique identifier of gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k; + opus_int32 gainsID; + + gainsID = 0; + for( k = 0; k < nb_subfr; k++ ) { + gainsID = silk_ADD_LSHIFT32( ind[ k ], gainsID, 8 ); + } + + return gainsID; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/init_decoder.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/init_decoder.c new file mode 100644 index 000000000..16c03dcd1 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/init_decoder.c @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/************************/ +/* Init Decoder State */ +/************************/ +opus_int silk_init_decoder( + silk_decoder_state *psDec /* I/O Decoder state pointer */ +) +{ + /* Clear the entire encoder state, except anything copied */ + silk_memset( psDec, 0, sizeof( silk_decoder_state ) ); + + /* Used to deactivate LSF interpolation */ + psDec->first_frame_after_reset = 1; + psDec->prev_gain_Q16 = 65536; + psDec->arch = opus_select_arch(); + + /* Reset CNG state */ + silk_CNG_Reset( psDec ); + + /* Reset PLC state */ + silk_PLC_Reset( psDec ); + + return(0); +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/init_encoder.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/init_encoder.c new file mode 100644 index 000000000..65995c33f --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/init_encoder.c @@ -0,0 +1,64 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef FIXED_POINT +#include "main_FIX.h" +#else +#include "main_FLP.h" +#endif +#include "tuning_parameters.h" +#include "cpu_support.h" + +/*********************************/ +/* Initialize Silk Encoder state */ +/*********************************/ +opus_int silk_init_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk FIX encoder state */ + int arch /* I Run-time architecture */ +) +{ + opus_int ret = 0; + + /* Clear the entire encoder state */ + silk_memset( psEnc, 0, sizeof( silk_encoder_state_Fxx ) ); + + psEnc->sCmn.arch = arch; + + psEnc->sCmn.variable_HP_smth1_Q15 = silk_LSHIFT( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ), 8 ); + psEnc->sCmn.variable_HP_smth2_Q15 = psEnc->sCmn.variable_HP_smth1_Q15; + + /* Used to deactivate LSF interpolation, pitch prediction */ + psEnc->sCmn.first_frame_after_reset = 1; + + /* Initialize Silk VAD */ + ret += silk_VAD_Init( &psEnc->sCmn.sVAD ); + + return ret; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/inner_prod_aligned.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/inner_prod_aligned.c new file mode 100644 index 000000000..257ae9e04 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/inner_prod_aligned.c @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +opus_int32 silk_inner_prod_aligned_scale( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int scale, /* I number of bits to shift */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i; + opus_int32 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_ADD_RSHIFT32( sum, silk_SMULBB( inVec1[ i ], inVec2[ i ] ), scale ); + } + return sum; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/interpolate.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/interpolate.c new file mode 100644 index 000000000..833c28ef8 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/interpolate.c @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Interpolate two vectors */ +void silk_interpolate( + opus_int16 xi[ MAX_LPC_ORDER ], /* O interpolated vector */ + const opus_int16 x0[ MAX_LPC_ORDER ], /* I first vector */ + const opus_int16 x1[ MAX_LPC_ORDER ], /* I second vector */ + const opus_int ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const opus_int d /* I number of parameters */ +) +{ + opus_int i; + + celt_assert( ifact_Q2 >= 0 ); + celt_assert( ifact_Q2 <= 4 ); + + for( i = 0; i < d; i++ ) { + xi[ i ] = (opus_int16)silk_ADD_RSHIFT( x0[ i ], silk_SMULBB( x1[ i ] - x0[ i ], ifact_Q2 ), 2 ); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/lin2log.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/lin2log.c new file mode 100644 index 000000000..0d5155aa8 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/lin2log.c @@ -0,0 +1,46 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +/* Approximation of 128 * log2() (very close inverse of silk_log2lin()) */ +/* Convert input to a log scale */ +opus_int32 silk_lin2log( + const opus_int32 inLin /* I input in linear scale */ +) +{ + opus_int32 lz, frac_Q7; + + silk_CLZ_FRAC( inLin, &lz, &frac_Q7 ); + + /* Piece-wise parabolic approximation */ + return silk_ADD_LSHIFT32( silk_SMLAWB( frac_Q7, silk_MUL( frac_Q7, 128 - frac_Q7 ), 179 ), 31 - lz, 7 ); +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/log2lin.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/log2lin.c new file mode 100644 index 000000000..b7c48e474 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/log2lin.c @@ -0,0 +1,58 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Approximation of 2^() (very close inverse of silk_lin2log()) */ +/* Convert input to a linear scale */ +opus_int32 silk_log2lin( + const opus_int32 inLog_Q7 /* I input on log scale */ +) +{ + opus_int32 out, frac_Q7; + + if( inLog_Q7 < 0 ) { + return 0; + } else if ( inLog_Q7 >= 3967 ) { + return silk_int32_MAX; + } + + out = silk_LSHIFT( 1, silk_RSHIFT( inLog_Q7, 7 ) ); + frac_Q7 = inLog_Q7 & 0x7F; + if( inLog_Q7 < 2048 ) { + /* Piece-wise parabolic approximation */ + out = silk_ADD_RSHIFT32( out, silk_MUL( out, silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) ), 7 ); + } else { + /* Piece-wise parabolic approximation */ + out = silk_MLA( out, silk_RSHIFT( out, 7 ), silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) ); + } + return out; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/macros.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/macros.h new file mode 100644 index 000000000..3c67b6e5d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/macros.h @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_MACROS_H +#define SILK_MACROS_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_types.h" +#include "opus_defines.h" +#include "arch.h" + +/* This is an OPUS_INLINE header file for general platform. */ + +/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */ +#if OPUS_FAST_INT64 +#define silk_SMULWB(a32, b32) ((opus_int32)(((a32) * (opus_int64)((opus_int16)(b32))) >> 16)) +#else +#define silk_SMULWB(a32, b32) ((((a32) >> 16) * (opus_int32)((opus_int16)(b32))) + ((((a32) & 0x0000FFFF) * (opus_int32)((opus_int16)(b32))) >> 16)) +#endif + +/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */ +#if OPUS_FAST_INT64 +#define silk_SMLAWB(a32, b32, c32) ((opus_int32)((a32) + (((b32) * (opus_int64)((opus_int16)(c32))) >> 16))) +#else +#define silk_SMLAWB(a32, b32, c32) ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16))) +#endif + +/* (a32 * (b32 >> 16)) >> 16 */ +#if OPUS_FAST_INT64 +#define silk_SMULWT(a32, b32) ((opus_int32)(((a32) * (opus_int64)((b32) >> 16)) >> 16)) +#else +#define silk_SMULWT(a32, b32) (((a32) >> 16) * ((b32) >> 16) + ((((a32) & 0x0000FFFF) * ((b32) >> 16)) >> 16)) +#endif + +/* a32 + (b32 * (c32 >> 16)) >> 16 */ +#if OPUS_FAST_INT64 +#define silk_SMLAWT(a32, b32, c32) ((opus_int32)((a32) + (((b32) * ((opus_int64)(c32) >> 16)) >> 16))) +#else +#define silk_SMLAWT(a32, b32, c32) ((a32) + (((b32) >> 16) * ((c32) >> 16)) + ((((b32) & 0x0000FFFF) * ((c32) >> 16)) >> 16)) +#endif + +/* (opus_int32)((opus_int16)(a3))) * (opus_int32)((opus_int16)(b32)) output have to be 32bit int */ +#define silk_SMULBB(a32, b32) ((opus_int32)((opus_int16)(a32)) * (opus_int32)((opus_int16)(b32))) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (opus_int32)((opus_int16)(c32)) output have to be 32bit int */ +#define silk_SMLABB(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32))) + +/* (opus_int32)((opus_int16)(a32)) * (b32 >> 16) */ +#define silk_SMULBT(a32, b32) ((opus_int32)((opus_int16)(a32)) * ((b32) >> 16)) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (c32 >> 16) */ +#define silk_SMLABT(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * ((c32) >> 16)) + +/* a64 + (b32 * c32) */ +#define silk_SMLAL(a64, b32, c32) (silk_ADD64((a64), ((opus_int64)(b32) * (opus_int64)(c32)))) + +/* (a32 * b32) >> 16 */ +#if OPUS_FAST_INT64 +#define silk_SMULWW(a32, b32) ((opus_int32)(((opus_int64)(a32) * (b32)) >> 16)) +#else +#define silk_SMULWW(a32, b32) silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)) +#endif + +/* a32 + ((b32 * c32) >> 16) */ +#if OPUS_FAST_INT64 +#define silk_SMLAWW(a32, b32, c32) ((opus_int32)((a32) + (((opus_int64)(b32) * (c32)) >> 16))) +#else +#define silk_SMLAWW(a32, b32, c32) silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16)) +#endif + +/* add/subtract with output saturated */ +#define silk_ADD_SAT32(a, b) ((((opus_uint32)(a) + (opus_uint32)(b)) & 0x80000000) == 0 ? \ + ((((a) & (b)) & 0x80000000) != 0 ? silk_int32_MIN : (a)+(b)) : \ + ((((a) | (b)) & 0x80000000) == 0 ? silk_int32_MAX : (a)+(b)) ) + +#define silk_SUB_SAT32(a, b) ((((opus_uint32)(a)-(opus_uint32)(b)) & 0x80000000) == 0 ? \ + (( (a) & ((b)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a)-(b)) : \ + ((((a)^0x80000000) & (b) & 0x80000000) ? silk_int32_MAX : (a)-(b)) ) + +#if defined(MIPSr1_ASM) +#include "mips/macros_mipsr1.h" +#endif + +#include "ecintrin.h" +#ifndef OVERRIDE_silk_CLZ16 +static OPUS_INLINE opus_int32 silk_CLZ16(opus_int16 in16) +{ + return 32 - EC_ILOG(in16<<16|0x8000); +} +#endif + +#ifndef OVERRIDE_silk_CLZ32 +static OPUS_INLINE opus_int32 silk_CLZ32(opus_int32 in32) +{ + return in32 ? 32 - EC_ILOG(in32) : 32; +} +#endif + +/* Row based */ +#define matrix_ptr(Matrix_base_adr, row, column, N) \ + (*((Matrix_base_adr) + ((row)*(N)+(column)))) +#define matrix_adr(Matrix_base_adr, row, column, N) \ + ((Matrix_base_adr) + ((row)*(N)+(column))) + +/* Column based */ +#ifndef matrix_c_ptr +# define matrix_c_ptr(Matrix_base_adr, row, column, M) \ + (*((Matrix_base_adr) + ((row)+(M)*(column)))) +#endif + +#ifdef OPUS_ARM_INLINE_ASM +#include "arm/macros_armv4.h" +#endif + +#ifdef OPUS_ARM_INLINE_EDSP +#include "arm/macros_armv5e.h" +#endif + +#ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR +#include "arm/macros_arm64.h" +#endif + +#endif /* SILK_MACROS_H */ + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/main.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/main.h new file mode 100644 index 000000000..1a33eed54 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/main.h @@ -0,0 +1,476 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_MAIN_H +#define SILK_MAIN_H + +#include "SigProc_FIX.h" +#include "define.h" +#include "structs.h" +#include "tables.h" +#include "PLC.h" +#include "control.h" +#include "debug.h" +#include "entenc.h" +#include "entdec.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) +#include "x86/main_sse.h" +#endif + +#if (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#include "arm/NSQ_del_dec_arm.h" +#endif + +/* Convert Left/Right stereo signal to adaptive Mid/Side representation */ +void silk_stereo_LR_to_MS( + stereo_enc_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */ + opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */ + opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */ + opus_int32 total_rate_bps, /* I Total bitrate */ + opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */ + opus_int toMono, /* I Last frame before a stereo->mono transition */ + opus_int fs_kHz, /* I Sample rate (kHz) */ + opus_int frame_length /* I Number of samples */ +); + +/* Convert adaptive Mid/Side representation to Left/Right stereo signal */ +void silk_stereo_MS_to_LR( + stereo_dec_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + const opus_int32 pred_Q13[], /* I Predictors */ + opus_int fs_kHz, /* I Samples rate (kHz) */ + opus_int frame_length /* I Number of samples */ +); + +/* Find least-squares prediction gain for one signal based on another and quantize it */ +opus_int32 silk_stereo_find_predictor( /* O Returns predictor in Q13 */ + opus_int32 *ratio_Q14, /* O Ratio of residual and mid energies */ + const opus_int16 x[], /* I Basis signal */ + const opus_int16 y[], /* I Target signal */ + opus_int32 mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */ + opus_int length, /* I Number of samples */ + opus_int smooth_coef_Q16 /* I Smoothing coefficient */ +); + +/* Quantize mid/side predictors */ +void silk_stereo_quant_pred( + opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */ + opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */ +); + +/* Entropy code the mid/side quantization indices */ +void silk_stereo_encode_pred( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */ +); + +/* Entropy code the mid-only flag */ +void silk_stereo_encode_mid_only( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 mid_only_flag +); + +/* Decode mid/side predictors */ +void silk_stereo_decode_pred( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int32 pred_Q13[] /* O Predictors */ +); + +/* Decode mid-only flag */ +void silk_stereo_decode_mid_only( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int *decode_only_mid /* O Flag that only mid channel has been coded */ +); + +/* Encodes signs of excitation */ +void silk_encode_signs( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + const opus_int8 pulses[], /* I pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +); + +/* Decodes signs of excitation */ +void silk_decode_signs( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pulses[], /* I/O pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +); + +/* Check encoder control struct */ +opus_int check_control_input( + silk_EncControlStruct *encControl /* I Control structure */ +); + +/* Control internal sampling rate */ +opus_int silk_control_audio_bandwidth( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl /* I Control structure */ +); + +/* Control SNR of redidual quantizer */ +opus_int silk_control_SNR( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + opus_int32 TargetRate_bps /* I Target max bitrate (bps) */ +); + +/***************/ +/* Shell coder */ +/***************/ + +/* Encode quantization indices of excitation */ +void silk_encode_pulses( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I quantOffsetType */ + opus_int8 pulses[], /* I quantization indices */ + const opus_int frame_length /* I Frame length */ +); + +/* Shell encoder, operates on one shell code frame of 16 pulses */ +void silk_shell_encoder( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int *pulses0 /* I data: nonnegative pulse amplitudes */ +); + +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void silk_shell_decoder( + opus_int16 *pulses0, /* O data: nonnegative pulse amplitudes */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int pulses4 /* I number of pulses per pulse-subframe */ +); + +/* Gain scalar quantization with hysteresis, uniform on log scale */ +void silk_gains_quant( + opus_int8 ind[ MAX_NB_SUBFR ], /* O gain indices */ + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* I/O gains (quantized out) */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Gains scalar dequantization, uniform on log scale */ +void silk_gains_dequant( + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Compute unique identifier of gain indices vector */ +opus_int32 silk_gains_ID( /* O returns unique identifier of gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Interpolate two vectors */ +void silk_interpolate( + opus_int16 xi[ MAX_LPC_ORDER ], /* O interpolated vector */ + const opus_int16 x0[ MAX_LPC_ORDER ], /* I first vector */ + const opus_int16 x1[ MAX_LPC_ORDER ], /* I second vector */ + const opus_int ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const opus_int d /* I number of parameters */ +); + +/* LTP tap quantizer */ +void silk_quant_LTP_gains( + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */ + opus_int8 *periodicity_index, /* O Periodicity Index */ + opus_int32 *sum_gain_dB_Q7, /* I/O Cumulative max prediction gain */ + opus_int *pred_gain_dB_Q7, /* O LTP prediction gain */ + const opus_int32 XX_Q17[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Correlation matrix in Q18 */ + const opus_int32 xX_Q17[ MAX_NB_SUBFR*LTP_ORDER ], /* I Correlation vector in Q18 */ + const opus_int subfr_len, /* I Number of samples per subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +); + +/* Entropy constrained matrix-weighted VQ, for a single input data vector */ +void silk_VQ_WMat_EC_c( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *res_nrg_Q15, /* O best residual energy */ + opus_int32 *rate_dist_Q8, /* O best total bitrate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int32 *XX_Q17, /* I correlation matrix */ + const opus_int32 *xX_Q17, /* I correlation vector */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int subfr_len, /* I number of samples per subframe */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + const opus_int L /* I number of vectors in codebook */ +); + +#if !defined(OVERRIDE_silk_VQ_WMat_EC) +#define silk_VQ_WMat_EC(ind, res_nrg_Q15, rate_dist_Q8, gain_Q7, XX_Q17, xX_Q17, cb_Q7, cb_gain_Q7, cl_Q5, subfr_len, max_gain_Q7, L, arch) \ + ((void)(arch),silk_VQ_WMat_EC_c(ind, res_nrg_Q15, rate_dist_Q8, gain_Q7, XX_Q17, xX_Q17, cb_Q7, cb_gain_Q7, cl_Q5, subfr_len, max_gain_Q7, L)) +#endif + +/************************************/ +/* Noise shaping quantization (NSQ) */ +/************************************/ + +void silk_NSQ_c( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +#if !defined(OVERRIDE_silk_NSQ) +#define silk_NSQ(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((void)(arch),silk_NSQ_c(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) +#endif + +/* Noise shaping using delayed decision */ +void silk_NSQ_del_dec_c( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +#if !defined(OVERRIDE_silk_NSQ_del_dec) +#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((void)(arch),silk_NSQ_del_dec_c(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) +#endif + +/************/ +/* Silk VAD */ +/************/ +/* Initialize the Silk VAD */ +opus_int silk_VAD_Init( /* O Return value, 0 if success */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); + +/* Get speech activity level in Q8 */ +opus_int silk_VAD_GetSA_Q8_c( /* O Return value, 0 if success */ + silk_encoder_state *psEncC, /* I/O Encoder state */ + const opus_int16 pIn[] /* I PCM input */ +); + +#if !defined(OVERRIDE_silk_VAD_GetSA_Q8) +#define silk_VAD_GetSA_Q8(psEnC, pIn, arch) ((void)(arch),silk_VAD_GetSA_Q8_c(psEnC, pIn)) +#endif + +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting transition_frame_no = 1; */ +void silk_LP_variable_cutoff( + silk_LP_state *psLP, /* I/O LP filter state */ + opus_int16 *frame, /* I/O Low-pass filtered output signal */ + const opus_int frame_length /* I Frame length */ +); + +/******************/ +/* NLSF Quantizer */ +/******************/ +/* Limit, stabilize, convert and quantize NLSFs */ +void silk_process_NLSFs( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +); + +opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + opus_int16 *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int16 *pW_QW, /* I NLSF weight vector [ LPC_ORDER ] */ + const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */ + const opus_int nSurvivors, /* I Max survivors after first stage */ + const opus_int signalType /* I Signal type: 0/1/2 */ +); + +/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */ +void silk_NLSF_VQ( + opus_int32 err_Q26[], /* O Quantization errors [K] */ + const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */ + const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */ + const opus_int16 pWght_Q9[], /* I Codebook weights [K*LPC_order] */ + const opus_int K, /* I Number of codebook vectors */ + const opus_int LPC_order /* I Number of LPCs */ +); + +/* Delayed-decision quantizer for NLSF residuals */ +opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */ + opus_int8 indices[], /* O Quantization indices [ order ] */ + const opus_int16 x_Q10[], /* I Input [ order ] */ + const opus_int16 w_Q5[], /* I Weights [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */ + const opus_uint8 ec_rates_Q5[], /* I Rates [] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */ + const opus_int32 mu_Q20, /* I R/D tradeoff */ + const opus_int16 order /* I Number of input values */ +); + +/* Unpack predictor values and indices for entropy coding tables */ +void silk_NLSF_unpack( + opus_int16 ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */ + opus_uint8 pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int CB1_index /* I Index of vector in first LSF codebook */ +); + +/***********************/ +/* NLSF vector decoder */ +/***********************/ +void silk_NLSF_decode( + opus_int16 *pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + const silk_NLSF_CB_struct *psNLSF_CB /* I Codebook object */ +); + +/****************************************************/ +/* Decoder Functions */ +/****************************************************/ +opus_int silk_init_decoder( + silk_decoder_state *psDec /* I/O Decoder state pointer */ +); + +/* Set decoder sampling rate */ +opus_int silk_decoder_set_fs( + silk_decoder_state *psDec, /* I/O Decoder state pointer */ + opus_int fs_kHz, /* I Sampling frequency (kHz) */ + opus_int32 fs_API_Hz /* I API Sampling frequency (Hz) */ +); + +/****************/ +/* Decode frame */ +/****************/ +opus_int silk_decode_frame( + silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pOut[], /* O Pointer to output speech frame */ + opus_int32 *pN, /* O Pointer to size of output frame */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int condCoding, /* I The type of conditional coding to use */ + int arch /* I Run-time architecture */ +); + +/* Decode indices from bitstream */ +void silk_decode_indices( + silk_decoder_state *psDec, /* I/O State */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int decode_LBRR, /* I Flag indicating LBRR data is being decoded */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* Decode parameters from payload */ +void silk_decode_parameters( + silk_decoder_state *psDec, /* I/O State */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +void silk_decode_core( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I Decoder control */ + opus_int16 xq[], /* O Decoded speech */ + const opus_int16 pulses[ MAX_FRAME_LENGTH ], /* I Pulse signal */ + int arch /* I Run-time architecture */ +); + +/* Decode quantization indices of excitation (Shell coding) */ +void silk_decode_pulses( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pulses[], /* O Excitation signal */ + const opus_int signalType, /* I Sigtype */ + const opus_int quantOffsetType, /* I quantOffsetType */ + const opus_int frame_length /* I Frame length */ +); + +/******************/ +/* CNG */ +/******************/ + +/* Reset CNG */ +void silk_CNG_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +); + +/* Updates CNG estimate, and applies the CNG when packet was lost */ +void silk_CNG( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O Signal */ + opus_int length /* I Length of residual */ +); + +/* Encoding of various parameters */ +void silk_encode_indices( + silk_encoder_state *psEncC, /* I/O Encoder state */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/meson.build b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/meson.build new file mode 100644 index 000000000..706923727 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/meson.build @@ -0,0 +1,53 @@ +silk_sources = sources['SILK_SOURCES'] + +silk_sources_sse4_1 = sources['SILK_SOURCES_SSE4_1'] + +silk_sources_neon_intr = sources['SILK_SOURCES_ARM_NEON_INTR'] + +silk_sources_fixed_neon_intr = sources['SILK_SOURCES_FIXED_ARM_NEON_INTR'] + +silk_sources_fixed = sources['SILK_SOURCES_FIXED'] + +silk_sources_fixed_sse4_1 = sources['SILK_SOURCES_FIXED_SSE4_1'] + +silk_sources_float = sources['SILK_SOURCES_FLOAT'] + +if opt_fixed_point + silk_sources += silk_sources_fixed +else + silk_sources += silk_sources_float +endif + +silk_includes = [opus_includes, include_directories('float', 'fixed')] +silk_static_libs = [] + +foreach intr_name : ['sse4_1', 'neon_intr'] + have_intr = get_variable('have_' + intr_name) + if not have_intr + continue + endif + + intr_sources = get_variable('silk_sources_' + intr_name) + if opt_fixed_point + intr_sources += get_variable('silk_sources_fixed_' + intr_name) + endif + + intr_args = get_variable('opus_@0@_args'.format(intr_name), []) + silk_static_libs += static_library('silk_' + intr_name, intr_sources, + c_args: intr_args, + include_directories: silk_includes, + install: false) +endforeach + +silk_c_args = [] +if host_machine.system() == 'windows' + silk_c_args += ['-DDLL_EXPORT'] +endif + +silk_lib = static_library('opus-silk', + silk_sources, + c_args: silk_c_args, + include_directories: silk_includes, + link_whole: silk_static_libs, + dependencies: libm, + install: false) diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/mips/NSQ_del_dec_mipsr1.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/mips/NSQ_del_dec_mipsr1.h new file mode 100644 index 000000000..cd70713a8 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/mips/NSQ_del_dec_mipsr1.h @@ -0,0 +1,410 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef __NSQ_DEL_DEC_MIPSR1_H__ +#define __NSQ_DEL_DEC_MIPSR1_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +#define OVERRIDE_silk_noise_shape_quantizer_del_dec +static inline void silk_noise_shape_quantizer_del_dec( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay, /* I */ + int arch /* I */ +) +{ + opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + opus_int32 Winner_rand_state; + opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14; + opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10; + opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14; + NSQ_sample_struct psSampleState[ MAX_DEL_DEC_STATES ][ 2 ]; + NSQ_del_dec_struct *psDD; + NSQ_sample_struct *psSS; + opus_int16 b_Q14_0, b_Q14_1, b_Q14_2, b_Q14_3, b_Q14_4; + opus_int16 a_Q12_0, a_Q12_1, a_Q12_2, a_Q12_3, a_Q12_4, a_Q12_5, a_Q12_6; + opus_int16 a_Q12_7, a_Q12_8, a_Q12_9, a_Q12_10, a_Q12_11, a_Q12_12, a_Q12_13; + opus_int16 a_Q12_14, a_Q12_15; + + opus_int32 cur, prev, next; + + /*Unused.*/ + (void)arch; + + //Intialize b_Q14 variables + b_Q14_0 = b_Q14[ 0 ]; + b_Q14_1 = b_Q14[ 1 ]; + b_Q14_2 = b_Q14[ 2 ]; + b_Q14_3 = b_Q14[ 3 ]; + b_Q14_4 = b_Q14[ 4 ]; + + //Intialize a_Q12 variables + a_Q12_0 = a_Q12[0]; + a_Q12_1 = a_Q12[1]; + a_Q12_2 = a_Q12[2]; + a_Q12_3 = a_Q12[3]; + a_Q12_4 = a_Q12[4]; + a_Q12_5 = a_Q12[5]; + a_Q12_6 = a_Q12[6]; + a_Q12_7 = a_Q12[7]; + a_Q12_8 = a_Q12[8]; + a_Q12_9 = a_Q12[9]; + a_Q12_10 = a_Q12[10]; + a_Q12_11 = a_Q12[11]; + a_Q12_12 = a_Q12[12]; + a_Q12_13 = a_Q12[13]; + a_Q12_14 = a_Q12[14]; + a_Q12_15 = a_Q12[15]; + + long long temp64; + + silk_assert( nStatesDelayedDecision > 0 ); + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + for( i = 0; i < length; i++ ) { + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + temp64 = __builtin_mips_mult(pred_lag_ptr[ 0 ], b_Q14_0 ); + temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -1 ], b_Q14_1 ); + temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -2 ], b_Q14_2 ); + temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -3 ], b_Q14_3 ); + temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -4 ], b_Q14_4 ); + temp64 += 32768; + LTP_pred_Q14 = __builtin_mips_extr_w(temp64, 16); + LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */ + pred_lag_ptr++; + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */ + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + /* Delayed decision state */ + psDD = &psDelDec[ k ]; + + /* Sample state */ + psSS = psSampleState[ k ]; + + /* Generate dither */ + psDD->Seed = silk_RAND( psDD->Seed ); + + /* Pointer used in short term prediction and shaping */ + psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ]; + /* Short-term prediction */ + silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 ); + temp64 = __builtin_mips_mult(psLPC_Q14[ 0 ], a_Q12_0 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -1 ], a_Q12_1 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -2 ], a_Q12_2 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -3 ], a_Q12_3 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -4 ], a_Q12_4 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -5 ], a_Q12_5 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -6 ], a_Q12_6 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -7 ], a_Q12_7 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -8 ], a_Q12_8 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -9 ], a_Q12_9 ); + if( predictLPCOrder == 16 ) { + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -10 ], a_Q12_10 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -11 ], a_Q12_11 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -12 ], a_Q12_12 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -13 ], a_Q12_13 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -14 ], a_Q12_14 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -15 ], a_Q12_15 ); + } + temp64 += 32768; + LPC_pred_Q14 = __builtin_mips_extr_w(temp64, 16); + + LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */ + + /* Noise shape feedback */ + silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ 0 ] = tmp2; + + temp64 = __builtin_mips_mult(tmp2, AR_shp_Q13[ 0 ] ); + + prev = psDD->sAR2_Q14[ 1 ]; + + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + cur = psDD->sAR2_Q14[ j ]; + next = psDD->sAR2_Q14[ j+1 ]; + /* Output of allpass section */ + tmp2 = silk_SMLAWB( prev, cur - tmp1, warping_Q16 ); + psDD->sAR2_Q14[ j - 1 ] = tmp1; + temp64 = __builtin_mips_madd( temp64, tmp1, AR_shp_Q13[ j - 1 ] ); + temp64 = __builtin_mips_madd( temp64, tmp2, AR_shp_Q13[ j ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( cur, next - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ j + 0 ] = tmp2; + prev = next; + } + psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + temp64 = __builtin_mips_madd( temp64, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + temp64 += 32768; + n_AR_Q14 = __builtin_mips_extr_w(temp64, 16); + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */ + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */ + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */ + + n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */ + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */ + tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */ + tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */ + + r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if ( psDD->Seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 ); + + if( rd1_Q10 < rd2_Q10 ) { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 0 ].Q_Q10 = q1_Q10; + psSS[ 1 ].Q_Q10 = q2_Q10; + } else { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 0 ].Q_Q10 = q2_Q10; + psSS[ 1 ].Q_Q10 = q1_Q10; + } + + /* Update states for best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 ); + psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 0 ].xq_Q14 = xq_Q14; + + /* Update states for second best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 ); + psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 1 ].xq_Q14 = xq_Q14; + } + + *smpl_buf_idx = ( *smpl_buf_idx - 1 ) % DECISION_DELAY; + if( *smpl_buf_idx < 0 ) *smpl_buf_idx += DECISION_DELAY; + last_smple_idx = ( *smpl_buf_idx + decisionDelay ) % DECISION_DELAY; + + /* Find winner */ + RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + Winner_ind = k; + } + } + + /* Increase RD values of expired states */ + Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ]; + for( k = 0; k < nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) { + psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 ); + psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 ); + silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 ); + } + } + + /* Find worst in first set and best in second set */ + RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10; + RDmax_ind = 0; + RDmin_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + /* find worst in first set */ + if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) { + RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + RDmax_ind = k; + } + /* find best in second set */ + if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10; + RDmin_ind = k; + } + } + + /* Replace a state if best from second set outperforms worst in first set */ + if( RDmin_Q10 < RDmax_Q10 ) { + silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i, + ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) ); + silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) ); + } + + /* Write samples from winner to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + if( subfr > 0 || i >= decisionDelay ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ]; + sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ]; + } + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Update states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psSS = &psSampleState[ k ][ 0 ]; + psDD->LF_AR_Q14 = psSS->LF_AR_Q14; + psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14; + psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14; + psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10; + psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 ); + psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14; + psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) ); + psDD->RandState[ *smpl_buf_idx ] = psDD->Seed; + psDD->RD_Q10 = psSS->RD_Q10; + } + delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10; + } + /* Update LPC states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + } +} + +#endif /* __NSQ_DEL_DEC_MIPSR1_H__ */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/mips/macros_mipsr1.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/mips/macros_mipsr1.h new file mode 100644 index 000000000..12ed981a6 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/mips/macros_mipsr1.h @@ -0,0 +1,92 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + + +#ifndef __SILK_MACROS_MIPSR1_H__ +#define __SILK_MACROS_MIPSR1_H__ + +#define mips_clz(x) __builtin_clz(x) + +#undef silk_SMULWB +static inline int silk_SMULWB(int a, int b) +{ + long long ac; + int c; + + ac = __builtin_mips_mult(a, (opus_int32)(opus_int16)b); + c = __builtin_mips_extr_w(ac, 16); + + return c; +} + +#undef silk_SMLAWB +#define silk_SMLAWB(a32, b32, c32) ((a32) + silk_SMULWB(b32, c32)) + +#undef silk_SMULWW +static inline int silk_SMULWW(int a, int b) +{ + long long ac; + int c; + + ac = __builtin_mips_mult(a, b); + c = __builtin_mips_extr_w(ac, 16); + + return c; +} + +#undef silk_SMLAWW +static inline int silk_SMLAWW(int a, int b, int c) +{ + long long ac; + int res; + + ac = __builtin_mips_mult(b, c); + res = __builtin_mips_extr_w(ac, 16); + res += a; + + return res; +} + +#define OVERRIDE_silk_CLZ16 +static inline opus_int32 silk_CLZ16(opus_int16 in16) +{ + int re32; + opus_int32 in32 = (opus_int32 )in16; + re32 = mips_clz(in32); + re32-=16; + return re32; +} + +#define OVERRIDE_silk_CLZ32 +static inline opus_int32 silk_CLZ32(opus_int32 in32) +{ + int re32; + re32 = mips_clz(in32); + return re32; +} + +#endif /* __SILK_MACROS_MIPSR1_H__ */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/mips/sigproc_fix_mipsr1.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/mips/sigproc_fix_mipsr1.h new file mode 100644 index 000000000..51520c0a6 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/mips/sigproc_fix_mipsr1.h @@ -0,0 +1,60 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FIX_MIPSR1_H +#define SILK_SIGPROC_FIX_MIPSR1_H + +#undef silk_SAT16 +static inline short int silk_SAT16(int a) +{ + int c; + c = __builtin_mips_shll_s_w(a, 16); + c = c>>16; + + return c; +} + +#undef silk_LSHIFT_SAT32 +static inline int silk_LSHIFT_SAT32(int a, int shift) +{ + int r; + + r = __builtin_mips_shll_s_w(a, shift); + + return r; +} + +#undef silk_RSHIFT_ROUND +static inline int silk_RSHIFT_ROUND(int a, int shift) +{ + int r; + + r = __builtin_mips_shra_r_w(a, shift); + return r; +} + +#endif /* SILK_SIGPROC_FIX_MIPSR1_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/pitch_est_defines.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/pitch_est_defines.h new file mode 100644 index 000000000..e1e4b5d76 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/pitch_est_defines.h @@ -0,0 +1,88 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_PE_DEFINES_H +#define SILK_PE_DEFINES_H + +#include "SigProc_FIX.h" + +/********************************************************/ +/* Definitions for pitch estimator */ +/********************************************************/ + +#define PE_MAX_FS_KHZ 16 /* Maximum sampling frequency used */ + +#define PE_MAX_NB_SUBFR 4 +#define PE_SUBFR_LENGTH_MS 5 /* 5 ms */ + +#define PE_LTP_MEM_LENGTH_MS ( 4 * PE_SUBFR_LENGTH_MS ) + +#define PE_MAX_FRAME_LENGTH_MS ( PE_LTP_MEM_LENGTH_MS + PE_MAX_NB_SUBFR * PE_SUBFR_LENGTH_MS ) +#define PE_MAX_FRAME_LENGTH ( PE_MAX_FRAME_LENGTH_MS * PE_MAX_FS_KHZ ) +#define PE_MAX_FRAME_LENGTH_ST_1 ( PE_MAX_FRAME_LENGTH >> 2 ) +#define PE_MAX_FRAME_LENGTH_ST_2 ( PE_MAX_FRAME_LENGTH >> 1 ) + +#define PE_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ +#define PE_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ +#define PE_MAX_LAG ( PE_MAX_LAG_MS * PE_MAX_FS_KHZ ) +#define PE_MIN_LAG ( PE_MIN_LAG_MS * PE_MAX_FS_KHZ ) + +#define PE_D_SRCH_LENGTH 24 + +#define PE_NB_STAGE3_LAGS 5 + +#define PE_NB_CBKS_STAGE2 3 +#define PE_NB_CBKS_STAGE2_EXT 11 + +#define PE_NB_CBKS_STAGE3_MAX 34 +#define PE_NB_CBKS_STAGE3_MID 24 +#define PE_NB_CBKS_STAGE3_MIN 16 + +#define PE_NB_CBKS_STAGE3_10MS 12 +#define PE_NB_CBKS_STAGE2_10MS 3 + +#define PE_SHORTLAG_BIAS 0.2f /* for logarithmic weighting */ +#define PE_PREVLAG_BIAS 0.2f /* for logarithmic weighting */ +#define PE_FLATCONTOUR_BIAS 0.05f + +#define SILK_PE_MIN_COMPLEX 0 +#define SILK_PE_MID_COMPLEX 1 +#define SILK_PE_MAX_COMPLEX 2 + +/* Tables for 20 ms frames */ +extern const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ]; +extern const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ]; +extern const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ]; +extern const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ]; + +/* Tables for 10 ms frames */ +extern const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ 3 ]; +extern const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 12 ]; +extern const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ]; + +#endif + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/pitch_est_tables.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/pitch_est_tables.c new file mode 100644 index 000000000..81a8bacac --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/pitch_est_tables.c @@ -0,0 +1,99 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "typedef.h" +#include "pitch_est_defines.h" + +const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ PE_NB_CBKS_STAGE2_10MS ] = +{ + {0, 1, 0}, + {0, 0, 1} +}; + +const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ PE_NB_CBKS_STAGE3_10MS ] = +{ + { 0, 0, 1,-1, 1,-1, 2,-2, 2,-2, 3,-3}, + { 0, 1, 0, 1,-1, 2,-1, 2,-2, 3,-2, 3} +}; + +const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ] = +{ + {-3, 7}, + {-2, 7} +}; + +const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ] = +{ + {0, 2,-1,-1,-1, 0, 0, 1, 1, 0, 1}, + {0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0}, + {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0}, + {0,-1, 2, 1, 0, 1, 1, 0, 0,-1,-1} +}; + +const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ] = +{ + {0, 0, 1,-1, 0, 1,-1, 0,-1, 1,-2, 2,-2,-2, 2,-3, 2, 3,-3,-4, 3,-4, 4, 4,-5, 5,-6,-5, 6,-7, 6, 5, 8,-9}, + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1,-1, 0, 1,-1,-1, 1,-1, 2, 1,-1, 2,-2,-2, 2,-2, 2, 2, 3,-3}, + {0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1,-1, 1, 0, 0, 2, 1,-1, 2,-1,-1, 2,-1, 2, 2,-1, 3,-2,-2,-2, 3}, + {0, 1, 0, 0, 1, 0, 1,-1, 2,-1, 2,-1, 2, 3,-2, 3,-2,-2, 4, 4,-3, 5,-3,-4, 6,-4, 6, 5,-5, 8,-6,-5,-7, 9} +}; + +const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ] = +{ + /* Lags to search for low number of stage3 cbks */ + { + {-5,8}, + {-1,6}, + {-1,6}, + {-4,10} + }, + /* Lags to search for middle number of stage3 cbks */ + { + {-6,10}, + {-2,6}, + {-1,6}, + {-5,10} + }, + /* Lags to search for max number of stage3 cbks */ + { + {-9,12}, + {-3,7}, + {-2,7}, + {-7,13} + } +}; + +const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ] = +{ + PE_NB_CBKS_STAGE3_MIN, + PE_NB_CBKS_STAGE3_MID, + PE_NB_CBKS_STAGE3_MAX +}; diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/process_NLSFs.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/process_NLSFs.c new file mode 100644 index 000000000..d13080954 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/process_NLSFs.c @@ -0,0 +1,107 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Limit, stabilize, convert and quantize NLSFs */ +void silk_process_NLSFs( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +) +{ + opus_int i, doInterpolate; + opus_int NLSF_mu_Q20; + opus_int16 i_sqr_Q15; + opus_int16 pNLSF0_temp_Q15[ MAX_LPC_ORDER ]; + opus_int16 pNLSFW_QW[ MAX_LPC_ORDER ]; + opus_int16 pNLSFW0_temp_QW[ MAX_LPC_ORDER ]; + + silk_assert( psEncC->speech_activity_Q8 >= 0 ); + silk_assert( psEncC->speech_activity_Q8 <= SILK_FIX_CONST( 1.0, 8 ) ); + celt_assert( psEncC->useInterpolatedNLSFs == 1 || psEncC->indices.NLSFInterpCoef_Q2 == ( 1 << 2 ) ); + + /***********************/ + /* Calculate mu values */ + /***********************/ + /* NLSF_mu = 0.003 - 0.0015 * psEnc->speech_activity; */ + NLSF_mu_Q20 = silk_SMLAWB( SILK_FIX_CONST( 0.003, 20 ), SILK_FIX_CONST( -0.001, 28 ), psEncC->speech_activity_Q8 ); + if( psEncC->nb_subfr == 2 ) { + /* Multiply by 1.5 for 10 ms packets */ + NLSF_mu_Q20 = silk_ADD_RSHIFT( NLSF_mu_Q20, NLSF_mu_Q20, 1 ); + } + + celt_assert( NLSF_mu_Q20 > 0 ); + silk_assert( NLSF_mu_Q20 <= SILK_FIX_CONST( 0.005, 20 ) ); + + /* Calculate NLSF weights */ + silk_NLSF_VQ_weights_laroia( pNLSFW_QW, pNLSF_Q15, psEncC->predictLPCOrder ); + + /* Update NLSF weights for interpolated NLSFs */ + doInterpolate = ( psEncC->useInterpolatedNLSFs == 1 ) && ( psEncC->indices.NLSFInterpCoef_Q2 < 4 ); + if( doInterpolate ) { + /* Calculate the interpolated NLSF vector for the first half */ + silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15, + psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder ); + + /* Calculate first half NLSF weights for the interpolated NLSFs */ + silk_NLSF_VQ_weights_laroia( pNLSFW0_temp_QW, pNLSF0_temp_Q15, psEncC->predictLPCOrder ); + + /* Update NLSF weights with contribution from first half */ + i_sqr_Q15 = silk_LSHIFT( silk_SMULBB( psEncC->indices.NLSFInterpCoef_Q2, psEncC->indices.NLSFInterpCoef_Q2 ), 11 ); + for( i = 0; i < psEncC->predictLPCOrder; i++ ) { + pNLSFW_QW[ i ] = silk_ADD16( silk_RSHIFT( pNLSFW_QW[ i ], 1 ), silk_RSHIFT( + silk_SMULBB( pNLSFW0_temp_QW[ i ], i_sqr_Q15 ), 16) ); + silk_assert( pNLSFW_QW[ i ] >= 1 ); + } + } + + silk_NLSF_encode( psEncC->indices.NLSFIndices, pNLSF_Q15, psEncC->psNLSF_CB, pNLSFW_QW, + NLSF_mu_Q20, psEncC->NLSF_MSVQ_Survivors, psEncC->indices.signalType ); + + /* Convert quantized NLSFs back to LPC coefficients */ + silk_NLSF2A( PredCoef_Q12[ 1 ], pNLSF_Q15, psEncC->predictLPCOrder, psEncC->arch ); + + if( doInterpolate ) { + /* Calculate the interpolated, quantized LSF vector for the first half */ + silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15, + psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder ); + + /* Convert back to LPC coefficients */ + silk_NLSF2A( PredCoef_Q12[ 0 ], pNLSF0_temp_Q15, psEncC->predictLPCOrder, psEncC->arch ); + + } else { + /* Copy LPC coefficients for first half from second half */ + celt_assert( psEncC->predictLPCOrder <= MAX_LPC_ORDER ); + silk_memcpy( PredCoef_Q12[ 0 ], PredCoef_Q12[ 1 ], psEncC->predictLPCOrder * sizeof( opus_int16 ) ); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/quant_LTP_gains.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/quant_LTP_gains.c new file mode 100644 index 000000000..d6b8eff8d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/quant_LTP_gains.c @@ -0,0 +1,132 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "tuning_parameters.h" + +void silk_quant_LTP_gains( + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */ + opus_int8 *periodicity_index, /* O Periodicity Index */ + opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */ + opus_int *pred_gain_dB_Q7, /* O LTP prediction gain */ + const opus_int32 XX_Q17[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Correlation matrix in Q18 */ + const opus_int32 xX_Q17[ MAX_NB_SUBFR*LTP_ORDER ], /* I Correlation vector in Q18 */ + const opus_int subfr_len, /* I Number of samples per subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +) +{ + opus_int j, k, cbk_size; + opus_int8 temp_idx[ MAX_NB_SUBFR ]; + const opus_uint8 *cl_ptr_Q5; + const opus_int8 *cbk_ptr_Q7; + const opus_uint8 *cbk_gain_ptr_Q7; + const opus_int32 *XX_Q17_ptr, *xX_Q17_ptr; + opus_int32 res_nrg_Q15_subfr, res_nrg_Q15, rate_dist_Q7_subfr, rate_dist_Q7, min_rate_dist_Q7; + opus_int32 sum_log_gain_tmp_Q7, best_sum_log_gain_Q7, max_gain_Q7; + opus_int gain_Q7; + + /***************************************************/ + /* iterate over different codebooks with different */ + /* rates/distortions, and choose best */ + /***************************************************/ + min_rate_dist_Q7 = silk_int32_MAX; + best_sum_log_gain_Q7 = 0; + for( k = 0; k < 3; k++ ) { + /* Safety margin for pitch gain control, to take into account factors + such as state rescaling/rewhitening. */ + opus_int32 gain_safety = SILK_FIX_CONST( 0.4, 7 ); + + cl_ptr_Q5 = silk_LTP_gain_BITS_Q5_ptrs[ k ]; + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ k ]; + cbk_gain_ptr_Q7 = silk_LTP_vq_gain_ptrs_Q7[ k ]; + cbk_size = silk_LTP_vq_sizes[ k ]; + + /* Set up pointers to first subframe */ + XX_Q17_ptr = XX_Q17; + xX_Q17_ptr = xX_Q17; + + res_nrg_Q15 = 0; + rate_dist_Q7 = 0; + sum_log_gain_tmp_Q7 = *sum_log_gain_Q7; + for( j = 0; j < nb_subfr; j++ ) { + max_gain_Q7 = silk_log2lin( ( SILK_FIX_CONST( MAX_SUM_LOG_GAIN_DB / 6.0, 7 ) - sum_log_gain_tmp_Q7 ) + + SILK_FIX_CONST( 7, 7 ) ) - gain_safety; + silk_VQ_WMat_EC( + &temp_idx[ j ], /* O index of best codebook vector */ + &res_nrg_Q15_subfr, /* O residual energy */ + &rate_dist_Q7_subfr, /* O best weighted quantization error + mu * rate */ + &gain_Q7, /* O sum of absolute LTP coefficients */ + XX_Q17_ptr, /* I correlation matrix */ + xX_Q17_ptr, /* I correlation vector */ + cbk_ptr_Q7, /* I codebook */ + cbk_gain_ptr_Q7, /* I codebook effective gains */ + cl_ptr_Q5, /* I code length for each codebook vector */ + subfr_len, /* I number of samples per subframe */ + max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + cbk_size, /* I number of vectors in codebook */ + arch /* I Run-time architecture */ + ); + + res_nrg_Q15 = silk_ADD_POS_SAT32( res_nrg_Q15, res_nrg_Q15_subfr ); + rate_dist_Q7 = silk_ADD_POS_SAT32( rate_dist_Q7, rate_dist_Q7_subfr ); + sum_log_gain_tmp_Q7 = silk_max(0, sum_log_gain_tmp_Q7 + + silk_lin2log( gain_safety + gain_Q7 ) - SILK_FIX_CONST( 7, 7 )); + + XX_Q17_ptr += LTP_ORDER * LTP_ORDER; + xX_Q17_ptr += LTP_ORDER; + } + + if( rate_dist_Q7 <= min_rate_dist_Q7 ) { + min_rate_dist_Q7 = rate_dist_Q7; + *periodicity_index = (opus_int8)k; + silk_memcpy( cbk_index, temp_idx, nb_subfr * sizeof( opus_int8 ) ); + best_sum_log_gain_Q7 = sum_log_gain_tmp_Q7; + } + } + + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ *periodicity_index ]; + for( j = 0; j < nb_subfr; j++ ) { + for( k = 0; k < LTP_ORDER; k++ ) { + B_Q14[ j * LTP_ORDER + k ] = silk_LSHIFT( cbk_ptr_Q7[ cbk_index[ j ] * LTP_ORDER + k ], 7 ); + } + } + + if( nb_subfr == 2 ) { + res_nrg_Q15 = silk_RSHIFT32( res_nrg_Q15, 1 ); + } else { + res_nrg_Q15 = silk_RSHIFT32( res_nrg_Q15, 2 ); + } + + *sum_log_gain_Q7 = best_sum_log_gain_Q7; + *pred_gain_dB_Q7 = (opus_int)silk_SMULBB( -3, silk_lin2log( res_nrg_Q15 ) - ( 15 << 7 ) ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler.c new file mode 100644 index 000000000..1f11e5089 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler.c @@ -0,0 +1,215 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + * Matrix of resampling methods used: + * Fs_out (kHz) + * 8 12 16 24 48 + * + * 8 C UF U UF UF + * 12 AF C UF U UF + * Fs_in (kHz) 16 D AF C UF UF + * 24 AF D AF C U + * 48 AF AF AF D C + * + * C -> Copy (no resampling) + * D -> Allpass-based 2x downsampling + * U -> Allpass-based 2x upsampling + * UF -> Allpass-based 2x upsampling followed by FIR interpolation + * AF -> AR2 filter followed by FIR interpolation + */ + +#include "resampler_private.h" + +/* Tables with delay compensation values to equalize total delay for different modes */ +static const opus_int8 delay_matrix_enc[ 5 ][ 3 ] = { +/* in \ out 8 12 16 */ +/* 8 */ { 6, 0, 3 }, +/* 12 */ { 0, 7, 3 }, +/* 16 */ { 0, 1, 10 }, +/* 24 */ { 0, 2, 6 }, +/* 48 */ { 18, 10, 12 } +}; + +static const opus_int8 delay_matrix_dec[ 3 ][ 5 ] = { +/* in \ out 8 12 16 24 48 */ +/* 8 */ { 4, 0, 2, 0, 0 }, +/* 12 */ { 0, 9, 4, 7, 4 }, +/* 16 */ { 0, 3, 12, 7, 7 } +}; + +/* Simple way to make [8000, 12000, 16000, 24000, 48000] to [0, 1, 2, 3, 4] */ +#define rateID(R) ( ( ( ((R)>>12) - ((R)>16000) ) >> ((R)>24000) ) - 1 ) + +#define USE_silk_resampler_copy (0) +#define USE_silk_resampler_private_up2_HQ_wrapper (1) +#define USE_silk_resampler_private_IIR_FIR (2) +#define USE_silk_resampler_private_down_FIR (3) + +/* Initialize/reset the resampler state for a given pair of input/output sampling rates */ +opus_int silk_resampler_init( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int32 Fs_Hz_in, /* I Input sampling rate (Hz) */ + opus_int32 Fs_Hz_out, /* I Output sampling rate (Hz) */ + opus_int forEnc /* I If 1: encoder; if 0: decoder */ +) +{ + opus_int up2x; + + /* Clear state */ + silk_memset( S, 0, sizeof( silk_resampler_state_struct ) ); + + /* Input checking */ + if( forEnc ) { + if( ( Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 && Fs_Hz_in != 24000 && Fs_Hz_in != 48000 ) || + ( Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 ) ) { + celt_assert( 0 ); + return -1; + } + S->inputDelay = delay_matrix_enc[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ]; + } else { + if( ( Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 ) || + ( Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 && Fs_Hz_out != 24000 && Fs_Hz_out != 48000 ) ) { + celt_assert( 0 ); + return -1; + } + S->inputDelay = delay_matrix_dec[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ]; + } + + S->Fs_in_kHz = silk_DIV32_16( Fs_Hz_in, 1000 ); + S->Fs_out_kHz = silk_DIV32_16( Fs_Hz_out, 1000 ); + + /* Number of samples processed per batch */ + S->batchSize = S->Fs_in_kHz * RESAMPLER_MAX_BATCH_SIZE_MS; + + /* Find resampler with the right sampling ratio */ + up2x = 0; + if( Fs_Hz_out > Fs_Hz_in ) { + /* Upsample */ + if( Fs_Hz_out == silk_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 1 */ + /* Special case: directly use 2x upsampler */ + S->resampler_function = USE_silk_resampler_private_up2_HQ_wrapper; + } else { + /* Default resampler */ + S->resampler_function = USE_silk_resampler_private_IIR_FIR; + up2x = 1; + } + } else if ( Fs_Hz_out < Fs_Hz_in ) { + /* Downsample */ + S->resampler_function = USE_silk_resampler_private_down_FIR; + if( silk_MUL( Fs_Hz_out, 4 ) == silk_MUL( Fs_Hz_in, 3 ) ) { /* Fs_out : Fs_in = 3 : 4 */ + S->FIR_Fracs = 3; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0; + S->Coefs = silk_Resampler_3_4_COEFS; + } else if( silk_MUL( Fs_Hz_out, 3 ) == silk_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 3 */ + S->FIR_Fracs = 2; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0; + S->Coefs = silk_Resampler_2_3_COEFS; + } else if( silk_MUL( Fs_Hz_out, 2 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 2 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR1; + S->Coefs = silk_Resampler_1_2_COEFS; + } else if( silk_MUL( Fs_Hz_out, 3 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 3 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_3_COEFS; + } else if( silk_MUL( Fs_Hz_out, 4 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 4 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_4_COEFS; + } else if( silk_MUL( Fs_Hz_out, 6 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 6 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_6_COEFS; + } else { + /* None available */ + celt_assert( 0 ); + return -1; + } + } else { + /* Input and output sampling rates are equal: copy */ + S->resampler_function = USE_silk_resampler_copy; + } + + /* Ratio of input/output samples */ + S->invRatio_Q16 = silk_LSHIFT32( silk_DIV32( silk_LSHIFT32( Fs_Hz_in, 14 + up2x ), Fs_Hz_out ), 2 ); + /* Make sure the ratio is rounded up */ + while( silk_SMULWW( S->invRatio_Q16, Fs_Hz_out ) < silk_LSHIFT32( Fs_Hz_in, up2x ) ) { + S->invRatio_Q16++; + } + + return 0; +} + +/* Resampler: convert from one sampling rate to another */ +/* Input and output sampling rate are at most 48000 Hz */ +opus_int silk_resampler( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int nSamples; + + /* Need at least 1 ms of input data */ + celt_assert( inLen >= S->Fs_in_kHz ); + /* Delay can't exceed the 1 ms of buffering */ + celt_assert( S->inputDelay <= S->Fs_in_kHz ); + + nSamples = S->Fs_in_kHz - S->inputDelay; + + /* Copy to delay buffer */ + silk_memcpy( &S->delayBuf[ S->inputDelay ], in, nSamples * sizeof( opus_int16 ) ); + + switch( S->resampler_function ) { + case USE_silk_resampler_private_up2_HQ_wrapper: + silk_resampler_private_up2_HQ_wrapper( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_up2_HQ_wrapper( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + case USE_silk_resampler_private_IIR_FIR: + silk_resampler_private_IIR_FIR( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_IIR_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + case USE_silk_resampler_private_down_FIR: + silk_resampler_private_down_FIR( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_down_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + default: + silk_memcpy( out, S->delayBuf, S->Fs_in_kHz * sizeof( opus_int16 ) ); + silk_memcpy( &out[ S->Fs_out_kHz ], &in[ nSamples ], ( inLen - S->Fs_in_kHz ) * sizeof( opus_int16 ) ); + } + + /* Copy to delay buffer */ + silk_memcpy( S->delayBuf, &in[ inLen - S->inputDelay ], S->inputDelay * sizeof( opus_int16 ) ); + + return 0; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_down2.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_down2.c new file mode 100644 index 000000000..971d7bfd4 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_down2.c @@ -0,0 +1,74 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_rom.h" + +/* Downsample by a factor 2 */ +void silk_resampler_down2( + opus_int32 *S, /* I/O State vector [ 2 ] */ + opus_int16 *out, /* O Output signal [ floor(len/2) ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int32 k, len2 = silk_RSHIFT32( inLen, 1 ); + opus_int32 in32, out32, Y, X; + + celt_assert( silk_resampler_down2_0 > 0 ); + celt_assert( silk_resampler_down2_1 < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len2; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 ); + + /* All-pass section for even input sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_down2_1 ); + out32 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 ); + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = silk_SUB32( in32, S[ 1 ] ); + X = silk_SMULWB( Y, silk_resampler_down2_0 ); + out32 = silk_ADD32( out32, S[ 1 ] ); + out32 = silk_ADD32( out32, X ); + S[ 1 ] = silk_ADD32( in32, X ); + + /* Add, convert back to int16 and store to output */ + out[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32, 11 ) ); + } +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_down2_3.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_down2_3.c new file mode 100644 index 000000000..4342614dc --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_down2_3.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" +#include "stack_alloc.h" + +#define ORDER_FIR 4 + +/* Downsample by a factor 2/3, low quality */ +void silk_resampler_down2_3( + opus_int32 *S, /* I/O State vector [ 6 ] */ + opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */ + const opus_int16 *in, /* I Input signal [ inLen ] */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int32 nSamplesIn, counter, res_Q6; + VARDECL( opus_int32, buf ); + opus_int32 *buf_ptr; + SAVE_STACK; + + ALLOC( buf, RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR, opus_int32 ); + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S, ORDER_FIR * sizeof( opus_int32 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + while( 1 ) { + nSamplesIn = silk_min( inLen, RESAMPLER_MAX_BATCH_SIZE_IN ); + + /* Second-order AR filter (output in Q8) */ + silk_resampler_private_AR2( &S[ ORDER_FIR ], &buf[ ORDER_FIR ], in, + silk_Resampler_2_3_COEFS_LQ, nSamplesIn ); + + /* Interpolate filtered signal */ + buf_ptr = buf; + counter = nSamplesIn; + while( counter > 2 ) { + /* Inner product */ + res_Q6 = silk_SMULWB( buf_ptr[ 0 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + + res_Q6 = silk_SMULWB( buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + + buf_ptr += 3; + counter -= 3; + } + + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + silk_memcpy( buf, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) ); + RESTORE_STACK; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_private.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_private.h new file mode 100644 index 000000000..422a7d9d9 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_private.h @@ -0,0 +1,88 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_RESAMPLER_PRIVATE_H +#define SILK_RESAMPLER_PRIVATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "SigProc_FIX.h" +#include "resampler_structs.h" +#include "resampler_rom.h" + +/* Number of input samples to process in the inner loop */ +#define RESAMPLER_MAX_BATCH_SIZE_MS 10 +#define RESAMPLER_MAX_FS_KHZ 48 +#define RESAMPLER_MAX_BATCH_SIZE_IN ( RESAMPLER_MAX_BATCH_SIZE_MS * RESAMPLER_MAX_FS_KHZ ) + +/* Description: Hybrid IIR/FIR polyphase implementation of resampling */ +void silk_resampler_private_IIR_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/* Description: Hybrid IIR/FIR polyphase implementation of resampling */ +void silk_resampler_private_down_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/* Upsample by a factor 2, high quality */ +void silk_resampler_private_up2_HQ_wrapper( + void *SS, /* I/O Resampler state (unused) */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +); + +/* Upsample by a factor 2, high quality */ +void silk_resampler_private_up2_HQ( + opus_int32 *S, /* I/O Resampler state [ 6 ] */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +); + +/* Second order AR filter */ +void silk_resampler_private_AR2( + opus_int32 S[], /* I/O State vector [ 2 ] */ + opus_int32 out_Q8[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + const opus_int16 A_Q14[], /* I AR coefficients, Q14 */ + opus_int32 len /* I Signal length */ +); + +#ifdef __cplusplus +} +#endif +#endif /* SILK_RESAMPLER_PRIVATE_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_private_AR2.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_private_AR2.c new file mode 100644 index 000000000..5fff23714 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_private_AR2.c @@ -0,0 +1,55 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +/* Second order AR filter with single delay elements */ +void silk_resampler_private_AR2( + opus_int32 S[], /* I/O State vector [ 2 ] */ + opus_int32 out_Q8[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + const opus_int16 A_Q14[], /* I AR coefficients, Q14 */ + opus_int32 len /* I Signal length */ +) +{ + opus_int32 k; + opus_int32 out32; + + for( k = 0; k < len; k++ ) { + out32 = silk_ADD_LSHIFT32( S[ 0 ], (opus_int32)in[ k ], 8 ); + out_Q8[ k ] = out32; + out32 = silk_LSHIFT( out32, 2 ); + S[ 0 ] = silk_SMLAWB( S[ 1 ], out32, A_Q14[ 0 ] ); + S[ 1 ] = silk_SMULWB( out32, A_Q14[ 1 ] ); + } +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_private_IIR_FIR.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_private_IIR_FIR.c new file mode 100644 index 000000000..6b2b3a2e1 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_private_IIR_FIR.c @@ -0,0 +1,107 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" +#include "stack_alloc.h" + +static OPUS_INLINE opus_int16 *silk_resampler_private_IIR_FIR_INTERPOL( + opus_int16 *out, + opus_int16 *buf, + opus_int32 max_index_Q16, + opus_int32 index_increment_Q16 +) +{ + opus_int32 index_Q16, res_Q15; + opus_int16 *buf_ptr; + opus_int32 table_index; + + /* Interpolate upsampled signal and store in output array */ + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + table_index = silk_SMULWB( index_Q16 & 0xFFFF, 12 ); + buf_ptr = &buf[ index_Q16 >> 16 ]; + + res_Q15 = silk_SMULBB( buf_ptr[ 0 ], silk_resampler_frac_FIR_12[ table_index ][ 0 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 1 ], silk_resampler_frac_FIR_12[ table_index ][ 1 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 2 ], silk_resampler_frac_FIR_12[ table_index ][ 2 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 3 ], silk_resampler_frac_FIR_12[ table_index ][ 3 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 4 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 3 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 5 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 2 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 6 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 1 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 7 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 0 ] ); + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q15, 15 ) ); + } + return out; +} +/* Upsample using a combination of allpass-based 2x upsampling and FIR interpolation */ +void silk_resampler_private_IIR_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; + VARDECL( opus_int16, buf ); + SAVE_STACK; + + ALLOC( buf, 2 * S->batchSize + RESAMPLER_ORDER_FIR_12, opus_int16 ); + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S->sFIR.i16, RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = silk_min( inLen, S->batchSize ); + + /* Upsample 2x */ + silk_resampler_private_up2_HQ( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_12 ], in, nSamplesIn ); + + max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 + 1 ); /* + 1 because 2x upsampling */ + out = silk_resampler_private_IIR_FIR_INTERPOL( out, buf, max_index_Q16, index_increment_Q16 ); + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + silk_memcpy( buf, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S->sFIR.i16, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + RESTORE_STACK; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_private_down_FIR.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_private_down_FIR.c new file mode 100644 index 000000000..3e8735a35 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_private_down_FIR.c @@ -0,0 +1,194 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" +#include "stack_alloc.h" + +static OPUS_INLINE opus_int16 *silk_resampler_private_down_FIR_INTERPOL( + opus_int16 *out, + opus_int32 *buf, + const opus_int16 *FIR_Coefs, + opus_int FIR_Order, + opus_int FIR_Fracs, + opus_int32 max_index_Q16, + opus_int32 index_increment_Q16 +) +{ + opus_int32 index_Q16, res_Q6; + opus_int32 *buf_ptr; + opus_int32 interpol_ind; + const opus_int16 *interpol_ptr; + + switch( FIR_Order ) { + case RESAMPLER_DOWN_ORDER_FIR0: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Fractional part gives interpolation coefficients */ + interpol_ind = silk_SMULWB( index_Q16 & 0xFFFF, FIR_Fracs ); + + /* Inner product */ + interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * interpol_ind ]; + res_Q6 = silk_SMULWB( buf_ptr[ 0 ], interpol_ptr[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], interpol_ptr[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], interpol_ptr[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], interpol_ptr[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], interpol_ptr[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 5 ], interpol_ptr[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 6 ], interpol_ptr[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 7 ], interpol_ptr[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 8 ], interpol_ptr[ 8 ] ); + interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * ( FIR_Fracs - 1 - interpol_ind ) ]; + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 17 ], interpol_ptr[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 16 ], interpol_ptr[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 15 ], interpol_ptr[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 14 ], interpol_ptr[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 13 ], interpol_ptr[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 12 ], interpol_ptr[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 11 ], interpol_ptr[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 10 ], interpol_ptr[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 9 ], interpol_ptr[ 8 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + case RESAMPLER_DOWN_ORDER_FIR1: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Inner product */ + res_Q6 = silk_SMULWB( silk_ADD32( buf_ptr[ 0 ], buf_ptr[ 23 ] ), FIR_Coefs[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 1 ], buf_ptr[ 22 ] ), FIR_Coefs[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 2 ], buf_ptr[ 21 ] ), FIR_Coefs[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 3 ], buf_ptr[ 20 ] ), FIR_Coefs[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 4 ], buf_ptr[ 19 ] ), FIR_Coefs[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 5 ], buf_ptr[ 18 ] ), FIR_Coefs[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 6 ], buf_ptr[ 17 ] ), FIR_Coefs[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 7 ], buf_ptr[ 16 ] ), FIR_Coefs[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 8 ], buf_ptr[ 15 ] ), FIR_Coefs[ 8 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 9 ], buf_ptr[ 14 ] ), FIR_Coefs[ 9 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 13 ] ), FIR_Coefs[ 10 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 12 ] ), FIR_Coefs[ 11 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + case RESAMPLER_DOWN_ORDER_FIR2: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Inner product */ + res_Q6 = silk_SMULWB( silk_ADD32( buf_ptr[ 0 ], buf_ptr[ 35 ] ), FIR_Coefs[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 1 ], buf_ptr[ 34 ] ), FIR_Coefs[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 2 ], buf_ptr[ 33 ] ), FIR_Coefs[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 3 ], buf_ptr[ 32 ] ), FIR_Coefs[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 4 ], buf_ptr[ 31 ] ), FIR_Coefs[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 5 ], buf_ptr[ 30 ] ), FIR_Coefs[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 6 ], buf_ptr[ 29 ] ), FIR_Coefs[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 7 ], buf_ptr[ 28 ] ), FIR_Coefs[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 8 ], buf_ptr[ 27 ] ), FIR_Coefs[ 8 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 9 ], buf_ptr[ 26 ] ), FIR_Coefs[ 9 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 25 ] ), FIR_Coefs[ 10 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 24 ] ), FIR_Coefs[ 11 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 12 ], buf_ptr[ 23 ] ), FIR_Coefs[ 12 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 13 ], buf_ptr[ 22 ] ), FIR_Coefs[ 13 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 14 ], buf_ptr[ 21 ] ), FIR_Coefs[ 14 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 15 ], buf_ptr[ 20 ] ), FIR_Coefs[ 15 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 16 ], buf_ptr[ 19 ] ), FIR_Coefs[ 16 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 17 ], buf_ptr[ 18 ] ), FIR_Coefs[ 17 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + default: + celt_assert( 0 ); + } + return out; +} + +/* Resample with a 2nd order AR filter followed by FIR interpolation */ +void silk_resampler_private_down_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; + VARDECL( opus_int32, buf ); + const opus_int16 *FIR_Coefs; + SAVE_STACK; + + ALLOC( buf, S->batchSize + S->FIR_Order, opus_int32 ); + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S->sFIR.i32, S->FIR_Order * sizeof( opus_int32 ) ); + + FIR_Coefs = &S->Coefs[ 2 ]; + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = silk_min( inLen, S->batchSize ); + + /* Second-order AR filter (output in Q8) */ + silk_resampler_private_AR2( S->sIIR, &buf[ S->FIR_Order ], in, S->Coefs, nSamplesIn ); + + max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 ); + + /* Interpolate filtered signal */ + out = silk_resampler_private_down_FIR_INTERPOL( out, buf, FIR_Coefs, S->FIR_Order, + S->FIR_Fracs, max_index_Q16, index_increment_Q16 ); + + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 1 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + silk_memcpy( buf, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S->sFIR.i32, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) ); + RESTORE_STACK; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_private_up2_HQ.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_private_up2_HQ.c new file mode 100644 index 000000000..c7ec8de36 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_private_up2_HQ.c @@ -0,0 +1,113 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +/* Upsample by a factor 2, high quality */ +/* Uses 2nd order allpass filters for the 2x upsampling, followed by a */ +/* notch filter just above Nyquist. */ +void silk_resampler_private_up2_HQ( + opus_int32 *S, /* I/O Resampler state [ 6 ] */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +) +{ + opus_int32 k; + opus_int32 in32, out32_1, out32_2, Y, X; + + silk_assert( silk_resampler_up2_hq_0[ 0 ] > 0 ); + silk_assert( silk_resampler_up2_hq_0[ 1 ] > 0 ); + silk_assert( silk_resampler_up2_hq_0[ 2 ] < 0 ); + silk_assert( silk_resampler_up2_hq_1[ 0 ] > 0 ); + silk_assert( silk_resampler_up2_hq_1[ 1 ] > 0 ); + silk_assert( silk_resampler_up2_hq_1[ 2 ] < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ k ], 10 ); + + /* First all-pass section for even output sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 0 ] ); + out32_1 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Second all-pass section for even output sample */ + Y = silk_SUB32( out32_1, S[ 1 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 1 ] ); + out32_2 = silk_ADD32( S[ 1 ], X ); + S[ 1 ] = silk_ADD32( out32_1, X ); + + /* Third all-pass section for even output sample */ + Y = silk_SUB32( out32_2, S[ 2 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_0[ 2 ] ); + out32_1 = silk_ADD32( S[ 2 ], X ); + S[ 2 ] = silk_ADD32( out32_2, X ); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[ 2 * k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) ); + + /* First all-pass section for odd output sample */ + Y = silk_SUB32( in32, S[ 3 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 0 ] ); + out32_1 = silk_ADD32( S[ 3 ], X ); + S[ 3 ] = silk_ADD32( in32, X ); + + /* Second all-pass section for odd output sample */ + Y = silk_SUB32( out32_1, S[ 4 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 1 ] ); + out32_2 = silk_ADD32( S[ 4 ], X ); + S[ 4 ] = silk_ADD32( out32_1, X ); + + /* Third all-pass section for odd output sample */ + Y = silk_SUB32( out32_2, S[ 5 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_1[ 2 ] ); + out32_1 = silk_ADD32( S[ 5 ], X ); + S[ 5 ] = silk_ADD32( out32_2, X ); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) ); + } +} + +void silk_resampler_private_up2_HQ_wrapper( + void *SS, /* I/O Resampler state (unused) */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + silk_resampler_private_up2_HQ( S->sIIR, out, in, len ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_rom.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_rom.c new file mode 100644 index 000000000..5e6b04476 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_rom.c @@ -0,0 +1,96 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Filter coefficients for IIR/FIR polyphase resampling * + * Total size: 179 Words (358 Bytes) */ + +#include "resampler_private.h" + +/* Matlab code for the notch filter coefficients: */ +/* B = [1, 0.147, 1]; A = [1, 0.107, 0.89]; G = 0.93; freqz(G * B, A, 2^14, 16e3); axis([0, 8000, -10, 1]) */ +/* fprintf('\t%6d, %6d, %6d, %6d\n', round(B(2)*2^16), round(-A(2)*2^16), round((1-A(3))*2^16), round(G*2^15)) */ +/* const opus_int16 silk_resampler_up2_hq_notch[ 4 ] = { 9634, -7012, 7209, 30474 }; */ + +/* Tables with IIR and FIR coefficients for fractional downsamplers (123 Words) */ +silk_DWORD_ALIGN const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = { + -20694, -13867, + -49, 64, 17, -157, 353, -496, 163, 11047, 22205, + -39, 6, 91, -170, 186, 23, -896, 6336, 19928, + -19, -36, 102, -89, -24, 328, -951, 2568, 15909, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = { + -14457, -14019, + 64, 128, -122, 36, 310, -768, 584, 9267, 17733, + 12, 128, 18, -142, 288, -117, -865, 4123, 14459, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ] = { + 616, -14323, + -10, 39, 58, -46, -84, 120, 184, -315, -541, 1284, 5380, 9024, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 16102, -15162, + -13, 0, 20, 26, 5, -31, -43, -4, 65, 90, 7, -157, -248, -44, 593, 1583, 2612, 3271, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 22500, -15099, + 3, -14, -20, -15, 2, 25, 37, 25, -16, -71, -107, -79, 50, 292, 623, 982, 1288, 1464, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 27540, -15257, + 17, 12, 8, 1, -10, -22, -30, -32, -22, 3, 44, 100, 168, 243, 317, 381, 429, 455, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ] = { + -2797, -6507, + 4697, 10739, + 1567, 8276, +}; + +/* Table with interplation fractions of 1/24, 3/24, 5/24, ... , 23/24 : 23/24 (46 Words) */ +silk_DWORD_ALIGN const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ] = { + { 189, -600, 617, 30567 }, + { 117, -159, -1070, 29704 }, + { 52, 221, -2392, 28276 }, + { -4, 529, -3350, 26341 }, + { -48, 758, -3956, 23973 }, + { -80, 905, -4235, 21254 }, + { -99, 972, -4222, 18278 }, + { -107, 967, -3957, 15143 }, + { -103, 896, -3487, 11950 }, + { -91, 773, -2865, 8798 }, + { -71, 611, -2143, 5784 }, + { -46, 425, -1375, 2996 }, +}; diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_rom.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_rom.h new file mode 100644 index 000000000..490b3388d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_rom.h @@ -0,0 +1,68 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_FIX_RESAMPLER_ROM_H +#define SILK_FIX_RESAMPLER_ROM_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "typedef.h" +#include "resampler_structs.h" + +#define RESAMPLER_DOWN_ORDER_FIR0 18 +#define RESAMPLER_DOWN_ORDER_FIR1 24 +#define RESAMPLER_DOWN_ORDER_FIR2 36 +#define RESAMPLER_ORDER_FIR_12 8 + +/* Tables for 2x downsampler */ +static const opus_int16 silk_resampler_down2_0 = 9872; +static const opus_int16 silk_resampler_down2_1 = 39809 - 65536; + +/* Tables for 2x upsampler, high quality */ +static const opus_int16 silk_resampler_up2_hq_0[ 3 ] = { 1746, 14986, 39083 - 65536 }; +static const opus_int16 silk_resampler_up2_hq_1[ 3 ] = { 6854, 25769, 55542 - 65536 }; + +/* Tables with IIR and FIR coefficients for fractional downsamplers */ +extern const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ]; +extern const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ]; +extern const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ]; +extern const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ]; + +/* Table with interplation fractions of 1/24, 3/24, ..., 23/24 */ +extern const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ]; + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_FIX_RESAMPLER_ROM_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_structs.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_structs.h new file mode 100644 index 000000000..9e9457d11 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/resampler_structs.h @@ -0,0 +1,60 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_RESAMPLER_STRUCTS_H +#define SILK_RESAMPLER_STRUCTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SILK_RESAMPLER_MAX_FIR_ORDER 36 +#define SILK_RESAMPLER_MAX_IIR_ORDER 6 + +typedef struct _silk_resampler_state_struct{ + opus_int32 sIIR[ SILK_RESAMPLER_MAX_IIR_ORDER ]; /* this must be the first element of this struct */ + union{ + opus_int32 i32[ SILK_RESAMPLER_MAX_FIR_ORDER ]; + opus_int16 i16[ SILK_RESAMPLER_MAX_FIR_ORDER ]; + } sFIR; + opus_int16 delayBuf[ 48 ]; + opus_int resampler_function; + opus_int batchSize; + opus_int32 invRatio_Q16; + opus_int FIR_Order; + opus_int FIR_Fracs; + opus_int Fs_in_kHz; + opus_int Fs_out_kHz; + opus_int inputDelay; + const opus_int16 *Coefs; +} silk_resampler_state_struct; + +#ifdef __cplusplus +} +#endif +#endif /* SILK_RESAMPLER_STRUCTS_H */ + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/shell_coder.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/shell_coder.c new file mode 100644 index 000000000..4af341474 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/shell_coder.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* shell coder; pulse-subframe length is hardcoded */ + +static OPUS_INLINE void combine_pulses( + opus_int *out, /* O combined pulses vector [len] */ + const opus_int *in, /* I input vector [2 * len] */ + const opus_int len /* I number of OUTPUT samples */ +) +{ + opus_int k; + for( k = 0; k < len; k++ ) { + out[ k ] = in[ 2 * k ] + in[ 2 * k + 1 ]; + } +} + +static OPUS_INLINE void encode_split( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int p_child1, /* I pulse amplitude of first child subframe */ + const opus_int p, /* I pulse amplitude of current subframe */ + const opus_uint8 *shell_table /* I table of shell cdfs */ +) +{ + if( p > 0 ) { + ec_enc_icdf( psRangeEnc, p_child1, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 ); + } +} + +static OPUS_INLINE void decode_split( + opus_int16 *p_child1, /* O pulse amplitude of first child subframe */ + opus_int16 *p_child2, /* O pulse amplitude of second child subframe */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int p, /* I pulse amplitude of current subframe */ + const opus_uint8 *shell_table /* I table of shell cdfs */ +) +{ + if( p > 0 ) { + p_child1[ 0 ] = ec_dec_icdf( psRangeDec, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 ); + p_child2[ 0 ] = p - p_child1[ 0 ]; + } else { + p_child1[ 0 ] = 0; + p_child2[ 0 ] = 0; + } +} + +/* Shell encoder, operates on one shell code frame of 16 pulses */ +void silk_shell_encoder( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int *pulses0 /* I data: nonnegative pulse amplitudes */ +) +{ + opus_int pulses1[ 8 ], pulses2[ 4 ], pulses3[ 2 ], pulses4[ 1 ]; + + /* this function operates on one shell code frame of 16 pulses */ + silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 ); + + /* tree representation per pulse-subframe */ + combine_pulses( pulses1, pulses0, 8 ); + combine_pulses( pulses2, pulses1, 4 ); + combine_pulses( pulses3, pulses2, 2 ); + combine_pulses( pulses4, pulses3, 1 ); + + encode_split( psRangeEnc, pulses3[ 0 ], pulses4[ 0 ], silk_shell_code_table3 ); + + encode_split( psRangeEnc, pulses2[ 0 ], pulses3[ 0 ], silk_shell_code_table2 ); + + encode_split( psRangeEnc, pulses1[ 0 ], pulses2[ 0 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 0 ], pulses1[ 0 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 2 ], pulses1[ 1 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses1[ 2 ], pulses2[ 1 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 4 ], pulses1[ 2 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 6 ], pulses1[ 3 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses2[ 2 ], pulses3[ 1 ], silk_shell_code_table2 ); + + encode_split( psRangeEnc, pulses1[ 4 ], pulses2[ 2 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 8 ], pulses1[ 4 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 10 ], pulses1[ 5 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses1[ 6 ], pulses2[ 3 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 12 ], pulses1[ 6 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 14 ], pulses1[ 7 ], silk_shell_code_table0 ); +} + + +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void silk_shell_decoder( + opus_int16 *pulses0, /* O data: nonnegative pulse amplitudes */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int pulses4 /* I number of pulses per pulse-subframe */ +) +{ + opus_int16 pulses3[ 2 ], pulses2[ 4 ], pulses1[ 8 ]; + + /* this function operates on one shell code frame of 16 pulses */ + silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 ); + + decode_split( &pulses3[ 0 ], &pulses3[ 1 ], psRangeDec, pulses4, silk_shell_code_table3 ); + + decode_split( &pulses2[ 0 ], &pulses2[ 1 ], psRangeDec, pulses3[ 0 ], silk_shell_code_table2 ); + + decode_split( &pulses1[ 0 ], &pulses1[ 1 ], psRangeDec, pulses2[ 0 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 0 ], &pulses0[ 1 ], psRangeDec, pulses1[ 0 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 2 ], &pulses0[ 3 ], psRangeDec, pulses1[ 1 ], silk_shell_code_table0 ); + + decode_split( &pulses1[ 2 ], &pulses1[ 3 ], psRangeDec, pulses2[ 1 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 4 ], &pulses0[ 5 ], psRangeDec, pulses1[ 2 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 6 ], &pulses0[ 7 ], psRangeDec, pulses1[ 3 ], silk_shell_code_table0 ); + + decode_split( &pulses2[ 2 ], &pulses2[ 3 ], psRangeDec, pulses3[ 1 ], silk_shell_code_table2 ); + + decode_split( &pulses1[ 4 ], &pulses1[ 5 ], psRangeDec, pulses2[ 2 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 8 ], &pulses0[ 9 ], psRangeDec, pulses1[ 4 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 10 ], &pulses0[ 11 ], psRangeDec, pulses1[ 5 ], silk_shell_code_table0 ); + + decode_split( &pulses1[ 6 ], &pulses1[ 7 ], psRangeDec, pulses2[ 3 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 12 ], &pulses0[ 13 ], psRangeDec, pulses1[ 6 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 14 ], &pulses0[ 15 ], psRangeDec, pulses1[ 7 ], silk_shell_code_table0 ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/sigm_Q15.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/sigm_Q15.c new file mode 100644 index 000000000..3c507d255 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/sigm_Q15.c @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Approximate sigmoid function */ + +#include "SigProc_FIX.h" + +/* fprintf(1, '%d, ', round(1024 * ([1 ./ (1 + exp(-(1:5))), 1] - 1 ./ (1 + exp(-(0:5)))))); */ +static const opus_int32 sigm_LUT_slope_Q10[ 6 ] = { + 237, 153, 73, 30, 12, 7 +}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp(-(0:5))))); */ +static const opus_int32 sigm_LUT_pos_Q15[ 6 ] = { + 16384, 23955, 28861, 31213, 32178, 32548 +}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp((0:5))))); */ +static const opus_int32 sigm_LUT_neg_Q15[ 6 ] = { + 16384, 8812, 3906, 1554, 589, 219 +}; + +opus_int silk_sigm_Q15( + opus_int in_Q5 /* I */ +) +{ + opus_int ind; + + if( in_Q5 < 0 ) { + /* Negative input */ + in_Q5 = -in_Q5; + if( in_Q5 >= 6 * 32 ) { + return 0; /* Clip */ + } else { + /* Linear interpolation of look up table */ + ind = silk_RSHIFT( in_Q5, 5 ); + return( sigm_LUT_neg_Q15[ ind ] - silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) ); + } + } else { + /* Positive input */ + if( in_Q5 >= 6 * 32 ) { + return 32767; /* clip */ + } else { + /* Linear interpolation of look up table */ + ind = silk_RSHIFT( in_Q5, 5 ); + return( sigm_LUT_pos_Q15[ ind ] + silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) ); + } + } +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/sort.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/sort.c new file mode 100644 index 000000000..4fba16f83 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/sort.c @@ -0,0 +1,154 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Insertion sort (fast for already almost sorted arrays): */ +/* Best case: O(n) for an already sorted array */ +/* Worst case: O(n^2) for an inversely sorted array */ +/* */ +/* Shell short: https://en.wikipedia.org/wiki/Shell_sort */ + +#include "SigProc_FIX.h" + +void silk_insertion_sort_increasing( + opus_int32 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + opus_int32 value; + opus_int i, j; + + /* Safety checks */ + celt_assert( K > 0 ); + celt_assert( L > 0 ); + celt_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ i ] = i; + } + + /* Sort vector elements by value, increasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked for, check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value < a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} + +#ifdef FIXED_POINT +/* This function is only used by the fixed-point build */ +void silk_insertion_sort_decreasing_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + opus_int i, j; + opus_int value; + + /* Safety checks */ + celt_assert( K > 0 ); + celt_assert( L > 0 ); + celt_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ i ] = i; + } + + /* Sort vector elements by value, decreasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked for, check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value > a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} +#endif + +void silk_insertion_sort_increasing_all_values_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + const opus_int L /* I Vector length */ +) +{ + opus_int value; + opus_int i, j; + + /* Safety checks */ + celt_assert( L > 0 ); + + /* Sort vector elements by value, increasing order */ + for( i = 1; i < L; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + } + a[ j + 1 ] = value; /* Write value */ + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_LR_to_MS.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_LR_to_MS.c new file mode 100644 index 000000000..c8226663c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_LR_to_MS.c @@ -0,0 +1,229 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/* Convert Left/Right stereo signal to adaptive Mid/Side representation */ +void silk_stereo_LR_to_MS( + stereo_enc_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */ + opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */ + opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */ + opus_int32 total_rate_bps, /* I Total bitrate */ + opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */ + opus_int toMono, /* I Last frame before a stereo->mono transition */ + opus_int fs_kHz, /* I Sample rate (kHz) */ + opus_int frame_length /* I Number of samples */ +) +{ + opus_int n, is10msFrame, denom_Q16, delta0_Q13, delta1_Q13; + opus_int32 sum, diff, smooth_coef_Q16, pred_Q13[ 2 ], pred0_Q13, pred1_Q13; + opus_int32 LP_ratio_Q14, HP_ratio_Q14, frac_Q16, frac_3_Q16, min_mid_rate_bps, width_Q14, w_Q24, deltaw_Q24; + VARDECL( opus_int16, side ); + VARDECL( opus_int16, LP_mid ); + VARDECL( opus_int16, HP_mid ); + VARDECL( opus_int16, LP_side ); + VARDECL( opus_int16, HP_side ); + opus_int16 *mid = &x1[ -2 ]; + SAVE_STACK; + + ALLOC( side, frame_length + 2, opus_int16 ); + /* Convert to basic mid/side signals */ + for( n = 0; n < frame_length + 2; n++ ) { + sum = x1[ n - 2 ] + (opus_int32)x2[ n - 2 ]; + diff = x1[ n - 2 ] - (opus_int32)x2[ n - 2 ]; + mid[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 ); + side[ n ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( diff, 1 ) ); + } + + /* Buffering */ + silk_memcpy( mid, state->sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( side, state->sSide, 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sMid, &mid[ frame_length ], 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sSide, &side[ frame_length ], 2 * sizeof( opus_int16 ) ); + + /* LP and HP filter mid signal */ + ALLOC( LP_mid, frame_length, opus_int16 ); + ALLOC( HP_mid, frame_length, opus_int16 ); + for( n = 0; n < frame_length; n++ ) { + sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 2 ); + LP_mid[ n ] = sum; + HP_mid[ n ] = mid[ n + 1 ] - sum; + } + + /* LP and HP filter side signal */ + ALLOC( LP_side, frame_length, opus_int16 ); + ALLOC( HP_side, frame_length, opus_int16 ); + for( n = 0; n < frame_length; n++ ) { + sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( side[ n ] + (opus_int32)side[ n + 2 ], side[ n + 1 ], 1 ), 2 ); + LP_side[ n ] = sum; + HP_side[ n ] = side[ n + 1 ] - sum; + } + + /* Find energies and predictors */ + is10msFrame = frame_length == 10 * fs_kHz; + smooth_coef_Q16 = is10msFrame ? + SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF / 2, 16 ) : + SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF, 16 ); + smooth_coef_Q16 = silk_SMULWB( silk_SMULBB( prev_speech_act_Q8, prev_speech_act_Q8 ), smooth_coef_Q16 ); + + pred_Q13[ 0 ] = silk_stereo_find_predictor( &LP_ratio_Q14, LP_mid, LP_side, &state->mid_side_amp_Q0[ 0 ], frame_length, smooth_coef_Q16 ); + pred_Q13[ 1 ] = silk_stereo_find_predictor( &HP_ratio_Q14, HP_mid, HP_side, &state->mid_side_amp_Q0[ 2 ], frame_length, smooth_coef_Q16 ); + /* Ratio of the norms of residual and mid signals */ + frac_Q16 = silk_SMLABB( HP_ratio_Q14, LP_ratio_Q14, 3 ); + frac_Q16 = silk_min( frac_Q16, SILK_FIX_CONST( 1, 16 ) ); + + /* Determine bitrate distribution between mid and side, and possibly reduce stereo width */ + total_rate_bps -= is10msFrame ? 1200 : 600; /* Subtract approximate bitrate for coding stereo parameters */ + if( total_rate_bps < 1 ) { + total_rate_bps = 1; + } + min_mid_rate_bps = silk_SMLABB( 2000, fs_kHz, 600 ); + silk_assert( min_mid_rate_bps < 32767 ); + /* Default bitrate distribution: 8 parts for Mid and (5+3*frac) parts for Side. so: mid_rate = ( 8 / ( 13 + 3 * frac ) ) * total_ rate */ + frac_3_Q16 = silk_MUL( 3, frac_Q16 ); + mid_side_rates_bps[ 0 ] = silk_DIV32_varQ( total_rate_bps, SILK_FIX_CONST( 8 + 5, 16 ) + frac_3_Q16, 16+3 ); + /* If Mid bitrate below minimum, reduce stereo width */ + if( mid_side_rates_bps[ 0 ] < min_mid_rate_bps ) { + mid_side_rates_bps[ 0 ] = min_mid_rate_bps; + mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ]; + /* width = 4 * ( 2 * side_rate - min_rate ) / ( ( 1 + 3 * frac ) * min_rate ) */ + width_Q14 = silk_DIV32_varQ( silk_LSHIFT( mid_side_rates_bps[ 1 ], 1 ) - min_mid_rate_bps, + silk_SMULWB( SILK_FIX_CONST( 1, 16 ) + frac_3_Q16, min_mid_rate_bps ), 14+2 ); + width_Q14 = silk_LIMIT( width_Q14, 0, SILK_FIX_CONST( 1, 14 ) ); + } else { + mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ]; + width_Q14 = SILK_FIX_CONST( 1, 14 ); + } + + /* Smoother */ + state->smth_width_Q14 = (opus_int16)silk_SMLAWB( state->smth_width_Q14, width_Q14 - state->smth_width_Q14, smooth_coef_Q16 ); + + /* At very low bitrates or for inputs that are nearly amplitude panned, switch to panned-mono coding */ + *mid_only_flag = 0; + if( toMono ) { + /* Last frame before stereo->mono transition; collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + silk_stereo_quant_pred( pred_Q13, ix ); + } else if( state->width_prev_Q14 == 0 && + ( 8 * total_rate_bps < 13 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.05, 14 ) ) ) + { + /* Code as panned-mono; previous frame already had zero width */ + /* Scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + /* Collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + mid_side_rates_bps[ 0 ] = total_rate_bps; + mid_side_rates_bps[ 1 ] = 0; + *mid_only_flag = 1; + } else if( state->width_prev_Q14 != 0 && + ( 8 * total_rate_bps < 11 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.02, 14 ) ) ) + { + /* Transition to zero-width stereo */ + /* Scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + /* Collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + } else if( state->smth_width_Q14 > SILK_FIX_CONST( 0.95, 14 ) ) { + /* Full-width stereo coding */ + silk_stereo_quant_pred( pred_Q13, ix ); + width_Q14 = SILK_FIX_CONST( 1, 14 ); + } else { + /* Reduced-width stereo coding; scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + width_Q14 = state->smth_width_Q14; + } + + /* Make sure to keep on encoding until the tapered output has been transmitted */ + if( *mid_only_flag == 1 ) { + state->silent_side_len += frame_length - STEREO_INTERP_LEN_MS * fs_kHz; + if( state->silent_side_len < LA_SHAPE_MS * fs_kHz ) { + *mid_only_flag = 0; + } else { + /* Limit to avoid wrapping around */ + state->silent_side_len = 10000; + } + } else { + state->silent_side_len = 0; + } + + if( *mid_only_flag == 0 && mid_side_rates_bps[ 1 ] < 1 ) { + mid_side_rates_bps[ 1 ] = 1; + mid_side_rates_bps[ 0 ] = silk_max_int( 1, total_rate_bps - mid_side_rates_bps[ 1 ]); + } + + /* Interpolate predictors and subtract prediction from side channel */ + pred0_Q13 = -state->pred_prev_Q13[ 0 ]; + pred1_Q13 = -state->pred_prev_Q13[ 1 ]; + w_Q24 = silk_LSHIFT( state->width_prev_Q14, 10 ); + denom_Q16 = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz ); + delta0_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 ); + delta1_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 ); + deltaw_Q24 = silk_LSHIFT( silk_SMULWB( width_Q14 - state->width_prev_Q14, denom_Q16 ), 10 ); + for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) { + pred0_Q13 += delta0_Q13; + pred1_Q13 += delta1_Q13; + w_Q24 += deltaw_Q24; + sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + + pred0_Q13 = -pred_Q13[ 0 ]; + pred1_Q13 = -pred_Q13[ 1 ]; + w_Q24 = silk_LSHIFT( width_Q14, 10 ); + for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) { + sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + state->pred_prev_Q13[ 0 ] = (opus_int16)pred_Q13[ 0 ]; + state->pred_prev_Q13[ 1 ] = (opus_int16)pred_Q13[ 1 ]; + state->width_prev_Q14 = (opus_int16)width_Q14; + RESTORE_STACK; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_MS_to_LR.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_MS_to_LR.c new file mode 100644 index 000000000..62521a4f3 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_MS_to_LR.c @@ -0,0 +1,85 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Convert adaptive Mid/Side representation to Left/Right stereo signal */ +void silk_stereo_MS_to_LR( + stereo_dec_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + const opus_int32 pred_Q13[], /* I Predictors */ + opus_int fs_kHz, /* I Samples rate (kHz) */ + opus_int frame_length /* I Number of samples */ +) +{ + opus_int n, denom_Q16, delta0_Q13, delta1_Q13; + opus_int32 sum, diff, pred0_Q13, pred1_Q13; + + /* Buffering */ + silk_memcpy( x1, state->sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( x2, state->sSide, 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sMid, &x1[ frame_length ], 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sSide, &x2[ frame_length ], 2 * sizeof( opus_int16 ) ); + + /* Interpolate predictors and add prediction to side channel */ + pred0_Q13 = state->pred_prev_Q13[ 0 ]; + pred1_Q13 = state->pred_prev_Q13[ 1 ]; + denom_Q16 = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz ); + delta0_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 ); + delta1_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 ); + for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) { + pred0_Q13 += delta0_Q13; + pred1_Q13 += delta1_Q13; + sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + pred0_Q13 = pred_Q13[ 0 ]; + pred1_Q13 = pred_Q13[ 1 ]; + for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) { + sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + state->pred_prev_Q13[ 0 ] = pred_Q13[ 0 ]; + state->pred_prev_Q13[ 1 ] = pred_Q13[ 1 ]; + + /* Convert to left/right signals */ + for( n = 0; n < frame_length; n++ ) { + sum = x1[ n + 1 ] + (opus_int32)x2[ n + 1 ]; + diff = x1[ n + 1 ] - (opus_int32)x2[ n + 1 ]; + x1[ n + 1 ] = (opus_int16)silk_SAT16( sum ); + x2[ n + 1 ] = (opus_int16)silk_SAT16( diff ); + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_decode_pred.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_decode_pred.c new file mode 100644 index 000000000..56ba3925e --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_decode_pred.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Decode mid/side predictors */ +void silk_stereo_decode_pred( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int32 pred_Q13[] /* O Predictors */ +) +{ + opus_int n, ix[ 2 ][ 3 ]; + opus_int32 low_Q13, step_Q13; + + /* Entropy decoding */ + n = ec_dec_icdf( psRangeDec, silk_stereo_pred_joint_iCDF, 8 ); + ix[ 0 ][ 2 ] = silk_DIV32_16( n, 5 ); + ix[ 1 ][ 2 ] = n - 5 * ix[ 0 ][ 2 ]; + for( n = 0; n < 2; n++ ) { + ix[ n ][ 0 ] = ec_dec_icdf( psRangeDec, silk_uniform3_iCDF, 8 ); + ix[ n ][ 1 ] = ec_dec_icdf( psRangeDec, silk_uniform5_iCDF, 8 ); + } + + /* Dequantize */ + for( n = 0; n < 2; n++ ) { + ix[ n ][ 0 ] += 3 * ix[ n ][ 2 ]; + low_Q13 = silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] ]; + step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] + 1 ] - low_Q13, + SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) ); + pred_Q13[ n ] = silk_SMLABB( low_Q13, step_Q13, 2 * ix[ n ][ 1 ] + 1 ); + } + + /* Subtract second from first predictor (helps when actually applying these) */ + pred_Q13[ 0 ] -= pred_Q13[ 1 ]; +} + +/* Decode mid-only flag */ +void silk_stereo_decode_mid_only( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int *decode_only_mid /* O Flag that only mid channel has been coded */ +) +{ + /* Decode flag that only mid channel is coded */ + *decode_only_mid = ec_dec_icdf( psRangeDec, silk_stereo_only_code_mid_iCDF, 8 ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_encode_pred.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_encode_pred.c new file mode 100644 index 000000000..03becb673 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_encode_pred.c @@ -0,0 +1,62 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Entropy code the mid/side quantization indices */ +void silk_stereo_encode_pred( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */ +) +{ + opus_int n; + + /* Entropy coding */ + n = 5 * ix[ 0 ][ 2 ] + ix[ 1 ][ 2 ]; + celt_assert( n < 25 ); + ec_enc_icdf( psRangeEnc, n, silk_stereo_pred_joint_iCDF, 8 ); + for( n = 0; n < 2; n++ ) { + celt_assert( ix[ n ][ 0 ] < 3 ); + celt_assert( ix[ n ][ 1 ] < STEREO_QUANT_SUB_STEPS ); + ec_enc_icdf( psRangeEnc, ix[ n ][ 0 ], silk_uniform3_iCDF, 8 ); + ec_enc_icdf( psRangeEnc, ix[ n ][ 1 ], silk_uniform5_iCDF, 8 ); + } +} + +/* Entropy code the mid-only flag */ +void silk_stereo_encode_mid_only( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 mid_only_flag +) +{ + /* Encode flag that only mid channel is coded */ + ec_enc_icdf( psRangeEnc, mid_only_flag, silk_stereo_only_code_mid_iCDF, 8 ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_find_predictor.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_find_predictor.c new file mode 100644 index 000000000..e30e90bdd --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_find_predictor.c @@ -0,0 +1,79 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Find least-squares prediction gain for one signal based on another and quantize it */ +opus_int32 silk_stereo_find_predictor( /* O Returns predictor in Q13 */ + opus_int32 *ratio_Q14, /* O Ratio of residual and mid energies */ + const opus_int16 x[], /* I Basis signal */ + const opus_int16 y[], /* I Target signal */ + opus_int32 mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */ + opus_int length, /* I Number of samples */ + opus_int smooth_coef_Q16 /* I Smoothing coefficient */ +) +{ + opus_int scale, scale1, scale2; + opus_int32 nrgx, nrgy, corr, pred_Q13, pred2_Q10; + + /* Find predictor */ + silk_sum_sqr_shift( &nrgx, &scale1, x, length ); + silk_sum_sqr_shift( &nrgy, &scale2, y, length ); + scale = silk_max_int( scale1, scale2 ); + scale = scale + ( scale & 1 ); /* make even */ + nrgy = silk_RSHIFT32( nrgy, scale - scale2 ); + nrgx = silk_RSHIFT32( nrgx, scale - scale1 ); + nrgx = silk_max_int( nrgx, 1 ); + corr = silk_inner_prod_aligned_scale( x, y, scale, length ); + pred_Q13 = silk_DIV32_varQ( corr, nrgx, 13 ); + pred_Q13 = silk_LIMIT( pred_Q13, -(1 << 14), 1 << 14 ); + pred2_Q10 = silk_SMULWB( pred_Q13, pred_Q13 ); + + /* Faster update for signals with large prediction parameters */ + smooth_coef_Q16 = (opus_int)silk_max_int( smooth_coef_Q16, silk_abs( pred2_Q10 ) ); + + /* Smoothed mid and residual norms */ + silk_assert( smooth_coef_Q16 < 32768 ); + scale = silk_RSHIFT( scale, 1 ); + mid_res_amp_Q0[ 0 ] = silk_SMLAWB( mid_res_amp_Q0[ 0 ], silk_LSHIFT( silk_SQRT_APPROX( nrgx ), scale ) - mid_res_amp_Q0[ 0 ], + smooth_coef_Q16 ); + /* Residual energy = nrgy - 2 * pred * corr + pred^2 * nrgx */ + nrgy = silk_SUB_LSHIFT32( nrgy, silk_SMULWB( corr, pred_Q13 ), 3 + 1 ); + nrgy = silk_ADD_LSHIFT32( nrgy, silk_SMULWB( nrgx, pred2_Q10 ), 6 ); + mid_res_amp_Q0[ 1 ] = silk_SMLAWB( mid_res_amp_Q0[ 1 ], silk_LSHIFT( silk_SQRT_APPROX( nrgy ), scale ) - mid_res_amp_Q0[ 1 ], + smooth_coef_Q16 ); + + /* Ratio of smoothed residual and mid norms */ + *ratio_Q14 = silk_DIV32_varQ( mid_res_amp_Q0[ 1 ], silk_max( mid_res_amp_Q0[ 0 ], 1 ), 14 ); + *ratio_Q14 = silk_LIMIT( *ratio_Q14, 0, 32767 ); + + return pred_Q13; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_quant_pred.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_quant_pred.c new file mode 100644 index 000000000..d4ced6c3e --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/stereo_quant_pred.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Quantize mid/side predictors */ +void silk_stereo_quant_pred( + opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */ + opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */ +) +{ + opus_int i, j, n; + opus_int32 low_Q13, step_Q13, lvl_Q13, err_min_Q13, err_Q13, quant_pred_Q13 = 0; + + /* Quantize */ + for( n = 0; n < 2; n++ ) { + /* Brute-force search over quantization levels */ + err_min_Q13 = silk_int32_MAX; + for( i = 0; i < STEREO_QUANT_TAB_SIZE - 1; i++ ) { + low_Q13 = silk_stereo_pred_quant_Q13[ i ]; + step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ i + 1 ] - low_Q13, + SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) ); + for( j = 0; j < STEREO_QUANT_SUB_STEPS; j++ ) { + lvl_Q13 = silk_SMLABB( low_Q13, step_Q13, 2 * j + 1 ); + err_Q13 = silk_abs( pred_Q13[ n ] - lvl_Q13 ); + if( err_Q13 < err_min_Q13 ) { + err_min_Q13 = err_Q13; + quant_pred_Q13 = lvl_Q13; + ix[ n ][ 0 ] = i; + ix[ n ][ 1 ] = j; + } else { + /* Error increasing, so we're past the optimum */ + goto done; + } + } + } + done: + ix[ n ][ 2 ] = silk_DIV32_16( ix[ n ][ 0 ], 3 ); + ix[ n ][ 0 ] -= ix[ n ][ 2 ] * 3; + pred_Q13[ n ] = quant_pred_Q13; + } + + /* Subtract second from first predictor (helps when actually applying these) */ + pred_Q13[ 0 ] -= pred_Q13[ 1 ]; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/structs.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/structs.h new file mode 100644 index 000000000..3380c757b --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/structs.h @@ -0,0 +1,329 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_STRUCTS_H +#define SILK_STRUCTS_H + +#include "typedef.h" +#include "SigProc_FIX.h" +#include "define.h" +#include "entenc.h" +#include "entdec.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************/ +/* Noise shaping quantization state */ +/************************************/ +typedef struct { + opus_int16 xq[ 2 * MAX_FRAME_LENGTH ]; /* Buffer for quantized output signal */ + opus_int32 sLTP_shp_Q14[ 2 * MAX_FRAME_LENGTH ]; + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 sLF_AR_shp_Q14; + opus_int32 sDiff_shp_Q14; + opus_int lagPrev; + opus_int sLTP_buf_idx; + opus_int sLTP_shp_buf_idx; + opus_int32 rand_seed; + opus_int32 prev_gain_Q16; + opus_int rewhite_flag; +} silk_nsq_state; + +/********************************/ +/* VAD state */ +/********************************/ +typedef struct { + opus_int32 AnaState[ 2 ]; /* Analysis filterbank state: 0-8 kHz */ + opus_int32 AnaState1[ 2 ]; /* Analysis filterbank state: 0-4 kHz */ + opus_int32 AnaState2[ 2 ]; /* Analysis filterbank state: 0-2 kHz */ + opus_int32 XnrgSubfr[ VAD_N_BANDS ]; /* Subframe energies */ + opus_int32 NrgRatioSmth_Q8[ VAD_N_BANDS ]; /* Smoothed energy level in each band */ + opus_int16 HPstate; /* State of differentiator in the lowest band */ + opus_int32 NL[ VAD_N_BANDS ]; /* Noise energy level in each band */ + opus_int32 inv_NL[ VAD_N_BANDS ]; /* Inverse noise energy level in each band */ + opus_int32 NoiseLevelBias[ VAD_N_BANDS ]; /* Noise level estimator bias/offset */ + opus_int32 counter; /* Frame counter used in the initial phase */ +} silk_VAD_state; + +/* Variable cut-off low-pass filter state */ +typedef struct { + opus_int32 In_LP_State[ 2 ]; /* Low pass filter state */ + opus_int32 transition_frame_no; /* Counter which is mapped to a cut-off frequency */ + opus_int mode; /* Operating mode, <0: switch down, >0: switch up; 0: do nothing */ + opus_int32 saved_fs_kHz; /* If non-zero, holds the last sampling rate before a bandwidth switching reset. */ +} silk_LP_state; + +/* Structure containing NLSF codebook */ +typedef struct { + const opus_int16 nVectors; + const opus_int16 order; + const opus_int16 quantStepSize_Q16; + const opus_int16 invQuantStepSize_Q6; + const opus_uint8 *CB1_NLSF_Q8; + const opus_int16 *CB1_Wght_Q9; + const opus_uint8 *CB1_iCDF; + const opus_uint8 *pred_Q8; + const opus_uint8 *ec_sel; + const opus_uint8 *ec_iCDF; + const opus_uint8 *ec_Rates_Q5; + const opus_int16 *deltaMin_Q15; +} silk_NLSF_CB_struct; + +typedef struct { + opus_int16 pred_prev_Q13[ 2 ]; + opus_int16 sMid[ 2 ]; + opus_int16 sSide[ 2 ]; + opus_int32 mid_side_amp_Q0[ 4 ]; + opus_int16 smth_width_Q14; + opus_int16 width_prev_Q14; + opus_int16 silent_side_len; + opus_int8 predIx[ MAX_FRAMES_PER_PACKET ][ 2 ][ 3 ]; + opus_int8 mid_only_flags[ MAX_FRAMES_PER_PACKET ]; +} stereo_enc_state; + +typedef struct { + opus_int16 pred_prev_Q13[ 2 ]; + opus_int16 sMid[ 2 ]; + opus_int16 sSide[ 2 ]; +} stereo_dec_state; + +typedef struct { + opus_int8 GainsIndices[ MAX_NB_SUBFR ]; + opus_int8 LTPIndex[ MAX_NB_SUBFR ]; + opus_int8 NLSFIndices[ MAX_LPC_ORDER + 1 ]; + opus_int16 lagIndex; + opus_int8 contourIndex; + opus_int8 signalType; + opus_int8 quantOffsetType; + opus_int8 NLSFInterpCoef_Q2; + opus_int8 PERIndex; + opus_int8 LTP_scaleIndex; + opus_int8 Seed; +} SideInfoIndices; + +/********************************/ +/* Encoder state */ +/********************************/ +typedef struct { + opus_int32 In_HP_State[ 2 ]; /* High pass filter state */ + opus_int32 variable_HP_smth1_Q15; /* State of first smoother */ + opus_int32 variable_HP_smth2_Q15; /* State of second smoother */ + silk_LP_state sLP; /* Low pass filter state */ + silk_VAD_state sVAD; /* Voice activity detector state */ + silk_nsq_state sNSQ; /* Noise Shape Quantizer State */ + opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ]; /* Previously quantized NLSF vector */ + opus_int speech_activity_Q8; /* Speech activity */ + opus_int allow_bandwidth_switch; /* Flag indicating that switching of internal bandwidth is allowed */ + opus_int8 LBRRprevLastGainIndex; + opus_int8 prevSignalType; + opus_int prevLag; + opus_int pitch_LPC_win_length; + opus_int max_pitch_lag; /* Highest possible pitch lag (samples) */ + opus_int32 API_fs_Hz; /* API sampling frequency (Hz) */ + opus_int32 prev_API_fs_Hz; /* Previous API sampling frequency (Hz) */ + opus_int maxInternal_fs_Hz; /* Maximum internal sampling frequency (Hz) */ + opus_int minInternal_fs_Hz; /* Minimum internal sampling frequency (Hz) */ + opus_int desiredInternal_fs_Hz; /* Soft request for internal sampling frequency (Hz) */ + opus_int fs_kHz; /* Internal sampling frequency (kHz) */ + opus_int nb_subfr; /* Number of 5 ms subframes in a frame */ + opus_int frame_length; /* Frame length (samples) */ + opus_int subfr_length; /* Subframe length (samples) */ + opus_int ltp_mem_length; /* Length of LTP memory */ + opus_int la_pitch; /* Look-ahead for pitch analysis (samples) */ + opus_int la_shape; /* Look-ahead for noise shape analysis (samples) */ + opus_int shapeWinLength; /* Window length for noise shape analysis (samples) */ + opus_int32 TargetRate_bps; /* Target bitrate (bps) */ + opus_int PacketSize_ms; /* Number of milliseconds to put in each packet */ + opus_int PacketLoss_perc; /* Packet loss rate measured by farend */ + opus_int32 frameCounter; + opus_int Complexity; /* Complexity setting */ + opus_int nStatesDelayedDecision; /* Number of states in delayed decision quantization */ + opus_int useInterpolatedNLSFs; /* Flag for using NLSF interpolation */ + opus_int shapingLPCOrder; /* Filter order for noise shaping filters */ + opus_int predictLPCOrder; /* Filter order for prediction filters */ + opus_int pitchEstimationComplexity; /* Complexity level for pitch estimator */ + opus_int pitchEstimationLPCOrder; /* Whitening filter order for pitch estimator */ + opus_int32 pitchEstimationThreshold_Q16; /* Threshold for pitch estimator */ + opus_int32 sum_log_gain_Q7; /* Cumulative max prediction gain */ + opus_int NLSF_MSVQ_Survivors; /* Number of survivors in NLSF MSVQ */ + opus_int first_frame_after_reset; /* Flag for deactivating NLSF interpolation, pitch prediction */ + opus_int controlled_since_last_payload; /* Flag for ensuring codec_control only runs once per packet */ + opus_int warping_Q16; /* Warping parameter for warped noise shaping */ + opus_int useCBR; /* Flag to enable constant bitrate */ + opus_int prefillFlag; /* Flag to indicate that only buffers are prefilled, no coding */ + const opus_uint8 *pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */ + const opus_uint8 *pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */ + const silk_NLSF_CB_struct *psNLSF_CB; /* Pointer to NLSF codebook */ + opus_int input_quality_bands_Q15[ VAD_N_BANDS ]; + opus_int input_tilt_Q15; + opus_int SNR_dB_Q7; /* Quality setting */ + + opus_int8 VAD_flags[ MAX_FRAMES_PER_PACKET ]; + opus_int8 LBRR_flag; + opus_int LBRR_flags[ MAX_FRAMES_PER_PACKET ]; + + SideInfoIndices indices; + opus_int8 pulses[ MAX_FRAME_LENGTH ]; + + int arch; + + /* Input/output buffering */ + opus_int16 inputBuf[ MAX_FRAME_LENGTH + 2 ]; /* Buffer containing input signal */ + opus_int inputBufIx; + opus_int nFramesPerPacket; + opus_int nFramesEncoded; /* Number of frames analyzed in current packet */ + + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int channelNb; + + /* Parameters For LTP scaling Control */ + opus_int frames_since_onset; + + /* Specifically for entropy coding */ + opus_int ec_prevSignalType; + opus_int16 ec_prevLagIndex; + + silk_resampler_state_struct resampler_state; + + /* DTX */ + opus_int useDTX; /* Flag to enable DTX */ + opus_int inDTX; /* Flag to signal DTX period */ + opus_int noSpeechCounter; /* Counts concecutive nonactive frames, used by DTX */ + + /* Inband Low Bitrate Redundancy (LBRR) data */ + opus_int useInBandFEC; /* Saves the API setting for query */ + opus_int LBRR_enabled; /* Depends on useInBandFRC, bitrate and packet loss rate */ + opus_int LBRR_GainIncreases; /* Gains increment for coding LBRR frames */ + SideInfoIndices indices_LBRR[ MAX_FRAMES_PER_PACKET ]; + opus_int8 pulses_LBRR[ MAX_FRAMES_PER_PACKET ][ MAX_FRAME_LENGTH ]; +} silk_encoder_state; + + +/* Struct for Packet Loss Concealment */ +typedef struct { + opus_int32 pitchL_Q8; /* Pitch lag to use for voiced concealment */ + opus_int16 LTPCoef_Q14[ LTP_ORDER ]; /* LTP coeficients to use for voiced concealment */ + opus_int16 prevLPC_Q12[ MAX_LPC_ORDER ]; + opus_int last_frame_lost; /* Was previous frame lost */ + opus_int32 rand_seed; /* Seed for unvoiced signal generation */ + opus_int16 randScale_Q14; /* Scaling of unvoiced random signal */ + opus_int32 conc_energy; + opus_int conc_energy_shift; + opus_int16 prevLTP_scale_Q14; + opus_int32 prevGain_Q16[ 2 ]; + opus_int fs_kHz; + opus_int nb_subfr; + opus_int subfr_length; +} silk_PLC_struct; + +/* Struct for CNG */ +typedef struct { + opus_int32 CNG_exc_buf_Q14[ MAX_FRAME_LENGTH ]; + opus_int16 CNG_smth_NLSF_Q15[ MAX_LPC_ORDER ]; + opus_int32 CNG_synth_state[ MAX_LPC_ORDER ]; + opus_int32 CNG_smth_Gain_Q16; + opus_int32 rand_seed; + opus_int fs_kHz; +} silk_CNG_struct; + +/********************************/ +/* Decoder state */ +/********************************/ +typedef struct { + opus_int32 prev_gain_Q16; + opus_int32 exc_Q14[ MAX_FRAME_LENGTH ]; + opus_int32 sLPC_Q14_buf[ MAX_LPC_ORDER ]; + opus_int16 outBuf[ MAX_FRAME_LENGTH + 2 * MAX_SUB_FRAME_LENGTH ]; /* Buffer for output signal */ + opus_int lagPrev; /* Previous Lag */ + opus_int8 LastGainIndex; /* Previous gain index */ + opus_int fs_kHz; /* Sampling frequency in kHz */ + opus_int32 fs_API_hz; /* API sample frequency (Hz) */ + opus_int nb_subfr; /* Number of 5 ms subframes in a frame */ + opus_int frame_length; /* Frame length (samples) */ + opus_int subfr_length; /* Subframe length (samples) */ + opus_int ltp_mem_length; /* Length of LTP memory */ + opus_int LPC_order; /* LPC order */ + opus_int16 prevNLSF_Q15[ MAX_LPC_ORDER ]; /* Used to interpolate LSFs */ + opus_int first_frame_after_reset; /* Flag for deactivating NLSF interpolation */ + const opus_uint8 *pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */ + const opus_uint8 *pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */ + + /* For buffering payload in case of more frames per packet */ + opus_int nFramesDecoded; + opus_int nFramesPerPacket; + + /* Specifically for entropy coding */ + opus_int ec_prevSignalType; + opus_int16 ec_prevLagIndex; + + opus_int VAD_flags[ MAX_FRAMES_PER_PACKET ]; + opus_int LBRR_flag; + opus_int LBRR_flags[ MAX_FRAMES_PER_PACKET ]; + + silk_resampler_state_struct resampler_state; + + const silk_NLSF_CB_struct *psNLSF_CB; /* Pointer to NLSF codebook */ + + /* Quantization indices */ + SideInfoIndices indices; + + /* CNG state */ + silk_CNG_struct sCNG; + + /* Stuff used for PLC */ + opus_int lossCnt; + opus_int prevSignalType; + int arch; + + silk_PLC_struct sPLC; + +} silk_decoder_state; + +/************************/ +/* Decoder control */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + opus_int pitchL[ MAX_NB_SUBFR ]; + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + /* Holds interpolated and final coefficients, 4-byte aligned */ + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; +} silk_decoder_control; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/sum_sqr_shift.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/sum_sqr_shift.c new file mode 100644 index 000000000..4fd0c3d7d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/sum_sqr_shift.c @@ -0,0 +1,83 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Compute number of bits to right shift the sum of squares of a vector */ +/* of int16s to make it fit in an int32 */ +void silk_sum_sqr_shift( + opus_int32 *energy, /* O Energy of x, after shifting to the right */ + opus_int *shift, /* O Number of bits right shift applied to energy */ + const opus_int16 *x, /* I Input vector */ + opus_int len /* I Length of input vector */ +) +{ + opus_int i, shft; + opus_uint32 nrg_tmp; + opus_int32 nrg; + + /* Do a first run with the maximum shift we could have. */ + shft = 31-silk_CLZ32(len); + /* Let's be conservative with rounding and start with nrg=len. */ + nrg = len; + for( i = 0; i < len - 1; i += 2 ) { + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg_tmp = silk_SMLABB_ovflw( nrg_tmp, x[ i + 1 ], x[ i + 1 ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + if( i < len ) { + /* One sample left to process */ + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + silk_assert( nrg >= 0 ); + /* Make sure the result will fit in a 32-bit signed integer with two bits + of headroom. */ + shft = silk_max_32(0, shft+3 - silk_CLZ32(nrg)); + nrg = 0; + for( i = 0 ; i < len - 1; i += 2 ) { + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg_tmp = silk_SMLABB_ovflw( nrg_tmp, x[ i + 1 ], x[ i + 1 ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + if( i < len ) { + /* One sample left to process */ + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + + silk_assert( nrg >= 0 ); + + /* Output arguments */ + *shift = shft; + *energy = nrg; +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/table_LSF_cos.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/table_LSF_cos.c new file mode 100644 index 000000000..ec9dc6392 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/table_LSF_cos.c @@ -0,0 +1,70 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +/* Cosine approximation table for LSF conversion */ +/* Q12 values (even) */ +const opus_int16 silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ] = { + 8192, 8190, 8182, 8170, + 8152, 8130, 8104, 8072, + 8034, 7994, 7946, 7896, + 7840, 7778, 7714, 7644, + 7568, 7490, 7406, 7318, + 7226, 7128, 7026, 6922, + 6812, 6698, 6580, 6458, + 6332, 6204, 6070, 5934, + 5792, 5648, 5502, 5352, + 5198, 5040, 4880, 4718, + 4552, 4382, 4212, 4038, + 3862, 3684, 3502, 3320, + 3136, 2948, 2760, 2570, + 2378, 2186, 1990, 1794, + 1598, 1400, 1202, 1002, + 802, 602, 402, 202, + 0, -202, -402, -602, + -802, -1002, -1202, -1400, + -1598, -1794, -1990, -2186, + -2378, -2570, -2760, -2948, + -3136, -3320, -3502, -3684, + -3862, -4038, -4212, -4382, + -4552, -4718, -4880, -5040, + -5198, -5352, -5502, -5648, + -5792, -5934, -6070, -6204, + -6332, -6458, -6580, -6698, + -6812, -6922, -7026, -7128, + -7226, -7318, -7406, -7490, + -7568, -7644, -7714, -7778, + -7840, -7896, -7946, -7994, + -8034, -8072, -8104, -8130, + -8152, -8170, -8182, -8190, + -8192 +}; diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables.h new file mode 100644 index 000000000..95230c451 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables.h @@ -0,0 +1,114 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_TABLES_H +#define SILK_TABLES_H + +#include "define.h" +#include "structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Entropy coding tables (with size in bytes indicated) */ +extern const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ]; /* 24 */ +extern const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ]; /* 41 */ + +extern const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ];/* 32 */ +extern const opus_uint8 silk_pitch_delta_iCDF[ 21 ]; /* 21 */ +extern const opus_uint8 silk_pitch_contour_iCDF[ 34 ]; /* 34 */ +extern const opus_uint8 silk_pitch_contour_NB_iCDF[ 11 ]; /* 11 */ +extern const opus_uint8 silk_pitch_contour_10_ms_iCDF[ 12 ]; /* 12 */ +extern const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[ 3 ]; /* 3 */ + +extern const opus_uint8 silk_pulses_per_block_iCDF[ N_RATE_LEVELS ][ SILK_MAX_PULSES + 2 ]; /* 180 */ +extern const opus_uint8 silk_pulses_per_block_BITS_Q5[ N_RATE_LEVELS - 1 ][ SILK_MAX_PULSES + 2 ]; /* 162 */ + +extern const opus_uint8 silk_rate_levels_iCDF[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */ +extern const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */ + +extern const opus_uint8 silk_max_pulses_table[ 4 ]; /* 4 */ + +extern const opus_uint8 silk_shell_code_table0[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table1[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table2[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table3[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table_offsets[ SILK_MAX_PULSES + 1 ]; /* 17 */ + +extern const opus_uint8 silk_lsb_iCDF[ 2 ]; /* 2 */ + +extern const opus_uint8 silk_sign_iCDF[ 42 ]; /* 42 */ + +extern const opus_uint8 silk_uniform3_iCDF[ 3 ]; /* 3 */ +extern const opus_uint8 silk_uniform4_iCDF[ 4 ]; /* 4 */ +extern const opus_uint8 silk_uniform5_iCDF[ 5 ]; /* 5 */ +extern const opus_uint8 silk_uniform6_iCDF[ 6 ]; /* 6 */ +extern const opus_uint8 silk_uniform8_iCDF[ 8 ]; /* 8 */ + +extern const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ]; /* 7 */ + +extern const opus_uint8 silk_LTP_per_index_iCDF[ 3 ]; /* 3 */ +extern const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[ NB_LTP_CBKS ]; /* 3 */ +extern const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[ NB_LTP_CBKS ]; /* 3 */ +extern const opus_int8 * const silk_LTP_vq_ptrs_Q7[ NB_LTP_CBKS ]; /* 168 */ +extern const opus_uint8 * const silk_LTP_vq_gain_ptrs_Q7[NB_LTP_CBKS]; +extern const opus_int8 silk_LTP_vq_sizes[ NB_LTP_CBKS ]; /* 3 */ + +extern const opus_uint8 silk_LTPscale_iCDF[ 3 ]; /* 4 */ +extern const opus_int16 silk_LTPScales_table_Q14[ 3 ]; /* 6 */ + +extern const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ]; /* 4 */ +extern const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ]; /* 2 */ + +extern const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ]; /* 32 */ +extern const opus_uint8 silk_stereo_pred_joint_iCDF[ 25 ]; /* 25 */ +extern const opus_uint8 silk_stereo_only_code_mid_iCDF[ 2 ]; /* 2 */ + +extern const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ]; /* 10 */ + +extern const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ]; /* 5 */ + +extern const silk_NLSF_CB_struct silk_NLSF_CB_WB; /* 1040 */ +extern const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB; /* 728 */ + +/* Quantization offsets */ +extern const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ]; /* 8 */ + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +extern const opus_int32 silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ]; /* 60 */ +extern const opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ]; /* 60 */ + +/* Rom table with cosine values */ +extern const opus_int16 silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ]; /* 258 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_LTP.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_LTP.c new file mode 100644 index 000000000..5e12c8643 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_LTP.c @@ -0,0 +1,294 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_LTP_per_index_iCDF[3] = { + 179, 99, 0 +}; + +static const opus_uint8 silk_LTP_gain_iCDF_0[8] = { + 71, 56, 43, 30, 21, 12, 6, 0 +}; + +static const opus_uint8 silk_LTP_gain_iCDF_1[16] = { + 199, 165, 144, 124, 109, 96, 84, 71, + 61, 51, 42, 32, 23, 15, 8, 0 +}; + +static const opus_uint8 silk_LTP_gain_iCDF_2[32] = { + 241, 225, 211, 199, 187, 175, 164, 153, + 142, 132, 123, 114, 105, 96, 88, 80, + 72, 64, 57, 50, 44, 38, 33, 29, + 24, 20, 16, 12, 9, 5, 2, 0 +}; + +static const opus_uint8 silk_LTP_gain_BITS_Q5_0[8] = { + 15, 131, 138, 138, 155, 155, 173, 173 +}; + +static const opus_uint8 silk_LTP_gain_BITS_Q5_1[16] = { + 69, 93, 115, 118, 131, 138, 141, 138, + 150, 150, 155, 150, 155, 160, 166, 160 +}; + +static const opus_uint8 silk_LTP_gain_BITS_Q5_2[32] = { + 131, 128, 134, 141, 141, 141, 145, 145, + 145, 150, 155, 155, 155, 155, 160, 160, + 160, 160, 166, 166, 173, 173, 182, 192, + 182, 192, 192, 192, 205, 192, 205, 224 +}; + +const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[NB_LTP_CBKS] = { + silk_LTP_gain_iCDF_0, + silk_LTP_gain_iCDF_1, + silk_LTP_gain_iCDF_2 +}; + +const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[NB_LTP_CBKS] = { + silk_LTP_gain_BITS_Q5_0, + silk_LTP_gain_BITS_Q5_1, + silk_LTP_gain_BITS_Q5_2 +}; + +static const opus_int8 silk_LTP_gain_vq_0[8][5] = +{ +{ + 4, 6, 24, 7, 5 +}, +{ + 0, 0, 2, 0, 0 +}, +{ + 12, 28, 41, 13, -4 +}, +{ + -9, 15, 42, 25, 14 +}, +{ + 1, -2, 62, 41, -9 +}, +{ + -10, 37, 65, -4, 3 +}, +{ + -6, 4, 66, 7, -8 +}, +{ + 16, 14, 38, -3, 33 +} +}; + +static const opus_int8 silk_LTP_gain_vq_1[16][5] = +{ +{ + 13, 22, 39, 23, 12 +}, +{ + -1, 36, 64, 27, -6 +}, +{ + -7, 10, 55, 43, 17 +}, +{ + 1, 1, 8, 1, 1 +}, +{ + 6, -11, 74, 53, -9 +}, +{ + -12, 55, 76, -12, 8 +}, +{ + -3, 3, 93, 27, -4 +}, +{ + 26, 39, 59, 3, -8 +}, +{ + 2, 0, 77, 11, 9 +}, +{ + -8, 22, 44, -6, 7 +}, +{ + 40, 9, 26, 3, 9 +}, +{ + -7, 20, 101, -7, 4 +}, +{ + 3, -8, 42, 26, 0 +}, +{ + -15, 33, 68, 2, 23 +}, +{ + -2, 55, 46, -2, 15 +}, +{ + 3, -1, 21, 16, 41 +} +}; + +static const opus_int8 silk_LTP_gain_vq_2[32][5] = +{ +{ + -6, 27, 61, 39, 5 +}, +{ + -11, 42, 88, 4, 1 +}, +{ + -2, 60, 65, 6, -4 +}, +{ + -1, -5, 73, 56, 1 +}, +{ + -9, 19, 94, 29, -9 +}, +{ + 0, 12, 99, 6, 4 +}, +{ + 8, -19, 102, 46, -13 +}, +{ + 3, 2, 13, 3, 2 +}, +{ + 9, -21, 84, 72, -18 +}, +{ + -11, 46, 104, -22, 8 +}, +{ + 18, 38, 48, 23, 0 +}, +{ + -16, 70, 83, -21, 11 +}, +{ + 5, -11, 117, 22, -8 +}, +{ + -6, 23, 117, -12, 3 +}, +{ + 3, -8, 95, 28, 4 +}, +{ + -10, 15, 77, 60, -15 +}, +{ + -1, 4, 124, 2, -4 +}, +{ + 3, 38, 84, 24, -25 +}, +{ + 2, 13, 42, 13, 31 +}, +{ + 21, -4, 56, 46, -1 +}, +{ + -1, 35, 79, -13, 19 +}, +{ + -7, 65, 88, -9, -14 +}, +{ + 20, 4, 81, 49, -29 +}, +{ + 20, 0, 75, 3, -17 +}, +{ + 5, -9, 44, 92, -8 +}, +{ + 1, -3, 22, 69, 31 +}, +{ + -6, 95, 41, -12, 5 +}, +{ + 39, 67, 16, -4, 1 +}, +{ + 0, -6, 120, 55, -36 +}, +{ + -13, 44, 122, 4, -24 +}, +{ + 81, 5, 11, 3, 7 +}, +{ + 2, 0, 9, 10, 88 +} +}; + +const opus_int8 * const silk_LTP_vq_ptrs_Q7[NB_LTP_CBKS] = { + (opus_int8 *)&silk_LTP_gain_vq_0[0][0], + (opus_int8 *)&silk_LTP_gain_vq_1[0][0], + (opus_int8 *)&silk_LTP_gain_vq_2[0][0] +}; + +/* Maximum frequency-dependent response of the pitch taps above, + computed as max(abs(freqz(taps))) */ +static const opus_uint8 silk_LTP_gain_vq_0_gain[8] = { + 46, 2, 90, 87, 93, 91, 82, 98 +}; + +static const opus_uint8 silk_LTP_gain_vq_1_gain[16] = { + 109, 120, 118, 12, 113, 115, 117, 119, + 99, 59, 87, 111, 63, 111, 112, 80 +}; + +static const opus_uint8 silk_LTP_gain_vq_2_gain[32] = { + 126, 124, 125, 124, 129, 121, 126, 23, + 132, 127, 127, 127, 126, 127, 122, 133, + 130, 134, 101, 118, 119, 145, 126, 86, + 124, 120, 123, 119, 170, 173, 107, 109 +}; + +const opus_uint8 * const silk_LTP_vq_gain_ptrs_Q7[NB_LTP_CBKS] = { + &silk_LTP_gain_vq_0_gain[0], + &silk_LTP_gain_vq_1_gain[0], + &silk_LTP_gain_vq_2_gain[0] +}; + +const opus_int8 silk_LTP_vq_sizes[NB_LTP_CBKS] = { + 8, 16, 32 +}; diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_NLSF_CB_NB_MB.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_NLSF_CB_NB_MB.c new file mode 100644 index 000000000..195d5b95b --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_NLSF_CB_NB_MB.c @@ -0,0 +1,195 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +static const opus_uint8 silk_NLSF_CB1_NB_MB_Q8[ 320 ] = { + 12, 35, 60, 83, 108, 132, 157, 180, + 206, 228, 15, 32, 55, 77, 101, 125, + 151, 175, 201, 225, 19, 42, 66, 89, + 114, 137, 162, 184, 209, 230, 12, 25, + 50, 72, 97, 120, 147, 172, 200, 223, + 26, 44, 69, 90, 114, 135, 159, 180, + 205, 225, 13, 22, 53, 80, 106, 130, + 156, 180, 205, 228, 15, 25, 44, 64, + 90, 115, 142, 168, 196, 222, 19, 24, + 62, 82, 100, 120, 145, 168, 190, 214, + 22, 31, 50, 79, 103, 120, 151, 170, + 203, 227, 21, 29, 45, 65, 106, 124, + 150, 171, 196, 224, 30, 49, 75, 97, + 121, 142, 165, 186, 209, 229, 19, 25, + 52, 70, 93, 116, 143, 166, 192, 219, + 26, 34, 62, 75, 97, 118, 145, 167, + 194, 217, 25, 33, 56, 70, 91, 113, + 143, 165, 196, 223, 21, 34, 51, 72, + 97, 117, 145, 171, 196, 222, 20, 29, + 50, 67, 90, 117, 144, 168, 197, 221, + 22, 31, 48, 66, 95, 117, 146, 168, + 196, 222, 24, 33, 51, 77, 116, 134, + 158, 180, 200, 224, 21, 28, 70, 87, + 106, 124, 149, 170, 194, 217, 26, 33, + 53, 64, 83, 117, 152, 173, 204, 225, + 27, 34, 65, 95, 108, 129, 155, 174, + 210, 225, 20, 26, 72, 99, 113, 131, + 154, 176, 200, 219, 34, 43, 61, 78, + 93, 114, 155, 177, 205, 229, 23, 29, + 54, 97, 124, 138, 163, 179, 209, 229, + 30, 38, 56, 89, 118, 129, 158, 178, + 200, 231, 21, 29, 49, 63, 85, 111, + 142, 163, 193, 222, 27, 48, 77, 103, + 133, 158, 179, 196, 215, 232, 29, 47, + 74, 99, 124, 151, 176, 198, 220, 237, + 33, 42, 61, 76, 93, 121, 155, 174, + 207, 225, 29, 53, 87, 112, 136, 154, + 170, 188, 208, 227, 24, 30, 52, 84, + 131, 150, 166, 186, 203, 229, 37, 48, + 64, 84, 104, 118, 156, 177, 201, 230 +}; + +static const opus_int16 silk_NLSF_CB1_Wght_Q9[ 320 ] = { + 2897, 2314, 2314, 2314, 2287, 2287, 2314, 2300, 2327, 2287, + 2888, 2580, 2394, 2367, 2314, 2274, 2274, 2274, 2274, 2194, + 2487, 2340, 2340, 2314, 2314, 2314, 2340, 2340, 2367, 2354, + 3216, 2766, 2340, 2340, 2314, 2274, 2221, 2207, 2261, 2194, + 2460, 2474, 2367, 2394, 2394, 2394, 2394, 2367, 2407, 2314, + 3479, 3056, 2127, 2207, 2274, 2274, 2274, 2287, 2314, 2261, + 3282, 3141, 2580, 2394, 2247, 2221, 2207, 2194, 2194, 2114, + 4096, 3845, 2221, 2620, 2620, 2407, 2314, 2394, 2367, 2074, + 3178, 3244, 2367, 2221, 2553, 2434, 2340, 2314, 2167, 2221, + 3338, 3488, 2726, 2194, 2261, 2460, 2354, 2367, 2207, 2101, + 2354, 2420, 2327, 2367, 2394, 2420, 2420, 2420, 2460, 2367, + 3779, 3629, 2434, 2527, 2367, 2274, 2274, 2300, 2207, 2048, + 3254, 3225, 2713, 2846, 2447, 2327, 2300, 2300, 2274, 2127, + 3263, 3300, 2753, 2806, 2447, 2261, 2261, 2247, 2127, 2101, + 2873, 2981, 2633, 2367, 2407, 2354, 2194, 2247, 2247, 2114, + 3225, 3197, 2633, 2580, 2274, 2181, 2247, 2221, 2221, 2141, + 3178, 3310, 2740, 2407, 2274, 2274, 2274, 2287, 2194, 2114, + 3141, 3272, 2460, 2061, 2287, 2500, 2367, 2487, 2434, 2181, + 3507, 3282, 2314, 2700, 2647, 2474, 2367, 2394, 2340, 2127, + 3423, 3535, 3038, 3056, 2300, 1950, 2221, 2274, 2274, 2274, + 3404, 3366, 2087, 2687, 2873, 2354, 2420, 2274, 2474, 2540, + 3760, 3488, 1950, 2660, 2897, 2527, 2394, 2367, 2460, 2261, + 3028, 3272, 2740, 2888, 2740, 2154, 2127, 2287, 2234, 2247, + 3695, 3657, 2025, 1969, 2660, 2700, 2580, 2500, 2327, 2367, + 3207, 3413, 2354, 2074, 2888, 2888, 2340, 2487, 2247, 2167, + 3338, 3366, 2846, 2780, 2327, 2154, 2274, 2287, 2114, 2061, + 2327, 2300, 2181, 2167, 2181, 2367, 2633, 2700, 2700, 2553, + 2407, 2434, 2221, 2261, 2221, 2221, 2340, 2420, 2607, 2700, + 3038, 3244, 2806, 2888, 2474, 2074, 2300, 2314, 2354, 2380, + 2221, 2154, 2127, 2287, 2500, 2793, 2793, 2620, 2580, 2367, + 3676, 3713, 2234, 1838, 2181, 2753, 2726, 2673, 2513, 2207, + 2793, 3160, 2726, 2553, 2846, 2513, 2181, 2394, 2221, 2181 +}; + +static const opus_uint8 silk_NLSF_CB1_iCDF_NB_MB[ 64 ] = { + 212, 178, 148, 129, 108, 96, 85, 82, + 79, 77, 61, 59, 57, 56, 51, 49, + 48, 45, 42, 41, 40, 38, 36, 34, + 31, 30, 21, 12, 10, 3, 1, 0, + 255, 245, 244, 236, 233, 225, 217, 203, + 190, 176, 175, 161, 149, 136, 125, 114, + 102, 91, 81, 71, 60, 52, 43, 35, + 28, 20, 19, 18, 12, 11, 5, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_SELECT_NB_MB[ 160 ] = { + 16, 0, 0, 0, 0, 99, 66, 36, + 36, 34, 36, 34, 34, 34, 34, 83, + 69, 36, 52, 34, 116, 102, 70, 68, + 68, 176, 102, 68, 68, 34, 65, 85, + 68, 84, 36, 116, 141, 152, 139, 170, + 132, 187, 184, 216, 137, 132, 249, 168, + 185, 139, 104, 102, 100, 68, 68, 178, + 218, 185, 185, 170, 244, 216, 187, 187, + 170, 244, 187, 187, 219, 138, 103, 155, + 184, 185, 137, 116, 183, 155, 152, 136, + 132, 217, 184, 184, 170, 164, 217, 171, + 155, 139, 244, 169, 184, 185, 170, 164, + 216, 223, 218, 138, 214, 143, 188, 218, + 168, 244, 141, 136, 155, 170, 168, 138, + 220, 219, 139, 164, 219, 202, 216, 137, + 168, 186, 246, 185, 139, 116, 185, 219, + 185, 138, 100, 100, 134, 100, 102, 34, + 68, 68, 100, 68, 168, 203, 221, 218, + 168, 167, 154, 136, 104, 70, 164, 246, + 171, 137, 139, 137, 155, 218, 219, 139 +}; + +static const opus_uint8 silk_NLSF_CB2_iCDF_NB_MB[ 72 ] = { + 255, 254, 253, 238, 14, 3, 2, 1, + 0, 255, 254, 252, 218, 35, 3, 2, + 1, 0, 255, 254, 250, 208, 59, 4, + 2, 1, 0, 255, 254, 246, 194, 71, + 10, 2, 1, 0, 255, 252, 236, 183, + 82, 8, 2, 1, 0, 255, 252, 235, + 180, 90, 17, 2, 1, 0, 255, 248, + 224, 171, 97, 30, 4, 1, 0, 255, + 254, 236, 173, 95, 37, 7, 1, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_BITS_NB_MB_Q5[ 72 ] = { + 255, 255, 255, 131, 6, 145, 255, 255, + 255, 255, 255, 236, 93, 15, 96, 255, + 255, 255, 255, 255, 194, 83, 25, 71, + 221, 255, 255, 255, 255, 162, 73, 34, + 66, 162, 255, 255, 255, 210, 126, 73, + 43, 57, 173, 255, 255, 255, 201, 125, + 71, 48, 58, 130, 255, 255, 255, 166, + 110, 73, 57, 62, 104, 210, 255, 255, + 251, 123, 65, 55, 68, 100, 171, 255 +}; + +static const opus_uint8 silk_NLSF_PRED_NB_MB_Q8[ 18 ] = { + 179, 138, 140, 148, 151, 149, 153, 151, + 163, 116, 67, 82, 59, 92, 72, 100, + 89, 92 +}; + +static const opus_int16 silk_NLSF_DELTA_MIN_NB_MB_Q15[ 11 ] = { + 250, 3, 6, 3, 3, 3, 4, 3, + 3, 3, 461 +}; + +const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB = +{ + 32, + 10, + SILK_FIX_CONST( 0.18, 16 ), + SILK_FIX_CONST( 1.0 / 0.18, 6 ), + silk_NLSF_CB1_NB_MB_Q8, + silk_NLSF_CB1_Wght_Q9, + silk_NLSF_CB1_iCDF_NB_MB, + silk_NLSF_PRED_NB_MB_Q8, + silk_NLSF_CB2_SELECT_NB_MB, + silk_NLSF_CB2_iCDF_NB_MB, + silk_NLSF_CB2_BITS_NB_MB_Q5, + silk_NLSF_DELTA_MIN_NB_MB_Q15, +}; diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_NLSF_CB_WB.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_NLSF_CB_WB.c new file mode 100644 index 000000000..5cc9f57bf --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_NLSF_CB_WB.c @@ -0,0 +1,234 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +static const opus_uint8 silk_NLSF_CB1_WB_Q8[ 512 ] = { + 7, 23, 38, 54, 69, 85, 100, 116, + 131, 147, 162, 178, 193, 208, 223, 239, + 13, 25, 41, 55, 69, 83, 98, 112, + 127, 142, 157, 171, 187, 203, 220, 236, + 15, 21, 34, 51, 61, 78, 92, 106, + 126, 136, 152, 167, 185, 205, 225, 240, + 10, 21, 36, 50, 63, 79, 95, 110, + 126, 141, 157, 173, 189, 205, 221, 237, + 17, 20, 37, 51, 59, 78, 89, 107, + 123, 134, 150, 164, 184, 205, 224, 240, + 10, 15, 32, 51, 67, 81, 96, 112, + 129, 142, 158, 173, 189, 204, 220, 236, + 8, 21, 37, 51, 65, 79, 98, 113, + 126, 138, 155, 168, 179, 192, 209, 218, + 12, 15, 34, 55, 63, 78, 87, 108, + 118, 131, 148, 167, 185, 203, 219, 236, + 16, 19, 32, 36, 56, 79, 91, 108, + 118, 136, 154, 171, 186, 204, 220, 237, + 11, 28, 43, 58, 74, 89, 105, 120, + 135, 150, 165, 180, 196, 211, 226, 241, + 6, 16, 33, 46, 60, 75, 92, 107, + 123, 137, 156, 169, 185, 199, 214, 225, + 11, 19, 30, 44, 57, 74, 89, 105, + 121, 135, 152, 169, 186, 202, 218, 234, + 12, 19, 29, 46, 57, 71, 88, 100, + 120, 132, 148, 165, 182, 199, 216, 233, + 17, 23, 35, 46, 56, 77, 92, 106, + 123, 134, 152, 167, 185, 204, 222, 237, + 14, 17, 45, 53, 63, 75, 89, 107, + 115, 132, 151, 171, 188, 206, 221, 240, + 9, 16, 29, 40, 56, 71, 88, 103, + 119, 137, 154, 171, 189, 205, 222, 237, + 16, 19, 36, 48, 57, 76, 87, 105, + 118, 132, 150, 167, 185, 202, 218, 236, + 12, 17, 29, 54, 71, 81, 94, 104, + 126, 136, 149, 164, 182, 201, 221, 237, + 15, 28, 47, 62, 79, 97, 115, 129, + 142, 155, 168, 180, 194, 208, 223, 238, + 8, 14, 30, 45, 62, 78, 94, 111, + 127, 143, 159, 175, 192, 207, 223, 239, + 17, 30, 49, 62, 79, 92, 107, 119, + 132, 145, 160, 174, 190, 204, 220, 235, + 14, 19, 36, 45, 61, 76, 91, 108, + 121, 138, 154, 172, 189, 205, 222, 238, + 12, 18, 31, 45, 60, 76, 91, 107, + 123, 138, 154, 171, 187, 204, 221, 236, + 13, 17, 31, 43, 53, 70, 83, 103, + 114, 131, 149, 167, 185, 203, 220, 237, + 17, 22, 35, 42, 58, 78, 93, 110, + 125, 139, 155, 170, 188, 206, 224, 240, + 8, 15, 34, 50, 67, 83, 99, 115, + 131, 146, 162, 178, 193, 209, 224, 239, + 13, 16, 41, 66, 73, 86, 95, 111, + 128, 137, 150, 163, 183, 206, 225, 241, + 17, 25, 37, 52, 63, 75, 92, 102, + 119, 132, 144, 160, 175, 191, 212, 231, + 19, 31, 49, 65, 83, 100, 117, 133, + 147, 161, 174, 187, 200, 213, 227, 242, + 18, 31, 52, 68, 88, 103, 117, 126, + 138, 149, 163, 177, 192, 207, 223, 239, + 16, 29, 47, 61, 76, 90, 106, 119, + 133, 147, 161, 176, 193, 209, 224, 240, + 15, 21, 35, 50, 61, 73, 86, 97, + 110, 119, 129, 141, 175, 198, 218, 237 +}; + +static const opus_int16 silk_NLSF_CB1_WB_Wght_Q9[ 512 ] = { + 3657, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2963, 2963, 2925, 2846, + 3216, 3085, 2972, 3056, 3056, 3010, 3010, 3010, 2963, 2963, 3010, 2972, 2888, 2846, 2846, 2726, + 3920, 4014, 2981, 3207, 3207, 2934, 3056, 2846, 3122, 3244, 2925, 2846, 2620, 2553, 2780, 2925, + 3516, 3197, 3010, 3103, 3019, 2888, 2925, 2925, 2925, 2925, 2888, 2888, 2888, 2888, 2888, 2753, + 5054, 5054, 2934, 3573, 3385, 3056, 3085, 2793, 3160, 3160, 2972, 2846, 2513, 2540, 2753, 2888, + 4428, 4149, 2700, 2753, 2972, 3010, 2925, 2846, 2981, 3019, 2925, 2925, 2925, 2925, 2888, 2726, + 3620, 3019, 2972, 3056, 3056, 2873, 2806, 3056, 3216, 3047, 2981, 3291, 3291, 2981, 3310, 2991, + 5227, 5014, 2540, 3338, 3526, 3385, 3197, 3094, 3376, 2981, 2700, 2647, 2687, 2793, 2846, 2673, + 5081, 5174, 4615, 4428, 2460, 2897, 3047, 3207, 3169, 2687, 2740, 2888, 2846, 2793, 2846, 2700, + 3122, 2888, 2963, 2925, 2925, 2925, 2925, 2963, 2963, 2963, 2963, 2925, 2925, 2963, 2963, 2963, + 4202, 3207, 2981, 3103, 3010, 2888, 2888, 2925, 2972, 2873, 2916, 3019, 2972, 3010, 3197, 2873, + 3760, 3760, 3244, 3103, 2981, 2888, 2925, 2888, 2972, 2934, 2793, 2793, 2846, 2888, 2888, 2660, + 3854, 4014, 3207, 3122, 3244, 2934, 3047, 2963, 2963, 3085, 2846, 2793, 2793, 2793, 2793, 2580, + 3845, 4080, 3357, 3516, 3094, 2740, 3010, 2934, 3122, 3085, 2846, 2846, 2647, 2647, 2846, 2806, + 5147, 4894, 3225, 3845, 3441, 3169, 2897, 3413, 3451, 2700, 2580, 2673, 2740, 2846, 2806, 2753, + 4109, 3789, 3291, 3160, 2925, 2888, 2888, 2925, 2793, 2740, 2793, 2740, 2793, 2846, 2888, 2806, + 5081, 5054, 3047, 3545, 3244, 3056, 3085, 2944, 3103, 2897, 2740, 2740, 2740, 2846, 2793, 2620, + 4309, 4309, 2860, 2527, 3207, 3376, 3376, 3075, 3075, 3376, 3056, 2846, 2647, 2580, 2726, 2753, + 3056, 2916, 2806, 2888, 2740, 2687, 2897, 3103, 3150, 3150, 3216, 3169, 3056, 3010, 2963, 2846, + 4375, 3882, 2925, 2888, 2846, 2888, 2846, 2846, 2888, 2888, 2888, 2846, 2888, 2925, 2888, 2846, + 2981, 2916, 2916, 2981, 2981, 3056, 3122, 3216, 3150, 3056, 3010, 2972, 2972, 2972, 2925, 2740, + 4229, 4149, 3310, 3347, 2925, 2963, 2888, 2981, 2981, 2846, 2793, 2740, 2846, 2846, 2846, 2793, + 4080, 4014, 3103, 3010, 2925, 2925, 2925, 2888, 2925, 2925, 2846, 2846, 2846, 2793, 2888, 2780, + 4615, 4575, 3169, 3441, 3207, 2981, 2897, 3038, 3122, 2740, 2687, 2687, 2687, 2740, 2793, 2700, + 4149, 4269, 3789, 3657, 2726, 2780, 2888, 2888, 3010, 2972, 2925, 2846, 2687, 2687, 2793, 2888, + 4215, 3554, 2753, 2846, 2846, 2888, 2888, 2888, 2925, 2925, 2888, 2925, 2925, 2925, 2963, 2888, + 5174, 4921, 2261, 3432, 3789, 3479, 3347, 2846, 3310, 3479, 3150, 2897, 2460, 2487, 2753, 2925, + 3451, 3685, 3122, 3197, 3357, 3047, 3207, 3207, 2981, 3216, 3085, 2925, 2925, 2687, 2540, 2434, + 2981, 3010, 2793, 2793, 2740, 2793, 2846, 2972, 3056, 3103, 3150, 3150, 3150, 3103, 3010, 3010, + 2944, 2873, 2687, 2726, 2780, 3010, 3432, 3545, 3357, 3244, 3056, 3010, 2963, 2925, 2888, 2846, + 3019, 2944, 2897, 3010, 3010, 2972, 3019, 3103, 3056, 3056, 3010, 2888, 2846, 2925, 2925, 2888, + 3920, 3967, 3010, 3197, 3357, 3216, 3291, 3291, 3479, 3704, 3441, 2726, 2181, 2460, 2580, 2607 +}; + +static const opus_uint8 silk_NLSF_CB1_iCDF_WB[ 64 ] = { + 225, 204, 201, 184, 183, 175, 158, 154, + 153, 135, 119, 115, 113, 110, 109, 99, + 98, 95, 79, 68, 52, 50, 48, 45, + 43, 32, 31, 27, 18, 10, 3, 0, + 255, 251, 235, 230, 212, 201, 196, 182, + 167, 166, 163, 151, 138, 124, 110, 104, + 90, 78, 76, 70, 69, 57, 45, 34, + 24, 21, 11, 6, 5, 4, 3, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_SELECT_WB[ 256 ] = { + 0, 0, 0, 0, 0, 0, 0, 1, + 100, 102, 102, 68, 68, 36, 34, 96, + 164, 107, 158, 185, 180, 185, 139, 102, + 64, 66, 36, 34, 34, 0, 1, 32, + 208, 139, 141, 191, 152, 185, 155, 104, + 96, 171, 104, 166, 102, 102, 102, 132, + 1, 0, 0, 0, 0, 16, 16, 0, + 80, 109, 78, 107, 185, 139, 103, 101, + 208, 212, 141, 139, 173, 153, 123, 103, + 36, 0, 0, 0, 0, 0, 0, 1, + 48, 0, 0, 0, 0, 0, 0, 32, + 68, 135, 123, 119, 119, 103, 69, 98, + 68, 103, 120, 118, 118, 102, 71, 98, + 134, 136, 157, 184, 182, 153, 139, 134, + 208, 168, 248, 75, 189, 143, 121, 107, + 32, 49, 34, 34, 34, 0, 17, 2, + 210, 235, 139, 123, 185, 137, 105, 134, + 98, 135, 104, 182, 100, 183, 171, 134, + 100, 70, 68, 70, 66, 66, 34, 131, + 64, 166, 102, 68, 36, 2, 1, 0, + 134, 166, 102, 68, 34, 34, 66, 132, + 212, 246, 158, 139, 107, 107, 87, 102, + 100, 219, 125, 122, 137, 118, 103, 132, + 114, 135, 137, 105, 171, 106, 50, 34, + 164, 214, 141, 143, 185, 151, 121, 103, + 192, 34, 0, 0, 0, 0, 0, 1, + 208, 109, 74, 187, 134, 249, 159, 137, + 102, 110, 154, 118, 87, 101, 119, 101, + 0, 2, 0, 36, 36, 66, 68, 35, + 96, 164, 102, 100, 36, 0, 2, 33, + 167, 138, 174, 102, 100, 84, 2, 2, + 100, 107, 120, 119, 36, 197, 24, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_iCDF_WB[ 72 ] = { + 255, 254, 253, 244, 12, 3, 2, 1, + 0, 255, 254, 252, 224, 38, 3, 2, + 1, 0, 255, 254, 251, 209, 57, 4, + 2, 1, 0, 255, 254, 244, 195, 69, + 4, 2, 1, 0, 255, 251, 232, 184, + 84, 7, 2, 1, 0, 255, 254, 240, + 186, 86, 14, 2, 1, 0, 255, 254, + 239, 178, 91, 30, 5, 1, 0, 255, + 248, 227, 177, 100, 19, 2, 1, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_BITS_WB_Q5[ 72 ] = { + 255, 255, 255, 156, 4, 154, 255, 255, + 255, 255, 255, 227, 102, 15, 92, 255, + 255, 255, 255, 255, 213, 83, 24, 72, + 236, 255, 255, 255, 255, 150, 76, 33, + 63, 214, 255, 255, 255, 190, 121, 77, + 43, 55, 185, 255, 255, 255, 245, 137, + 71, 43, 59, 139, 255, 255, 255, 255, + 131, 66, 50, 66, 107, 194, 255, 255, + 166, 116, 76, 55, 53, 125, 255, 255 +}; + +static const opus_uint8 silk_NLSF_PRED_WB_Q8[ 30 ] = { + 175, 148, 160, 176, 178, 173, 174, 164, + 177, 174, 196, 182, 198, 192, 182, 68, + 62, 66, 60, 72, 117, 85, 90, 118, + 136, 151, 142, 160, 142, 155 +}; + +static const opus_int16 silk_NLSF_DELTA_MIN_WB_Q15[ 17 ] = { + 100, 3, 40, 3, 3, 3, 5, 14, + 14, 10, 11, 3, 8, 9, 7, 3, + 347 +}; + +const silk_NLSF_CB_struct silk_NLSF_CB_WB = +{ + 32, + 16, + SILK_FIX_CONST( 0.15, 16 ), + SILK_FIX_CONST( 1.0 / 0.15, 6 ), + silk_NLSF_CB1_WB_Q8, + silk_NLSF_CB1_WB_Wght_Q9, + silk_NLSF_CB1_iCDF_WB, + silk_NLSF_PRED_WB_Q8, + silk_NLSF_CB2_SELECT_WB, + silk_NLSF_CB2_iCDF_WB, + silk_NLSF_CB2_BITS_WB_Q5, + silk_NLSF_DELTA_MIN_WB_Q15, +}; + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_gain.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_gain.c new file mode 100644 index 000000000..37e41d890 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_gain.c @@ -0,0 +1,63 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ] = +{ +{ + 224, 112, 44, 15, 3, 2, 1, 0 +}, +{ + 254, 237, 192, 132, 70, 23, 4, 0 +}, +{ + 255, 252, 226, 155, 61, 11, 2, 0 +} +}; + +const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ] = { + 250, 245, 234, 203, 71, 50, 42, 38, + 35, 33, 31, 29, 28, 27, 26, 25, + 24, 23, 22, 21, 20, 19, 18, 17, + 16, 15, 14, 13, 12, 11, 10, 9, + 8, 7, 6, 5, 4, 3, 2, 1, + 0 +}; + +#ifdef __cplusplus +} +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_other.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_other.c new file mode 100644 index 000000000..e34d90777 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_other.c @@ -0,0 +1,124 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "structs.h" +#include "define.h" +#include "tables.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Tables for stereo predictor coding */ +const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ] = { + -13732, -10050, -8266, -7526, -6500, -5000, -2950, -820, + 820, 2950, 5000, 6500, 7526, 8266, 10050, 13732 +}; +const opus_uint8 silk_stereo_pred_joint_iCDF[ 25 ] = { + 249, 247, 246, 245, 244, + 234, 210, 202, 201, 200, + 197, 174, 82, 59, 56, + 55, 54, 46, 22, 12, + 11, 10, 9, 7, 0 +}; +const opus_uint8 silk_stereo_only_code_mid_iCDF[ 2 ] = { 64, 0 }; + +/* Tables for LBRR flags */ +static const opus_uint8 silk_LBRR_flags_2_iCDF[ 3 ] = { 203, 150, 0 }; +static const opus_uint8 silk_LBRR_flags_3_iCDF[ 7 ] = { 215, 195, 166, 125, 110, 82, 0 }; +const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ] = { + silk_LBRR_flags_2_iCDF, + silk_LBRR_flags_3_iCDF +}; + +/* Table for LSB coding */ +const opus_uint8 silk_lsb_iCDF[ 2 ] = { 120, 0 }; + +/* Tables for LTPScale */ +const opus_uint8 silk_LTPscale_iCDF[ 3 ] = { 128, 64, 0 }; + +/* Tables for signal type and offset coding */ +const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ] = { + 232, 158, 10, 0 +}; +const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ] = { + 230, 0 +}; + +/* Tables for NLSF interpolation factor */ +const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ] = { 243, 221, 192, 181, 0 }; + +/* Quantization offsets */ +const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ] = { + { OFFSET_UVL_Q10, OFFSET_UVH_Q10 }, { OFFSET_VL_Q10, OFFSET_VH_Q10 } +}; + +/* Table for LTPScale */ +const opus_int16 silk_LTPScales_table_Q14[ 3 ] = { 15565, 12288, 8192 }; + +/* Uniform entropy tables */ +const opus_uint8 silk_uniform3_iCDF[ 3 ] = { 171, 85, 0 }; +const opus_uint8 silk_uniform4_iCDF[ 4 ] = { 192, 128, 64, 0 }; +const opus_uint8 silk_uniform5_iCDF[ 5 ] = { 205, 154, 102, 51, 0 }; +const opus_uint8 silk_uniform6_iCDF[ 6 ] = { 213, 171, 128, 85, 43, 0 }; +const opus_uint8 silk_uniform8_iCDF[ 8 ] = { 224, 192, 160, 128, 96, 64, 32, 0 }; + +const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ] = { 100, 40, 16, 7, 3, 1, 0 }; + +/* Elliptic/Cauer filters designed with 0.1 dB passband ripple, + 80 dB minimum stopband attenuation, and + [0.95 : 0.15 : 0.35] normalized cut off frequencies. */ + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +const opus_int32 silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ] = +{ +{ 250767114, 501534038, 250767114 }, +{ 209867381, 419732057, 209867381 }, +{ 170987846, 341967853, 170987846 }, +{ 131531482, 263046905, 131531482 }, +{ 89306658, 178584282, 89306658 } +}; + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +const opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ] = +{ +{ 506393414, 239854379 }, +{ 411067935, 169683996 }, +{ 306733530, 116694253 }, +{ 185807084, 77959395 }, +{ 35497197, 57401098 } +}; + +#ifdef __cplusplus +} +#endif + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_pitch_lag.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_pitch_lag.c new file mode 100644 index 000000000..e80cc59a2 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_pitch_lag.c @@ -0,0 +1,69 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ] = { + 253, 250, 244, 233, 212, 182, 150, 131, + 120, 110, 98, 85, 72, 60, 49, 40, + 32, 25, 19, 15, 13, 11, 9, 8, + 7, 6, 5, 4, 3, 2, 1, 0 +}; + +const opus_uint8 silk_pitch_delta_iCDF[21] = { + 210, 208, 206, 203, 199, 193, 183, 168, + 142, 104, 74, 52, 37, 27, 20, 14, + 10, 6, 4, 2, 0 +}; + +const opus_uint8 silk_pitch_contour_iCDF[34] = { + 223, 201, 183, 167, 152, 138, 124, 111, + 98, 88, 79, 70, 62, 56, 50, 44, + 39, 35, 31, 27, 24, 21, 18, 16, + 14, 12, 10, 8, 6, 4, 3, 2, + 1, 0 +}; + +const opus_uint8 silk_pitch_contour_NB_iCDF[11] = { + 188, 176, 155, 138, 119, 97, 67, 43, + 26, 10, 0 +}; + +const opus_uint8 silk_pitch_contour_10_ms_iCDF[12] = { + 165, 119, 80, 61, 47, 35, 27, 20, + 14, 9, 4, 0 +}; + +const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[3] = { + 113, 63, 0 +}; + + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_pulses_per_block.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_pulses_per_block.c new file mode 100644 index 000000000..c7c01c889 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tables_pulses_per_block.c @@ -0,0 +1,264 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_max_pulses_table[ 4 ] = { + 8, 10, 12, 16 +}; + +const opus_uint8 silk_pulses_per_block_iCDF[ 10 ][ 18 ] = { +{ + 125, 51, 26, 18, 15, 12, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 198, 105, 45, 22, 15, 12, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 213, 162, 116, 83, 59, 43, 32, 24, + 18, 15, 12, 9, 7, 6, 5, 3, + 2, 0 +}, +{ + 239, 187, 116, 59, 28, 16, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 250, 229, 188, 135, 86, 51, 30, 19, + 13, 10, 8, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 249, 235, 213, 185, 156, 128, 103, 83, + 66, 53, 42, 33, 26, 21, 17, 13, + 10, 0 +}, +{ + 254, 249, 235, 206, 164, 118, 77, 46, + 27, 16, 10, 7, 5, 4, 3, 2, + 1, 0 +}, +{ + 255, 253, 249, 239, 220, 191, 156, 119, + 85, 57, 37, 23, 15, 10, 6, 4, + 2, 0 +}, +{ + 255, 253, 251, 246, 237, 223, 203, 179, + 152, 124, 98, 75, 55, 40, 29, 21, + 15, 0 +}, +{ + 255, 254, 253, 247, 220, 162, 106, 67, + 42, 28, 18, 12, 9, 6, 4, 3, + 2, 0 +} +}; + +const opus_uint8 silk_pulses_per_block_BITS_Q5[ 9 ][ 18 ] = { +{ + 31, 57, 107, 160, 205, 205, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255 +}, +{ + 69, 47, 67, 111, 166, 205, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255 +}, +{ + 82, 74, 79, 95, 109, 128, 145, 160, + 173, 205, 205, 205, 224, 255, 255, 224, + 255, 224 +}, +{ + 125, 74, 59, 69, 97, 141, 182, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255 +}, +{ + 173, 115, 85, 73, 76, 92, 115, 145, + 173, 205, 224, 224, 255, 255, 255, 255, + 255, 255 +}, +{ + 166, 134, 113, 102, 101, 102, 107, 118, + 125, 138, 145, 155, 166, 182, 192, 192, + 205, 150 +}, +{ + 224, 182, 134, 101, 83, 79, 85, 97, + 120, 145, 173, 205, 224, 255, 255, 255, + 255, 255 +}, +{ + 255, 224, 192, 150, 120, 101, 92, 89, + 93, 102, 118, 134, 160, 182, 192, 224, + 224, 224 +}, +{ + 255, 224, 224, 182, 155, 134, 118, 109, + 104, 102, 106, 111, 118, 131, 145, 160, + 173, 131 +} +}; + +const opus_uint8 silk_rate_levels_iCDF[ 2 ][ 9 ] = +{ +{ + 241, 190, 178, 132, 87, 74, 41, 14, + 0 +}, +{ + 223, 193, 157, 140, 106, 57, 39, 18, + 0 +} +}; + +const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ 9 ] = +{ +{ + 131, 74, 141, 79, 80, 138, 95, 104, + 134 +}, +{ + 95, 99, 91, 125, 93, 76, 123, 115, + 123 +} +}; + +const opus_uint8 silk_shell_code_table0[ 152 ] = { + 128, 0, 214, 42, 0, 235, 128, 21, + 0, 244, 184, 72, 11, 0, 248, 214, + 128, 42, 7, 0, 248, 225, 170, 80, + 25, 5, 0, 251, 236, 198, 126, 54, + 18, 3, 0, 250, 238, 211, 159, 82, + 35, 15, 5, 0, 250, 231, 203, 168, + 128, 88, 53, 25, 6, 0, 252, 238, + 216, 185, 148, 108, 71, 40, 18, 4, + 0, 253, 243, 225, 199, 166, 128, 90, + 57, 31, 13, 3, 0, 254, 246, 233, + 212, 183, 147, 109, 73, 44, 23, 10, + 2, 0, 255, 250, 240, 223, 198, 166, + 128, 90, 58, 33, 16, 6, 1, 0, + 255, 251, 244, 231, 210, 181, 146, 110, + 75, 46, 25, 12, 5, 1, 0, 255, + 253, 248, 238, 221, 196, 164, 128, 92, + 60, 35, 18, 8, 3, 1, 0, 255, + 253, 249, 242, 229, 208, 180, 146, 110, + 76, 48, 27, 14, 7, 3, 1, 0 +}; + +const opus_uint8 silk_shell_code_table1[ 152 ] = { + 129, 0, 207, 50, 0, 236, 129, 20, + 0, 245, 185, 72, 10, 0, 249, 213, + 129, 42, 6, 0, 250, 226, 169, 87, + 27, 4, 0, 251, 233, 194, 130, 62, + 20, 4, 0, 250, 236, 207, 160, 99, + 47, 17, 3, 0, 255, 240, 217, 182, + 131, 81, 41, 11, 1, 0, 255, 254, + 233, 201, 159, 107, 61, 20, 2, 1, + 0, 255, 249, 233, 206, 170, 128, 86, + 50, 23, 7, 1, 0, 255, 250, 238, + 217, 186, 148, 108, 70, 39, 18, 6, + 1, 0, 255, 252, 243, 226, 200, 166, + 128, 90, 56, 30, 13, 4, 1, 0, + 255, 252, 245, 231, 209, 180, 146, 110, + 76, 47, 25, 11, 4, 1, 0, 255, + 253, 248, 237, 219, 194, 163, 128, 93, + 62, 37, 19, 8, 3, 1, 0, 255, + 254, 250, 241, 226, 205, 177, 145, 111, + 79, 51, 30, 15, 6, 2, 1, 0 +}; + +const opus_uint8 silk_shell_code_table2[ 152 ] = { + 129, 0, 203, 54, 0, 234, 129, 23, + 0, 245, 184, 73, 10, 0, 250, 215, + 129, 41, 5, 0, 252, 232, 173, 86, + 24, 3, 0, 253, 240, 200, 129, 56, + 15, 2, 0, 253, 244, 217, 164, 94, + 38, 10, 1, 0, 253, 245, 226, 189, + 132, 71, 27, 7, 1, 0, 253, 246, + 231, 203, 159, 105, 56, 23, 6, 1, + 0, 255, 248, 235, 213, 179, 133, 85, + 47, 19, 5, 1, 0, 255, 254, 243, + 221, 194, 159, 117, 70, 37, 12, 2, + 1, 0, 255, 254, 248, 234, 208, 171, + 128, 85, 48, 22, 8, 2, 1, 0, + 255, 254, 250, 240, 220, 189, 149, 107, + 67, 36, 16, 6, 2, 1, 0, 255, + 254, 251, 243, 227, 201, 166, 128, 90, + 55, 29, 13, 5, 2, 1, 0, 255, + 254, 252, 246, 234, 213, 183, 147, 109, + 73, 43, 22, 10, 4, 2, 1, 0 +}; + +const opus_uint8 silk_shell_code_table3[ 152 ] = { + 130, 0, 200, 58, 0, 231, 130, 26, + 0, 244, 184, 76, 12, 0, 249, 214, + 130, 43, 6, 0, 252, 232, 173, 87, + 24, 3, 0, 253, 241, 203, 131, 56, + 14, 2, 0, 254, 246, 221, 167, 94, + 35, 8, 1, 0, 254, 249, 232, 193, + 130, 65, 23, 5, 1, 0, 255, 251, + 239, 211, 162, 99, 45, 15, 4, 1, + 0, 255, 251, 243, 223, 186, 131, 74, + 33, 11, 3, 1, 0, 255, 252, 245, + 230, 202, 158, 105, 57, 24, 8, 2, + 1, 0, 255, 253, 247, 235, 214, 179, + 132, 84, 44, 19, 7, 2, 1, 0, + 255, 254, 250, 240, 223, 196, 159, 112, + 69, 36, 15, 6, 2, 1, 0, 255, + 254, 253, 245, 231, 209, 176, 136, 93, + 55, 27, 11, 3, 2, 1, 0, 255, + 254, 253, 252, 239, 221, 194, 158, 117, + 76, 42, 18, 4, 3, 2, 1, 0 +}; + +const opus_uint8 silk_shell_code_table_offsets[ 17 ] = { + 0, 0, 2, 5, 9, 14, 20, 27, + 35, 44, 54, 65, 77, 90, 104, 119, + 135 +}; + +const opus_uint8 silk_sign_iCDF[ 42 ] = { + 254, 49, 67, 77, 82, 93, 99, + 198, 11, 18, 24, 31, 36, 45, + 255, 46, 66, 78, 87, 94, 104, + 208, 14, 21, 32, 42, 51, 66, + 255, 94, 104, 109, 112, 115, 118, + 248, 53, 69, 80, 88, 95, 102 +}; diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tests/meson.build b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tests/meson.build new file mode 100644 index 000000000..b7c70f75f --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tests/meson.build @@ -0,0 +1,8 @@ +exe = executable('test_unit_LPC_inv_pred_gain', + 'test_unit_LPC_inv_pred_gain.c', '../LPC_inv_pred_gain.c', + include_directories: opus_includes, + link_with: [celt_lib, celt_static_libs, silk_lib, silk_static_libs], + dependencies: libm, + install: false) + +test(test_name, exe) diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tests/test_unit_LPC_inv_pred_gain.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tests/test_unit_LPC_inv_pred_gain.c new file mode 100644 index 000000000..67067cead --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tests/test_unit_LPC_inv_pred_gain.c @@ -0,0 +1,129 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc., Jean-Marc Valin +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "celt/stack_alloc.h" +#include "cpu_support.h" +#include "SigProc_FIX.h" + +/* Computes the impulse response of the filter so we + can catch filters that are definitely unstable. Some + unstable filters may be classified as stable, but not + the other way around. */ +int check_stability(opus_int16 *A_Q12, int order) { + int i; + int j; + int sum_a, sum_abs_a; + sum_a = sum_abs_a = 0; + for( j = 0; j < order; j++ ) { + sum_a += A_Q12[ j ]; + sum_abs_a += silk_abs( A_Q12[ j ] ); + } + /* Check DC stability. */ + if( sum_a >= 4096 ) { + return 0; + } + /* If the sum of absolute values is less than 1, the filter + has to be stable. */ + if( sum_abs_a < 4096 ) { + return 1; + } + double y[SILK_MAX_ORDER_LPC] = {0}; + y[0] = 1; + for( i = 0; i < 10000; i++ ) { + double sum = 0; + for( j = 0; j < order; j++ ) { + sum += y[ j ]*A_Q12[ j ]; + } + for( j = order - 1; j > 0; j-- ) { + y[ j ] = y[ j - 1 ]; + } + y[ 0 ] = sum*(1./4096); + /* If impulse response reaches +/- 10000, the filter + is definitely unstable. */ + if( !(y[ 0 ] < 10000 && y[ 0 ] > -10000) ) { + return 0; + } + /* Test every 8 sample for low amplitude. */ + if( ( i & 0x7 ) == 0 ) { + double amp = 0; + for( j = 0; j < order; j++ ) { + amp += fabs(y[j]); + } + if( amp < 0.00001 ) { + return 1; + } + } + } + return 1; +} + +int main(void) { + const int arch = opus_select_arch(); + /* Set to 10000 so all branches in C function are triggered */ + const int loop_num = 10000; + int count = 0; + ALLOC_STACK; + + /* FIXME: Make the seed random (with option to set it explicitly) + so we get wider coverage. */ + srand(0); + + printf("Testing silk_LPC_inverse_pred_gain() optimization ...\n"); + for( count = 0; count < loop_num; count++ ) { + unsigned int i; + opus_int order; + unsigned int shift; + opus_int16 A_Q12[ SILK_MAX_ORDER_LPC ]; + opus_int32 gain; + + for( order = 2; order <= SILK_MAX_ORDER_LPC; order += 2 ) { /* order must be even. */ + for( shift = 0; shift < 16; shift++ ) { /* Different dynamic range. */ + for( i = 0; i < SILK_MAX_ORDER_LPC; i++ ) { + A_Q12[i] = ((opus_int16)rand()) >> shift; + } + gain = silk_LPC_inverse_pred_gain(A_Q12, order, arch); + /* Look for filters that silk_LPC_inverse_pred_gain() thinks are + stable but definitely aren't. */ + if( gain != 0 && !check_stability(A_Q12, order) ) { + fprintf(stderr, "**Loop %4d failed!**\n", count); + return 1; + } + } + } + if( !(count % 500) ) { + printf("Loop %4d passed\n", count); + } + } + printf("silk_LPC_inverse_pred_gain() optimization passed\n"); + return 0; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tuning_parameters.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tuning_parameters.h new file mode 100644 index 000000000..d70275fd8 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/tuning_parameters.h @@ -0,0 +1,155 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_TUNING_PARAMETERS_H +#define SILK_TUNING_PARAMETERS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Decay time for bitreservoir */ +#define BITRESERVOIR_DECAY_TIME_MS 500 + +/*******************/ +/* Pitch estimator */ +/*******************/ + +/* Level of noise floor for whitening filter LPC analysis in pitch analysis */ +#define FIND_PITCH_WHITE_NOISE_FRACTION 1e-3f + +/* Bandwidth expansion for whitening filter in pitch analysis */ +#define FIND_PITCH_BANDWIDTH_EXPANSION 0.99f + +/*********************/ +/* Linear prediction */ +/*********************/ + +/* LPC analysis regularization */ +#define FIND_LPC_COND_FAC 1e-5f + +/* Max cumulative LTP gain */ +#define MAX_SUM_LOG_GAIN_DB 250.0f + +/* LTP analysis defines */ +#define LTP_CORR_INV_MAX 0.03f + +/***********************/ +/* High pass filtering */ +/***********************/ + +/* Smoothing parameters for low end of pitch frequency range estimation */ +#define VARIABLE_HP_SMTH_COEF1 0.1f +#define VARIABLE_HP_SMTH_COEF2 0.015f +#define VARIABLE_HP_MAX_DELTA_FREQ 0.4f + +/* Min and max cut-off frequency values (-3 dB points) */ +#define VARIABLE_HP_MIN_CUTOFF_HZ 60 +#define VARIABLE_HP_MAX_CUTOFF_HZ 100 + +/***********/ +/* Various */ +/***********/ + +/* VAD threshold */ +#define SPEECH_ACTIVITY_DTX_THRES 0.05f + +/* Speech Activity LBRR enable threshold */ +#define LBRR_SPEECH_ACTIVITY_THRES 0.3f + +/*************************/ +/* Perceptual parameters */ +/*************************/ + +/* reduction in coding SNR during low speech activity */ +#define BG_SNR_DECR_dB 2.0f + +/* factor for reducing quantization noise during voiced speech */ +#define HARM_SNR_INCR_dB 2.0f + +/* factor for reducing quantization noise for unvoiced sparse signals */ +#define SPARSE_SNR_INCR_dB 2.0f + +/* threshold for sparseness measure above which to use lower quantization offset during unvoiced */ +#define ENERGY_VARIATION_THRESHOLD_QNT_OFFSET 0.6f + +/* warping control */ +#define WARPING_MULTIPLIER 0.015f + +/* fraction added to first autocorrelation value */ +#define SHAPE_WHITE_NOISE_FRACTION 3e-5f + +/* noise shaping filter chirp factor */ +#define BANDWIDTH_EXPANSION 0.94f + +/* harmonic noise shaping */ +#define HARMONIC_SHAPING 0.3f + +/* extra harmonic noise shaping for high bitrates or noisy input */ +#define HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING 0.2f + +/* parameter for shaping noise towards higher frequencies */ +#define HP_NOISE_COEF 0.25f + +/* parameter for shaping noise even more towards higher frequencies during voiced speech */ +#define HARM_HP_NOISE_COEF 0.35f + +/* parameter for applying a high-pass tilt to the input signal */ +#define INPUT_TILT 0.05f + +/* parameter for extra high-pass tilt to the input signal at high rates */ +#define HIGH_RATE_INPUT_TILT 0.1f + +/* parameter for reducing noise at the very low frequencies */ +#define LOW_FREQ_SHAPING 4.0f + +/* less reduction of noise at the very low frequencies for signals with low SNR at low frequencies */ +#define LOW_QUALITY_LOW_FREQ_SHAPING_DECR 0.5f + +/* subframe smoothing coefficient for HarmBoost, HarmShapeGain, Tilt (lower -> more smoothing) */ +#define SUBFR_SMTH_COEF 0.4f + +/* parameters defining the R/D tradeoff in the residual quantizer */ +#define LAMBDA_OFFSET 1.2f +#define LAMBDA_SPEECH_ACT -0.2f +#define LAMBDA_DELAYED_DECISIONS -0.05f +#define LAMBDA_INPUT_QUALITY -0.1f +#define LAMBDA_CODING_QUALITY -0.2f +#define LAMBDA_QUANT_OFFSET 0.8f + +/* Compensation in bitrate calculations for 10 ms modes */ +#define REDUCE_BITRATE_10_MS_BPS 2200 + +/* Maximum time before allowing a bandwidth transition */ +#define MAX_BANDWIDTH_SWITCH_DELAY_MS 5000 + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_TUNING_PARAMETERS_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/typedef.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/typedef.h new file mode 100644 index 000000000..793d2c0c1 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/typedef.h @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- 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. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific 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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_TYPEDEF_H +#define SILK_TYPEDEF_H + +#include "opus_types.h" +#include "opus_defines.h" + +#ifndef FIXED_POINT +# include +# define silk_float float +# define silk_float_MAX FLT_MAX +#endif + +#define silk_int64_MAX ((opus_int64)0x7FFFFFFFFFFFFFFFLL) /* 2^63 - 1 */ +#define silk_int64_MIN ((opus_int64)0x8000000000000000LL) /* -2^63 */ +#define silk_int32_MAX 0x7FFFFFFF /* 2^31 - 1 = 2147483647 */ +#define silk_int32_MIN ((opus_int32)0x80000000) /* -2^31 = -2147483648 */ +#define silk_int16_MAX 0x7FFF /* 2^15 - 1 = 32767 */ +#define silk_int16_MIN ((opus_int16)0x8000) /* -2^15 = -32768 */ +#define silk_int8_MAX 0x7F /* 2^7 - 1 = 127 */ +#define silk_int8_MIN ((opus_int8)0x80) /* -2^7 = -128 */ +#define silk_uint8_MAX 0xFF /* 2^8 - 1 = 255 */ + +#define silk_TRUE 1 +#define silk_FALSE 0 + +/* assertions */ +#if (defined _WIN32 && !defined _WINCE && !defined(__GNUC__) && !defined(NO_ASSERTS)) +# ifndef silk_assert +# include /* ASSERTE() */ +# define silk_assert(COND) _ASSERTE(COND) +# endif +#else +# ifdef ENABLE_ASSERTIONS +# include +# include +#define silk_fatal(str) _silk_fatal(str, __FILE__, __LINE__); +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +static OPUS_INLINE void _silk_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); +#if defined(_MSC_VER) + _set_abort_behavior( 0, _WRITE_ABORT_MSG); +#endif + abort(); +} +# define silk_assert(COND) {if (!(COND)) {silk_fatal("assertion failed: " #COND);}} +# else +# define silk_assert(COND) +# endif +#endif + +#endif /* SILK_TYPEDEF_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/NSQ_del_dec_sse4_1.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/NSQ_del_dec_sse4_1.c new file mode 100644 index 000000000..2c75ede2d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/NSQ_del_dec_sse4_1.c @@ -0,0 +1,859 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "main.h" +#include "celt/x86/x86cpu.h" + +#include "stack_alloc.h" + +typedef struct { + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ]; + opus_int32 RandState[ DECISION_DELAY ]; + opus_int32 Q_Q10[ DECISION_DELAY ]; + opus_int32 Xq_Q14[ DECISION_DELAY ]; + opus_int32 Pred_Q15[ DECISION_DELAY ]; + opus_int32 Shape_Q14[ DECISION_DELAY ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_AR_Q14; + opus_int32 Seed; + opus_int32 SeedInit; + opus_int32 RD_Q10; +} NSQ_del_dec_struct; + +typedef struct { + opus_int32 Q_Q10; + opus_int32 RD_Q10; + opus_int32 xq_Q14; + opus_int32 LF_AR_Q14; + opus_int32 sLTP_shp_Q14; + opus_int32 LPC_exc_Q14; +} NSQ_sample_struct; + +typedef NSQ_sample_struct NSQ_sample_pair[ 2 ]; + +static OPUS_INLINE void silk_nsq_del_dec_scale_states_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int32 x_Q3[], /* I Input in Q3 */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +); + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_sse4_1( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay /* I */ +); + +void silk_NSQ_del_dec_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr; + opus_int last_smple_idx, smpl_buf_idx, decisionDelay; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + opus_int32 RDmin_Q10, Gain_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + VARDECL( opus_int32, delayedGain_Q10 ); + VARDECL( NSQ_del_dec_struct, psDelDec ); + NSQ_del_dec_struct *psDD; + SAVE_STACK; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + /* Initialize delayed decision states */ + ALLOC( psDelDec, psEncC->nStatesDelayedDecision, NSQ_del_dec_struct ); + silk_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) ); + for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psDD->Seed = ( k + psIndices->Seed ) & 3; + psDD->SeedInit = psDD->Seed; + psDD->RD_Q10 = 0; + psDD->LF_AR_Q14 = NSQ->sLF_AR_shp_Q14; + psDD->Shape_Q14[ 0 ] = NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ]; + silk_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) ); + } + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + smpl_buf_idx = 0; /* index of oldest samples */ + + decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length ); + + /* For voiced frames limit the decision delay to lower than the pitch lag */ + if( psIndices->signalType == TYPE_VOICED ) { + for( k = 0; k < psEncC->nb_subfr; k++ ) { + decisionDelay = silk_min_int( decisionDelay, pitchL[ k ] - LTP_ORDER / 2 - 1 ); + } + } else { + if( lag > 0 ) { + decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 ); + } + } + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, + psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 ); + /* Set up pointers to start of sub frame */ + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + subfr = 0; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + if( k == 2 ) { + /* RESET DELAYED DECISIONS */ + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) { + if( psDelDec[ i ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ i ].RD_Q10; + Winner_ind = i; + } + } + for( i = 0; i < psEncC->nStatesDelayedDecision; i++ ) { + if( i != Winner_ind ) { + psDelDec[ i ].RD_Q10 += ( silk_int32_MAX >> 4 ); + silk_assert( psDelDec[ i ].RD_Q10 >= 0 ); + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + last_smple_idx = smpl_buf_idx + decisionDelay; + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY; + if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY; + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gains_Q16[ 1 ] ), 14 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + + subfr = 0; + } + + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + NSQ->rewhite_flag = 1; + } + } + + silk_nsq_del_dec_scale_states_sse4_1( psEncC, NSQ, psDelDec, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k, + psEncC->nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay ); + + silk_noise_shape_quantizer_del_dec_sse4_1( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, + delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], + Gains_Q16[ k ], Lambda_Q10, offset_Q10, psEncC->subfr_length, subfr++, psEncC->shapingLPCOrder, + psEncC->predictLPCOrder, psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay ); + + x_Q3 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ k ].RD_Q10; + Winner_ind = k; + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + psIndices->Seed = psDD->SeedInit; + last_smple_idx = smpl_buf_idx + decisionDelay; + Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 ); + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY; + if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY; + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gain_Q10 ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + silk_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) ); + + /* Update states */ + NSQ->sLF_AR_shp_Q14 = psDD->LF_AR_Q14; + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech signal */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; +} + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_sse4_1( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay /* I */ +) +{ + opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + opus_int32 Winner_rand_state; + opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14; + opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10; + opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14; + VARDECL( NSQ_sample_pair, psSampleState ); + NSQ_del_dec_struct *psDD; + NSQ_sample_struct *psSS; + + __m128i a_Q12_0123, a_Q12_4567, a_Q12_89AB, a_Q12_CDEF; + __m128i b_Q12_0123, b_sr_Q12_0123; + SAVE_STACK; + + celt_assert( nStatesDelayedDecision > 0 ); + ALLOC( psSampleState, nStatesDelayedDecision, NSQ_sample_pair ); + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + a_Q12_0123 = OP_CVTEPI16_EPI32_M64( a_Q12 ); + a_Q12_4567 = OP_CVTEPI16_EPI32_M64( a_Q12 + 4 ); + + if( opus_likely( predictLPCOrder == 16 ) ) { + a_Q12_89AB = OP_CVTEPI16_EPI32_M64( a_Q12 + 8 ); + a_Q12_CDEF = OP_CVTEPI16_EPI32_M64( a_Q12 + 12 ); + } + + if( signalType == TYPE_VOICED ){ + b_Q12_0123 = OP_CVTEPI16_EPI32_M64( b_Q14 ); + b_sr_Q12_0123 = _mm_shuffle_epi32( b_Q12_0123, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + } + for( i = 0; i < length; i++ ) { + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q14 = 2; + { + __m128i tmpa, tmpb, pred_lag_ptr_tmp; + pred_lag_ptr_tmp = _mm_loadu_si128( (__m128i *)(&pred_lag_ptr[ -3 ] ) ); + pred_lag_ptr_tmp = _mm_shuffle_epi32( pred_lag_ptr_tmp, 0x1B ); + tmpa = _mm_mul_epi32( pred_lag_ptr_tmp, b_Q12_0123 ); + tmpa = _mm_srli_si128( tmpa, 2 ); + + pred_lag_ptr_tmp = _mm_shuffle_epi32( pred_lag_ptr_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) );/* equal shift right 4 bytes */ + pred_lag_ptr_tmp = _mm_mul_epi32( pred_lag_ptr_tmp, b_sr_Q12_0123 ); + pred_lag_ptr_tmp = _mm_srli_si128( pred_lag_ptr_tmp, 2 ); + pred_lag_ptr_tmp = _mm_add_epi32( pred_lag_ptr_tmp, tmpa ); + + tmpb = _mm_shuffle_epi32( pred_lag_ptr_tmp, _MM_SHUFFLE( 0, 0, 3, 2 ) );/* equal shift right 8 bytes */ + pred_lag_ptr_tmp = _mm_add_epi32( pred_lag_ptr_tmp, tmpb ); + LTP_pred_Q14 += _mm_cvtsi128_si32( pred_lag_ptr_tmp ); + + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */ + pred_lag_ptr++; + } + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */ + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + { + __m128i tmpa, tmpb, psLPC_Q14_tmp, a_Q12_tmp; + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + /* Delayed decision state */ + psDD = &psDelDec[ k ]; + + /* Sample state */ + psSS = psSampleState[ k ]; + + /* Generate dither */ + psDD->Seed = silk_RAND( psDD->Seed ); + + /* Pointer used in short term prediction and shaping */ + psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ]; + /* Short-term prediction */ + silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q14 = silk_RSHIFT( predictLPCOrder, 1 ); + + tmpb = _mm_setzero_si128(); + + /* step 1 */ + psLPC_Q14_tmp = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -3 ] ) ); /* -3, -2 , -1, 0 */ + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B ); /* 0, -1, -2, -3 */ + tmpa = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_0123 ); /* 0, -1, -2, -3 * 0123 -> 0*0, 2*-2 */ + + tmpa = _mm_srli_epi64( tmpa, 16 ); + tmpb = _mm_add_epi32( tmpb, tmpa ); + + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + a_Q12_tmp = _mm_shuffle_epi32( a_Q12_0123, _MM_SHUFFLE(0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + psLPC_Q14_tmp = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp ); /* 1*-1, 3*-3 */ + psLPC_Q14_tmp = _mm_srli_epi64( psLPC_Q14_tmp, 16 ); + tmpb = _mm_add_epi32( tmpb, psLPC_Q14_tmp ); + + /* step 2 */ + psLPC_Q14_tmp = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -7 ] ) ); + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B ); + tmpa = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_4567 ); + tmpa = _mm_srli_epi64( tmpa, 16 ); + tmpb = _mm_add_epi32( tmpb, tmpa ); + + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + a_Q12_tmp = _mm_shuffle_epi32( a_Q12_4567, _MM_SHUFFLE(0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + psLPC_Q14_tmp = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp ); + psLPC_Q14_tmp = _mm_srli_epi64( psLPC_Q14_tmp, 16 ); + tmpb = _mm_add_epi32( tmpb, psLPC_Q14_tmp ); + + if ( opus_likely( predictLPCOrder == 16 ) ) + { + /* step 3 */ + psLPC_Q14_tmp = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -11 ] ) ); + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B ); + tmpa = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_89AB ); + tmpa = _mm_srli_epi64( tmpa, 16 ); + tmpb = _mm_add_epi32( tmpb, tmpa ); + + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + a_Q12_tmp = _mm_shuffle_epi32( a_Q12_89AB, _MM_SHUFFLE(0, 3, 2, 1 ) );/* equal shift right 4 bytes */ + psLPC_Q14_tmp = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp ); + psLPC_Q14_tmp = _mm_srli_epi64( psLPC_Q14_tmp, 16 ); + tmpb = _mm_add_epi32( tmpb, psLPC_Q14_tmp ); + + /* setp 4 */ + psLPC_Q14_tmp = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -15 ] ) ); + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B ); + tmpa = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_CDEF ); + tmpa = _mm_srli_epi64( tmpa, 16 ); + tmpb = _mm_add_epi32( tmpb, tmpa ); + + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + a_Q12_tmp = _mm_shuffle_epi32( a_Q12_CDEF, _MM_SHUFFLE(0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + psLPC_Q14_tmp = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp ); + psLPC_Q14_tmp = _mm_srli_epi64( psLPC_Q14_tmp, 16 ); + tmpb = _mm_add_epi32( tmpb, psLPC_Q14_tmp ); + + /* add at last */ + /* equal shift right 8 bytes*/ + tmpa = _mm_shuffle_epi32( tmpb, _MM_SHUFFLE( 0, 0, 3, 2 ) ); + tmpb = _mm_add_epi32( tmpb, tmpa ); + LPC_pred_Q14 += _mm_cvtsi128_si32( tmpb ); + } + else + { + /* add at last */ + tmpa = _mm_shuffle_epi32( tmpb, _MM_SHUFFLE( 0, 0, 3, 2 ) ); /* equal shift right 8 bytes*/ + tmpb = _mm_add_epi32( tmpb, tmpa ); + LPC_pred_Q14 += _mm_cvtsi128_si32( tmpb ); + + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -8 ], a_Q12[ 8 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -9 ], a_Q12[ 9 ] ); + } + + LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */ + + /* Noise shape feedback */ + silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ 0 ] = tmp2; + n_AR_Q14 = silk_RSHIFT( shapingLPCOrder, 1 ); + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 ); + psDD->sAR2_Q14[ j - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ j - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ j + 0 ] = tmp2; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ j ] ); + } + psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */ + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */ + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */ + + n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */ + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */ + tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */ + tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */ + + r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if ( psDD->Seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 ); + + if( rd1_Q10 < rd2_Q10 ) { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 0 ].Q_Q10 = q1_Q10; + psSS[ 1 ].Q_Q10 = q2_Q10; + } else { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 0 ].Q_Q10 = q2_Q10; + psSS[ 1 ].Q_Q10 = q1_Q10; + } + + /* Update states for best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 ); + psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 0 ].xq_Q14 = xq_Q14; + + /* Update states for second best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 ); + psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 1 ].xq_Q14 = xq_Q14; + } + } + *smpl_buf_idx = ( *smpl_buf_idx - 1 ) % DECISION_DELAY; + if( *smpl_buf_idx < 0 ) *smpl_buf_idx += DECISION_DELAY; + last_smple_idx = ( *smpl_buf_idx + decisionDelay ) % DECISION_DELAY; + + /* Find winner */ + RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + Winner_ind = k; + } + } + + /* Increase RD values of expired states */ + Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ]; + for( k = 0; k < nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) { + psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 ); + psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 ); + silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 ); + } + } + + /* Find worst in first set and best in second set */ + RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10; + RDmax_ind = 0; + RDmin_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + /* find worst in first set */ + if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) { + RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + RDmax_ind = k; + } + /* find best in second set */ + if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10; + RDmin_ind = k; + } + } + + /* Replace a state if best from second set outperforms worst in first set */ + if( RDmin_Q10 < RDmax_Q10 ) { + silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i, + ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) ); + silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) ); + } + + /* Write samples from winner to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + if( subfr > 0 || i >= decisionDelay ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ]; + sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ]; + } + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Update states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psSS = &psSampleState[ k ][ 0 ]; + psDD->LF_AR_Q14 = psSS->LF_AR_Q14; + psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14; + psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14; + psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10; + psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 ); + psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14; + psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) ); + psDD->RandState[ *smpl_buf_idx ] = psDD->Seed; + psDD->RD_Q10 = psSS->RD_Q10; + } + delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10; + } + /* Update LPC states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + } + RESTORE_STACK; +} + +static OPUS_INLINE void silk_nsq_del_dec_scale_states_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int32 x_Q3[], /* I Input in Q3 */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +) +{ + opus_int i, k, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23; + NSQ_del_dec_struct *psDD; + __m128i xmm_inv_gain_Q23, xmm_x_Q3_x2x0, xmm_x_Q3_x3x1; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + + silk_assert( inv_gain_Q31 != 0 ); + + /* Calculate gain adjustment factor */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + } else { + gain_adj_Q16 = (opus_int32)1 << 16; + } + + /* Scale input */ + inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 ); + + /* prepare inv_gain_Q23 in packed 4 32-bits */ + xmm_inv_gain_Q23 = _mm_set1_epi32(inv_gain_Q23); + + for( i = 0; i < psEncC->subfr_length - 3; i += 4 ) { + xmm_x_Q3_x2x0 = _mm_loadu_si128( (__m128i *)(&(x_Q3[ i ] ) ) ); + /* equal shift right 4 bytes*/ + xmm_x_Q3_x3x1 = _mm_shuffle_epi32( xmm_x_Q3_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_x_Q3_x2x0 = _mm_mul_epi32( xmm_x_Q3_x2x0, xmm_inv_gain_Q23 ); + xmm_x_Q3_x3x1 = _mm_mul_epi32( xmm_x_Q3_x3x1, xmm_inv_gain_Q23 ); + + xmm_x_Q3_x2x0 = _mm_srli_epi64( xmm_x_Q3_x2x0, 16 ); + xmm_x_Q3_x3x1 = _mm_slli_epi64( xmm_x_Q3_x3x1, 16 ); + + xmm_x_Q3_x2x0 = _mm_blend_epi16( xmm_x_Q3_x2x0, xmm_x_Q3_x3x1, 0xCC ); + + _mm_storeu_si128( (__m128i *)(&(x_sc_Q10[ i ])), xmm_x_Q3_x2x0 ); + } + + for( ; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 ); + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( gain_adj_Q16 != (opus_int32)1 << 16 ) { + /* Scale long-term shaping state */ + { + __m128i xmm_gain_adj_Q16, xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1; + + /* prepare gain_adj_Q16 in packed 4 32-bits */ + xmm_gain_adj_Q16 = _mm_set1_epi32( gain_adj_Q16 ); + + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx - 3; i += 4 ) + { + xmm_sLTP_shp_Q14_x2x0 = _mm_loadu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ) ); + /* equal shift right 4 bytes*/ + xmm_sLTP_shp_Q14_x3x1 = _mm_shuffle_epi32( xmm_sLTP_shp_Q14_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x2x0, xmm_gain_adj_Q16 ); + xmm_sLTP_shp_Q14_x3x1 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x3x1, xmm_gain_adj_Q16 ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_srli_epi64( xmm_sLTP_shp_Q14_x2x0, 16 ); + xmm_sLTP_shp_Q14_x3x1 = _mm_slli_epi64( xmm_sLTP_shp_Q14_x3x1, 16 ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_blend_epi16( xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1, 0xCC ); + + _mm_storeu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ), xmm_sLTP_shp_Q14_x2x0 ); + } + + for( ; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + + /* Scale scalar states */ + psDD->LF_AR_Q14 = silk_SMULWW( gain_adj_Q16, psDD->LF_AR_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + psDD->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + psDD->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] ); + } + for( i = 0; i < DECISION_DELAY; i++ ) { + psDD->Pred_Q15[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Pred_Q15[ i ] ); + psDD->Shape_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Shape_Q14[ i ] ); + } + } + } + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/NSQ_sse4_1.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/NSQ_sse4_1.c new file mode 100644 index 000000000..b0315e35f --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/NSQ_sse4_1.c @@ -0,0 +1,719 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "main.h" +#include "celt/x86/x86cpu.h" +#include "stack_alloc.h" + +static OPUS_INLINE void silk_nsq_scale_states_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int32 x_Q3[], /* I input in Q3 */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +); + +static OPUS_INLINE void silk_noise_shape_quantizer_10_16_sse4_1( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int32 table[][4] /* I */ +); + +void silk_NSQ_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int k, lag, start_idx, LSF_interpolation_flag; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + + opus_int32 table[ 64 ][ 4 ]; + opus_int32 tmp1; + opus_int32 q1_Q10, q2_Q10, rd1_Q20, rd2_Q20; + + SAVE_STACK; + + NSQ->rand_seed = psIndices->Seed; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + + /* 0 */ + q1_Q10 = offset_Q10; + q2_Q10 = offset_Q10 + ( 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q20 = q1_Q10 * Lambda_Q10; + rd2_Q20 = q2_Q10 * Lambda_Q10; + + table[ 32 ][ 0 ] = q1_Q10; + table[ 32 ][ 1 ] = q2_Q10; + table[ 32 ][ 2 ] = 2 * (q1_Q10 - q2_Q10); + table[ 32 ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10); + + /* -1 */ + q1_Q10 = offset_Q10 - ( 1024 - QUANT_LEVEL_ADJUST_Q10 ); + q2_Q10 = offset_Q10; + rd1_Q20 = - q1_Q10 * Lambda_Q10; + rd2_Q20 = q2_Q10 * Lambda_Q10; + + table[ 31 ][ 0 ] = q1_Q10; + table[ 31 ][ 1 ] = q2_Q10; + table[ 31 ][ 2 ] = 2 * (q1_Q10 - q2_Q10); + table[ 31 ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10); + + /* > 0 */ + for (k = 1; k <= 31; k++) + { + tmp1 = offset_Q10 + silk_LSHIFT( k, 10 ); + + q1_Q10 = tmp1 - QUANT_LEVEL_ADJUST_Q10; + q2_Q10 = tmp1 - QUANT_LEVEL_ADJUST_Q10 + 1024; + rd1_Q20 = q1_Q10 * Lambda_Q10; + rd2_Q20 = q2_Q10 * Lambda_Q10; + + table[ 32 + k ][ 0 ] = q1_Q10; + table[ 32 + k ][ 1 ] = q2_Q10; + table[ 32 + k ][ 2 ] = 2 * (q1_Q10 - q2_Q10); + table[ 32 + k ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10); + } + + /* < -1 */ + for (k = -32; k <= -2; k++) + { + tmp1 = offset_Q10 + silk_LSHIFT( k, 10 ); + + q1_Q10 = tmp1 + QUANT_LEVEL_ADJUST_Q10; + q2_Q10 = tmp1 + QUANT_LEVEL_ADJUST_Q10 + 1024; + rd1_Q20 = - q1_Q10 * Lambda_Q10; + rd2_Q20 = - q2_Q10 * Lambda_Q10; + + table[ 32 + k ][ 0 ] = q1_Q10; + table[ 32 + k ][ 1 ] = q2_Q10; + table[ 32 + k ][ 2 ] = 2 * (q1_Q10 - q2_Q10); + table[ 32 + k ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10); + } + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, + psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + /* Set up pointers to start of sub frame */ + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->rewhite_flag = 1; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + } + } + + silk_nsq_scale_states_sse4_1( psEncC, NSQ, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType ); + + if ( opus_likely( ( 10 == psEncC->shapingLPCOrder ) && ( 16 == psEncC->predictLPCOrder) ) ) + { + silk_noise_shape_quantizer_10_16_sse4_1( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14, + AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], + offset_Q10, psEncC->subfr_length, &(table[32]) ); + } + else + { + silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14, + AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], Lambda_Q10, + offset_Q10, psEncC->subfr_length, psEncC->shapingLPCOrder, psEncC->predictLPCOrder, psEncC->arch ); + } + + x_Q3 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Update lagPrev for next frame */ + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech and noise shaping signals */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; +} + +/***********************************/ +/* silk_noise_shape_quantizer_10_16 */ +/***********************************/ +static OPUS_INLINE void silk_noise_shape_quantizer_10_16_sse4_1( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int32 table[][4] /* I */ +) +{ + opus_int i; + opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13; + opus_int32 n_LF_Q12, r_Q10, q1_Q0, q1_Q10, q2_Q10; + opus_int32 exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr; + + __m128i xmm_tempa, xmm_tempb; + + __m128i xmm_one; + + __m128i psLPC_Q14_hi_01234567, psLPC_Q14_hi_89ABCDEF; + __m128i psLPC_Q14_lo_01234567, psLPC_Q14_lo_89ABCDEF; + __m128i a_Q12_01234567, a_Q12_89ABCDEF; + + __m128i sAR2_Q14_hi_76543210, sAR2_Q14_lo_76543210; + __m128i AR_shp_Q13_76543210; + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + /* Set up short term AR state */ + psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ]; + + sLF_AR_shp_Q14 = NSQ->sLF_AR_shp_Q14; + xq_Q14 = psLPC_Q14[ 0 ]; + LTP_pred_Q13 = 0; + + /* load a_Q12 */ + xmm_one = _mm_set_epi8( 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14 ); + + /* load a_Q12[0] - a_Q12[7] */ + a_Q12_01234567 = _mm_loadu_si128( (__m128i *)(&a_Q12[ 0 ] ) ); + /* load a_Q12[ 8 ] - a_Q12[ 15 ] */ + a_Q12_89ABCDEF = _mm_loadu_si128( (__m128i *)(&a_Q12[ 8 ] ) ); + + a_Q12_01234567 = _mm_shuffle_epi8( a_Q12_01234567, xmm_one ); + a_Q12_89ABCDEF = _mm_shuffle_epi8( a_Q12_89ABCDEF, xmm_one ); + + /* load AR_shp_Q13 */ + AR_shp_Q13_76543210 = _mm_loadu_si128( (__m128i *)(&AR_shp_Q13[0] ) ); + + /* load psLPC_Q14 */ + xmm_one = _mm_set_epi8(15, 14, 11, 10, 7, 6, 3, 2, 13, 12, 9, 8, 5, 4, 1, 0 ); + + xmm_tempa = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[-16]) ); + xmm_tempb = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[-12]) ); + + xmm_tempa = _mm_shuffle_epi8( xmm_tempa, xmm_one ); + xmm_tempb = _mm_shuffle_epi8( xmm_tempb, xmm_one ); + + psLPC_Q14_hi_89ABCDEF = _mm_unpackhi_epi64( xmm_tempa, xmm_tempb ); + psLPC_Q14_lo_89ABCDEF = _mm_unpacklo_epi64( xmm_tempa, xmm_tempb ); + + xmm_tempa = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -8 ]) ); + xmm_tempb = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -4 ]) ); + + xmm_tempa = _mm_shuffle_epi8( xmm_tempa, xmm_one ); + xmm_tempb = _mm_shuffle_epi8( xmm_tempb, xmm_one ); + + psLPC_Q14_hi_01234567 = _mm_unpackhi_epi64( xmm_tempa, xmm_tempb ); + psLPC_Q14_lo_01234567 = _mm_unpacklo_epi64( xmm_tempa, xmm_tempb ); + + /* load sAR2_Q14 */ + xmm_tempa = _mm_loadu_si128( (__m128i *)(&(NSQ->sAR2_Q14[ 0 ]) ) ); + xmm_tempb = _mm_loadu_si128( (__m128i *)(&(NSQ->sAR2_Q14[ 4 ]) ) ); + + xmm_tempa = _mm_shuffle_epi8( xmm_tempa, xmm_one ); + xmm_tempb = _mm_shuffle_epi8( xmm_tempb, xmm_one ); + + sAR2_Q14_hi_76543210 = _mm_unpackhi_epi64( xmm_tempa, xmm_tempb ); + sAR2_Q14_lo_76543210 = _mm_unpacklo_epi64( xmm_tempa, xmm_tempb ); + + /* prepare 1 in 8 * 16bit */ + xmm_one = _mm_set1_epi16(1); + + for( i = 0; i < length; i++ ) + { + /* Short-term prediction */ + __m128i xmm_hi_07, xmm_hi_8F, xmm_lo_07, xmm_lo_8F; + + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = 8; /* silk_RSHIFT( predictLPCOrder, 1 ); */ + + /* shift psLPC_Q14 */ + psLPC_Q14_hi_89ABCDEF = _mm_alignr_epi8( psLPC_Q14_hi_01234567, psLPC_Q14_hi_89ABCDEF, 2 ); + psLPC_Q14_lo_89ABCDEF = _mm_alignr_epi8( psLPC_Q14_lo_01234567, psLPC_Q14_lo_89ABCDEF, 2 ); + + psLPC_Q14_hi_01234567 = _mm_srli_si128( psLPC_Q14_hi_01234567, 2 ); + psLPC_Q14_lo_01234567 = _mm_srli_si128( psLPC_Q14_lo_01234567, 2 ); + + psLPC_Q14_hi_01234567 = _mm_insert_epi16( psLPC_Q14_hi_01234567, (xq_Q14 >> 16), 7 ); + psLPC_Q14_lo_01234567 = _mm_insert_epi16( psLPC_Q14_lo_01234567, (xq_Q14), 7 ); + + /* high part, use pmaddwd, results in 4 32-bit */ + xmm_hi_07 = _mm_madd_epi16( psLPC_Q14_hi_01234567, a_Q12_01234567 ); + xmm_hi_8F = _mm_madd_epi16( psLPC_Q14_hi_89ABCDEF, a_Q12_89ABCDEF ); + + /* low part, use pmulhw, results in 8 16-bit, note we need simulate unsigned * signed, _mm_srai_epi16(psLPC_Q14_lo_01234567, 15) */ + xmm_tempa = _mm_cmpgt_epi16( _mm_setzero_si128(), psLPC_Q14_lo_01234567 ); + xmm_tempb = _mm_cmpgt_epi16( _mm_setzero_si128(), psLPC_Q14_lo_89ABCDEF ); + + xmm_tempa = _mm_and_si128( xmm_tempa, a_Q12_01234567 ); + xmm_tempb = _mm_and_si128( xmm_tempb, a_Q12_89ABCDEF ); + + xmm_lo_07 = _mm_mulhi_epi16( psLPC_Q14_lo_01234567, a_Q12_01234567 ); + xmm_lo_8F = _mm_mulhi_epi16( psLPC_Q14_lo_89ABCDEF, a_Q12_89ABCDEF ); + + xmm_lo_07 = _mm_add_epi16( xmm_lo_07, xmm_tempa ); + xmm_lo_8F = _mm_add_epi16( xmm_lo_8F, xmm_tempb ); + + xmm_lo_07 = _mm_madd_epi16( xmm_lo_07, xmm_one ); + xmm_lo_8F = _mm_madd_epi16( xmm_lo_8F, xmm_one ); + + /* accumulate */ + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, xmm_hi_8F ); + xmm_lo_07 = _mm_add_epi32( xmm_lo_07, xmm_lo_8F ); + + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, xmm_lo_07 ); + + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_unpackhi_epi64(xmm_hi_07, xmm_hi_07 ) ); + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_shufflelo_epi16(xmm_hi_07, 0x0E ) ); + + LPC_pred_Q10 += _mm_cvtsi128_si32( xmm_hi_07 ); + + /* Long-term prediction */ + if ( opus_likely( signalType == TYPE_VOICED ) ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q13 = 2; + { + __m128i b_Q14_3210, b_Q14_0123, pred_lag_ptr_0123; + + b_Q14_3210 = OP_CVTEPI16_EPI32_M64( b_Q14 ); + b_Q14_0123 = _mm_shuffle_epi32( b_Q14_3210, 0x1B ); + + /* loaded: [0] [-1] [-2] [-3] */ + pred_lag_ptr_0123 = _mm_loadu_si128( (__m128i *)(&pred_lag_ptr[ -3 ] ) ); + /* shuffle to [-3] [-2] [-1] [0] and to new xmm */ + xmm_tempa = _mm_shuffle_epi32( pred_lag_ptr_0123, 0x1B ); + /*64-bit multiply, a[2] * b[-2], a[0] * b[0] */ + xmm_tempa = _mm_mul_epi32( xmm_tempa, b_Q14_3210 ); + /* right shift 2 bytes (16 bits), zero extended */ + xmm_tempa = _mm_srli_si128( xmm_tempa, 2 ); + + /* a[1] * b[-1], a[3] * b[-3] */ + pred_lag_ptr_0123 = _mm_mul_epi32( pred_lag_ptr_0123, b_Q14_0123 ); + pred_lag_ptr_0123 = _mm_srli_si128( pred_lag_ptr_0123, 2 ); + + pred_lag_ptr_0123 = _mm_add_epi32( pred_lag_ptr_0123, xmm_tempa ); + /* equal shift right 8 bytes*/ + xmm_tempa = _mm_shuffle_epi32( pred_lag_ptr_0123, _MM_SHUFFLE( 0, 0, 3, 2 ) ); + xmm_tempa = _mm_add_epi32( xmm_tempa, pred_lag_ptr_0123 ); + + LTP_pred_Q13 += _mm_cvtsi128_si32( xmm_tempa ); + + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + pred_lag_ptr++; + } + } + + /* Noise shape feedback */ + NSQ->sAR2_Q14[ 9 ] = NSQ->sAR2_Q14[ 8 ]; + NSQ->sAR2_Q14[ 8 ] = _mm_cvtsi128_si32( _mm_srli_si128(_mm_unpackhi_epi16( sAR2_Q14_lo_76543210, sAR2_Q14_hi_76543210 ), 12 ) ); + + sAR2_Q14_hi_76543210 = _mm_slli_si128( sAR2_Q14_hi_76543210, 2 ); + sAR2_Q14_lo_76543210 = _mm_slli_si128( sAR2_Q14_lo_76543210, 2 ); + + sAR2_Q14_hi_76543210 = _mm_insert_epi16( sAR2_Q14_hi_76543210, (xq_Q14 >> 16), 0 ); + sAR2_Q14_lo_76543210 = _mm_insert_epi16( sAR2_Q14_lo_76543210, (xq_Q14), 0 ); + + /* high part, use pmaddwd, results in 4 32-bit */ + xmm_hi_07 = _mm_madd_epi16( sAR2_Q14_hi_76543210, AR_shp_Q13_76543210 ); + + /* low part, use pmulhw, results in 8 16-bit, note we need simulate unsigned * signed,_mm_srai_epi16(sAR2_Q14_lo_76543210, 15) */ + xmm_tempa = _mm_cmpgt_epi16( _mm_setzero_si128(), sAR2_Q14_lo_76543210 ); + xmm_tempa = _mm_and_si128( xmm_tempa, AR_shp_Q13_76543210 ); + + xmm_lo_07 = _mm_mulhi_epi16( sAR2_Q14_lo_76543210, AR_shp_Q13_76543210 ); + xmm_lo_07 = _mm_add_epi16( xmm_lo_07, xmm_tempa ); + + xmm_lo_07 = _mm_madd_epi16( xmm_lo_07, xmm_one ); + + /* accumulate */ + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, xmm_lo_07 ); + + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_unpackhi_epi64(xmm_hi_07, xmm_hi_07 ) ); + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_shufflelo_epi16(xmm_hi_07, 0x0E ) ); + + n_AR_Q12 = 5 + _mm_cvtsi128_si32( xmm_hi_07 ); + + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sAR2_Q14[ 8 ], AR_shp_Q13[ 8 ] ); + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sAR2_Q14[ 9 ], AR_shp_Q13[ 9 ] ); + + n_AR_Q12 = silk_LSHIFT32( n_AR_Q12, 1 ); /* Q11 -> Q12 */ + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, sLF_AR_shp_Q14, Tilt_Q14 ); + + n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 ); + n_LF_Q12 = silk_SMLAWT( n_LF_Q12, sLF_AR_shp_Q14, LF_shp_Q14 ); + + silk_assert( lag > 0 || signalType != TYPE_VOICED ); + + /* Combine prediction and noise shaping signals */ + tmp1 = silk_SUB32( silk_LSHIFT32( LPC_pred_Q10, 2 ), n_AR_Q12 ); /* Q12 */ + tmp1 = silk_SUB32( tmp1, n_LF_Q12 ); /* Q12 */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q13 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_SMLAWT( n_LTP_Q13, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_LSHIFT( n_LTP_Q13, 1 ); + shp_lag_ptr++; + + tmp2 = silk_SUB32( LTP_pred_Q13, n_LTP_Q13 ); /* Q13 */ + tmp1 = silk_ADD_LSHIFT32( tmp2, tmp1, 1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 3 ); /* Q10 */ + } else { + tmp1 = silk_RSHIFT_ROUND( tmp1, 2 ); /* Q10 */ + } + + r_Q10 = silk_SUB32( x_sc_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Generate dither */ + NSQ->rand_seed = silk_RAND( NSQ->rand_seed ); + + /* Flip sign depending on dither */ + tmp2 = -r_Q10; + if ( NSQ->rand_seed < 0 ) r_Q10 = tmp2; + + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + + q1_Q10 = table[q1_Q0][0]; + q2_Q10 = table[q1_Q0][1]; + + if (r_Q10 * table[q1_Q0][2] - table[q1_Q0][3] < 0) + { + q1_Q10 = q2_Q10; + } + + pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 ); + + /* Excitation */ + exc_Q14 = silk_LSHIFT( q1_Q10, 4 ); + + tmp2 = -exc_Q14; + if ( NSQ->rand_seed < 0 ) exc_Q14 = tmp2; + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD_LSHIFT32( exc_Q14, LTP_pred_Q13, 1 ); + xq_Q14 = silk_ADD_LSHIFT32( LPC_exc_Q14, LPC_pred_Q10, 4 ); + + /* Update states */ + psLPC_Q14++; + *psLPC_Q14 = xq_Q14; + sLF_AR_shp_Q14 = silk_SUB_LSHIFT32( xq_Q14, n_AR_Q12, 2 ); + + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx ] = silk_SUB_LSHIFT32( sLF_AR_shp_Q14, n_LF_Q12, 2 ); + sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q14, 1 ); + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Make dither dependent on quantized signal */ + NSQ->rand_seed = silk_ADD32_ovflw( NSQ->rand_seed, pulses[ i ] ); + } + + NSQ->sLF_AR_shp_Q14 = sLF_AR_shp_Q14; + + /* Scale XQ back to normal level before saving */ + psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH ]; + + /* write back sAR2_Q14 */ + xmm_tempa = _mm_unpackhi_epi16( sAR2_Q14_lo_76543210, sAR2_Q14_hi_76543210 ); + xmm_tempb = _mm_unpacklo_epi16( sAR2_Q14_lo_76543210, sAR2_Q14_hi_76543210 ); + _mm_storeu_si128( (__m128i *)(&NSQ->sAR2_Q14[ 4 ]), xmm_tempa ); + _mm_storeu_si128( (__m128i *)(&NSQ->sAR2_Q14[ 0 ]), xmm_tempb ); + + /* xq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( psLPC_Q14[ i ], Gain_Q10 ), 8 ) ); */ + { + __m128i xmm_Gain_Q10; + __m128i xmm_xq_Q14_3210, xmm_xq_Q14_x3x1, xmm_xq_Q14_7654, xmm_xq_Q14_x7x5; + + /* prepare (1 << 7) in packed 4 32-bits */ + xmm_tempa = _mm_set1_epi32( (1 << 7) ); + + /* prepare Gain_Q10 in packed 4 32-bits */ + xmm_Gain_Q10 = _mm_set1_epi32( Gain_Q10 ); + + /* process xq */ + for (i = 0; i < length - 7; i += 8) + { + xmm_xq_Q14_3210 = _mm_loadu_si128( (__m128i *)(&(psLPC_Q14[ i + 0 ] ) ) ); + xmm_xq_Q14_7654 = _mm_loadu_si128( (__m128i *)(&(psLPC_Q14[ i + 4 ] ) ) ); + + /* equal shift right 4 bytes*/ + xmm_xq_Q14_x3x1 = _mm_shuffle_epi32( xmm_xq_Q14_3210, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + /* equal shift right 4 bytes*/ + xmm_xq_Q14_x7x5 = _mm_shuffle_epi32( xmm_xq_Q14_7654, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_xq_Q14_3210 = _mm_mul_epi32( xmm_xq_Q14_3210, xmm_Gain_Q10 ); + xmm_xq_Q14_x3x1 = _mm_mul_epi32( xmm_xq_Q14_x3x1, xmm_Gain_Q10 ); + xmm_xq_Q14_7654 = _mm_mul_epi32( xmm_xq_Q14_7654, xmm_Gain_Q10 ); + xmm_xq_Q14_x7x5 = _mm_mul_epi32( xmm_xq_Q14_x7x5, xmm_Gain_Q10 ); + + xmm_xq_Q14_3210 = _mm_srli_epi64( xmm_xq_Q14_3210, 16 ); + xmm_xq_Q14_x3x1 = _mm_slli_epi64( xmm_xq_Q14_x3x1, 16 ); + xmm_xq_Q14_7654 = _mm_srli_epi64( xmm_xq_Q14_7654, 16 ); + xmm_xq_Q14_x7x5 = _mm_slli_epi64( xmm_xq_Q14_x7x5, 16 ); + + xmm_xq_Q14_3210 = _mm_blend_epi16( xmm_xq_Q14_3210, xmm_xq_Q14_x3x1, 0xCC ); + xmm_xq_Q14_7654 = _mm_blend_epi16( xmm_xq_Q14_7654, xmm_xq_Q14_x7x5, 0xCC ); + + /* silk_RSHIFT_ROUND(xq, 8) */ + xmm_xq_Q14_3210 = _mm_add_epi32( xmm_xq_Q14_3210, xmm_tempa ); + xmm_xq_Q14_7654 = _mm_add_epi32( xmm_xq_Q14_7654, xmm_tempa ); + + xmm_xq_Q14_3210 = _mm_srai_epi32( xmm_xq_Q14_3210, 8 ); + xmm_xq_Q14_7654 = _mm_srai_epi32( xmm_xq_Q14_7654, 8 ); + + /* silk_SAT16 */ + xmm_xq_Q14_3210 = _mm_packs_epi32( xmm_xq_Q14_3210, xmm_xq_Q14_7654 ); + + /* save to xq */ + _mm_storeu_si128( (__m128i *)(&xq[ i ] ), xmm_xq_Q14_3210 ); + } + } + for ( ; i < length; i++) + { + xq[i] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( psLPC_Q14[ i ], Gain_Q10 ), 8 ) ); + } + + /* Update LPC synth buffer */ + silk_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); +} + +static OPUS_INLINE void silk_nsq_scale_states_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int32 x_Q3[], /* I input in Q3 */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +) +{ + opus_int i, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23; + __m128i xmm_inv_gain_Q23, xmm_x_Q3_x2x0, xmm_x_Q3_x3x1; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Calculate gain adjustment factor */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + } else { + gain_adj_Q16 = (opus_int32)1 << 16; + } + + /* Scale input */ + inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 ); + + /* prepare inv_gain_Q23 in packed 4 32-bits */ + xmm_inv_gain_Q23 = _mm_set1_epi32(inv_gain_Q23); + + for( i = 0; i < psEncC->subfr_length - 3; i += 4 ) { + xmm_x_Q3_x2x0 = _mm_loadu_si128( (__m128i *)(&(x_Q3[ i ] ) ) ); + + /* equal shift right 4 bytes*/ + xmm_x_Q3_x3x1 = _mm_shuffle_epi32( xmm_x_Q3_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_x_Q3_x2x0 = _mm_mul_epi32( xmm_x_Q3_x2x0, xmm_inv_gain_Q23 ); + xmm_x_Q3_x3x1 = _mm_mul_epi32( xmm_x_Q3_x3x1, xmm_inv_gain_Q23 ); + + xmm_x_Q3_x2x0 = _mm_srli_epi64( xmm_x_Q3_x2x0, 16 ); + xmm_x_Q3_x3x1 = _mm_slli_epi64( xmm_x_Q3_x3x1, 16 ); + + xmm_x_Q3_x2x0 = _mm_blend_epi16( xmm_x_Q3_x2x0, xmm_x_Q3_x3x1, 0xCC ); + + _mm_storeu_si128( (__m128i *)(&(x_sc_Q10[ i ] ) ), xmm_x_Q3_x2x0 ); + } + + for( ; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 ); + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( gain_adj_Q16 != (opus_int32)1 << 16 ) { + /* Scale long-term shaping state */ + __m128i xmm_gain_adj_Q16, xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1; + + /* prepare gain_adj_Q16 in packed 4 32-bits */ + xmm_gain_adj_Q16 = _mm_set1_epi32(gain_adj_Q16); + + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx - 3; i += 4 ) + { + xmm_sLTP_shp_Q14_x2x0 = _mm_loadu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ) ); + /* equal shift right 4 bytes*/ + xmm_sLTP_shp_Q14_x3x1 = _mm_shuffle_epi32( xmm_sLTP_shp_Q14_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x2x0, xmm_gain_adj_Q16 ); + xmm_sLTP_shp_Q14_x3x1 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x3x1, xmm_gain_adj_Q16 ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_srli_epi64( xmm_sLTP_shp_Q14_x2x0, 16 ); + xmm_sLTP_shp_Q14_x3x1 = _mm_slli_epi64( xmm_sLTP_shp_Q14_x3x1, 16 ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_blend_epi16( xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1, 0xCC ); + + _mm_storeu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ), xmm_sLTP_shp_Q14_x2x0 ); + } + + for( ; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + NSQ->sLF_AR_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + NSQ->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + NSQ->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] ); + } + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/SigProc_FIX_sse.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/SigProc_FIX_sse.h new file mode 100644 index 000000000..61efa8da4 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/SigProc_FIX_sse.h @@ -0,0 +1,94 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef SIGPROC_FIX_SSE_H +#define SIGPROC_FIX_SSE_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) +void silk_burg_modified_sse4_1( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +); + +#if defined(OPUS_X86_PRESUME_SSE4_1) +#define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \ + ((void)(arch), silk_burg_modified_sse4_1(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch)) + +#else + +extern void (*const SILK_BURG_MODIFIED_IMPL[OPUS_ARCHMASK + 1])( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */); + +# define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \ + ((*SILK_BURG_MODIFIED_IMPL[(arch) & OPUS_ARCHMASK])(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch)) + +#endif + +opus_int64 silk_inner_prod16_aligned_64_sse4_1( + const opus_int16 *inVec1, + const opus_int16 *inVec2, + const opus_int len +); + + +#if defined(OPUS_X86_PRESUME_SSE4_1) + +#define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \ + ((void)(arch),silk_inner_prod16_aligned_64_sse4_1(inVec1, inVec2, len)) + +#else + +extern opus_int64 (*const SILK_INNER_PROD16_ALIGNED_64_IMPL[OPUS_ARCHMASK + 1])( + const opus_int16 *inVec1, + const opus_int16 *inVec2, + const opus_int len); + +# define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \ + ((*SILK_INNER_PROD16_ALIGNED_64_IMPL[(arch) & OPUS_ARCHMASK])(inVec1, inVec2, len)) + +#endif +#endif +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/VAD_sse4_1.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/VAD_sse4_1.c new file mode 100644 index 000000000..d02ddf4ad --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/VAD_sse4_1.c @@ -0,0 +1,277 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "main.h" +#include "stack_alloc.h" + +/* Weighting factors for tilt measure */ +static const opus_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 }; + +/***************************************/ +/* Get the speech activity level in Q8 */ +/***************************************/ +opus_int silk_VAD_GetSA_Q8_sse4_1( /* O Return value, 0 if success */ + silk_encoder_state *psEncC, /* I/O Encoder state */ + const opus_int16 pIn[] /* I PCM input */ +) +{ + opus_int SA_Q15, pSNR_dB_Q7, input_tilt; + opus_int decimated_framelength1, decimated_framelength2; + opus_int decimated_framelength; + opus_int dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s; + opus_int32 sumSquared, smooth_coef_Q16; + opus_int16 HPstateTmp; + VARDECL( opus_int16, X ); + opus_int32 Xnrg[ VAD_N_BANDS ]; + opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ]; + opus_int32 speech_nrg, x_tmp; + opus_int X_offset[ VAD_N_BANDS ]; + opus_int ret = 0; + silk_VAD_state *psSilk_VAD = &psEncC->sVAD; + + SAVE_STACK; + + /* Safety checks */ + silk_assert( VAD_N_BANDS == 4 ); + celt_assert( MAX_FRAME_LENGTH >= psEncC->frame_length ); + celt_assert( psEncC->frame_length <= 512 ); + celt_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) ); + + /***********************/ + /* Filter and Decimate */ + /***********************/ + decimated_framelength1 = silk_RSHIFT( psEncC->frame_length, 1 ); + decimated_framelength2 = silk_RSHIFT( psEncC->frame_length, 2 ); + decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 ); + /* Decimate into 4 bands: + 0 L 3L L 3L 5L + - -- - -- -- + 8 8 2 4 4 + + [0-1 kHz| temp. |1-2 kHz| 2-4 kHz | 4-8 kHz | + + They're arranged to allow the minimal ( frame_length / 4 ) extra + scratch space during the downsampling process */ + X_offset[ 0 ] = 0; + X_offset[ 1 ] = decimated_framelength + decimated_framelength2; + X_offset[ 2 ] = X_offset[ 1 ] + decimated_framelength; + X_offset[ 3 ] = X_offset[ 2 ] + decimated_framelength2; + ALLOC( X, X_offset[ 3 ] + decimated_framelength1, opus_int16 ); + + /* 0-8 kHz to 0-4 kHz and 4-8 kHz */ + silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ], + X, &X[ X_offset[ 3 ] ], psEncC->frame_length ); + + /* 0-4 kHz to 0-2 kHz and 2-4 kHz */ + silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState1[ 0 ], + X, &X[ X_offset[ 2 ] ], decimated_framelength1 ); + + /* 0-2 kHz to 0-1 kHz and 1-2 kHz */ + silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState2[ 0 ], + X, &X[ X_offset[ 1 ] ], decimated_framelength2 ); + + /*********************************************/ + /* HP filter on lowest band (differentiator) */ + /*********************************************/ + X[ decimated_framelength - 1 ] = silk_RSHIFT( X[ decimated_framelength - 1 ], 1 ); + HPstateTmp = X[ decimated_framelength - 1 ]; + for( i = decimated_framelength - 1; i > 0; i-- ) { + X[ i - 1 ] = silk_RSHIFT( X[ i - 1 ], 1 ); + X[ i ] -= X[ i - 1 ]; + } + X[ 0 ] -= psSilk_VAD->HPstate; + psSilk_VAD->HPstate = HPstateTmp; + + /*************************************/ + /* Calculate the energy in each band */ + /*************************************/ + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Find the decimated framelength in the non-uniformly divided bands */ + decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) ); + + /* Split length into subframe lengths */ + dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 ); + dec_subframe_offset = 0; + + /* Compute energy per sub-frame */ + /* initialize with summed energy of last subframe */ + Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ]; + for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) { + __m128i xmm_X, xmm_acc; + sumSquared = 0; + + xmm_acc = _mm_setzero_si128(); + + for( i = 0; i < dec_subframe_length - 7; i += 8 ) + { + xmm_X = _mm_loadu_si128( (__m128i *)&(X[ X_offset[ b ] + i + dec_subframe_offset ] ) ); + xmm_X = _mm_srai_epi16( xmm_X, 3 ); + xmm_X = _mm_madd_epi16( xmm_X, xmm_X ); + xmm_acc = _mm_add_epi32( xmm_acc, xmm_X ); + } + + xmm_acc = _mm_add_epi32( xmm_acc, _mm_unpackhi_epi64( xmm_acc, xmm_acc ) ); + xmm_acc = _mm_add_epi32( xmm_acc, _mm_shufflelo_epi16( xmm_acc, 0x0E ) ); + + sumSquared += _mm_cvtsi128_si32( xmm_acc ); + + for( ; i < dec_subframe_length; i++ ) { + /* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2. */ + /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */ + x_tmp = silk_RSHIFT( + X[ X_offset[ b ] + i + dec_subframe_offset ], 3 ); + sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp ); + + /* Safety check */ + silk_assert( sumSquared >= 0 ); + } + + /* Add/saturate summed energy of current subframe */ + if( s < VAD_INTERNAL_SUBFRAMES - 1 ) { + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared ); + } else { + /* Look-ahead subframe */ + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) ); + } + + dec_subframe_offset += dec_subframe_length; + } + psSilk_VAD->XnrgSubfr[ b ] = sumSquared; + } + + /********************/ + /* Noise estimation */ + /********************/ + silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD ); + + /***********************************************/ + /* Signal-plus-noise to noise ratio estimation */ + /***********************************************/ + sumSquared = 0; + input_tilt = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ]; + if( speech_nrg > 0 ) { + /* Divide, with sufficient resolution */ + if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 ); + } else { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 ); + } + + /* Convert to log domain */ + SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128; + + /* Sum-of-squares */ + sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */ + + /* Tilt measure */ + if( speech_nrg < ( (opus_int32)1 << 20 ) ) { + /* Scale down SNR value for small subband speech energies */ + SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 ); + } + input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 ); + } else { + NrgToNoiseRatio_Q8[ b ] = 256; + } + } + + /* Mean-of-squares */ + sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */ + + /* Root-mean-square approximation, scale to dBs, and write to output pointer */ + pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */ + + /*********************************/ + /* Speech Probability Estimation */ + /*********************************/ + SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 ); + + /**************************/ + /* Frequency Tilt Measure */ + /**************************/ + psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 ); + + /**************************************************/ + /* Scale the sigmoid output based on power levels */ + /**************************************************/ + speech_nrg = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Accumulate signal-without-noise energies, higher frequency bands have more weight */ + speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 ); + } + + /* Power scaling */ + if( speech_nrg <= 0 ) { + SA_Q15 = silk_RSHIFT( SA_Q15, 1 ); + } else if( speech_nrg < 32768 ) { + if( psEncC->frame_length == 10 * psEncC->fs_kHz ) { + speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 16 ); + } else { + speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 15 ); + } + + /* square-root */ + speech_nrg = silk_SQRT_APPROX( speech_nrg ); + SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 ); + } + + /* Copy the resulting speech activity in Q8 */ + psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX ); + + /***********************************/ + /* Energy Level and SNR estimation */ + /***********************************/ + /* Smoothing coefficient */ + smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) ); + + if( psEncC->frame_length == 10 * psEncC->fs_kHz ) { + smooth_coef_Q16 >>= 1; + } + + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* compute smoothed energy-to-noise ratio per band */ + psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ], + NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 ); + + /* signal to noise ratio in dB per band */ + SNR_Q7 = 3 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 ); + /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */ + psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) ); + } + + RESTORE_STACK; + return( ret ); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/VQ_WMat_EC_sse4_1.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/VQ_WMat_EC_sse4_1.c new file mode 100644 index 000000000..74d6c6d0e --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/VQ_WMat_EC_sse4_1.c @@ -0,0 +1,142 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "main.h" +#include "celt/x86/x86cpu.h" + +/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */ +void silk_VQ_WMat_EC_sse4_1( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int16 *in_Q14, /* I input vector to be quantized */ + const opus_int32 *W_Q18, /* I weighting matrix */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + opus_int L /* I number of vectors in codebook */ +) +{ + opus_int k, gain_tmp_Q7; + const opus_int8 *cb_row_Q7; + opus_int16 diff_Q14[ 5 ]; + opus_int32 sum1_Q14, sum2_Q16; + + __m128i C_tmp1, C_tmp2, C_tmp3, C_tmp4, C_tmp5; + /* Loop over codebook */ + *rate_dist_Q14 = silk_int32_MAX; + cb_row_Q7 = cb_Q7; + for( k = 0; k < L; k++ ) { + gain_tmp_Q7 = cb_gain_Q7[k]; + + diff_Q14[ 0 ] = in_Q14[ 0 ] - silk_LSHIFT( cb_row_Q7[ 0 ], 7 ); + + C_tmp1 = OP_CVTEPI16_EPI32_M64( &in_Q14[ 1 ] ); + C_tmp2 = OP_CVTEPI8_EPI32_M32( &cb_row_Q7[ 1 ] ); + C_tmp2 = _mm_slli_epi32( C_tmp2, 7 ); + C_tmp1 = _mm_sub_epi32( C_tmp1, C_tmp2 ); + + diff_Q14[ 1 ] = _mm_extract_epi16( C_tmp1, 0 ); + diff_Q14[ 2 ] = _mm_extract_epi16( C_tmp1, 2 ); + diff_Q14[ 3 ] = _mm_extract_epi16( C_tmp1, 4 ); + diff_Q14[ 4 ] = _mm_extract_epi16( C_tmp1, 6 ); + + /* Weighted rate */ + sum1_Q14 = silk_SMULBB( mu_Q9, cl_Q5[ k ] ); + + /* Penalty for too large gain */ + sum1_Q14 = silk_ADD_LSHIFT32( sum1_Q14, silk_max( silk_SUB32( gain_tmp_Q7, max_gain_Q7 ), 0 ), 10 ); + + silk_assert( sum1_Q14 >= 0 ); + + /* first row of W_Q18 */ + C_tmp3 = _mm_loadu_si128( (__m128i *)(&W_Q18[ 1 ] ) ); + C_tmp4 = _mm_mul_epi32( C_tmp3, C_tmp1 ); + C_tmp4 = _mm_srli_si128( C_tmp4, 2 ); + + C_tmp1 = _mm_shuffle_epi32( C_tmp1, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* shift right 4 bytes */ + C_tmp3 = _mm_shuffle_epi32( C_tmp3, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* shift right 4 bytes */ + + C_tmp5 = _mm_mul_epi32( C_tmp3, C_tmp1 ); + C_tmp5 = _mm_srli_si128( C_tmp5, 2 ); + + C_tmp5 = _mm_add_epi32( C_tmp4, C_tmp5 ); + C_tmp5 = _mm_slli_epi32( C_tmp5, 1 ); + + C_tmp5 = _mm_add_epi32( C_tmp5, _mm_shuffle_epi32( C_tmp5, _MM_SHUFFLE( 0, 0, 0, 2 ) ) ); + sum2_Q16 = _mm_cvtsi128_si32( C_tmp5 ); + + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 0 ], diff_Q14[ 0 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 0 ] ); + + /* second row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 7 ], diff_Q14[ 2 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 8 ], diff_Q14[ 3 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 9 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 6 ], diff_Q14[ 1 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 1 ] ); + + /* third row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 13 ], diff_Q14[ 3 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 14 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 12 ], diff_Q14[ 2 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 2 ] ); + + /* fourth row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 19 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 18 ], diff_Q14[ 3 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 3 ] ); + + /* last row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 24 ], diff_Q14[ 4 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 4 ] ); + + silk_assert( sum1_Q14 >= 0 ); + + /* find best */ + if( sum1_Q14 < *rate_dist_Q14 ) { + *rate_dist_Q14 = sum1_Q14; + *ind = (opus_int8)k; + *gain_Q7 = gain_tmp_Q7; + } + + /* Go to next cbk vector */ + cb_row_Q7 += LTP_ORDER; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/main_sse.h b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/main_sse.h new file mode 100644 index 000000000..2f15d4486 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/main_sse.h @@ -0,0 +1,248 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifndef MAIN_SSE_H +#define MAIN_SSE_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +# if defined(OPUS_X86_MAY_HAVE_SSE4_1) + +#if 0 /* FIXME: SSE disabled until silk_VQ_WMat_EC_sse4_1() gets updated. */ +# define OVERRIDE_silk_VQ_WMat_EC + +void silk_VQ_WMat_EC_sse4_1( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int16 *in_Q14, /* I input vector to be quantized */ + const opus_int32 *W_Q18, /* I weighting matrix */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + opus_int L /* I number of vectors in codebook */ +); + +#if defined OPUS_X86_PRESUME_SSE4_1 + +#define silk_VQ_WMat_EC(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \ + mu_Q9, max_gain_Q7, L, arch) \ + ((void)(arch),silk_VQ_WMat_EC_sse4_1(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \ + mu_Q9, max_gain_Q7, L)) + +#else + +extern void (*const SILK_VQ_WMAT_EC_IMPL[OPUS_ARCHMASK + 1])( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int16 *in_Q14, /* I input vector to be quantized */ + const opus_int32 *W_Q18, /* I weighting matrix */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + opus_int L /* I number of vectors in codebook */ +); + +# define silk_VQ_WMat_EC(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \ + mu_Q9, max_gain_Q7, L, arch) \ + ((*SILK_VQ_WMAT_EC_IMPL[(arch) & OPUS_ARCHMASK])(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \ + mu_Q9, max_gain_Q7, L)) + +#endif +#endif + +#if 0 /* FIXME: SSE disabled until the NSQ code gets updated. */ +# define OVERRIDE_silk_NSQ + +void silk_NSQ_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +#if defined OPUS_X86_PRESUME_SSE4_1 + +#define silk_NSQ(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((void)(arch),silk_NSQ_sse4_1(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) + +#else + +extern void (*const SILK_NSQ_IMPL[OPUS_ARCHMASK + 1])( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +# define silk_NSQ(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((*SILK_NSQ_IMPL[(arch) & OPUS_ARCHMASK])(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) + +#endif + +# define OVERRIDE_silk_NSQ_del_dec + +void silk_NSQ_del_dec_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +#if defined OPUS_X86_PRESUME_SSE4_1 + +#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((void)(arch),silk_NSQ_del_dec_sse4_1(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) + +#else + +extern void (*const SILK_NSQ_DEL_DEC_IMPL[OPUS_ARCHMASK + 1])( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +# define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((*SILK_NSQ_DEL_DEC_IMPL[(arch) & OPUS_ARCHMASK])(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) + +#endif +#endif + +void silk_noise_shape_quantizer( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int shapingLPCOrder, /* I Noise shaping AR filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + int arch /* I Architecture */ +); + +/**************************/ +/* Noise level estimation */ +/**************************/ +void silk_VAD_GetNoiseLevels( + const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); + +# define OVERRIDE_silk_VAD_GetSA_Q8 + +opus_int silk_VAD_GetSA_Q8_sse4_1( + silk_encoder_state *psEnC, + const opus_int16 pIn[] +); + +#if defined(OPUS_X86_PRESUME_SSE4_1) +#define silk_VAD_GetSA_Q8(psEnC, pIn, arch) ((void)(arch),silk_VAD_GetSA_Q8_sse4_1(psEnC, pIn)) + +#else + +# define silk_VAD_GetSA_Q8(psEnC, pIn, arch) \ + ((*SILK_VAD_GETSA_Q8_IMPL[(arch) & OPUS_ARCHMASK])(psEnC, pIn)) + +extern opus_int (*const SILK_VAD_GETSA_Q8_IMPL[OPUS_ARCHMASK + 1])( + silk_encoder_state *psEnC, + const opus_int16 pIn[]); + +#endif + +# endif +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/x86_silk_map.c b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/x86_silk_map.c new file mode 100644 index 000000000..32dcc3cab --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk/x86/x86_silk_map.c @@ -0,0 +1,164 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include "celt/x86/x86cpu.h" +#include "structs.h" +#include "SigProc_FIX.h" +#include "pitch.h" +#include "main.h" + +#if !defined(OPUS_X86_PRESUME_SSE4_1) + +#if defined(FIXED_POINT) + +#include "fixed/main_FIX.h" + +opus_int64 (*const SILK_INNER_PROD16_ALIGNED_64_IMPL[ OPUS_ARCHMASK + 1 ] )( + const opus_int16 *inVec1, + const opus_int16 *inVec2, + const opus_int len +) = { + silk_inner_prod16_aligned_64_c, /* non-sse */ + silk_inner_prod16_aligned_64_c, + silk_inner_prod16_aligned_64_c, + MAY_HAVE_SSE4_1( silk_inner_prod16_aligned_64 ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_inner_prod16_aligned_64 ) /* avx */ +}; + +#endif + +opus_int (*const SILK_VAD_GETSA_Q8_IMPL[ OPUS_ARCHMASK + 1 ] )( + silk_encoder_state *psEncC, + const opus_int16 pIn[] +) = { + silk_VAD_GetSA_Q8_c, /* non-sse */ + silk_VAD_GetSA_Q8_c, + silk_VAD_GetSA_Q8_c, + MAY_HAVE_SSE4_1( silk_VAD_GetSA_Q8 ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_VAD_GetSA_Q8 ) /* avx */ +}; + +#if 0 /* FIXME: SSE disabled until the NSQ code gets updated. */ +void (*const SILK_NSQ_IMPL[ OPUS_ARCHMASK + 1 ] )( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) = { + silk_NSQ_c, /* non-sse */ + silk_NSQ_c, + silk_NSQ_c, + MAY_HAVE_SSE4_1( silk_NSQ ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_NSQ ) /* avx */ +}; +#endif + +#if 0 /* FIXME: SSE disabled until silk_VQ_WMat_EC_sse4_1() gets updated. */ +void (*const SILK_VQ_WMAT_EC_IMPL[ OPUS_ARCHMASK + 1 ] )( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int16 *in_Q14, /* I input vector to be quantized */ + const opus_int32 *W_Q18, /* I weighting matrix */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + opus_int L /* I number of vectors in codebook */ +) = { + silk_VQ_WMat_EC_c, /* non-sse */ + silk_VQ_WMat_EC_c, + silk_VQ_WMat_EC_c, + MAY_HAVE_SSE4_1( silk_VQ_WMat_EC ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_VQ_WMat_EC ) /* avx */ +}; +#endif + +#if 0 /* FIXME: SSE disabled until the NSQ code gets updated. */ +void (*const SILK_NSQ_DEL_DEC_IMPL[ OPUS_ARCHMASK + 1 ] )( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) = { + silk_NSQ_del_dec_c, /* non-sse */ + silk_NSQ_del_dec_c, + silk_NSQ_del_dec_c, + MAY_HAVE_SSE4_1( silk_NSQ_del_dec ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_NSQ_del_dec ) /* avx */ +}; +#endif + +#if defined(FIXED_POINT) + +void (*const SILK_BURG_MODIFIED_IMPL[ OPUS_ARCHMASK + 1 ] )( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +) = { + silk_burg_modified_c, /* non-sse */ + silk_burg_modified_c, + silk_burg_modified_c, + MAY_HAVE_SSE4_1( silk_burg_modified ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_burg_modified ) /* avx */ +}; + +#endif +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk_headers.mk b/native/opennow-streamer/vendor/audiopus-sys/opus/silk_headers.mk new file mode 100644 index 000000000..2588067c7 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk_headers.mk @@ -0,0 +1,44 @@ +SILK_HEAD = \ +silk/debug.h \ +silk/control.h \ +silk/errors.h \ +silk/API.h \ +silk/typedef.h \ +silk/define.h \ +silk/main.h \ +silk/x86/main_sse.h \ +silk/PLC.h \ +silk/structs.h \ +silk/tables.h \ +silk/tuning_parameters.h \ +silk/Inlines.h \ +silk/MacroCount.h \ +silk/MacroDebug.h \ +silk/macros.h \ +silk/NSQ.h \ +silk/pitch_est_defines.h \ +silk/resampler_private.h \ +silk/resampler_rom.h \ +silk/resampler_structs.h \ +silk/SigProc_FIX.h \ +silk/x86/SigProc_FIX_sse.h \ +silk/arm/biquad_alt_arm.h \ +silk/arm/LPC_inv_pred_gain_arm.h \ +silk/arm/macros_armv4.h \ +silk/arm/macros_armv5e.h \ +silk/arm/macros_arm64.h \ +silk/arm/SigProc_FIX_armv4.h \ +silk/arm/SigProc_FIX_armv5e.h \ +silk/arm/NSQ_del_dec_arm.h \ +silk/arm/NSQ_neon.h \ +silk/fixed/main_FIX.h \ +silk/fixed/structs_FIX.h \ +silk/fixed/arm/warped_autocorrelation_FIX_arm.h \ +silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h \ +silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h \ +silk/float/main_FLP.h \ +silk/float/structs_FLP.h \ +silk/float/SigProc_FLP.h \ +silk/mips/macros_mipsr1.h \ +silk/mips/NSQ_del_dec_mipsr1.h \ +silk/mips/sigproc_fix_mipsr1.h diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/silk_sources.mk b/native/opennow-streamer/vendor/audiopus-sys/opus/silk_sources.mk new file mode 100644 index 000000000..d2666e665 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/silk_sources.mk @@ -0,0 +1,154 @@ +SILK_SOURCES = \ +silk/CNG.c \ +silk/code_signs.c \ +silk/init_decoder.c \ +silk/decode_core.c \ +silk/decode_frame.c \ +silk/decode_parameters.c \ +silk/decode_indices.c \ +silk/decode_pulses.c \ +silk/decoder_set_fs.c \ +silk/dec_API.c \ +silk/enc_API.c \ +silk/encode_indices.c \ +silk/encode_pulses.c \ +silk/gain_quant.c \ +silk/interpolate.c \ +silk/LP_variable_cutoff.c \ +silk/NLSF_decode.c \ +silk/NSQ.c \ +silk/NSQ_del_dec.c \ +silk/PLC.c \ +silk/shell_coder.c \ +silk/tables_gain.c \ +silk/tables_LTP.c \ +silk/tables_NLSF_CB_NB_MB.c \ +silk/tables_NLSF_CB_WB.c \ +silk/tables_other.c \ +silk/tables_pitch_lag.c \ +silk/tables_pulses_per_block.c \ +silk/VAD.c \ +silk/control_audio_bandwidth.c \ +silk/quant_LTP_gains.c \ +silk/VQ_WMat_EC.c \ +silk/HP_variable_cutoff.c \ +silk/NLSF_encode.c \ +silk/NLSF_VQ.c \ +silk/NLSF_unpack.c \ +silk/NLSF_del_dec_quant.c \ +silk/process_NLSFs.c \ +silk/stereo_LR_to_MS.c \ +silk/stereo_MS_to_LR.c \ +silk/check_control_input.c \ +silk/control_SNR.c \ +silk/init_encoder.c \ +silk/control_codec.c \ +silk/A2NLSF.c \ +silk/ana_filt_bank_1.c \ +silk/biquad_alt.c \ +silk/bwexpander_32.c \ +silk/bwexpander.c \ +silk/debug.c \ +silk/decode_pitch.c \ +silk/inner_prod_aligned.c \ +silk/lin2log.c \ +silk/log2lin.c \ +silk/LPC_analysis_filter.c \ +silk/LPC_inv_pred_gain.c \ +silk/table_LSF_cos.c \ +silk/NLSF2A.c \ +silk/NLSF_stabilize.c \ +silk/NLSF_VQ_weights_laroia.c \ +silk/pitch_est_tables.c \ +silk/resampler.c \ +silk/resampler_down2_3.c \ +silk/resampler_down2.c \ +silk/resampler_private_AR2.c \ +silk/resampler_private_down_FIR.c \ +silk/resampler_private_IIR_FIR.c \ +silk/resampler_private_up2_HQ.c \ +silk/resampler_rom.c \ +silk/sigm_Q15.c \ +silk/sort.c \ +silk/sum_sqr_shift.c \ +silk/stereo_decode_pred.c \ +silk/stereo_encode_pred.c \ +silk/stereo_find_predictor.c \ +silk/stereo_quant_pred.c \ +silk/LPC_fit.c + +SILK_SOURCES_SSE4_1 = \ +silk/x86/NSQ_sse4_1.c \ +silk/x86/NSQ_del_dec_sse4_1.c \ +silk/x86/x86_silk_map.c \ +silk/x86/VAD_sse4_1.c \ +silk/x86/VQ_WMat_EC_sse4_1.c + +SILK_SOURCES_ARM_NEON_INTR = \ +silk/arm/arm_silk_map.c \ +silk/arm/biquad_alt_neon_intr.c \ +silk/arm/LPC_inv_pred_gain_neon_intr.c \ +silk/arm/NSQ_del_dec_neon_intr.c \ +silk/arm/NSQ_neon.c + +SILK_SOURCES_FIXED = \ +silk/fixed/LTP_analysis_filter_FIX.c \ +silk/fixed/LTP_scale_ctrl_FIX.c \ +silk/fixed/corrMatrix_FIX.c \ +silk/fixed/encode_frame_FIX.c \ +silk/fixed/find_LPC_FIX.c \ +silk/fixed/find_LTP_FIX.c \ +silk/fixed/find_pitch_lags_FIX.c \ +silk/fixed/find_pred_coefs_FIX.c \ +silk/fixed/noise_shape_analysis_FIX.c \ +silk/fixed/process_gains_FIX.c \ +silk/fixed/regularize_correlations_FIX.c \ +silk/fixed/residual_energy16_FIX.c \ +silk/fixed/residual_energy_FIX.c \ +silk/fixed/warped_autocorrelation_FIX.c \ +silk/fixed/apply_sine_window_FIX.c \ +silk/fixed/autocorr_FIX.c \ +silk/fixed/burg_modified_FIX.c \ +silk/fixed/k2a_FIX.c \ +silk/fixed/k2a_Q16_FIX.c \ +silk/fixed/pitch_analysis_core_FIX.c \ +silk/fixed/vector_ops_FIX.c \ +silk/fixed/schur64_FIX.c \ +silk/fixed/schur_FIX.c + +SILK_SOURCES_FIXED_SSE4_1 = \ +silk/fixed/x86/vector_ops_FIX_sse4_1.c \ +silk/fixed/x86/burg_modified_FIX_sse4_1.c + +SILK_SOURCES_FIXED_ARM_NEON_INTR = \ +silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c + +SILK_SOURCES_FLOAT = \ +silk/float/apply_sine_window_FLP.c \ +silk/float/corrMatrix_FLP.c \ +silk/float/encode_frame_FLP.c \ +silk/float/find_LPC_FLP.c \ +silk/float/find_LTP_FLP.c \ +silk/float/find_pitch_lags_FLP.c \ +silk/float/find_pred_coefs_FLP.c \ +silk/float/LPC_analysis_filter_FLP.c \ +silk/float/LTP_analysis_filter_FLP.c \ +silk/float/LTP_scale_ctrl_FLP.c \ +silk/float/noise_shape_analysis_FLP.c \ +silk/float/process_gains_FLP.c \ +silk/float/regularize_correlations_FLP.c \ +silk/float/residual_energy_FLP.c \ +silk/float/warped_autocorrelation_FLP.c \ +silk/float/wrappers_FLP.c \ +silk/float/autocorrelation_FLP.c \ +silk/float/burg_modified_FLP.c \ +silk/float/bwexpander_FLP.c \ +silk/float/energy_FLP.c \ +silk/float/inner_product_FLP.c \ +silk/float/k2a_FLP.c \ +silk/float/LPC_inv_pred_gain_FLP.c \ +silk/float/pitch_analysis_core_FLP.c \ +silk/float/scale_copy_vector_FLP.c \ +silk/float/scale_vector_FLP.c \ +silk/float/schur_FLP.c \ +silk/float/sort_FLP.c diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/analysis.c b/native/opennow-streamer/vendor/audiopus-sys/opus/src/analysis.c new file mode 100644 index 000000000..058328f0f --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/analysis.c @@ -0,0 +1,983 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 FOUNDATION 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define ANALYSIS_C + +#ifdef MLP_TRAINING +#include +#endif + +#include "mathops.h" +#include "kiss_fft.h" +#include "celt.h" +#include "modes.h" +#include "arch.h" +#include "quant_bands.h" +#include "analysis.h" +#include "mlp.h" +#include "stack_alloc.h" +#include "float_cast.h" + +#ifndef M_PI +#define M_PI 3.141592653 +#endif + +#ifndef DISABLE_FLOAT_API + +#define TRANSITION_PENALTY 10 + +static const float dct_table[128] = { + 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, + 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, + 0.351851f, 0.338330f, 0.311806f, 0.273300f, 0.224292f, 0.166664f, 0.102631f, 0.034654f, + -0.034654f,-0.102631f,-0.166664f,-0.224292f,-0.273300f,-0.311806f,-0.338330f,-0.351851f, + 0.346760f, 0.293969f, 0.196424f, 0.068975f,-0.068975f,-0.196424f,-0.293969f,-0.346760f, + -0.346760f,-0.293969f,-0.196424f,-0.068975f, 0.068975f, 0.196424f, 0.293969f, 0.346760f, + 0.338330f, 0.224292f, 0.034654f,-0.166664f,-0.311806f,-0.351851f,-0.273300f,-0.102631f, + 0.102631f, 0.273300f, 0.351851f, 0.311806f, 0.166664f,-0.034654f,-0.224292f,-0.338330f, + 0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f, + 0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f, + 0.311806f, 0.034654f,-0.273300f,-0.338330f,-0.102631f, 0.224292f, 0.351851f, 0.166664f, + -0.166664f,-0.351851f,-0.224292f, 0.102631f, 0.338330f, 0.273300f,-0.034654f,-0.311806f, + 0.293969f,-0.068975f,-0.346760f,-0.196424f, 0.196424f, 0.346760f, 0.068975f,-0.293969f, + -0.293969f, 0.068975f, 0.346760f, 0.196424f,-0.196424f,-0.346760f,-0.068975f, 0.293969f, + 0.273300f,-0.166664f,-0.338330f, 0.034654f, 0.351851f, 0.102631f,-0.311806f,-0.224292f, + 0.224292f, 0.311806f,-0.102631f,-0.351851f,-0.034654f, 0.338330f, 0.166664f,-0.273300f, +}; + +static const float analysis_window[240] = { + 0.000043f, 0.000171f, 0.000385f, 0.000685f, 0.001071f, 0.001541f, 0.002098f, 0.002739f, + 0.003466f, 0.004278f, 0.005174f, 0.006156f, 0.007222f, 0.008373f, 0.009607f, 0.010926f, + 0.012329f, 0.013815f, 0.015385f, 0.017037f, 0.018772f, 0.020590f, 0.022490f, 0.024472f, + 0.026535f, 0.028679f, 0.030904f, 0.033210f, 0.035595f, 0.038060f, 0.040604f, 0.043227f, + 0.045928f, 0.048707f, 0.051564f, 0.054497f, 0.057506f, 0.060591f, 0.063752f, 0.066987f, + 0.070297f, 0.073680f, 0.077136f, 0.080665f, 0.084265f, 0.087937f, 0.091679f, 0.095492f, + 0.099373f, 0.103323f, 0.107342f, 0.111427f, 0.115579f, 0.119797f, 0.124080f, 0.128428f, + 0.132839f, 0.137313f, 0.141849f, 0.146447f, 0.151105f, 0.155823f, 0.160600f, 0.165435f, + 0.170327f, 0.175276f, 0.180280f, 0.185340f, 0.190453f, 0.195619f, 0.200838f, 0.206107f, + 0.211427f, 0.216797f, 0.222215f, 0.227680f, 0.233193f, 0.238751f, 0.244353f, 0.250000f, + 0.255689f, 0.261421f, 0.267193f, 0.273005f, 0.278856f, 0.284744f, 0.290670f, 0.296632f, + 0.302628f, 0.308658f, 0.314721f, 0.320816f, 0.326941f, 0.333097f, 0.339280f, 0.345492f, + 0.351729f, 0.357992f, 0.364280f, 0.370590f, 0.376923f, 0.383277f, 0.389651f, 0.396044f, + 0.402455f, 0.408882f, 0.415325f, 0.421783f, 0.428254f, 0.434737f, 0.441231f, 0.447736f, + 0.454249f, 0.460770f, 0.467298f, 0.473832f, 0.480370f, 0.486912f, 0.493455f, 0.500000f, + 0.506545f, 0.513088f, 0.519630f, 0.526168f, 0.532702f, 0.539230f, 0.545751f, 0.552264f, + 0.558769f, 0.565263f, 0.571746f, 0.578217f, 0.584675f, 0.591118f, 0.597545f, 0.603956f, + 0.610349f, 0.616723f, 0.623077f, 0.629410f, 0.635720f, 0.642008f, 0.648271f, 0.654508f, + 0.660720f, 0.666903f, 0.673059f, 0.679184f, 0.685279f, 0.691342f, 0.697372f, 0.703368f, + 0.709330f, 0.715256f, 0.721144f, 0.726995f, 0.732807f, 0.738579f, 0.744311f, 0.750000f, + 0.755647f, 0.761249f, 0.766807f, 0.772320f, 0.777785f, 0.783203f, 0.788573f, 0.793893f, + 0.799162f, 0.804381f, 0.809547f, 0.814660f, 0.819720f, 0.824724f, 0.829673f, 0.834565f, + 0.839400f, 0.844177f, 0.848895f, 0.853553f, 0.858151f, 0.862687f, 0.867161f, 0.871572f, + 0.875920f, 0.880203f, 0.884421f, 0.888573f, 0.892658f, 0.896677f, 0.900627f, 0.904508f, + 0.908321f, 0.912063f, 0.915735f, 0.919335f, 0.922864f, 0.926320f, 0.929703f, 0.933013f, + 0.936248f, 0.939409f, 0.942494f, 0.945503f, 0.948436f, 0.951293f, 0.954072f, 0.956773f, + 0.959396f, 0.961940f, 0.964405f, 0.966790f, 0.969096f, 0.971321f, 0.973465f, 0.975528f, + 0.977510f, 0.979410f, 0.981228f, 0.982963f, 0.984615f, 0.986185f, 0.987671f, 0.989074f, + 0.990393f, 0.991627f, 0.992778f, 0.993844f, 0.994826f, 0.995722f, 0.996534f, 0.997261f, + 0.997902f, 0.998459f, 0.998929f, 0.999315f, 0.999615f, 0.999829f, 0.999957f, 1.000000f, +}; + +static const int tbands[NB_TBANDS+1] = { + 4, 8, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 136, 160, 192, 240 +}; + +#define NB_TONAL_SKIP_BANDS 9 + +static opus_val32 silk_resampler_down2_hp( + opus_val32 *S, /* I/O State vector [ 2 ] */ + opus_val32 *out, /* O Output signal [ floor(len/2) ] */ + const opus_val32 *in, /* I Input signal [ len ] */ + int inLen /* I Number of input samples */ +) +{ + int k, len2 = inLen/2; + opus_val32 in32, out32, out32_hp, Y, X; + opus_val64 hp_ener = 0; + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len2; k++ ) { + /* Convert to Q10 */ + in32 = in[ 2 * k ]; + + /* All-pass section for even input sample */ + Y = SUB32( in32, S[ 0 ] ); + X = MULT16_32_Q15(QCONST16(0.6074371f, 15), Y); + out32 = ADD32( S[ 0 ], X ); + S[ 0 ] = ADD32( in32, X ); + out32_hp = out32; + /* Convert to Q10 */ + in32 = in[ 2 * k + 1 ]; + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = SUB32( in32, S[ 1 ] ); + X = MULT16_32_Q15(QCONST16(0.15063f, 15), Y); + out32 = ADD32( out32, S[ 1 ] ); + out32 = ADD32( out32, X ); + S[ 1 ] = ADD32( in32, X ); + + Y = SUB32( -in32, S[ 2 ] ); + X = MULT16_32_Q15(QCONST16(0.15063f, 15), Y); + out32_hp = ADD32( out32_hp, S[ 2 ] ); + out32_hp = ADD32( out32_hp, X ); + S[ 2 ] = ADD32( -in32, X ); + + hp_ener += out32_hp*(opus_val64)out32_hp; + /* Add, convert back to int16 and store to output */ + out[ k ] = HALF32(out32); + } +#ifdef FIXED_POINT + /* len2 can be up to 480, so we shift by 8 more to make it fit. */ + hp_ener = hp_ener >> (2*SIG_SHIFT + 8); +#endif + return (opus_val32)hp_ener; +} + +static opus_val32 downmix_and_resample(downmix_func downmix, const void *_x, opus_val32 *y, opus_val32 S[3], int subframe, int offset, int c1, int c2, int C, int Fs) +{ + VARDECL(opus_val32, tmp); + opus_val32 scale; + int j; + opus_val32 ret = 0; + SAVE_STACK; + + if (subframe==0) return 0; + if (Fs == 48000) + { + subframe *= 2; + offset *= 2; + } else if (Fs == 16000) { + subframe = subframe*2/3; + offset = offset*2/3; + } + ALLOC(tmp, subframe, opus_val32); + + downmix(_x, tmp, subframe, offset, c1, c2, C); +#ifdef FIXED_POINT + scale = (1<-1) + scale /= 2; + for (j=0;jarch = opus_select_arch(); + tonal->Fs = Fs; + /* Clear remaining fields. */ + tonality_analysis_reset(tonal); +} + +void tonality_analysis_reset(TonalityAnalysisState *tonal) +{ + /* Clear non-reusable fields. */ + char *start = (char*)&tonal->TONALITY_ANALYSIS_RESET_START; + OPUS_CLEAR(start, sizeof(TonalityAnalysisState) - (start - (char*)tonal)); +} + +void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len) +{ + int pos; + int curr_lookahead; + float tonality_max; + float tonality_avg; + int tonality_count; + int i; + int pos0; + float prob_avg; + float prob_count; + float prob_min, prob_max; + float vad_prob; + int mpos, vpos; + int bandwidth_span; + + pos = tonal->read_pos; + curr_lookahead = tonal->write_pos-tonal->read_pos; + if (curr_lookahead<0) + curr_lookahead += DETECT_SIZE; + + tonal->read_subframe += len/(tonal->Fs/400); + while (tonal->read_subframe>=8) + { + tonal->read_subframe -= 8; + tonal->read_pos++; + } + if (tonal->read_pos>=DETECT_SIZE) + tonal->read_pos-=DETECT_SIZE; + + /* On long frames, look at the second analysis window rather than the first. */ + if (len > tonal->Fs/50 && pos != tonal->write_pos) + { + pos++; + if (pos==DETECT_SIZE) + pos=0; + } + if (pos == tonal->write_pos) + pos--; + if (pos<0) + pos = DETECT_SIZE-1; + pos0 = pos; + OPUS_COPY(info_out, &tonal->info[pos], 1); + if (!info_out->valid) + return; + tonality_max = tonality_avg = info_out->tonality; + tonality_count = 1; + /* Look at the neighbouring frames and pick largest bandwidth found (to be safe). */ + bandwidth_span = 6; + /* If possible, look ahead for a tone to compensate for the delay in the tone detector. */ + for (i=0;i<3;i++) + { + pos++; + if (pos==DETECT_SIZE) + pos = 0; + if (pos == tonal->write_pos) + break; + tonality_max = MAX32(tonality_max, tonal->info[pos].tonality); + tonality_avg += tonal->info[pos].tonality; + tonality_count++; + info_out->bandwidth = IMAX(info_out->bandwidth, tonal->info[pos].bandwidth); + bandwidth_span--; + } + pos = pos0; + /* Look back in time to see if any has a wider bandwidth than the current frame. */ + for (i=0;iwrite_pos) + break; + info_out->bandwidth = IMAX(info_out->bandwidth, tonal->info[pos].bandwidth); + } + info_out->tonality = MAX32(tonality_avg/tonality_count, tonality_max-.2f); + + mpos = vpos = pos0; + /* If we have enough look-ahead, compensate for the ~5-frame delay in the music prob and + ~1 frame delay in the VAD prob. */ + if (curr_lookahead > 15) + { + mpos += 5; + if (mpos>=DETECT_SIZE) + mpos -= DETECT_SIZE; + vpos += 1; + if (vpos>=DETECT_SIZE) + vpos -= DETECT_SIZE; + } + + /* The following calculations attempt to minimize a "badness function" + for the transition. When switching from speech to music, the badness + of switching at frame k is + b_k = S*v_k + \sum_{i=0}^{k-1} v_i*(p_i - T) + where + v_i is the activity probability (VAD) at frame i, + p_i is the music probability at frame i + T is the probability threshold for switching + S is the penalty for switching during active audio rather than silence + the current frame has index i=0 + + Rather than apply badness to directly decide when to switch, what we compute + instead is the threshold for which the optimal switching point is now. When + considering whether to switch now (frame 0) or at frame k, we have: + S*v_0 = S*v_k + \sum_{i=0}^{k-1} v_i*(p_i - T) + which gives us: + T = ( \sum_{i=0}^{k-1} v_i*p_i + S*(v_k-v_0) ) / ( \sum_{i=0}^{k-1} v_i ) + We take the min threshold across all positive values of k (up to the maximum + amount of lookahead we have) to give us the threshold for which the current + frame is the optimal switch point. + + The last step is that we need to consider whether we want to switch at all. + For that we use the average of the music probability over the entire window. + If the threshold is higher than that average we're not going to + switch, so we compute a min with the average as well. The result of all these + min operations is music_prob_min, which gives the threshold for switching to music + if we're currently encoding for speech. + + We do the exact opposite to compute music_prob_max which is used for switching + from music to speech. + */ + prob_min = 1.f; + prob_max = 0.f; + vad_prob = tonal->info[vpos].activity_probability; + prob_count = MAX16(.1f, vad_prob); + prob_avg = MAX16(.1f, vad_prob)*tonal->info[mpos].music_prob; + while (1) + { + float pos_vad; + mpos++; + if (mpos==DETECT_SIZE) + mpos = 0; + if (mpos == tonal->write_pos) + break; + vpos++; + if (vpos==DETECT_SIZE) + vpos = 0; + if (vpos == tonal->write_pos) + break; + pos_vad = tonal->info[vpos].activity_probability; + prob_min = MIN16((prob_avg - TRANSITION_PENALTY*(vad_prob - pos_vad))/prob_count, prob_min); + prob_max = MAX16((prob_avg + TRANSITION_PENALTY*(vad_prob - pos_vad))/prob_count, prob_max); + prob_count += MAX16(.1f, pos_vad); + prob_avg += MAX16(.1f, pos_vad)*tonal->info[mpos].music_prob; + } + info_out->music_prob = prob_avg/prob_count; + prob_min = MIN16(prob_avg/prob_count, prob_min); + prob_max = MAX16(prob_avg/prob_count, prob_max); + prob_min = MAX16(prob_min, 0.f); + prob_max = MIN16(prob_max, 1.f); + + /* If we don't have enough look-ahead, do our best to make a decent decision. */ + if (curr_lookahead < 10) + { + float pmin, pmax; + pmin = prob_min; + pmax = prob_max; + pos = pos0; + /* Look for min/max in the past. */ + for (i=0;icount-1, 15);i++) + { + pos--; + if (pos < 0) + pos = DETECT_SIZE-1; + pmin = MIN16(pmin, tonal->info[pos].music_prob); + pmax = MAX16(pmax, tonal->info[pos].music_prob); + } + /* Bias against switching on active audio. */ + pmin = MAX16(0.f, pmin - .1f*vad_prob); + pmax = MIN16(1.f, pmax + .1f*vad_prob); + prob_min += (1.f-.1f*curr_lookahead)*(pmin - prob_min); + prob_max += (1.f-.1f*curr_lookahead)*(pmax - prob_max); + } + info_out->music_prob_min = prob_min; + info_out->music_prob_max = prob_max; + + /* printf("%f %f %f %f %f\n", prob_min, prob_max, prob_avg/prob_count, vad_prob, info_out->music_prob); */ +} + +static const float std_feature_bias[9] = { + 5.684947f, 3.475288f, 1.770634f, 1.599784f, 3.773215f, + 2.163313f, 1.260756f, 1.116868f, 1.918795f +}; + +#define LEAKAGE_OFFSET 2.5f +#define LEAKAGE_SLOPE 2.f + +#ifdef FIXED_POINT +/* For fixed-point, the input is +/-2^15 shifted up by SIG_SHIFT, so we need to + compensate for that in the energy. */ +#define SCALE_COMPENS (1.f/((opus_int32)1<<(15+SIG_SHIFT))) +#define SCALE_ENER(e) ((SCALE_COMPENS*SCALE_COMPENS)*(e)) +#else +#define SCALE_ENER(e) (e) +#endif + +#ifdef FIXED_POINT +static int is_digital_silence32(const opus_val32* pcm, int frame_size, int channels, int lsb_depth) +{ + int silence = 0; + opus_val32 sample_max = 0; +#ifdef MLP_TRAINING + return 0; +#endif + sample_max = celt_maxabs32(pcm, frame_size*channels); + + silence = (sample_max == 0); + (void)lsb_depth; + return silence; +} +#else +#define is_digital_silence32(pcm, frame_size, channels, lsb_depth) is_digital_silence(pcm, frame_size, channels, lsb_depth) +#endif + +static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt_mode, const void *x, int len, int offset, int c1, int c2, int C, int lsb_depth, downmix_func downmix) +{ + int i, b; + const kiss_fft_state *kfft; + VARDECL(kiss_fft_cpx, in); + VARDECL(kiss_fft_cpx, out); + int N = 480, N2=240; + float * OPUS_RESTRICT A = tonal->angle; + float * OPUS_RESTRICT dA = tonal->d_angle; + float * OPUS_RESTRICT d2A = tonal->d2_angle; + VARDECL(float, tonality); + VARDECL(float, noisiness); + float band_tonality[NB_TBANDS]; + float logE[NB_TBANDS]; + float BFCC[8]; + float features[25]; + float frame_tonality; + float max_frame_tonality; + /*float tw_sum=0;*/ + float frame_noisiness; + const float pi4 = (float)(M_PI*M_PI*M_PI*M_PI); + float slope=0; + float frame_stationarity; + float relativeE; + float frame_probs[2]; + float alpha, alphaE, alphaE2; + float frame_loudness; + float bandwidth_mask; + int is_masked[NB_TBANDS+1]; + int bandwidth=0; + float maxE = 0; + float noise_floor; + int remaining; + AnalysisInfo *info; + float hp_ener; + float tonality2[240]; + float midE[8]; + float spec_variability=0; + float band_log2[NB_TBANDS+1]; + float leakage_from[NB_TBANDS+1]; + float leakage_to[NB_TBANDS+1]; + float layer_out[MAX_NEURONS]; + float below_max_pitch; + float above_max_pitch; + int is_silence; + SAVE_STACK; + + if (!tonal->initialized) + { + tonal->mem_fill = 240; + tonal->initialized = 1; + } + alpha = 1.f/IMIN(10, 1+tonal->count); + alphaE = 1.f/IMIN(25, 1+tonal->count); + /* Noise floor related decay for bandwidth detection: -2.2 dB/second */ + alphaE2 = 1.f/IMIN(100, 1+tonal->count); + if (tonal->count <= 1) alphaE2 = 1; + + if (tonal->Fs == 48000) + { + /* len and offset are now at 24 kHz. */ + len/= 2; + offset /= 2; + } else if (tonal->Fs == 16000) { + len = 3*len/2; + offset = 3*offset/2; + } + + kfft = celt_mode->mdct.kfft[0]; + tonal->hp_ener_accum += (float)downmix_and_resample(downmix, x, + &tonal->inmem[tonal->mem_fill], tonal->downmix_state, + IMIN(len, ANALYSIS_BUF_SIZE-tonal->mem_fill), offset, c1, c2, C, tonal->Fs); + if (tonal->mem_fill+len < ANALYSIS_BUF_SIZE) + { + tonal->mem_fill += len; + /* Don't have enough to update the analysis */ + RESTORE_STACK; + return; + } + hp_ener = tonal->hp_ener_accum; + info = &tonal->info[tonal->write_pos++]; + if (tonal->write_pos>=DETECT_SIZE) + tonal->write_pos-=DETECT_SIZE; + + is_silence = is_digital_silence32(tonal->inmem, ANALYSIS_BUF_SIZE, 1, lsb_depth); + + ALLOC(in, 480, kiss_fft_cpx); + ALLOC(out, 480, kiss_fft_cpx); + ALLOC(tonality, 240, float); + ALLOC(noisiness, 240, float); + for (i=0;iinmem[i]); + in[i].i = (kiss_fft_scalar)(w*tonal->inmem[N2+i]); + in[N-i-1].r = (kiss_fft_scalar)(w*tonal->inmem[N-i-1]); + in[N-i-1].i = (kiss_fft_scalar)(w*tonal->inmem[N+N2-i-1]); + } + OPUS_MOVE(tonal->inmem, tonal->inmem+ANALYSIS_BUF_SIZE-240, 240); + remaining = len - (ANALYSIS_BUF_SIZE-tonal->mem_fill); + tonal->hp_ener_accum = (float)downmix_and_resample(downmix, x, + &tonal->inmem[240], tonal->downmix_state, remaining, + offset+ANALYSIS_BUF_SIZE-tonal->mem_fill, c1, c2, C, tonal->Fs); + tonal->mem_fill = 240 + remaining; + if (is_silence) + { + /* On silence, copy the previous analysis. */ + int prev_pos = tonal->write_pos-2; + if (prev_pos < 0) + prev_pos += DETECT_SIZE; + OPUS_COPY(info, &tonal->info[prev_pos], 1); + RESTORE_STACK; + return; + } + opus_fft(kfft, in, out, tonal->arch); +#ifndef FIXED_POINT + /* If there's any NaN on the input, the entire output will be NaN, so we only need to check one value. */ + if (celt_isnan(out[0].r)) + { + info->valid = 0; + RESTORE_STACK; + return; + } +#endif + + for (i=1;iactivity = 0; + frame_noisiness = 0; + frame_stationarity = 0; + if (!tonal->count) + { + for (b=0;blowE[b] = 1e10; + tonal->highE[b] = -1e10; + } + } + relativeE = 0; + frame_loudness = 0; + /* The energy of the very first band is special because of DC. */ + { + float E = 0; + float X1r, X2r; + X1r = 2*(float)out[0].r; + X2r = 2*(float)out[0].i; + E = X1r*X1r + X2r*X2r; + for (i=1;i<4;i++) + { + float binE = out[i].r*(float)out[i].r + out[N-i].r*(float)out[N-i].r + + out[i].i*(float)out[i].i + out[N-i].i*(float)out[N-i].i; + E += binE; + } + E = SCALE_ENER(E); + band_log2[0] = .5f*1.442695f*(float)log(E+1e-10f); + } + for (b=0;bvalid = 0; + RESTORE_STACK; + return; + } +#endif + + tonal->E[tonal->E_count][b] = E; + frame_noisiness += nE/(1e-15f+E); + + frame_loudness += (float)sqrt(E+1e-10f); + logE[b] = (float)log(E+1e-10f); + band_log2[b+1] = .5f*1.442695f*(float)log(E+1e-10f); + tonal->logE[tonal->E_count][b] = logE[b]; + if (tonal->count==0) + tonal->highE[b] = tonal->lowE[b] = logE[b]; + if (tonal->highE[b] > tonal->lowE[b] + 7.5) + { + if (tonal->highE[b] - logE[b] > logE[b] - tonal->lowE[b]) + tonal->highE[b] -= .01f; + else + tonal->lowE[b] += .01f; + } + if (logE[b] > tonal->highE[b]) + { + tonal->highE[b] = logE[b]; + tonal->lowE[b] = MAX32(tonal->highE[b]-15, tonal->lowE[b]); + } else if (logE[b] < tonal->lowE[b]) + { + tonal->lowE[b] = logE[b]; + tonal->highE[b] = MIN32(tonal->lowE[b]+15, tonal->highE[b]); + } + relativeE += (logE[b]-tonal->lowE[b])/(1e-5f + (tonal->highE[b]-tonal->lowE[b])); + + L1=L2=0; + for (i=0;iE[i][b]); + L2 += tonal->E[i][b]; + } + + stationarity = MIN16(0.99f,L1/(float)sqrt(1e-15+NB_FRAMES*L2)); + stationarity *= stationarity; + stationarity *= stationarity; + frame_stationarity += stationarity; + /*band_tonality[b] = tE/(1e-15+E)*/; + band_tonality[b] = MAX16(tE/(1e-15f+E), stationarity*tonal->prev_band_tonality[b]); +#if 0 + if (b>=NB_TONAL_SKIP_BANDS) + { + frame_tonality += tweight[b]*band_tonality[b]; + tw_sum += tweight[b]; + } +#else + frame_tonality += band_tonality[b]; + if (b>=NB_TBANDS-NB_TONAL_SKIP_BANDS) + frame_tonality -= band_tonality[b-NB_TBANDS+NB_TONAL_SKIP_BANDS]; +#endif + max_frame_tonality = MAX16(max_frame_tonality, (1.f+.03f*(b-NB_TBANDS))*frame_tonality); + slope += band_tonality[b]*(b-8); + /*printf("%f %f ", band_tonality[b], stationarity);*/ + tonal->prev_band_tonality[b] = band_tonality[b]; + } + + leakage_from[0] = band_log2[0]; + leakage_to[0] = band_log2[0] - LEAKAGE_OFFSET; + for (b=1;b=0;b--) + { + float leak_slope = LEAKAGE_SLOPE*(tbands[b+1]-tbands[b])/4; + leakage_from[b] = MIN16(leakage_from[b+1]+leak_slope, leakage_from[b]); + leakage_to[b] = MAX16(leakage_to[b+1]-leak_slope, leakage_to[b]); + } + celt_assert(NB_TBANDS+1 <= LEAK_BANDS); + for (b=0;bleak_boost[b] = IMIN(255, (int)floor(.5 + 64.f*boost)); + } + for (;bleak_boost[b] = 0; + + for (i=0;ilogE[i][k] - tonal->logE[j][k]; + dist += tmp*tmp; + } + if (j!=i) + mindist = MIN32(mindist, dist); + } + spec_variability += mindist; + } + spec_variability = (float)sqrt(spec_variability/NB_FRAMES/NB_TBANDS); + bandwidth_mask = 0; + bandwidth = 0; + maxE = 0; + noise_floor = 5.7e-4f/(1<<(IMAX(0,lsb_depth-8))); + noise_floor *= noise_floor; + below_max_pitch=0; + above_max_pitch=0; + for (b=0;bmeanE[b] = MAX32((1-alphaE2)*tonal->meanE[b], E); + Em = MAX32(E, tonal->meanE[b]); + /* Consider the band "active" only if all these conditions are met: + 1) less than 90 dB below the peak band (maximal masking possible considering + both the ATH and the loudness-dependent slope of the spreading function) + 2) above the PCM quantization noise floor + We use b+1 because the first CELT band isn't included in tbands[] + */ + if (E*1e9f > maxE && (Em > 3*noise_floor*(band_end-band_start) || E > noise_floor*(band_end-band_start))) + bandwidth = b+1; + /* Check if the band is masked (see below). */ + is_masked[b] = E < (tonal->prev_bandwidth >= b+1 ? .01f : .05f)*bandwidth_mask; + /* Use a simple follower with 13 dB/Bark slope for spreading function. */ + bandwidth_mask = MAX32(.05f*bandwidth_mask, E); + } + /* Special case for the last two bands, for which we don't have spectrum but only + the energy above 12 kHz. The difficulty here is that the high-pass we use + leaks some LF energy, so we need to increase the threshold without accidentally cutting + off the band. */ + if (tonal->Fs == 48000) { + float noise_ratio; + float Em; + float E = hp_ener*(1.f/(60*60)); + noise_ratio = tonal->prev_bandwidth==20 ? 10.f : 30.f; + +#ifdef FIXED_POINT + /* silk_resampler_down2_hp() shifted right by an extra 8 bits. */ + E *= 256.f*(1.f/Q15ONE)*(1.f/Q15ONE); +#endif + above_max_pitch += E; + tonal->meanE[b] = MAX32((1-alphaE2)*tonal->meanE[b], E); + Em = MAX32(E, tonal->meanE[b]); + if (Em > 3*noise_ratio*noise_floor*160 || E > noise_ratio*noise_floor*160) + bandwidth = 20; + /* Check if the band is masked (see below). */ + is_masked[b] = E < (tonal->prev_bandwidth == 20 ? .01f : .05f)*bandwidth_mask; + } + if (above_max_pitch > below_max_pitch) + info->max_pitch_ratio = below_max_pitch/above_max_pitch; + else + info->max_pitch_ratio = 1; + /* In some cases, resampling aliasing can create a small amount of energy in the first band + being cut. So if the last band is masked, we don't include it. */ + if (bandwidth == 20 && is_masked[NB_TBANDS]) + bandwidth-=2; + else if (bandwidth > 0 && bandwidth <= NB_TBANDS && is_masked[bandwidth-1]) + bandwidth--; + if (tonal->count<=2) + bandwidth = 20; + frame_loudness = 20*(float)log10(frame_loudness); + tonal->Etracker = MAX32(tonal->Etracker-.003f, frame_loudness); + tonal->lowECount *= (1-alphaE); + if (frame_loudness < tonal->Etracker-30) + tonal->lowECount += alphaE; + + for (i=0;i<8;i++) + { + float sum=0; + for (b=0;b<16;b++) + sum += dct_table[i*16+b]*logE[b]; + BFCC[i] = sum; + } + for (i=0;i<8;i++) + { + float sum=0; + for (b=0;b<16;b++) + sum += dct_table[i*16+b]*.5f*(tonal->highE[b]+tonal->lowE[b]); + midE[i] = sum; + } + + frame_stationarity /= NB_TBANDS; + relativeE /= NB_TBANDS; + if (tonal->count<10) + relativeE = .5f; + frame_noisiness /= NB_TBANDS; +#if 1 + info->activity = frame_noisiness + (1-frame_noisiness)*relativeE; +#else + info->activity = .5*(1+frame_noisiness-frame_stationarity); +#endif + frame_tonality = (max_frame_tonality/(NB_TBANDS-NB_TONAL_SKIP_BANDS)); + frame_tonality = MAX16(frame_tonality, tonal->prev_tonality*.8f); + tonal->prev_tonality = frame_tonality; + + slope /= 8*8; + info->tonality_slope = slope; + + tonal->E_count = (tonal->E_count+1)%NB_FRAMES; + tonal->count = IMIN(tonal->count+1, ANALYSIS_COUNT_MAX); + info->tonality = frame_tonality; + + for (i=0;i<4;i++) + features[i] = -0.12299f*(BFCC[i]+tonal->mem[i+24]) + 0.49195f*(tonal->mem[i]+tonal->mem[i+16]) + 0.69693f*tonal->mem[i+8] - 1.4349f*tonal->cmean[i]; + + for (i=0;i<4;i++) + tonal->cmean[i] = (1-alpha)*tonal->cmean[i] + alpha*BFCC[i]; + + for (i=0;i<4;i++) + features[4+i] = 0.63246f*(BFCC[i]-tonal->mem[i+24]) + 0.31623f*(tonal->mem[i]-tonal->mem[i+16]); + for (i=0;i<3;i++) + features[8+i] = 0.53452f*(BFCC[i]+tonal->mem[i+24]) - 0.26726f*(tonal->mem[i]+tonal->mem[i+16]) -0.53452f*tonal->mem[i+8]; + + if (tonal->count > 5) + { + for (i=0;i<9;i++) + tonal->std[i] = (1-alpha)*tonal->std[i] + alpha*features[i]*features[i]; + } + for (i=0;i<4;i++) + features[i] = BFCC[i]-midE[i]; + + for (i=0;i<8;i++) + { + tonal->mem[i+24] = tonal->mem[i+16]; + tonal->mem[i+16] = tonal->mem[i+8]; + tonal->mem[i+8] = tonal->mem[i]; + tonal->mem[i] = BFCC[i]; + } + for (i=0;i<9;i++) + features[11+i] = (float)sqrt(tonal->std[i]) - std_feature_bias[i]; + features[18] = spec_variability - 0.78f; + features[20] = info->tonality - 0.154723f; + features[21] = info->activity - 0.724643f; + features[22] = frame_stationarity - 0.743717f; + features[23] = info->tonality_slope + 0.069216f; + features[24] = tonal->lowECount - 0.067930f; + + compute_dense(&layer0, layer_out, features); + compute_gru(&layer1, tonal->rnn_state, layer_out); + compute_dense(&layer2, frame_probs, tonal->rnn_state); + + /* Probability of speech or music vs noise */ + info->activity_probability = frame_probs[1]; + info->music_prob = frame_probs[0]; + + /*printf("%f %f %f\n", frame_probs[0], frame_probs[1], info->music_prob);*/ +#ifdef MLP_TRAINING + for (i=0;i<25;i++) + printf("%f ", features[i]); + printf("\n"); +#endif + + info->bandwidth = bandwidth; + tonal->prev_bandwidth = bandwidth; + /*printf("%d %d\n", info->bandwidth, info->opus_bandwidth);*/ + info->noisiness = frame_noisiness; + info->valid = 1; + RESTORE_STACK; +} + +void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm, + int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs, + int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info) +{ + int offset; + int pcm_len; + + analysis_frame_size -= analysis_frame_size&1; + if (analysis_pcm != NULL) + { + /* Avoid overflow/wrap-around of the analysis buffer */ + analysis_frame_size = IMIN((DETECT_SIZE-5)*Fs/50, analysis_frame_size); + + pcm_len = analysis_frame_size - analysis->analysis_offset; + offset = analysis->analysis_offset; + while (pcm_len>0) { + tonality_analysis(analysis, celt_mode, analysis_pcm, IMIN(Fs/50, pcm_len), offset, c1, c2, C, lsb_depth, downmix); + offset += Fs/50; + pcm_len -= Fs/50; + } + analysis->analysis_offset = analysis_frame_size; + + analysis->analysis_offset -= frame_size; + } + + tonality_get_info(analysis, analysis_info, frame_size); +} + +#endif /* DISABLE_FLOAT_API */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/analysis.h b/native/opennow-streamer/vendor/audiopus-sys/opus/src/analysis.h new file mode 100644 index 000000000..0b66555f2 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/analysis.h @@ -0,0 +1,103 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 FOUNDATION 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. +*/ + +#ifndef ANALYSIS_H +#define ANALYSIS_H + +#include "celt.h" +#include "opus_private.h" +#include "mlp.h" + +#define NB_FRAMES 8 +#define NB_TBANDS 18 +#define ANALYSIS_BUF_SIZE 720 /* 30 ms at 24 kHz */ + +/* At that point we can stop counting frames because it no longer matters. */ +#define ANALYSIS_COUNT_MAX 10000 + +#define DETECT_SIZE 100 + +/* Uncomment this to print the MLP features on stdout. */ +/*#define MLP_TRAINING*/ + +typedef struct { + int arch; + int application; + opus_int32 Fs; +#define TONALITY_ANALYSIS_RESET_START angle + float angle[240]; + float d_angle[240]; + float d2_angle[240]; + opus_val32 inmem[ANALYSIS_BUF_SIZE]; + int mem_fill; /* number of usable samples in the buffer */ + float prev_band_tonality[NB_TBANDS]; + float prev_tonality; + int prev_bandwidth; + float E[NB_FRAMES][NB_TBANDS]; + float logE[NB_FRAMES][NB_TBANDS]; + float lowE[NB_TBANDS]; + float highE[NB_TBANDS]; + float meanE[NB_TBANDS+1]; + float mem[32]; + float cmean[8]; + float std[9]; + float Etracker; + float lowECount; + int E_count; + int count; + int analysis_offset; + int write_pos; + int read_pos; + int read_subframe; + float hp_ener_accum; + int initialized; + float rnn_state[MAX_NEURONS]; + opus_val32 downmix_state[3]; + AnalysisInfo info[DETECT_SIZE]; +} TonalityAnalysisState; + +/** Initialize a TonalityAnalysisState struct. + * + * This performs some possibly slow initialization steps which should + * not be repeated every analysis step. No allocated memory is retained + * by the state struct, so no cleanup call is required. + */ +void tonality_analysis_init(TonalityAnalysisState *analysis, opus_int32 Fs); + +/** Reset a TonalityAnalysisState stuct. + * + * Call this when there's a discontinuity in the data. + */ +void tonality_analysis_reset(TonalityAnalysisState *analysis); + +void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len); + +void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm, + int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs, + int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info); + +#endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/mapping_matrix.c b/native/opennow-streamer/vendor/audiopus-sys/opus/src/mapping_matrix.c new file mode 100644 index 000000000..31298af05 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/mapping_matrix.c @@ -0,0 +1,378 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arch.h" +#include "float_cast.h" +#include "opus_private.h" +#include "opus_defines.h" +#include "mapping_matrix.h" + +#define MATRIX_INDEX(nb_rows, row, col) (nb_rows * col + row) + +opus_int32 mapping_matrix_get_size(int rows, int cols) +{ + opus_int32 size; + + /* Mapping Matrix must only support up to 255 channels in or out. + * Additionally, the total cell count must be <= 65004 octets in order + * for the matrix to be stored in an OGG header. + */ + if (rows > 255 || cols > 255) + return 0; + size = rows * (opus_int32)cols * sizeof(opus_int16); + if (size > 65004) + return 0; + + return align(sizeof(MappingMatrix)) + align(size); +} + +opus_int16 *mapping_matrix_get_data(const MappingMatrix *matrix) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (opus_int16*)(void*)((char*)matrix + align(sizeof(MappingMatrix))); +} + +void mapping_matrix_init(MappingMatrix * const matrix, + int rows, int cols, int gain, const opus_int16 *data, opus_int32 data_size) +{ + int i; + opus_int16 *ptr; + +#if !defined(ENABLE_ASSERTIONS) + (void)data_size; +#endif + celt_assert(align(data_size) == align(rows * cols * sizeof(opus_int16))); + + matrix->rows = rows; + matrix->cols = cols; + matrix->gain = gain; + ptr = mapping_matrix_get_data(matrix); + for (i = 0; i < rows * cols; i++) + { + ptr[i] = data[i]; + } +} + +#ifndef DISABLE_FLOAT_API +void mapping_matrix_multiply_channel_in_float( + const MappingMatrix *matrix, + const float *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, col; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { + float tmp = 0; + for (col = 0; col < input_rows; col++) + { + tmp += + matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * + input[MATRIX_INDEX(input_rows, col, i)]; + } +#if defined(FIXED_POINT) + output[output_rows * i] = FLOAT2INT16((1/32768.f)*tmp); +#else + output[output_rows * i] = (1/32768.f)*tmp; +#endif + } +} + +void mapping_matrix_multiply_channel_out_float( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + float *output, + int output_rows, + int frame_size +) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, row; + float input_sample; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { +#if defined(FIXED_POINT) + input_sample = (1/32768.f)*input[input_rows * i]; +#else + input_sample = input[input_rows * i]; +#endif + for (row = 0; row < output_rows; row++) + { + float tmp = + (1/32768.f)*matrix_data[MATRIX_INDEX(matrix->rows, row, input_row)] * + input_sample; + output[MATRIX_INDEX(output_rows, row, i)] += tmp; + } + } +} +#endif /* DISABLE_FLOAT_API */ + +void mapping_matrix_multiply_channel_in_short( + const MappingMatrix *matrix, + const opus_int16 *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, col; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { + opus_val32 tmp = 0; + for (col = 0; col < input_rows; col++) + { +#if defined(FIXED_POINT) + tmp += + ((opus_int32)matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * + (opus_int32)input[MATRIX_INDEX(input_rows, col, i)]) >> 8; +#else + tmp += + matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * + input[MATRIX_INDEX(input_rows, col, i)]; +#endif + } +#if defined(FIXED_POINT) + output[output_rows * i] = (opus_int16)((tmp + 64) >> 7); +#else + output[output_rows * i] = (1/(32768.f*32768.f))*tmp; +#endif + } +} + +void mapping_matrix_multiply_channel_out_short( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + opus_int16 *output, + int output_rows, + int frame_size) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, row; + opus_int32 input_sample; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { +#if defined(FIXED_POINT) + input_sample = (opus_int32)input[input_rows * i]; +#else + input_sample = (opus_int32)FLOAT2INT16(input[input_rows * i]); +#endif + for (row = 0; row < output_rows; row++) + { + opus_int32 tmp = + (opus_int32)matrix_data[MATRIX_INDEX(matrix->rows, row, input_row)] * + input_sample; + output[MATRIX_INDEX(output_rows, row, i)] += (tmp + 16384) >> 15; + } + } +} + +const MappingMatrix mapping_matrix_foa_mixing = { 6, 6, 0 }; +const opus_int16 mapping_matrix_foa_mixing_data[36] = { + 16384, 0, -16384, 23170, 0, 0, 16384, 23170, + 16384, 0, 0, 0, 16384, 0, -16384, -23170, + 0, 0, 16384, -23170, 16384, 0, 0, 0, + 0, 0, 0, 0, 32767, 0, 0, 0, + 0, 0, 0, 32767 +}; + +const MappingMatrix mapping_matrix_soa_mixing = { 11, 11, 0 }; +const opus_int16 mapping_matrix_soa_mixing_data[121] = { + 10923, 7723, 13377, -13377, 11585, 9459, 7723, -16384, + -6689, 0, 0, 10923, 7723, 13377, 13377, -11585, + 9459, 7723, 16384, -6689, 0, 0, 10923, -15447, + 13377, 0, 0, -18919, 7723, 0, 13377, 0, + 0, 10923, 7723, -13377, -13377, 11585, -9459, 7723, + 16384, -6689, 0, 0, 10923, -7723, 0, 13377, + -16384, 0, -15447, 0, 9459, 0, 0, 10923, + -7723, 0, -13377, 16384, 0, -15447, 0, 9459, + 0, 0, 10923, 15447, 0, 0, 0, 0, + -15447, 0, -18919, 0, 0, 10923, 7723, -13377, + 13377, -11585, -9459, 7723, -16384, -6689, 0, 0, + 10923, -15447, -13377, 0, 0, 18919, 7723, 0, + 13377, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32767, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32767 +}; + +const MappingMatrix mapping_matrix_toa_mixing = { 18, 18, 0 }; +const opus_int16 mapping_matrix_toa_mixing_data[324] = { + 8208, 0, -881, 14369, 0, 0, -8192, -4163, + 13218, 0, 0, 0, 11095, -8836, -6218, 14833, + 0, 0, 8208, -10161, 881, 10161, -13218, -2944, + -8192, 2944, 0, -10488, -6218, 6248, -11095, -6248, + 0, -10488, 0, 0, 8208, 10161, 881, -10161, + -13218, 2944, -8192, -2944, 0, 10488, -6218, -6248, + -11095, 6248, 0, 10488, 0, 0, 8176, 5566, + -11552, 5566, 9681, -11205, 8192, -11205, 0, 4920, + -15158, 9756, -3334, 9756, 0, -4920, 0, 0, + 8176, 7871, 11552, 0, 0, 15846, 8192, 0, + -9681, -6958, 0, 13797, 3334, 0, -15158, 0, + 0, 0, 8176, 0, 11552, 7871, 0, 0, + 8192, 15846, 9681, 0, 0, 0, 3334, 13797, + 15158, 6958, 0, 0, 8176, 5566, -11552, -5566, + -9681, -11205, 8192, 11205, 0, 4920, 15158, 9756, + -3334, -9756, 0, 4920, 0, 0, 8208, 14369, + -881, 0, 0, -4163, -8192, 0, -13218, -14833, + 0, -8836, 11095, 0, 6218, 0, 0, 0, + 8208, 10161, 881, 10161, 13218, 2944, -8192, 2944, + 0, 10488, 6218, -6248, -11095, -6248, 0, -10488, + 0, 0, 8208, -14369, -881, 0, 0, 4163, + -8192, 0, -13218, 14833, 0, 8836, 11095, 0, + 6218, 0, 0, 0, 8208, 0, -881, -14369, + 0, 0, -8192, 4163, 13218, 0, 0, 0, + 11095, 8836, -6218, -14833, 0, 0, 8176, -5566, + -11552, 5566, -9681, 11205, 8192, -11205, 0, -4920, + 15158, -9756, -3334, 9756, 0, -4920, 0, 0, + 8176, 0, 11552, -7871, 0, 0, 8192, -15846, + 9681, 0, 0, 0, 3334, -13797, 15158, -6958, + 0, 0, 8176, -7871, 11552, 0, 0, -15846, + 8192, 0, -9681, 6958, 0, -13797, 3334, 0, + -15158, 0, 0, 0, 8176, -5566, -11552, -5566, + 9681, 11205, 8192, 11205, 0, -4920, -15158, -9756, + -3334, -9756, 0, 4920, 0, 0, 8208, -10161, + 881, -10161, 13218, -2944, -8192, -2944, 0, -10488, + 6218, 6248, -11095, 6248, 0, 10488, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32767, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32767 +}; + +const MappingMatrix mapping_matrix_foa_demixing = { 6, 6, 0 }; +const opus_int16 mapping_matrix_foa_demixing_data[36] = { + 16384, 16384, 16384, 16384, 0, 0, 0, 23170, + 0, -23170, 0, 0, -16384, 16384, -16384, 16384, + 0, 0, 23170, 0, -23170, 0, 0, 0, + 0, 0, 0, 0, 32767, 0, 0, 0, + 0, 0, 0, 32767 +}; + +const MappingMatrix mapping_matrix_soa_demixing = { 11, 11, 3050 }; +const opus_int16 mapping_matrix_soa_demixing_data[121] = { + 2771, 2771, 2771, 2771, 2771, 2771, 2771, 2771, + 2771, 0, 0, 10033, 10033, -20066, 10033, 14189, + 14189, -28378, 10033, -20066, 0, 0, 3393, 3393, + 3393, -3393, 0, 0, 0, -3393, -3393, 0, + 0, -17378, 17378, 0, -17378, -24576, 24576, 0, + 17378, 0, 0, 0, -14189, 14189, 0, -14189, + -28378, 28378, 0, 14189, 0, 0, 0, 2399, + 2399, -4799, -2399, 0, 0, 0, -2399, 4799, + 0, 0, 1959, 1959, 1959, 1959, -3918, -3918, + -3918, 1959, 1959, 0, 0, -4156, 4156, 0, + 4156, 0, 0, 0, -4156, 0, 0, 0, + 8192, 8192, -16384, 8192, 16384, 16384, -32768, 8192, + -16384, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8312, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8312 +}; + +const MappingMatrix mapping_matrix_toa_demixing = { 18, 18, 0 }; +const opus_int16 mapping_matrix_toa_demixing_data[324] = { + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 0, 0, 0, -9779, 9779, 6263, 8857, 0, + 6263, 13829, 9779, -13829, 0, -6263, 0, -8857, + -6263, -9779, 0, 0, -3413, 3413, 3413, -11359, + 11359, 11359, -11359, -3413, 3413, -3413, -3413, -11359, + 11359, 11359, -11359, 3413, 0, 0, 13829, 9779, + -9779, 6263, 0, 8857, -6263, 0, 9779, 0, + -13829, 6263, -8857, 0, -6263, -9779, 0, 0, + 0, -15617, -15617, 6406, 0, 0, -6406, 0, + 15617, 0, 0, -6406, 0, 0, 6406, 15617, + 0, 0, 0, -5003, 5003, -10664, 15081, 0, + -10664, -7075, 5003, 7075, 0, 10664, 0, -15081, + 10664, -5003, 0, 0, -8176, -8176, -8176, 8208, + 8208, 8208, 8208, -8176, -8176, -8176, -8176, 8208, + 8208, 8208, 8208, -8176, 0, 0, -7075, 5003, + -5003, -10664, 0, 15081, 10664, 0, 5003, 0, + 7075, -10664, -15081, 0, 10664, -5003, 0, 0, + 15617, 0, 0, 0, -6406, 6406, 0, -15617, + 0, -15617, 15617, 0, 6406, -6406, 0, 0, + 0, 0, 0, -11393, 11393, 2993, -4233, 0, + 2993, -16112, 11393, 16112, 0, -2993, 0, 4233, + -2993, -11393, 0, 0, 0, -9974, -9974, -13617, + 0, 0, 13617, 0, 9974, 0, 0, 13617, + 0, 0, -13617, 9974, 0, 0, 0, 5579, + -5579, 10185, 14403, 0, 10185, -7890, -5579, 7890, + 0, -10185, 0, -14403, -10185, 5579, 0, 0, + 11826, -11826, -11826, -901, 901, 901, -901, 11826, + -11826, 11826, 11826, -901, 901, 901, -901, -11826, + 0, 0, -7890, -5579, 5579, 10185, 0, 14403, + -10185, 0, -5579, 0, 7890, 10185, -14403, 0, + -10185, 5579, 0, 0, -9974, 0, 0, 0, + -13617, 13617, 0, 9974, 0, 9974, -9974, 0, + 13617, -13617, 0, 0, 0, 0, 16112, -11393, + 11393, -2993, 0, 4233, 2993, 0, -11393, 0, + -16112, -2993, -4233, 0, 2993, 11393, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32767, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32767 +}; + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/mapping_matrix.h b/native/opennow-streamer/vendor/audiopus-sys/opus/src/mapping_matrix.h new file mode 100644 index 000000000..98bc82df3 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/mapping_matrix.h @@ -0,0 +1,133 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +/** + * @file mapping_matrix.h + * @brief Opus reference implementation mapping matrix API + */ + +#ifndef MAPPING_MATRIX_H +#define MAPPING_MATRIX_H + +#include "opus_types.h" +#include "opus_projection.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MappingMatrix +{ + int rows; /* number of channels outputted from matrix. */ + int cols; /* number of channels inputted to matrix. */ + int gain; /* in dB. S7.8-format. */ + /* Matrix cell data goes here using col-wise ordering. */ +} MappingMatrix; + +opus_int32 mapping_matrix_get_size(int rows, int cols); + +opus_int16 *mapping_matrix_get_data(const MappingMatrix *matrix); + +void mapping_matrix_init( + MappingMatrix * const matrix, + int rows, + int cols, + int gain, + const opus_int16 *data, + opus_int32 data_size +); + +#ifndef DISABLE_FLOAT_API +void mapping_matrix_multiply_channel_in_float( + const MappingMatrix *matrix, + const float *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size +); + +void mapping_matrix_multiply_channel_out_float( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + float *output, + int output_rows, + int frame_size +); +#endif /* DISABLE_FLOAT_API */ + +void mapping_matrix_multiply_channel_in_short( + const MappingMatrix *matrix, + const opus_int16 *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size +); + +void mapping_matrix_multiply_channel_out_short( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + opus_int16 *output, + int output_rows, + int frame_size +); + +/* Pre-computed mixing and demixing matrices for 1st to 3rd-order ambisonics. + * foa: first-order ambisonics + * soa: second-order ambisonics + * toa: third-order ambisonics + */ +extern const MappingMatrix mapping_matrix_foa_mixing; +extern const opus_int16 mapping_matrix_foa_mixing_data[36]; + +extern const MappingMatrix mapping_matrix_soa_mixing; +extern const opus_int16 mapping_matrix_soa_mixing_data[121]; + +extern const MappingMatrix mapping_matrix_toa_mixing; +extern const opus_int16 mapping_matrix_toa_mixing_data[324]; + +extern const MappingMatrix mapping_matrix_foa_demixing; +extern const opus_int16 mapping_matrix_foa_demixing_data[36]; + +extern const MappingMatrix mapping_matrix_soa_demixing; +extern const opus_int16 mapping_matrix_soa_demixing_data[121]; + +extern const MappingMatrix mapping_matrix_toa_demixing; +extern const opus_int16 mapping_matrix_toa_demixing_data[324]; + +#ifdef __cplusplus +} +#endif + +#endif /* MAPPING_MATRIX_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/meson.build b/native/opennow-streamer/vendor/audiopus-sys/opus/src/meson.build new file mode 100644 index 000000000..cc07ff06e --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/meson.build @@ -0,0 +1,45 @@ +opus_sources = sources['OPUS_SOURCES'] + +opus_sources_float = sources['OPUS_SOURCES_FLOAT'] + +if not disable_float_api + opus_sources += opus_sources_float +endif + +opus_lib_c_args = [] +if host_machine.system() == 'windows' + opus_lib_c_args += ['-DDLL_EXPORT'] +endif + +opus_lib = library('opus', + opus_sources, + version: libversion, + darwin_versions: macosversion, + c_args: opus_lib_c_args, + include_directories: opus_includes, + link_with: [celt_lib, silk_lib], + dependencies: libm, + install: true) + +opus_dep = declare_dependency(link_with: opus_lib, + include_directories: opus_public_includes) + +# Extra uninstalled Opus programs +if not extra_programs.disabled() + foreach prog : ['opus_compare', 'opus_demo', 'repacketizer_demo'] + executable(prog, '@0@.c'.format(prog), + include_directories: opus_includes, + link_with: opus_lib, + dependencies: libm, + install: false) + endforeach + + if opt_custom_modes + executable('opus_custom_demo', '../celt/opus_custom_demo.c', + include_directories: opus_includes, + link_with: opus_lib, + dependencies: libm, + install: false) + endif + +endif diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/mlp.c b/native/opennow-streamer/vendor/audiopus-sys/opus/src/mlp.c new file mode 100644 index 000000000..964c6a98f --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/mlp.c @@ -0,0 +1,144 @@ +/* Copyright (c) 2008-2011 Octasic Inc. + 2012-2017 Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 FOUNDATION 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "opus_types.h" +#include "opus_defines.h" +#include "arch.h" +#include "tansig_table.h" +#include "mlp.h" + +static OPUS_INLINE float tansig_approx(float x) +{ + int i; + float y, dy; + float sign=1; + /* Tests are reversed to catch NaNs */ + if (!(x<8)) + return 1; + if (!(x>-8)) + return -1; +#ifndef FIXED_POINT + /* Another check in case of -ffast-math */ + if (celt_isnan(x)) + return 0; +#endif + if (x<0) + { + x=-x; + sign=-1; + } + i = (int)floor(.5f+25*x); + x -= .04f*i; + y = tansig_table[i]; + dy = 1-y*y; + y = y + x*dy*(1 - y*x); + return sign*y; +} + +static OPUS_INLINE float sigmoid_approx(float x) +{ + return .5f + .5f*tansig_approx(.5f*x); +} + +static void gemm_accum(float *out, const opus_int8 *weights, int rows, int cols, int col_stride, const float *x) +{ + int i, j; + for (i=0;inb_inputs; + N = layer->nb_neurons; + stride = N; + for (i=0;ibias[i]; + gemm_accum(output, layer->input_weights, N, M, stride, input); + for (i=0;isigmoid) { + for (i=0;inb_inputs; + N = gru->nb_neurons; + stride = 3*N; + /* Compute update gate. */ + for (i=0;ibias[i]; + gemm_accum(z, gru->input_weights, N, M, stride, input); + gemm_accum(z, gru->recurrent_weights, N, N, stride, state); + for (i=0;ibias[N + i]; + gemm_accum(r, &gru->input_weights[N], N, M, stride, input); + gemm_accum(r, &gru->recurrent_weights[N], N, N, stride, state); + for (i=0;ibias[2*N + i]; + for (i=0;iinput_weights[2*N], N, M, stride, input); + gemm_accum(h, &gru->recurrent_weights[2*N], N, N, stride, tmp); + for (i=0;i=0) + break; + x[i*C] = x[i*C]+a*x[i*C]*x[i*C]; + } + + curr=0; + x0 = x[0]; + while(1) + { + int start, end; + float maxval; + int special=0; + int peak_pos; + for (i=curr;i1 || x[i*C]<-1) + break; + } + if (i==N) + { + a=0; + break; + } + peak_pos = i; + start=end=i; + maxval=ABS16(x[i*C]); + /* Look for first zero crossing before clipping */ + while (start>0 && x[i*C]*x[(start-1)*C]>=0) + start--; + /* Look for first zero crossing after clipping */ + while (end=0) + { + /* Look for other peaks until the next zero-crossing. */ + if (ABS16(x[end*C])>maxval) + { + maxval = ABS16(x[end*C]); + peak_pos = end; + } + end++; + } + /* Detect the special case where we clip before the first zero crossing */ + special = (start==0 && x[i*C]*x[0]>=0); + + /* Compute a such that maxval + a*maxval^2 = 1 */ + a=(maxval-1)/(maxval*maxval); + /* Slightly boost "a" by 2^-22. This is just enough to ensure -ffast-math + does not cause output values larger than +/-1, but small enough not + to matter even for 24-bit output. */ + a += a*2.4e-7f; + if (x[i*C]>0) + a = -a; + /* Apply soft clipping */ + for (i=start;i=2) + { + /* Add a linear ramp from the first sample to the signal peak. + This avoids a discontinuity at the beginning of the frame. */ + float delta; + float offset = x0-x[0]; + delta = offset / peak_pos; + for (i=curr;i>2; + return 2; + } +} + +static int parse_size(const unsigned char *data, opus_int32 len, opus_int16 *size) +{ + if (len<1) + { + *size = -1; + return -1; + } else if (data[0]<252) + { + *size = data[0]; + return 1; + } else if (len<2) + { + *size = -1; + return -1; + } else { + *size = 4*data[1] + data[0]; + return 2; + } +} + +int opus_packet_get_samples_per_frame(const unsigned char *data, + opus_int32 Fs) +{ + int audiosize; + if (data[0]&0x80) + { + audiosize = ((data[0]>>3)&0x3); + audiosize = (Fs<>3)&0x3); + if (audiosize == 3) + audiosize = Fs*60/1000; + else + audiosize = (Fs< len) + return OPUS_INVALID_PACKET; + data += bytes; + last_size = len-size[0]; + break; + /* Multiple CBR/VBR frames (from 0 to 120 ms) */ + default: /*case 3:*/ + if (len<1) + return OPUS_INVALID_PACKET; + /* Number of frames encoded in bits 0 to 5 */ + ch = *data++; + count = ch&0x3F; + if (count <= 0 || framesize*(opus_int32)count > 5760) + return OPUS_INVALID_PACKET; + len--; + /* Padding flag is bit 6 */ + if (ch&0x40) + { + int p; + do { + int tmp; + if (len<=0) + return OPUS_INVALID_PACKET; + p = *data++; + len--; + tmp = p==255 ? 254: p; + len -= tmp; + pad += tmp; + } while (p==255); + } + if (len<0) + return OPUS_INVALID_PACKET; + /* VBR flag is bit 7 */ + cbr = !(ch&0x80); + if (!cbr) + { + /* VBR case */ + last_size = len; + for (i=0;i len) + return OPUS_INVALID_PACKET; + data += bytes; + last_size -= bytes+size[i]; + } + if (last_size<0) + return OPUS_INVALID_PACKET; + } else if (!self_delimited) + { + /* CBR case */ + last_size = len/count; + if (last_size*count!=len) + return OPUS_INVALID_PACKET; + for (i=0;i len) + return OPUS_INVALID_PACKET; + data += bytes; + /* For CBR packets, apply the size to all the frames. */ + if (cbr) + { + if (size[count-1]*count > len) + return OPUS_INVALID_PACKET; + for (i=0;i last_size) + return OPUS_INVALID_PACKET; + } else + { + /* Because it's not encoded explicitly, it's possible the size of the + last packet (or all the packets, for the CBR case) is larger than + 1275. Reject them here.*/ + if (last_size > 1275) + return OPUS_INVALID_PACKET; + size[count-1] = (opus_int16)last_size; + } + + if (payload_offset) + *payload_offset = (int)(data-data0); + + for (i=0;i +#include +#include +#include + +#define OPUS_PI (3.14159265F) + +#define OPUS_COSF(_x) ((float)cos(_x)) +#define OPUS_SINF(_x) ((float)sin(_x)) + +static void *check_alloc(void *_ptr){ + if(_ptr==NULL){ + fprintf(stderr,"Out of memory.\n"); + exit(EXIT_FAILURE); + } + return _ptr; +} + +static void *opus_malloc(size_t _size){ + return check_alloc(malloc(_size)); +} + +static void *opus_realloc(void *_ptr,size_t _size){ + return check_alloc(realloc(_ptr,_size)); +} + +static size_t read_pcm16(float **_samples,FILE *_fin,int _nchannels){ + unsigned char buf[1024]; + float *samples; + size_t nsamples; + size_t csamples; + size_t xi; + size_t nread; + samples=NULL; + nsamples=csamples=0; + for(;;){ + nread=fread(buf,2*_nchannels,1024/(2*_nchannels),_fin); + if(nread<=0)break; + if(nsamples+nread>csamples){ + do csamples=csamples<<1|1; + while(nsamples+nread>csamples); + samples=(float *)opus_realloc(samples, + _nchannels*csamples*sizeof(*samples)); + } + for(xi=0;xi=_window_sz)ti-=_window_sz; + } + re*=_downsample; + im*=_downsample; + _ps[(xi*ps_sz+xj)*_nchannels+ci]=re*re+im*im+100000; + p[ci]+=_ps[(xi*ps_sz+xj)*_nchannels+ci]; + } + } + if(_out){ + _out[(xi*_nbands+bi)*_nchannels]=p[0]/(_bands[bi+1]-_bands[bi]); + if(_nchannels==2){ + _out[(xi*_nbands+bi)*_nchannels+1]=p[1]/(_bands[bi+1]-_bands[bi]); + } + } + } + } + free(window); +} + +#define NBANDS (21) +#define NFREQS (240) + +/*Bands on which we compute the pseudo-NMR (Bark-derived + CELT bands).*/ +static const int BANDS[NBANDS+1]={ + 0,2,4,6,8,10,12,14,16,20,24,28,32,40,48,56,68,80,96,120,156,200 +}; + +#define TEST_WIN_SIZE (480) +#define TEST_WIN_STEP (120) + +int main(int _argc,const char **_argv){ + FILE *fin1; + FILE *fin2; + float *x; + float *y; + float *xb; + float *X; + float *Y; + double err; + float Q; + size_t xlength; + size_t ylength; + size_t nframes; + size_t xi; + int ci; + int xj; + int bi; + int nchannels; + unsigned rate; + int downsample; + int ybands; + int yfreqs; + int max_compare; + if(_argc<3||_argc>6){ + fprintf(stderr,"Usage: %s [-s] [-r rate2] \n", + _argv[0]); + return EXIT_FAILURE; + } + nchannels=1; + if(strcmp(_argv[1],"-s")==0){ + nchannels=2; + _argv++; + } + rate=48000; + ybands=NBANDS; + yfreqs=NFREQS; + downsample=1; + if(strcmp(_argv[1],"-r")==0){ + rate=atoi(_argv[2]); + if(rate!=8000&&rate!=12000&&rate!=16000&&rate!=24000&&rate!=48000){ + fprintf(stderr, + "Sampling rate must be 8000, 12000, 16000, 24000, or 48000\n"); + return EXIT_FAILURE; + } + downsample=48000/rate; + switch(rate){ + case 8000:ybands=13;break; + case 12000:ybands=15;break; + case 16000:ybands=17;break; + case 24000:ybands=19;break; + } + yfreqs=NFREQS/downsample; + _argv+=2; + } + fin1=fopen(_argv[1],"rb"); + if(fin1==NULL){ + fprintf(stderr,"Error opening '%s'.\n",_argv[1]); + return EXIT_FAILURE; + } + fin2=fopen(_argv[2],"rb"); + if(fin2==NULL){ + fprintf(stderr,"Error opening '%s'.\n",_argv[2]); + fclose(fin1); + return EXIT_FAILURE; + } + /*Read in the data and allocate scratch space.*/ + xlength=read_pcm16(&x,fin1,2); + if(nchannels==1){ + for(xi=0;xi0;){ + for(ci=0;ci0){ + /*Temporal masking: -3 dB/2.5ms slope.*/ + for(bi=0;bi=79&&xj<=81)im*=0.1F; + if(xj==80)im*=0.1F; + Eb+=im; + } + } + Eb /= (BANDS[bi+1]-BANDS[bi])*nchannels; + Ef += Eb*Eb; + } + /*Using a fixed normalization value means we're willing to accept slightly + lower quality for lower sampling rates.*/ + Ef/=NBANDS; + Ef*=Ef; + err+=Ef*Ef; + } + free(xb); + free(X); + free(Y); + err=pow(err/nframes,1.0/16); + Q=100*(1-0.5*log(1+err)/log(1.13)); + if(Q<0){ + fprintf(stderr,"Test vector FAILS\n"); + fprintf(stderr,"Internal weighted error is %f\n",err); + return EXIT_FAILURE; + } + else{ + fprintf(stderr,"Test vector PASSES\n"); + fprintf(stderr, + "Opus quality metric: %.1f %% (internal weighted error is %f)\n",Q,err); + return EXIT_SUCCESS; + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_decoder.c b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_decoder.c new file mode 100644 index 000000000..9113638a0 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_decoder.c @@ -0,0 +1,1032 @@ +/* Copyright (c) 2010 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifndef OPUS_BUILD +# error "OPUS_BUILD _MUST_ be defined to build Opus. This probably means you need other defines as well, as in a config.h. See the included build files for details." +#endif + +#if defined(__GNUC__) && (__GNUC__ >= 2) && !defined(__OPTIMIZE__) && !defined(OPUS_WILL_BE_SLOW) +# pragma message "You appear to be compiling without optimization, if so opus will be very slow." +#endif + +#include +#include "celt.h" +#include "opus.h" +#include "entdec.h" +#include "modes.h" +#include "API.h" +#include "stack_alloc.h" +#include "float_cast.h" +#include "opus_private.h" +#include "os_support.h" +#include "structs.h" +#include "define.h" +#include "mathops.h" +#include "cpu_support.h" + +struct OpusDecoder { + int celt_dec_offset; + int silk_dec_offset; + int channels; + opus_int32 Fs; /** Sampling rate (at the API level) */ + silk_DecControlStruct DecControl; + int decode_gain; + int arch; + + /* Everything beyond this point gets cleared on a reset */ +#define OPUS_DECODER_RESET_START stream_channels + int stream_channels; + + int bandwidth; + int mode; + int prev_mode; + int frame_size; + int prev_redundancy; + int last_packet_duration; +#ifndef FIXED_POINT + opus_val16 softclip_mem[2]; +#endif + + opus_uint32 rangeFinal; +}; + +#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) +static void validate_opus_decoder(OpusDecoder *st) +{ + celt_assert(st->channels == 1 || st->channels == 2); + celt_assert(st->Fs == 48000 || st->Fs == 24000 || st->Fs == 16000 || st->Fs == 12000 || st->Fs == 8000); + celt_assert(st->DecControl.API_sampleRate == st->Fs); + celt_assert(st->DecControl.internalSampleRate == 0 || st->DecControl.internalSampleRate == 16000 || st->DecControl.internalSampleRate == 12000 || st->DecControl.internalSampleRate == 8000); + celt_assert(st->DecControl.nChannelsAPI == st->channels); + celt_assert(st->DecControl.nChannelsInternal == 0 || st->DecControl.nChannelsInternal == 1 || st->DecControl.nChannelsInternal == 2); + celt_assert(st->DecControl.payloadSize_ms == 0 || st->DecControl.payloadSize_ms == 10 || st->DecControl.payloadSize_ms == 20 || st->DecControl.payloadSize_ms == 40 || st->DecControl.payloadSize_ms == 60); +#ifdef OPUS_ARCHMASK + celt_assert(st->arch >= 0); + celt_assert(st->arch <= OPUS_ARCHMASK); +#endif + celt_assert(st->stream_channels == 1 || st->stream_channels == 2); +} +#define VALIDATE_OPUS_DECODER(st) validate_opus_decoder(st) +#else +#define VALIDATE_OPUS_DECODER(st) +#endif + +int opus_decoder_get_size(int channels) +{ + int silkDecSizeBytes, celtDecSizeBytes; + int ret; + if (channels<1 || channels > 2) + return 0; + ret = silk_Get_Decoder_Size( &silkDecSizeBytes ); + if(ret) + return 0; + silkDecSizeBytes = align(silkDecSizeBytes); + celtDecSizeBytes = celt_decoder_get_size(channels); + return align(sizeof(OpusDecoder))+silkDecSizeBytes+celtDecSizeBytes; +} + +int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels) +{ + void *silk_dec; + CELTDecoder *celt_dec; + int ret, silkDecSizeBytes; + + if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000) + || (channels!=1&&channels!=2)) + return OPUS_BAD_ARG; + + OPUS_CLEAR((char*)st, opus_decoder_get_size(channels)); + /* Initialize SILK decoder */ + ret = silk_Get_Decoder_Size(&silkDecSizeBytes); + if (ret) + return OPUS_INTERNAL_ERROR; + + silkDecSizeBytes = align(silkDecSizeBytes); + st->silk_dec_offset = align(sizeof(OpusDecoder)); + st->celt_dec_offset = st->silk_dec_offset+silkDecSizeBytes; + silk_dec = (char*)st+st->silk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + st->stream_channels = st->channels = channels; + + st->Fs = Fs; + st->DecControl.API_sampleRate = st->Fs; + st->DecControl.nChannelsAPI = st->channels; + + /* Reset decoder */ + ret = silk_InitDecoder( silk_dec ); + if(ret)return OPUS_INTERNAL_ERROR; + + /* Initialize CELT decoder */ + ret = celt_decoder_init(celt_dec, Fs, channels); + if(ret!=OPUS_OK)return OPUS_INTERNAL_ERROR; + + celt_decoder_ctl(celt_dec, CELT_SET_SIGNALLING(0)); + + st->prev_mode = 0; + st->frame_size = Fs/400; + st->arch = opus_select_arch(); + return OPUS_OK; +} + +OpusDecoder *opus_decoder_create(opus_int32 Fs, int channels, int *error) +{ + int ret; + OpusDecoder *st; + if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000) + || (channels!=1&&channels!=2)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + st = (OpusDecoder *)opus_alloc(opus_decoder_get_size(channels)); + if (st == NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_decoder_init(st, Fs, channels); + if (error) + *error = ret; + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + return st; +} + +static void smooth_fade(const opus_val16 *in1, const opus_val16 *in2, + opus_val16 *out, int overlap, int channels, + const opus_val16 *window, opus_int32 Fs) +{ + int i, c; + int inc = 48000/Fs; + for (c=0;csilk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + F20 = st->Fs/50; + F10 = F20>>1; + F5 = F10>>1; + F2_5 = F5>>1; + if (frame_size < F2_5) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + /* Limit frame_size to avoid excessive stack allocations. */ + frame_size = IMIN(frame_size, st->Fs/25*3); + /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */ + if (len<=1) + { + data = NULL; + /* In that case, don't conceal more than what the ToC says */ + frame_size = IMIN(frame_size, st->frame_size); + } + if (data != NULL) + { + audiosize = st->frame_size; + mode = st->mode; + bandwidth = st->bandwidth; + ec_dec_init(&dec,(unsigned char*)data,len); + } else { + audiosize = frame_size; + mode = st->prev_mode; + bandwidth = 0; + + if (mode == 0) + { + /* If we haven't got any packet yet, all we can do is return zeros */ + for (i=0;ichannels;i++) + pcm[i] = 0; + RESTORE_STACK; + return audiosize; + } + + /* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT), + 10, or 20 (e.g. 12.5 or 30 ms). */ + if (audiosize > F20) + { + do { + int ret = opus_decode_frame(st, NULL, 0, pcm, IMIN(audiosize, F20), 0); + if (ret<0) + { + RESTORE_STACK; + return ret; + } + pcm += ret*st->channels; + audiosize -= ret; + } while (audiosize > 0); + RESTORE_STACK; + return frame_size; + } else if (audiosize < F20) + { + if (audiosize > F10) + audiosize = F10; + else if (mode != MODE_SILK_ONLY && audiosize > F5 && audiosize < F10) + audiosize = F5; + } + } + + /* In fixed-point, we can tell CELT to do the accumulation on top of the + SILK PCM buffer. This saves some stack space. */ +#ifdef FIXED_POINT + celt_accum = (mode != MODE_CELT_ONLY) && (frame_size >= F10); +#else + celt_accum = 0; +#endif + + pcm_transition_silk_size = ALLOC_NONE; + pcm_transition_celt_size = ALLOC_NONE; + if (data!=NULL && st->prev_mode > 0 && ( + (mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY && !st->prev_redundancy) + || (mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) ) + ) + { + transition = 1; + /* Decide where to allocate the stack memory for pcm_transition */ + if (mode == MODE_CELT_ONLY) + pcm_transition_celt_size = F5*st->channels; + else + pcm_transition_silk_size = F5*st->channels; + } + ALLOC(pcm_transition_celt, pcm_transition_celt_size, opus_val16); + if (transition && mode == MODE_CELT_ONLY) + { + pcm_transition = pcm_transition_celt; + opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); + } + if (audiosize > frame_size) + { + /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/ + RESTORE_STACK; + return OPUS_BAD_ARG; + } else { + frame_size = audiosize; + } + + /* Don't allocate any memory when in CELT-only mode */ + pcm_silk_size = (mode != MODE_CELT_ONLY && !celt_accum) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE; + ALLOC(pcm_silk, pcm_silk_size, opus_int16); + + /* SILK processing */ + if (mode != MODE_CELT_ONLY) + { + int lost_flag, decoded_samples; + opus_int16 *pcm_ptr; +#ifdef FIXED_POINT + if (celt_accum) + pcm_ptr = pcm; + else +#endif + pcm_ptr = pcm_silk; + + if (st->prev_mode==MODE_CELT_ONLY) + silk_InitDecoder( silk_dec ); + + /* The SILK PLC cannot produce frames of less than 10 ms */ + st->DecControl.payloadSize_ms = IMAX(10, 1000 * audiosize / st->Fs); + + if (data != NULL) + { + st->DecControl.nChannelsInternal = st->stream_channels; + if( mode == MODE_SILK_ONLY ) { + if( bandwidth == OPUS_BANDWIDTH_NARROWBAND ) { + st->DecControl.internalSampleRate = 8000; + } else if( bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) { + st->DecControl.internalSampleRate = 12000; + } else if( bandwidth == OPUS_BANDWIDTH_WIDEBAND ) { + st->DecControl.internalSampleRate = 16000; + } else { + st->DecControl.internalSampleRate = 16000; + celt_assert( 0 ); + } + } else { + /* Hybrid mode */ + st->DecControl.internalSampleRate = 16000; + } + } + + lost_flag = data == NULL ? 1 : 2 * decode_fec; + decoded_samples = 0; + do { + /* Call SILK decoder */ + int first_frame = decoded_samples == 0; + silk_ret = silk_Decode( silk_dec, &st->DecControl, + lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size, st->arch ); + if( silk_ret ) { + if (lost_flag) { + /* PLC failure should not be fatal */ + silk_frame_size = frame_size; + for (i=0;ichannels;i++) + pcm_ptr[i] = 0; + } else { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + } + pcm_ptr += silk_frame_size * st->channels; + decoded_samples += silk_frame_size; + } while( decoded_samples < frame_size ); + } + + start_band = 0; + if (!decode_fec && mode != MODE_CELT_ONLY && data != NULL + && ec_tell(&dec)+17+20*(st->mode == MODE_HYBRID) <= 8*len) + { + /* Check if we have a redundant 0-8 kHz band */ + if (mode == MODE_HYBRID) + redundancy = ec_dec_bit_logp(&dec, 12); + else + redundancy = 1; + if (redundancy) + { + celt_to_silk = ec_dec_bit_logp(&dec, 1); + /* redundancy_bytes will be at least two, in the non-hybrid + case due to the ec_tell() check above */ + redundancy_bytes = mode==MODE_HYBRID ? + (opus_int32)ec_dec_uint(&dec, 256)+2 : + len-((ec_tell(&dec)+7)>>3); + len -= redundancy_bytes; + /* This is a sanity check. It should never happen for a valid + packet, so the exact behaviour is not normative. */ + if (len*8 < ec_tell(&dec)) + { + len = 0; + redundancy_bytes = 0; + redundancy = 0; + } + /* Shrink decoder because of raw bits */ + dec.storage -= redundancy_bytes; + } + } + if (mode != MODE_CELT_ONLY) + start_band = 17; + + if (redundancy) + { + transition = 0; + pcm_transition_silk_size=ALLOC_NONE; + } + + ALLOC(pcm_transition_silk, pcm_transition_silk_size, opus_val16); + + if (transition && mode != MODE_CELT_ONLY) + { + pcm_transition = pcm_transition_silk; + opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); + } + + + if (bandwidth) + { + int endband=21; + + switch(bandwidth) + { + case OPUS_BANDWIDTH_NARROWBAND: + endband = 13; + break; + case OPUS_BANDWIDTH_MEDIUMBAND: + case OPUS_BANDWIDTH_WIDEBAND: + endband = 17; + break; + case OPUS_BANDWIDTH_SUPERWIDEBAND: + endband = 19; + break; + case OPUS_BANDWIDTH_FULLBAND: + endband = 21; + break; + default: + celt_assert(0); + break; + } + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband))); + } + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels))); + + /* Only allocation memory for redundancy if/when needed */ + redundant_audio_size = redundancy ? F5*st->channels : ALLOC_NONE; + ALLOC(redundant_audio, redundant_audio_size, opus_val16); + + /* 5 ms redundant frame for CELT->SILK*/ + if (redundancy && celt_to_silk) + { + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0))); + celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, + redundant_audio, F5, NULL, 0); + MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng))); + } + + /* MUST be after PLC */ + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band))); + + if (mode != MODE_SILK_ONLY) + { + int celt_frame_size = IMIN(F20, frame_size); + /* Make sure to discard any previous CELT state */ + if (mode != st->prev_mode && st->prev_mode > 0 && !st->prev_redundancy) + MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_RESET_STATE)); + /* Decode CELT */ + celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data, + len, pcm, celt_frame_size, &dec, celt_accum); + } else { + unsigned char silence[2] = {0xFF, 0xFF}; + if (!celt_accum) + { + for (i=0;ichannels;i++) + pcm[i] = 0; + } + /* For hybrid -> SILK transitions, we let the CELT MDCT + do a fade-out by decoding a silence frame */ + if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) ) + { + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0))); + celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL, celt_accum); + } + } + + if (mode != MODE_CELT_ONLY && !celt_accum) + { +#ifdef FIXED_POINT + for (i=0;ichannels;i++) + pcm[i] = SAT16(ADD32(pcm[i], pcm_silk[i])); +#else + for (i=0;ichannels;i++) + pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]); +#endif + } + + { + const CELTMode *celt_mode; + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode))); + window = celt_mode->window; + } + + /* 5 ms redundant frame for SILK->CELT */ + if (redundancy && !celt_to_silk) + { + MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_RESET_STATE)); + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0))); + + celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL, 0); + MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng))); + smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5, + pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs); + } + if (redundancy && celt_to_silk) + { + for (c=0;cchannels;c++) + { + for (i=0;ichannels*i+c] = redundant_audio[st->channels*i+c]; + } + smooth_fade(redundant_audio+st->channels*F2_5, pcm+st->channels*F2_5, + pcm+st->channels*F2_5, F2_5, st->channels, window, st->Fs); + } + if (transition) + { + if (audiosize >= F5) + { + for (i=0;ichannels*F2_5;i++) + pcm[i] = pcm_transition[i]; + smooth_fade(pcm_transition+st->channels*F2_5, pcm+st->channels*F2_5, + pcm+st->channels*F2_5, F2_5, + st->channels, window, st->Fs); + } else { + /* Not enough time to do a clean transition, but we do it anyway + This will not preserve amplitude perfectly and may introduce + a bit of temporal aliasing, but it shouldn't be too bad and + that's pretty much the best we can do. In any case, generating this + transition it pretty silly in the first place */ + smooth_fade(pcm_transition, pcm, + pcm, F2_5, + st->channels, window, st->Fs); + } + } + + if(st->decode_gain) + { + opus_val32 gain; + gain = celt_exp2(MULT16_16_P15(QCONST16(6.48814081e-4f, 25), st->decode_gain)); + for (i=0;ichannels;i++) + { + opus_val32 x; + x = MULT16_32_P16(pcm[i],gain); + pcm[i] = SATURATE(x, 32767); + } + } + + if (len <= 1) + st->rangeFinal = 0; + else + st->rangeFinal = dec.rng ^ redundant_rng; + + st->prev_mode = mode; + st->prev_redundancy = redundancy && !celt_to_silk; + + if (celt_ret>=0) + { + if (OPUS_CHECK_ARRAY(pcm, audiosize*st->channels)) + OPUS_PRINT_INT(audiosize); + } + + RESTORE_STACK; + return celt_ret < 0 ? celt_ret : audiosize; + +} + +int opus_decode_native(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec, + int self_delimited, opus_int32 *packet_offset, int soft_clip) +{ + int i, nb_samples; + int count, offset; + unsigned char toc; + int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels; + /* 48 x 2.5 ms = 120 ms */ + opus_int16 size[48]; + VALIDATE_OPUS_DECODER(st); + if (decode_fec<0 || decode_fec>1) + return OPUS_BAD_ARG; + /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */ + if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0) + return OPUS_BAD_ARG; + if (len==0 || data==NULL) + { + int pcm_count=0; + do { + int ret; + ret = opus_decode_frame(st, NULL, 0, pcm+pcm_count*st->channels, frame_size-pcm_count, 0); + if (ret<0) + return ret; + pcm_count += ret; + } while (pcm_count < frame_size); + celt_assert(pcm_count == frame_size); + if (OPUS_CHECK_ARRAY(pcm, pcm_count*st->channels)) + OPUS_PRINT_INT(pcm_count); + st->last_packet_duration = pcm_count; + return pcm_count; + } else if (len<0) + return OPUS_BAD_ARG; + + packet_mode = opus_packet_get_mode(data); + packet_bandwidth = opus_packet_get_bandwidth(data); + packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs); + packet_stream_channels = opus_packet_get_nb_channels(data); + + count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, + size, &offset, packet_offset); + if (count<0) + return count; + + data += offset; + + if (decode_fec) + { + int duration_copy; + int ret; + /* If no FEC can be present, run the PLC (recursive call) */ + if (frame_size < packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY) + return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, soft_clip); + /* Otherwise, run the PLC on everything except the size for which we might have FEC */ + duration_copy = st->last_packet_duration; + if (frame_size-packet_frame_size!=0) + { + ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL, soft_clip); + if (ret<0) + { + st->last_packet_duration = duration_copy; + return ret; + } + celt_assert(ret==frame_size-packet_frame_size); + } + /* Complete with FEC */ + st->mode = packet_mode; + st->bandwidth = packet_bandwidth; + st->frame_size = packet_frame_size; + st->stream_channels = packet_stream_channels; + ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size), + packet_frame_size, 1); + if (ret<0) + return ret; + else { + if (OPUS_CHECK_ARRAY(pcm, frame_size*st->channels)) + OPUS_PRINT_INT(frame_size); + st->last_packet_duration = frame_size; + return frame_size; + } + } + + if (count*packet_frame_size > frame_size) + return OPUS_BUFFER_TOO_SMALL; + + /* Update the state as the last step to avoid updating it on an invalid packet */ + st->mode = packet_mode; + st->bandwidth = packet_bandwidth; + st->frame_size = packet_frame_size; + st->stream_channels = packet_stream_channels; + + nb_samples=0; + for (i=0;ichannels, frame_size-nb_samples, 0); + if (ret<0) + return ret; + celt_assert(ret==packet_frame_size); + data += size[i]; + nb_samples += ret; + } + st->last_packet_duration = nb_samples; + if (OPUS_CHECK_ARRAY(pcm, nb_samples*st->channels)) + OPUS_PRINT_INT(nb_samples); +#ifndef FIXED_POINT + if (soft_clip) + opus_pcm_soft_clip(pcm, nb_samples, st->channels, st->softclip_mem); + else + st->softclip_mem[0]=st->softclip_mem[1]=0; +#endif + return nb_samples; +} + +#ifdef FIXED_POINT + +int opus_decode(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) +{ + if(frame_size<=0) + return OPUS_BAD_ARG; + return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0); +} + +#ifndef DISABLE_FLOAT_API +int opus_decode_float(OpusDecoder *st, const unsigned char *data, + opus_int32 len, float *pcm, int frame_size, int decode_fec) +{ + VARDECL(opus_int16, out); + int ret, i; + int nb_samples; + ALLOC_STACK; + + if(frame_size<=0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + if (data != NULL && len > 0 && !decode_fec) + { + nb_samples = opus_decoder_get_nb_samples(st, data, len); + if (nb_samples>0) + frame_size = IMIN(frame_size, nb_samples); + else + return OPUS_INVALID_PACKET; + } + celt_assert(st->channels == 1 || st->channels == 2); + ALLOC(out, frame_size*st->channels, opus_int16); + + ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0); + if (ret > 0) + { + for (i=0;ichannels;i++) + pcm[i] = (1.f/32768.f)*(out[i]); + } + RESTORE_STACK; + return ret; +} +#endif + + +#else +int opus_decode(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec) +{ + VARDECL(float, out); + int ret, i; + int nb_samples; + ALLOC_STACK; + + if(frame_size<=0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + if (data != NULL && len > 0 && !decode_fec) + { + nb_samples = opus_decoder_get_nb_samples(st, data, len); + if (nb_samples>0) + frame_size = IMIN(frame_size, nb_samples); + else + return OPUS_INVALID_PACKET; + } + celt_assert(st->channels == 1 || st->channels == 2); + ALLOC(out, frame_size*st->channels, float); + + ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1); + if (ret > 0) + { + for (i=0;ichannels;i++) + pcm[i] = FLOAT2INT16(out[i]); + } + RESTORE_STACK; + return ret; +} + +int opus_decode_float(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) +{ + if(frame_size<=0) + return OPUS_BAD_ARG; + return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0); +} + +#endif + +int opus_decoder_ctl(OpusDecoder *st, int request, ...) +{ + int ret = OPUS_OK; + va_list ap; + void *silk_dec; + CELTDecoder *celt_dec; + + silk_dec = (char*)st+st->silk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + + + va_start(ap, request); + + switch (request) + { + case OPUS_GET_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->bandwidth; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 *value = va_arg(ap, opus_uint32*); + if (!value) + { + goto bad_arg; + } + *value = st->rangeFinal; + } + break; + case OPUS_RESET_STATE: + { + OPUS_CLEAR((char*)&st->OPUS_DECODER_RESET_START, + sizeof(OpusDecoder)- + ((char*)&st->OPUS_DECODER_RESET_START - (char*)st)); + + celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); + silk_InitDecoder( silk_dec ); + st->stream_channels = st->channels; + st->frame_size = st->Fs/400; + } + break; + case OPUS_GET_SAMPLE_RATE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->Fs; + } + break; + case OPUS_GET_PITCH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + if (st->prev_mode == MODE_CELT_ONLY) + ret = celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value)); + else + *value = st->DecControl.prevPitchLag; + } + break; + case OPUS_GET_GAIN_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->decode_gain; + } + break; + case OPUS_SET_GAIN_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<-32768 || value>32767) + { + goto bad_arg; + } + st->decode_gain = value; + } + break; + case OPUS_GET_LAST_PACKET_DURATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->last_packet_duration; + } + break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + ret = celt_decoder_ctl(celt_dec, OPUS_SET_PHASE_INVERSION_DISABLED(value)); + } + break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + ret = celt_decoder_ctl(celt_dec, OPUS_GET_PHASE_INVERSION_DISABLED(value)); + } + break; + default: + /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/ + ret = OPUS_UNIMPLEMENTED; + break; + } + + va_end(ap); + return ret; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +} + +void opus_decoder_destroy(OpusDecoder *st) +{ + opus_free(st); +} + + +int opus_packet_get_bandwidth(const unsigned char *data) +{ + int bandwidth; + if (data[0]&0x80) + { + bandwidth = OPUS_BANDWIDTH_MEDIUMBAND + ((data[0]>>5)&0x3); + if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + bandwidth = OPUS_BANDWIDTH_NARROWBAND; + } else if ((data[0]&0x60) == 0x60) + { + bandwidth = (data[0]&0x10) ? OPUS_BANDWIDTH_FULLBAND : + OPUS_BANDWIDTH_SUPERWIDEBAND; + } else { + bandwidth = OPUS_BANDWIDTH_NARROWBAND + ((data[0]>>5)&0x3); + } + return bandwidth; +} + +int opus_packet_get_nb_channels(const unsigned char *data) +{ + return (data[0]&0x4) ? 2 : 1; +} + +int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) +{ + int count; + if (len<1) + return OPUS_BAD_ARG; + count = packet[0]&0x3; + if (count==0) + return 1; + else if (count!=3) + return 2; + else if (len<2) + return OPUS_INVALID_PACKET; + else + return packet[1]&0x3F; +} + +int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, + opus_int32 Fs) +{ + int samples; + int count = opus_packet_get_nb_frames(packet, len); + + if (count<0) + return count; + + samples = count*opus_packet_get_samples_per_frame(packet, Fs); + /* Can't have more than 120 ms */ + if (samples*25 > Fs*3) + return OPUS_INVALID_PACKET; + else + return samples; +} + +int opus_decoder_get_nb_samples(const OpusDecoder *dec, + const unsigned char packet[], opus_int32 len) +{ + return opus_packet_get_nb_samples(packet, len, dec->Fs); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_demo.c b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_demo.c new file mode 100644 index 000000000..4cc26a6c7 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_demo.c @@ -0,0 +1,892 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include "opus.h" +#include "debug.h" +#include "opus_types.h" +#include "opus_private.h" +#include "opus_multistream.h" + +#define MAX_PACKET 1500 + +void print_usage( char* argv[] ) +{ + fprintf(stderr, "Usage: %s [-e] " + " [options] \n", argv[0]); + fprintf(stderr, " %s -d " + "[options] \n\n", argv[0]); + fprintf(stderr, "application: voip | audio | restricted-lowdelay\n" ); + fprintf(stderr, "options:\n" ); + fprintf(stderr, "-e : only runs the encoder (output the bit-stream)\n" ); + fprintf(stderr, "-d : only runs the decoder (reads the bit-stream as input)\n" ); + fprintf(stderr, "-cbr : enable constant bitrate; default: variable bitrate\n" ); + fprintf(stderr, "-cvbr : enable constrained variable bitrate; default: unconstrained\n" ); + fprintf(stderr, "-delayed-decision : use look-ahead for speech/music detection (experts only); default: disabled\n" ); + fprintf(stderr, "-bandwidth : audio bandwidth (from narrowband to fullband); default: sampling rate\n" ); + fprintf(stderr, "-framesize <2.5|5|10|20|40|60|80|100|120> : frame size in ms; default: 20 \n" ); + fprintf(stderr, "-max_payload : maximum payload size in bytes, default: 1024\n" ); + fprintf(stderr, "-complexity : complexity, 0 (lowest) ... 10 (highest); default: 10\n" ); + fprintf(stderr, "-inbandfec : enable SILK inband FEC\n" ); + fprintf(stderr, "-forcemono : force mono encoding, even for stereo input\n" ); + fprintf(stderr, "-dtx : enable SILK DTX\n" ); + fprintf(stderr, "-loss : simulate packet loss, in percent (0-100); default: 0\n" ); +} + +static void int_to_char(opus_uint32 i, unsigned char ch[4]) +{ + ch[0] = i>>24; + ch[1] = (i>>16)&0xFF; + ch[2] = (i>>8)&0xFF; + ch[3] = i&0xFF; +} + +static opus_uint32 char_to_int(unsigned char ch[4]) +{ + return ((opus_uint32)ch[0]<<24) | ((opus_uint32)ch[1]<<16) + | ((opus_uint32)ch[2]<< 8) | (opus_uint32)ch[3]; +} + +#define check_encoder_option(decode_only, opt) do {if (decode_only) {fprintf(stderr, "option %s is only for encoding\n", opt); goto failure;}} while(0) + +static const int silk8_test[][4] = { + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*3, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*2, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*3, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*2, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 2} +}; + +static const int silk12_test[][4] = { + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*3, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*2, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 480, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*3, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*2, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 480, 2} +}; + +static const int silk16_test[][4] = { + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*3, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*2, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*3, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*2, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 2} +}; + +static const int hybrid24_test[][4] = { + {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 2} +}; + +static const int hybrid48_test[][4] = { + {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 2} +}; + +static const int celt_test[][4] = { + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 1}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 1}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 240, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 240, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 240, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 240, 1}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 120, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 120, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 120, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 120, 1}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 2}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 2}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 240, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 240, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 240, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 240, 2}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 120, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 120, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 120, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 120, 2}, + +}; + +static const int celt_hq_test[][4] = { + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 240, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 120, 2}, +}; + +#if 0 /* This is a hack that replaces the normal encoder/decoder with the multistream version */ +#define OpusEncoder OpusMSEncoder +#define OpusDecoder OpusMSDecoder +#define opus_encode opus_multistream_encode +#define opus_decode opus_multistream_decode +#define opus_encoder_ctl opus_multistream_encoder_ctl +#define opus_decoder_ctl opus_multistream_decoder_ctl +#define opus_encoder_create ms_opus_encoder_create +#define opus_decoder_create ms_opus_decoder_create +#define opus_encoder_destroy opus_multistream_encoder_destroy +#define opus_decoder_destroy opus_multistream_decoder_destroy + +static OpusEncoder *ms_opus_encoder_create(opus_int32 Fs, int channels, int application, int *error) +{ + int streams, coupled_streams; + unsigned char mapping[256]; + return (OpusEncoder *)opus_multistream_surround_encoder_create(Fs, channels, 1, &streams, &coupled_streams, mapping, application, error); +} +static OpusDecoder *ms_opus_decoder_create(opus_int32 Fs, int channels, int *error) +{ + int streams; + int coupled_streams; + unsigned char mapping[256]={0,1}; + streams = 1; + coupled_streams = channels==2; + return (OpusDecoder *)opus_multistream_decoder_create(Fs, channels, streams, coupled_streams, mapping, error); +} +#endif + +int main(int argc, char *argv[]) +{ + int err; + char *inFile, *outFile; + FILE *fin=NULL; + FILE *fout=NULL; + OpusEncoder *enc=NULL; + OpusDecoder *dec=NULL; + int args; + int len[2]; + int frame_size, channels; + opus_int32 bitrate_bps=0; + unsigned char *data[2] = {NULL, NULL}; + unsigned char *fbytes=NULL; + opus_int32 sampling_rate; + int use_vbr; + int max_payload_bytes; + int complexity; + int use_inbandfec; + int use_dtx; + int forcechannels; + int cvbr = 0; + int packet_loss_perc; + opus_int32 count=0, count_act=0; + int k; + opus_int32 skip=0; + int stop=0; + short *in=NULL; + short *out=NULL; + int application=OPUS_APPLICATION_AUDIO; + double bits=0.0, bits_max=0.0, bits_act=0.0, bits2=0.0, nrg; + double tot_samples=0; + opus_uint64 tot_in, tot_out; + int bandwidth=OPUS_AUTO; + const char *bandwidth_string; + int lost = 0, lost_prev = 1; + int toggle = 0; + opus_uint32 enc_final_range[2]; + opus_uint32 dec_final_range; + int encode_only=0, decode_only=0; + int max_frame_size = 48000*2; + size_t num_read; + int curr_read=0; + int sweep_bps = 0; + int random_framesize=0, newsize=0, delayed_celt=0; + int sweep_max=0, sweep_min=0; + int random_fec=0; + const int (*mode_list)[4]=NULL; + int nb_modes_in_list=0; + int curr_mode=0; + int curr_mode_count=0; + int mode_switch_time = 48000; + int nb_encoded=0; + int remaining=0; + int variable_duration=OPUS_FRAMESIZE_ARG; + int delayed_decision=0; + int ret = EXIT_FAILURE; + + if (argc < 5 ) + { + print_usage( argv ); + goto failure; + } + + tot_in=tot_out=0; + fprintf(stderr, "%s\n", opus_get_version_string()); + + args = 1; + if (strcmp(argv[args], "-e")==0) + { + encode_only = 1; + args++; + } else if (strcmp(argv[args], "-d")==0) + { + decode_only = 1; + args++; + } + if (!decode_only && argc < 7 ) + { + print_usage( argv ); + goto failure; + } + + if (!decode_only) + { + if (strcmp(argv[args], "voip")==0) + application = OPUS_APPLICATION_VOIP; + else if (strcmp(argv[args], "restricted-lowdelay")==0) + application = OPUS_APPLICATION_RESTRICTED_LOWDELAY; + else if (strcmp(argv[args], "audio")!=0) { + fprintf(stderr, "unknown application: %s\n", argv[args]); + print_usage(argv); + goto failure; + } + args++; + } + sampling_rate = (opus_int32)atol(argv[args]); + args++; + + if (sampling_rate != 8000 && sampling_rate != 12000 + && sampling_rate != 16000 && sampling_rate != 24000 + && sampling_rate != 48000) + { + fprintf(stderr, "Supported sampling rates are 8000, 12000, " + "16000, 24000 and 48000.\n"); + goto failure; + } + frame_size = sampling_rate/50; + + channels = atoi(argv[args]); + args++; + + if (channels < 1 || channels > 2) + { + fprintf(stderr, "Opus_demo supports only 1 or 2 channels.\n"); + goto failure; + } + + if (!decode_only) + { + bitrate_bps = (opus_int32)atol(argv[args]); + args++; + } + + /* defaults: */ + use_vbr = 1; + max_payload_bytes = MAX_PACKET; + complexity = 10; + use_inbandfec = 0; + forcechannels = OPUS_AUTO; + use_dtx = 0; + packet_loss_perc = 0; + + while( args < argc - 2 ) { + /* process command line options */ + if( strcmp( argv[ args ], "-cbr" ) == 0 ) { + check_encoder_option(decode_only, "-cbr"); + use_vbr = 0; + args++; + } else if( strcmp( argv[ args ], "-bandwidth" ) == 0 ) { + check_encoder_option(decode_only, "-bandwidth"); + if (strcmp(argv[ args + 1 ], "NB")==0) + bandwidth = OPUS_BANDWIDTH_NARROWBAND; + else if (strcmp(argv[ args + 1 ], "MB")==0) + bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + else if (strcmp(argv[ args + 1 ], "WB")==0) + bandwidth = OPUS_BANDWIDTH_WIDEBAND; + else if (strcmp(argv[ args + 1 ], "SWB")==0) + bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + else if (strcmp(argv[ args + 1 ], "FB")==0) + bandwidth = OPUS_BANDWIDTH_FULLBAND; + else { + fprintf(stderr, "Unknown bandwidth %s. " + "Supported are NB, MB, WB, SWB, FB.\n", + argv[ args + 1 ]); + goto failure; + } + args += 2; + } else if( strcmp( argv[ args ], "-framesize" ) == 0 ) { + check_encoder_option(decode_only, "-framesize"); + if (strcmp(argv[ args + 1 ], "2.5")==0) + frame_size = sampling_rate/400; + else if (strcmp(argv[ args + 1 ], "5")==0) + frame_size = sampling_rate/200; + else if (strcmp(argv[ args + 1 ], "10")==0) + frame_size = sampling_rate/100; + else if (strcmp(argv[ args + 1 ], "20")==0) + frame_size = sampling_rate/50; + else if (strcmp(argv[ args + 1 ], "40")==0) + frame_size = sampling_rate/25; + else if (strcmp(argv[ args + 1 ], "60")==0) + frame_size = 3*sampling_rate/50; + else if (strcmp(argv[ args + 1 ], "80")==0) + frame_size = 4*sampling_rate/50; + else if (strcmp(argv[ args + 1 ], "100")==0) + frame_size = 5*sampling_rate/50; + else if (strcmp(argv[ args + 1 ], "120")==0) + frame_size = 6*sampling_rate/50; + else { + fprintf(stderr, "Unsupported frame size: %s ms. " + "Supported are 2.5, 5, 10, 20, 40, 60, 80, 100, 120.\n", + argv[ args + 1 ]); + goto failure; + } + args += 2; + } else if( strcmp( argv[ args ], "-max_payload" ) == 0 ) { + check_encoder_option(decode_only, "-max_payload"); + max_payload_bytes = atoi( argv[ args + 1 ] ); + args += 2; + } else if( strcmp( argv[ args ], "-complexity" ) == 0 ) { + check_encoder_option(decode_only, "-complexity"); + complexity = atoi( argv[ args + 1 ] ); + args += 2; + } else if( strcmp( argv[ args ], "-inbandfec" ) == 0 ) { + use_inbandfec = 1; + args++; + } else if( strcmp( argv[ args ], "-forcemono" ) == 0 ) { + check_encoder_option(decode_only, "-forcemono"); + forcechannels = 1; + args++; + } else if( strcmp( argv[ args ], "-cvbr" ) == 0 ) { + check_encoder_option(decode_only, "-cvbr"); + cvbr = 1; + args++; + } else if( strcmp( argv[ args ], "-delayed-decision" ) == 0 ) { + check_encoder_option(decode_only, "-delayed-decision"); + delayed_decision = 1; + args++; + } else if( strcmp( argv[ args ], "-dtx") == 0 ) { + check_encoder_option(decode_only, "-dtx"); + use_dtx = 1; + args++; + } else if( strcmp( argv[ args ], "-loss" ) == 0 ) { + packet_loss_perc = atoi( argv[ args + 1 ] ); + args += 2; + } else if( strcmp( argv[ args ], "-sweep" ) == 0 ) { + check_encoder_option(decode_only, "-sweep"); + sweep_bps = atoi( argv[ args + 1 ] ); + args += 2; + } else if( strcmp( argv[ args ], "-random_framesize" ) == 0 ) { + check_encoder_option(decode_only, "-random_framesize"); + random_framesize = 1; + args++; + } else if( strcmp( argv[ args ], "-sweep_max" ) == 0 ) { + check_encoder_option(decode_only, "-sweep_max"); + sweep_max = atoi( argv[ args + 1 ] ); + args += 2; + } else if( strcmp( argv[ args ], "-random_fec" ) == 0 ) { + check_encoder_option(decode_only, "-random_fec"); + random_fec = 1; + args++; + } else if( strcmp( argv[ args ], "-silk8k_test" ) == 0 ) { + check_encoder_option(decode_only, "-silk8k_test"); + mode_list = silk8_test; + nb_modes_in_list = 8; + args++; + } else if( strcmp( argv[ args ], "-silk12k_test" ) == 0 ) { + check_encoder_option(decode_only, "-silk12k_test"); + mode_list = silk12_test; + nb_modes_in_list = 8; + args++; + } else if( strcmp( argv[ args ], "-silk16k_test" ) == 0 ) { + check_encoder_option(decode_only, "-silk16k_test"); + mode_list = silk16_test; + nb_modes_in_list = 8; + args++; + } else if( strcmp( argv[ args ], "-hybrid24k_test" ) == 0 ) { + check_encoder_option(decode_only, "-hybrid24k_test"); + mode_list = hybrid24_test; + nb_modes_in_list = 4; + args++; + } else if( strcmp( argv[ args ], "-hybrid48k_test" ) == 0 ) { + check_encoder_option(decode_only, "-hybrid48k_test"); + mode_list = hybrid48_test; + nb_modes_in_list = 4; + args++; + } else if( strcmp( argv[ args ], "-celt_test" ) == 0 ) { + check_encoder_option(decode_only, "-celt_test"); + mode_list = celt_test; + nb_modes_in_list = 32; + args++; + } else if( strcmp( argv[ args ], "-celt_hq_test" ) == 0 ) { + check_encoder_option(decode_only, "-celt_hq_test"); + mode_list = celt_hq_test; + nb_modes_in_list = 4; + args++; + } else { + printf( "Error: unrecognized setting: %s\n\n", argv[ args ] ); + print_usage( argv ); + goto failure; + } + } + + if (sweep_max) + sweep_min = bitrate_bps; + + if (max_payload_bytes < 0 || max_payload_bytes > MAX_PACKET) + { + fprintf (stderr, "max_payload_bytes must be between 0 and %d\n", + MAX_PACKET); + goto failure; + } + + inFile = argv[argc-2]; + fin = fopen(inFile, "rb"); + if (!fin) + { + fprintf (stderr, "Could not open input file %s\n", argv[argc-2]); + goto failure; + } + if (mode_list) + { + int size; + fseek(fin, 0, SEEK_END); + size = ftell(fin); + fprintf(stderr, "File size is %d bytes\n", size); + fseek(fin, 0, SEEK_SET); + mode_switch_time = size/sizeof(short)/channels/nb_modes_in_list; + fprintf(stderr, "Switching mode every %d samples\n", mode_switch_time); + } + + outFile = argv[argc-1]; + fout = fopen(outFile, "wb+"); + if (!fout) + { + fprintf (stderr, "Could not open output file %s\n", argv[argc-1]); + goto failure; + } + + if (!decode_only) + { + enc = opus_encoder_create(sampling_rate, channels, application, &err); + if (err != OPUS_OK) + { + fprintf(stderr, "Cannot create encoder: %s\n", opus_strerror(err)); + goto failure; + } + opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps)); + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth)); + opus_encoder_ctl(enc, OPUS_SET_VBR(use_vbr)); + opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(cvbr)); + opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity)); + opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(use_inbandfec)); + opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(forcechannels)); + opus_encoder_ctl(enc, OPUS_SET_DTX(use_dtx)); + opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc)); + + opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&skip)); + opus_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(16)); + opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(variable_duration)); + } + if (!encode_only) + { + dec = opus_decoder_create(sampling_rate, channels, &err); + if (err != OPUS_OK) + { + fprintf(stderr, "Cannot create decoder: %s\n", opus_strerror(err)); + goto failure; + } + } + + + switch(bandwidth) + { + case OPUS_BANDWIDTH_NARROWBAND: + bandwidth_string = "narrowband"; + break; + case OPUS_BANDWIDTH_MEDIUMBAND: + bandwidth_string = "mediumband"; + break; + case OPUS_BANDWIDTH_WIDEBAND: + bandwidth_string = "wideband"; + break; + case OPUS_BANDWIDTH_SUPERWIDEBAND: + bandwidth_string = "superwideband"; + break; + case OPUS_BANDWIDTH_FULLBAND: + bandwidth_string = "fullband"; + break; + case OPUS_AUTO: + bandwidth_string = "auto bandwidth"; + break; + default: + bandwidth_string = "unknown"; + break; + } + + if (decode_only) + fprintf(stderr, "Decoding with %ld Hz output (%d channels)\n", + (long)sampling_rate, channels); + else + fprintf(stderr, "Encoding %ld Hz input at %.3f kb/s " + "in %s with %d-sample frames.\n", + (long)sampling_rate, bitrate_bps*0.001, + bandwidth_string, frame_size); + + in = (short*)malloc(max_frame_size*channels*sizeof(short)); + out = (short*)malloc(max_frame_size*channels*sizeof(short)); + /* We need to allocate for 16-bit PCM data, but we store it as unsigned char. */ + fbytes = (unsigned char*)malloc(max_frame_size*channels*sizeof(short)); + data[0] = (unsigned char*)calloc(max_payload_bytes,sizeof(unsigned char)); + if ( use_inbandfec ) { + data[1] = (unsigned char*)calloc(max_payload_bytes,sizeof(unsigned char)); + } + if(delayed_decision) + { + if (frame_size==sampling_rate/400) + variable_duration = OPUS_FRAMESIZE_2_5_MS; + else if (frame_size==sampling_rate/200) + variable_duration = OPUS_FRAMESIZE_5_MS; + else if (frame_size==sampling_rate/100) + variable_duration = OPUS_FRAMESIZE_10_MS; + else if (frame_size==sampling_rate/50) + variable_duration = OPUS_FRAMESIZE_20_MS; + else if (frame_size==sampling_rate/25) + variable_duration = OPUS_FRAMESIZE_40_MS; + else if (frame_size==3*sampling_rate/50) + variable_duration = OPUS_FRAMESIZE_60_MS; + else if (frame_size==4*sampling_rate/50) + variable_duration = OPUS_FRAMESIZE_80_MS; + else if (frame_size==5*sampling_rate/50) + variable_duration = OPUS_FRAMESIZE_100_MS; + else + variable_duration = OPUS_FRAMESIZE_120_MS; + opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(variable_duration)); + frame_size = 2*48000; + } + while (!stop) + { + if (delayed_celt) + { + frame_size = newsize; + delayed_celt = 0; + } else if (random_framesize && rand()%20==0) + { + newsize = rand()%6; + switch(newsize) + { + case 0: newsize=sampling_rate/400; break; + case 1: newsize=sampling_rate/200; break; + case 2: newsize=sampling_rate/100; break; + case 3: newsize=sampling_rate/50; break; + case 4: newsize=sampling_rate/25; break; + case 5: newsize=3*sampling_rate/50; break; + } + while (newsize < sampling_rate/25 && bitrate_bps-abs(sweep_bps) <= 3*12*sampling_rate/newsize) + newsize*=2; + if (newsize < sampling_rate/100 && frame_size >= sampling_rate/100) + { + opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY)); + delayed_celt=1; + } else { + frame_size = newsize; + } + } + if (random_fec && rand()%30==0) + { + opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(rand()%4==0)); + } + if (decode_only) + { + unsigned char ch[4]; + num_read = fread(ch, 1, 4, fin); + if (num_read!=4) + break; + len[toggle] = char_to_int(ch); + if (len[toggle]>max_payload_bytes || len[toggle]<0) + { + fprintf(stderr, "Invalid payload length: %d\n",len[toggle]); + break; + } + num_read = fread(ch, 1, 4, fin); + if (num_read!=4) + break; + enc_final_range[toggle] = char_to_int(ch); + num_read = fread(data[toggle], 1, len[toggle], fin); + if (num_read!=(size_t)len[toggle]) + { + fprintf(stderr, "Ran out of input, " + "expecting %d bytes got %d\n", + len[toggle],(int)num_read); + break; + } + } else { + int i; + if (mode_list!=NULL) + { + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(mode_list[curr_mode][1])); + opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(mode_list[curr_mode][0])); + opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(mode_list[curr_mode][3])); + frame_size = mode_list[curr_mode][2]; + } + num_read = fread(fbytes, sizeof(short)*channels, frame_size-remaining, fin); + curr_read = (int)num_read; + tot_in += curr_read; + for(i=0;i sweep_max) + sweep_bps = -sweep_bps; + else if (bitrate_bps < sweep_min) + sweep_bps = -sweep_bps; + } + /* safety */ + if (bitrate_bps<1000) + bitrate_bps = 1000; + opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps)); + } + opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range[toggle])); + if (len[toggle] < 0) + { + fprintf (stderr, "opus_encode() returned %d\n", len[toggle]); + goto failure; + } + curr_mode_count += frame_size; + if (curr_mode_count > mode_switch_time && curr_mode < nb_modes_in_list-1) + { + curr_mode++; + curr_mode_count = 0; + } + } + +#if 0 /* This is for testing the padding code, do not enable by default */ + if (len[toggle]<1275) + { + int new_len = len[toggle]+rand()%(max_payload_bytes-len[toggle]); + if ((err = opus_packet_pad(data[toggle], len[toggle], new_len)) != OPUS_OK) + { + fprintf(stderr, "padding failed: %s\n", opus_strerror(err)); + goto failure; + } + len[toggle] = new_len; + } +#endif + if (encode_only) + { + unsigned char int_field[4]; + int_to_char(len[toggle], int_field); + if (fwrite(int_field, 1, 4, fout) != 4) { + fprintf(stderr, "Error writing.\n"); + goto failure; + } + int_to_char(enc_final_range[toggle], int_field); + if (fwrite(int_field, 1, 4, fout) != 4) { + fprintf(stderr, "Error writing.\n"); + goto failure; + } + if (fwrite(data[toggle], 1, len[toggle], fout) != (unsigned)len[toggle]) { + fprintf(stderr, "Error writing.\n"); + goto failure; + } + tot_samples += nb_encoded; + } else { + opus_int32 output_samples; + lost = len[toggle]==0 || (packet_loss_perc>0 && rand()%100 < packet_loss_perc); + if (lost) + opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples)); + else + output_samples = max_frame_size; + if( count >= use_inbandfec ) { + /* delay by one packet when using in-band FEC */ + if( use_inbandfec ) { + if( lost_prev ) { + /* attempt to decode with in-band FEC from next packet */ + opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples)); + output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, output_samples, 1); + } else { + /* regular decode */ + output_samples = max_frame_size; + output_samples = opus_decode(dec, data[1-toggle], len[1-toggle], out, output_samples, 0); + } + } else { + output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, output_samples, 0); + } + if (output_samples>0) + { + if (!decode_only && tot_out + output_samples > tot_in) + { + stop=1; + output_samples = (opus_int32)(tot_in - tot_out); + } + if (output_samples>skip) { + int i; + for(i=0;i<(output_samples-skip)*channels;i++) + { + short s; + s=out[i+(skip*channels)]; + fbytes[2*i]=s&0xFF; + fbytes[2*i+1]=(s>>8)&0xFF; + } + if (fwrite(fbytes, sizeof(short)*channels, output_samples-skip, fout) != (unsigned)(output_samples-skip)){ + fprintf(stderr, "Error writing.\n"); + goto failure; + } + tot_out += output_samples-skip; + } + if (output_samples= use_inbandfec ) { + /* count bits */ + bits += len[toggle]*8; + bits_max = ( len[toggle]*8 > bits_max ) ? len[toggle]*8 : bits_max; + bits2 += len[toggle]*len[toggle]*64; + if (!decode_only) + { + nrg = 0.0; + for ( k = 0; k < frame_size * channels; k++ ) { + nrg += in[ k ] * (double)in[ k ]; + } + nrg /= frame_size * channels; + if( nrg > 1e5 ) { + bits_act += len[toggle]*8; + count_act++; + } + } + } + count++; + toggle = (toggle + use_inbandfec) & 1; + } + + if(decode_only && count > 0) + frame_size = (int)(tot_samples / count); + count -= use_inbandfec; + if (tot_samples >= 1 && count > 0 && frame_size) + { + /* Print out bitrate statistics */ + double var; + fprintf (stderr, "average bitrate: %7.3f kb/s\n", + 1e-3*bits*sampling_rate/tot_samples); + fprintf (stderr, "maximum bitrate: %7.3f kb/s\n", + 1e-3*bits_max*sampling_rate/frame_size); + if (!decode_only) + fprintf (stderr, "active bitrate: %7.3f kb/s\n", + 1e-3*bits_act*sampling_rate/(1e-15+frame_size*(double)count_act)); + var = bits2/count - bits*bits/(count*(double)count); + if (var < 0) + var = 0; + fprintf (stderr, "bitrate standard deviation: %7.3f kb/s\n", + 1e-3*sqrt(var)*sampling_rate/frame_size); + } else { + fprintf(stderr, "bitrate statistics are undefined\n"); + } + silk_TimerSave("opus_timing.txt"); + ret = EXIT_SUCCESS; +failure: + opus_encoder_destroy(enc); + opus_decoder_destroy(dec); + free(data[0]); + free(data[1]); + if (fin) + fclose(fin); + if (fout) + fclose(fout); + free(in); + free(out); + free(fbytes); + return ret; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_encoder.c b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_encoder.c new file mode 100644 index 000000000..321bb2bb1 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_encoder.c @@ -0,0 +1,2773 @@ +/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "celt.h" +#include "entenc.h" +#include "modes.h" +#include "API.h" +#include "stack_alloc.h" +#include "float_cast.h" +#include "opus.h" +#include "arch.h" +#include "pitch.h" +#include "opus_private.h" +#include "os_support.h" +#include "cpu_support.h" +#include "analysis.h" +#include "mathops.h" +#include "tuning_parameters.h" +#ifdef FIXED_POINT +#include "fixed/structs_FIX.h" +#else +#include "float/structs_FLP.h" +#endif + +#define MAX_ENCODER_BUFFER 480 + +#ifndef DISABLE_FLOAT_API +#define PSEUDO_SNR_THRESHOLD 316.23f /* 10^(25/10) */ +#endif + +typedef struct { + opus_val32 XX, XY, YY; + opus_val16 smoothed_width; + opus_val16 max_follower; +} StereoWidthState; + +struct OpusEncoder { + int celt_enc_offset; + int silk_enc_offset; + silk_EncControlStruct silk_mode; + int application; + int channels; + int delay_compensation; + int force_channels; + int signal_type; + int user_bandwidth; + int max_bandwidth; + int user_forced_mode; + int voice_ratio; + opus_int32 Fs; + int use_vbr; + int vbr_constraint; + int variable_duration; + opus_int32 bitrate_bps; + opus_int32 user_bitrate_bps; + int lsb_depth; + int encoder_buffer; + int lfe; + int arch; + int use_dtx; /* general DTX for both SILK and CELT */ +#ifndef DISABLE_FLOAT_API + TonalityAnalysisState analysis; +#endif + +#define OPUS_ENCODER_RESET_START stream_channels + int stream_channels; + opus_int16 hybrid_stereo_width_Q14; + opus_int32 variable_HP_smth2_Q15; + opus_val16 prev_HB_gain; + opus_val32 hp_mem[4]; + int mode; + int prev_mode; + int prev_channels; + int prev_framesize; + int bandwidth; + /* Bandwidth determined automatically from the rate (before any other adjustment) */ + int auto_bandwidth; + int silk_bw_switch; + /* Sampling rate (at the API level) */ + int first; + opus_val16 * energy_masking; + StereoWidthState width_mem; + opus_val16 delay_buffer[MAX_ENCODER_BUFFER*2]; +#ifndef DISABLE_FLOAT_API + int detected_bandwidth; + int nb_no_activity_ms_Q1; + opus_val32 peak_signal_energy; +#endif + int nonfinal_frame; /* current frame is not the final in a packet */ + opus_uint32 rangeFinal; +}; + +/* Transition tables for the voice and music. First column is the + middle (memoriless) threshold. The second column is the hysteresis + (difference with the middle) */ +static const opus_int32 mono_voice_bandwidth_thresholds[8] = { + 9000, 700, /* NB<->MB */ + 9000, 700, /* MB<->WB */ + 13500, 1000, /* WB<->SWB */ + 14000, 2000, /* SWB<->FB */ +}; +static const opus_int32 mono_music_bandwidth_thresholds[8] = { + 9000, 700, /* NB<->MB */ + 9000, 700, /* MB<->WB */ + 11000, 1000, /* WB<->SWB */ + 12000, 2000, /* SWB<->FB */ +}; +static const opus_int32 stereo_voice_bandwidth_thresholds[8] = { + 9000, 700, /* NB<->MB */ + 9000, 700, /* MB<->WB */ + 13500, 1000, /* WB<->SWB */ + 14000, 2000, /* SWB<->FB */ +}; +static const opus_int32 stereo_music_bandwidth_thresholds[8] = { + 9000, 700, /* NB<->MB */ + 9000, 700, /* MB<->WB */ + 11000, 1000, /* WB<->SWB */ + 12000, 2000, /* SWB<->FB */ +}; +/* Threshold bit-rates for switching between mono and stereo */ +static const opus_int32 stereo_voice_threshold = 19000; +static const opus_int32 stereo_music_threshold = 17000; + +/* Threshold bit-rate for switching between SILK/hybrid and CELT-only */ +static const opus_int32 mode_thresholds[2][2] = { + /* voice */ /* music */ + { 64000, 10000}, /* mono */ + { 44000, 10000}, /* stereo */ +}; + +static const opus_int32 fec_thresholds[] = { + 12000, 1000, /* NB */ + 14000, 1000, /* MB */ + 16000, 1000, /* WB */ + 20000, 1000, /* SWB */ + 22000, 1000, /* FB */ +}; + +int opus_encoder_get_size(int channels) +{ + int silkEncSizeBytes, celtEncSizeBytes; + int ret; + if (channels<1 || channels > 2) + return 0; + ret = silk_Get_Encoder_Size( &silkEncSizeBytes ); + if (ret) + return 0; + silkEncSizeBytes = align(silkEncSizeBytes); + celtEncSizeBytes = celt_encoder_get_size(channels); + return align(sizeof(OpusEncoder))+silkEncSizeBytes+celtEncSizeBytes; +} + +int opus_encoder_init(OpusEncoder* st, opus_int32 Fs, int channels, int application) +{ + void *silk_enc; + CELTEncoder *celt_enc; + int err; + int ret, silkEncSizeBytes; + + if((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)||(channels!=1&&channels!=2)|| + (application != OPUS_APPLICATION_VOIP && application != OPUS_APPLICATION_AUDIO + && application != OPUS_APPLICATION_RESTRICTED_LOWDELAY)) + return OPUS_BAD_ARG; + + OPUS_CLEAR((char*)st, opus_encoder_get_size(channels)); + /* Create SILK encoder */ + ret = silk_Get_Encoder_Size( &silkEncSizeBytes ); + if (ret) + return OPUS_BAD_ARG; + silkEncSizeBytes = align(silkEncSizeBytes); + st->silk_enc_offset = align(sizeof(OpusEncoder)); + st->celt_enc_offset = st->silk_enc_offset+silkEncSizeBytes; + silk_enc = (char*)st+st->silk_enc_offset; + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + + st->stream_channels = st->channels = channels; + + st->Fs = Fs; + + st->arch = opus_select_arch(); + + ret = silk_InitEncoder( silk_enc, st->arch, &st->silk_mode ); + if(ret)return OPUS_INTERNAL_ERROR; + + /* default SILK parameters */ + st->silk_mode.nChannelsAPI = channels; + st->silk_mode.nChannelsInternal = channels; + st->silk_mode.API_sampleRate = st->Fs; + st->silk_mode.maxInternalSampleRate = 16000; + st->silk_mode.minInternalSampleRate = 8000; + st->silk_mode.desiredInternalSampleRate = 16000; + st->silk_mode.payloadSize_ms = 20; + st->silk_mode.bitRate = 25000; + st->silk_mode.packetLossPercentage = 0; + st->silk_mode.complexity = 9; + st->silk_mode.useInBandFEC = 0; + st->silk_mode.useDTX = 0; + st->silk_mode.useCBR = 0; + st->silk_mode.reducedDependency = 0; + + /* Create CELT encoder */ + /* Initialize CELT encoder */ + err = celt_encoder_init(celt_enc, Fs, channels, st->arch); + if(err!=OPUS_OK)return OPUS_INTERNAL_ERROR; + + celt_encoder_ctl(celt_enc, CELT_SET_SIGNALLING(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(st->silk_mode.complexity)); + + st->use_vbr = 1; + /* Makes constrained VBR the default (safer for real-time use) */ + st->vbr_constraint = 1; + st->user_bitrate_bps = OPUS_AUTO; + st->bitrate_bps = 3000+Fs*channels; + st->application = application; + st->signal_type = OPUS_AUTO; + st->user_bandwidth = OPUS_AUTO; + st->max_bandwidth = OPUS_BANDWIDTH_FULLBAND; + st->force_channels = OPUS_AUTO; + st->user_forced_mode = OPUS_AUTO; + st->voice_ratio = -1; + st->encoder_buffer = st->Fs/100; + st->lsb_depth = 24; + st->variable_duration = OPUS_FRAMESIZE_ARG; + + /* Delay compensation of 4 ms (2.5 ms for SILK's extra look-ahead + + 1.5 ms for SILK resamplers and stereo prediction) */ + st->delay_compensation = st->Fs/250; + + st->hybrid_stereo_width_Q14 = 1 << 14; + st->prev_HB_gain = Q15ONE; + st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + st->first = 1; + st->mode = MODE_HYBRID; + st->bandwidth = OPUS_BANDWIDTH_FULLBAND; + +#ifndef DISABLE_FLOAT_API + tonality_analysis_init(&st->analysis, st->Fs); + st->analysis.application = st->application; +#endif + + return OPUS_OK; +} + +static unsigned char gen_toc(int mode, int framerate, int bandwidth, int channels) +{ + int period; + unsigned char toc; + period = 0; + while (framerate < 400) + { + framerate <<= 1; + period++; + } + if (mode == MODE_SILK_ONLY) + { + toc = (bandwidth-OPUS_BANDWIDTH_NARROWBAND)<<5; + toc |= (period-2)<<3; + } else if (mode == MODE_CELT_ONLY) + { + int tmp = bandwidth-OPUS_BANDWIDTH_MEDIUMBAND; + if (tmp < 0) + tmp = 0; + toc = 0x80; + toc |= tmp << 5; + toc |= period<<3; + } else /* Hybrid */ + { + toc = 0x60; + toc |= (bandwidth-OPUS_BANDWIDTH_SUPERWIDEBAND)<<4; + toc |= (period-2)<<3; + } + toc |= (channels==2)<<2; + return toc; +} + +#ifndef FIXED_POINT +static void silk_biquad_float( + const opus_val16 *in, /* I: Input signal */ + const opus_int32 *B_Q28, /* I: MA coefficients [3] */ + const opus_int32 *A_Q28, /* I: AR coefficients [2] */ + opus_val32 *S, /* I/O: State vector [2] */ + opus_val16 *out, /* O: Output signal */ + const opus_int32 len, /* I: Signal length (must be even) */ + int stride +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k; + opus_val32 vout; + opus_val32 inval; + opus_val32 A[2], B[3]; + + A[0] = (opus_val32)(A_Q28[0] * (1.f/((opus_int32)1<<28))); + A[1] = (opus_val32)(A_Q28[1] * (1.f/((opus_int32)1<<28))); + B[0] = (opus_val32)(B_Q28[0] * (1.f/((opus_int32)1<<28))); + B[1] = (opus_val32)(B_Q28[1] * (1.f/((opus_int32)1<<28))); + B[2] = (opus_val32)(B_Q28[2] * (1.f/((opus_int32)1<<28))); + + /* Negate A_Q28 values and split in two parts */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ]: Q12 */ + inval = in[ k*stride ]; + vout = S[ 0 ] + B[0]*inval; + + S[ 0 ] = S[1] - vout*A[0] + B[1]*inval; + + S[ 1 ] = - vout*A[1] + B[2]*inval + VERY_SMALL; + + /* Scale back to Q0 and saturate */ + out[ k*stride ] = vout; + } +} +#endif + +static void hp_cutoff(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs, int arch) +{ + opus_int32 B_Q28[ 3 ], A_Q28[ 2 ]; + opus_int32 Fc_Q19, r_Q28, r_Q22; + (void)arch; + + silk_assert( cutoff_Hz <= silk_int32_MAX / SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ) ); + Fc_Q19 = silk_DIV32_16( silk_SMULBB( SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ), cutoff_Hz ), Fs/1000 ); + silk_assert( Fc_Q19 > 0 && Fc_Q19 < 32768 ); + + r_Q28 = SILK_FIX_CONST( 1.0, 28 ) - silk_MUL( SILK_FIX_CONST( 0.92, 9 ), Fc_Q19 ); + + /* b = r * [ 1; -2; 1 ]; */ + /* a = [ 1; -2 * r * ( 1 - 0.5 * Fc^2 ); r^2 ]; */ + B_Q28[ 0 ] = r_Q28; + B_Q28[ 1 ] = silk_LSHIFT( -r_Q28, 1 ); + B_Q28[ 2 ] = r_Q28; + + /* -r * ( 2 - Fc * Fc ); */ + r_Q22 = silk_RSHIFT( r_Q28, 6 ); + A_Q28[ 0 ] = silk_SMULWW( r_Q22, silk_SMULWW( Fc_Q19, Fc_Q19 ) - SILK_FIX_CONST( 2.0, 22 ) ); + A_Q28[ 1 ] = silk_SMULWW( r_Q22, r_Q22 ); + +#ifdef FIXED_POINT + if( channels == 1 ) { + silk_biquad_alt_stride1( in, B_Q28, A_Q28, hp_mem, out, len ); + } else { + silk_biquad_alt_stride2( in, B_Q28, A_Q28, hp_mem, out, len, arch ); + } +#else + silk_biquad_float( in, B_Q28, A_Q28, hp_mem, out, len, channels ); + if( channels == 2 ) { + silk_biquad_float( in+1, B_Q28, A_Q28, hp_mem+2, out+1, len, channels ); + } +#endif +} + +#ifdef FIXED_POINT +static void dc_reject(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs) +{ + int c, i; + int shift; + + /* Approximates -round(log2(6.3*cutoff_Hz/Fs)) */ + shift=celt_ilog2(Fs/(cutoff_Hz*4)); + for (c=0;cFs/400; + if (st->user_bitrate_bps==OPUS_AUTO) + return 60*st->Fs/frame_size + st->Fs*st->channels; + else if (st->user_bitrate_bps==OPUS_BITRATE_MAX) + return max_data_bytes*8*st->Fs/frame_size; + else + return st->user_bitrate_bps; +} + +#ifndef DISABLE_FLOAT_API +#ifdef FIXED_POINT +#define PCM2VAL(x) FLOAT2INT16(x) +#else +#define PCM2VAL(x) SCALEIN(x) +#endif + +void downmix_float(const void *_x, opus_val32 *y, int subframe, int offset, int c1, int c2, int C) +{ + const float *x; + int j; + + x = (const float *)_x; + for (j=0;j-1) + { + for (j=0;j-1) + { + for (j=0;j= OPUS_FRAMESIZE_2_5_MS && variable_duration <= OPUS_FRAMESIZE_120_MS) + { + if (variable_duration <= OPUS_FRAMESIZE_40_MS) + new_size = (Fs/400)<<(variable_duration-OPUS_FRAMESIZE_2_5_MS); + else + new_size = (variable_duration-OPUS_FRAMESIZE_2_5_MS-2)*Fs/50; + } + else + return -1; + if (new_size>frame_size) + return -1; + if (400*new_size!=Fs && 200*new_size!=Fs && 100*new_size!=Fs && + 50*new_size!=Fs && 25*new_size!=Fs && 50*new_size!=3*Fs && + 50*new_size!=4*Fs && 50*new_size!=5*Fs && 50*new_size!=6*Fs) + return -1; + return new_size; +} + +opus_val16 compute_stereo_width(const opus_val16 *pcm, int frame_size, opus_int32 Fs, StereoWidthState *mem) +{ + opus_val32 xx, xy, yy; + opus_val16 sqrt_xx, sqrt_yy; + opus_val16 qrrt_xx, qrrt_yy; + int frame_rate; + int i; + opus_val16 short_alpha; + + frame_rate = Fs/frame_size; + short_alpha = Q15ONE - MULT16_16(25, Q15ONE)/IMAX(50,frame_rate); + xx=xy=yy=0; + /* Unroll by 4. The frame size is always a multiple of 4 *except* for + 2.5 ms frames at 12 kHz. Since this setting is very rare (and very + stupid), we just discard the last two samples. */ + for (i=0;iXX += MULT16_32_Q15(short_alpha, xx-mem->XX); + mem->XY += MULT16_32_Q15(short_alpha, xy-mem->XY); + mem->YY += MULT16_32_Q15(short_alpha, yy-mem->YY); + mem->XX = MAX32(0, mem->XX); + mem->XY = MAX32(0, mem->XY); + mem->YY = MAX32(0, mem->YY); + if (MAX32(mem->XX, mem->YY)>QCONST16(8e-4f, 18)) + { + opus_val16 corr; + opus_val16 ldiff; + opus_val16 width; + sqrt_xx = celt_sqrt(mem->XX); + sqrt_yy = celt_sqrt(mem->YY); + qrrt_xx = celt_sqrt(sqrt_xx); + qrrt_yy = celt_sqrt(sqrt_yy); + /* Inter-channel correlation */ + mem->XY = MIN32(mem->XY, sqrt_xx*sqrt_yy); + corr = SHR32(frac_div32(mem->XY,EPSILON+MULT16_16(sqrt_xx,sqrt_yy)),16); + /* Approximate loudness difference */ + ldiff = MULT16_16(Q15ONE, ABS16(qrrt_xx-qrrt_yy))/(EPSILON+qrrt_xx+qrrt_yy); + width = MULT16_16_Q15(celt_sqrt(QCONST32(1.f,30)-MULT16_16(corr,corr)), ldiff); + /* Smoothing over one second */ + mem->smoothed_width += (width-mem->smoothed_width)/frame_rate; + /* Peak follower */ + mem->max_follower = MAX16(mem->max_follower-QCONST16(.02f,15)/frame_rate, mem->smoothed_width); + } + /*printf("%f %f %f %f %f ", corr/(float)Q15ONE, ldiff/(float)Q15ONE, width/(float)Q15ONE, mem->smoothed_width/(float)Q15ONE, mem->max_follower/(float)Q15ONE);*/ + return EXTRACT16(MIN32(Q15ONE, MULT16_16(20, mem->max_follower))); +} + +static int decide_fec(int useInBandFEC, int PacketLoss_perc, int last_fec, int mode, int *bandwidth, opus_int32 rate) +{ + int orig_bandwidth; + if (!useInBandFEC || PacketLoss_perc == 0 || mode == MODE_CELT_ONLY) + return 0; + orig_bandwidth = *bandwidth; + for (;;) + { + opus_int32 hysteresis; + opus_int32 LBRR_rate_thres_bps; + /* Compute threshold for using FEC at the current bandwidth setting */ + LBRR_rate_thres_bps = fec_thresholds[2*(*bandwidth - OPUS_BANDWIDTH_NARROWBAND)]; + hysteresis = fec_thresholds[2*(*bandwidth - OPUS_BANDWIDTH_NARROWBAND) + 1]; + if (last_fec == 1) LBRR_rate_thres_bps -= hysteresis; + if (last_fec == 0) LBRR_rate_thres_bps += hysteresis; + LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps, + 125 - silk_min( PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) ); + /* If loss <= 5%, we look at whether we have enough rate to enable FEC. + If loss > 5%, we decrease the bandwidth until we can enable FEC. */ + if (rate > LBRR_rate_thres_bps) + return 1; + else if (PacketLoss_perc <= 5) + return 0; + else if (*bandwidth > OPUS_BANDWIDTH_NARROWBAND) + (*bandwidth)--; + else + break; + } + /* Couldn't find any bandwidth to enable FEC, keep original bandwidth. */ + *bandwidth = orig_bandwidth; + return 0; +} + +static int compute_silk_rate_for_hybrid(int rate, int bandwidth, int frame20ms, int vbr, int fec, int channels) { + int entry; + int i; + int N; + int silk_rate; + static int rate_table[][5] = { + /* |total| |-------- SILK------------| + |-- No FEC -| |--- FEC ---| + 10ms 20ms 10ms 20ms */ + { 0, 0, 0, 0, 0}, + {12000, 10000, 10000, 11000, 11000}, + {16000, 13500, 13500, 15000, 15000}, + {20000, 16000, 16000, 18000, 18000}, + {24000, 18000, 18000, 21000, 21000}, + {32000, 22000, 22000, 28000, 28000}, + {64000, 38000, 38000, 50000, 50000} + }; + /* Do the allocation per-channel. */ + rate /= channels; + entry = 1 + frame20ms + 2*fec; + N = sizeof(rate_table)/sizeof(rate_table[0]); + for (i=1;i rate) break; + } + if (i == N) + { + silk_rate = rate_table[i-1][entry]; + /* For now, just give 50% of the extra bits to SILK. */ + silk_rate += (rate-rate_table[i-1][0])/2; + } else { + opus_int32 lo, hi, x0, x1; + lo = rate_table[i-1][entry]; + hi = rate_table[i][entry]; + x0 = rate_table[i-1][0]; + x1 = rate_table[i][0]; + silk_rate = (lo*(x1-rate) + hi*(rate-x0))/(x1-x0); + } + if (!vbr) + { + /* Tiny boost to SILK for CBR. We should probably tune this better. */ + silk_rate += 100; + } + if (bandwidth==OPUS_BANDWIDTH_SUPERWIDEBAND) + silk_rate += 300; + silk_rate *= channels; + /* Small adjustment for stereo (calibrated for 32 kb/s, haven't tried other bitrates). */ + if (channels == 2 && rate >= 12000) + silk_rate -= 1000; + return silk_rate; +} + +/* Returns the equivalent bitrate corresponding to 20 ms frames, + complexity 10 VBR operation. */ +static opus_int32 compute_equiv_rate(opus_int32 bitrate, int channels, + int frame_rate, int vbr, int mode, int complexity, int loss) +{ + opus_int32 equiv; + equiv = bitrate; + /* Take into account overhead from smaller frames. */ + if (frame_rate > 50) + equiv -= (40*channels+20)*(frame_rate - 50); + /* CBR is about a 8% penalty for both SILK and CELT. */ + if (!vbr) + equiv -= equiv/12; + /* Complexity makes about 10% difference (from 0 to 10) in general. */ + equiv = equiv * (90+complexity)/100; + if (mode == MODE_SILK_ONLY || mode == MODE_HYBRID) + { + /* SILK complexity 0-1 uses the non-delayed-decision NSQ, which + costs about 20%. */ + if (complexity<2) + equiv = equiv*4/5; + equiv -= equiv*loss/(6*loss + 10); + } else if (mode == MODE_CELT_ONLY) { + /* CELT complexity 0-4 doesn't have the pitch filter, which costs + about 10%. */ + if (complexity<5) + equiv = equiv*9/10; + } else { + /* Mode not known yet */ + /* Half the SILK loss*/ + equiv -= equiv*loss/(12*loss + 20); + } + return equiv; +} + +#ifndef DISABLE_FLOAT_API + +int is_digital_silence(const opus_val16* pcm, int frame_size, int channels, int lsb_depth) +{ + int silence = 0; + opus_val32 sample_max = 0; +#ifdef MLP_TRAINING + return 0; +#endif + sample_max = celt_maxabs16(pcm, frame_size*channels); + +#ifdef FIXED_POINT + silence = (sample_max == 0); + (void)lsb_depth; +#else + silence = (sample_max <= (opus_val16) 1 / (1 << lsb_depth)); +#endif + + return silence; +} + +#ifdef FIXED_POINT +static opus_val32 compute_frame_energy(const opus_val16 *pcm, int frame_size, int channels, int arch) +{ + int i; + opus_val32 sample_max; + int max_shift; + int shift; + opus_val32 energy = 0; + int len = frame_size*channels; + (void)arch; + /* Max amplitude in the signal */ + sample_max = celt_maxabs16(pcm, len); + + /* Compute the right shift required in the MAC to avoid an overflow */ + max_shift = celt_ilog2(len); + shift = IMAX(0, (celt_ilog2(sample_max) << 1) + max_shift - 28); + + /* Compute the energy */ + for (i=0; i NB_SPEECH_FRAMES_BEFORE_DTX*20*2) + { + if (*nb_no_activity_ms_Q1 <= (NB_SPEECH_FRAMES_BEFORE_DTX + MAX_CONSECUTIVE_DTX)*20*2) + /* Valid frame for DTX! */ + return 1; + else + (*nb_no_activity_ms_Q1) = NB_SPEECH_FRAMES_BEFORE_DTX*20*2; + } + } else + (*nb_no_activity_ms_Q1) = 0; + + return 0; +} + +#endif + +static opus_int32 encode_multiframe_packet(OpusEncoder *st, + const opus_val16 *pcm, + int nb_frames, + int frame_size, + unsigned char *data, + opus_int32 out_data_bytes, + int to_celt, + int lsb_depth, + int float_api) +{ + int i; + int ret = 0; + VARDECL(unsigned char, tmp_data); + int bak_mode, bak_bandwidth, bak_channels, bak_to_mono; + VARDECL(OpusRepacketizer, rp); + int max_header_bytes; + opus_int32 bytes_per_frame; + opus_int32 cbr_bytes; + opus_int32 repacketize_len; + int tmp_len; + ALLOC_STACK; + + /* Worst cases: + * 2 frames: Code 2 with different compressed sizes + * >2 frames: Code 3 VBR */ + max_header_bytes = nb_frames == 2 ? 3 : (2+(nb_frames-1)*2); + + if (st->use_vbr || st->user_bitrate_bps==OPUS_BITRATE_MAX) + repacketize_len = out_data_bytes; + else { + cbr_bytes = 3*st->bitrate_bps/(3*8*st->Fs/(frame_size*nb_frames)); + repacketize_len = IMIN(cbr_bytes, out_data_bytes); + } + bytes_per_frame = IMIN(1276, 1+(repacketize_len-max_header_bytes)/nb_frames); + + ALLOC(tmp_data, nb_frames*bytes_per_frame, unsigned char); + ALLOC(rp, 1, OpusRepacketizer); + opus_repacketizer_init(rp); + + bak_mode = st->user_forced_mode; + bak_bandwidth = st->user_bandwidth; + bak_channels = st->force_channels; + + st->user_forced_mode = st->mode; + st->user_bandwidth = st->bandwidth; + st->force_channels = st->stream_channels; + + bak_to_mono = st->silk_mode.toMono; + if (bak_to_mono) + st->force_channels = 1; + else + st->prev_channels = st->stream_channels; + + for (i=0;isilk_mode.toMono = 0; + st->nonfinal_frame = i<(nb_frames-1); + + /* When switching from SILK/Hybrid to CELT, only ask for a switch at the last frame */ + if (to_celt && i==nb_frames-1) + st->user_forced_mode = MODE_CELT_ONLY; + + tmp_len = opus_encode_native(st, pcm+i*(st->channels*frame_size), frame_size, + tmp_data+i*bytes_per_frame, bytes_per_frame, lsb_depth, NULL, 0, 0, 0, 0, + NULL, float_api); + + if (tmp_len<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + + ret = opus_repacketizer_cat(rp, tmp_data+i*bytes_per_frame, tmp_len); + + if (ret<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + } + + ret = opus_repacketizer_out_range_impl(rp, 0, nb_frames, data, repacketize_len, 0, !st->use_vbr); + + if (ret<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + + /* Discard configs that were forced locally for the purpose of repacketization */ + st->user_forced_mode = bak_mode; + st->user_bandwidth = bak_bandwidth; + st->force_channels = bak_channels; + st->silk_mode.toMono = bak_to_mono; + + RESTORE_STACK; + return ret; +} + +static int compute_redundancy_bytes(opus_int32 max_data_bytes, opus_int32 bitrate_bps, int frame_rate, int channels) +{ + int redundancy_bytes_cap; + int redundancy_bytes; + opus_int32 redundancy_rate; + int base_bits; + opus_int32 available_bits; + base_bits = (40*channels+20); + + /* Equivalent rate for 5 ms frames. */ + redundancy_rate = bitrate_bps + base_bits*(200 - frame_rate); + /* For VBR, further increase the bitrate if we can afford it. It's pretty short + and we'll avoid artefacts. */ + redundancy_rate = 3*redundancy_rate/2; + redundancy_bytes = redundancy_rate/1600; + + /* Compute the max rate we can use given CBR or VBR with cap. */ + available_bits = max_data_bytes*8 - 2*base_bits; + redundancy_bytes_cap = (available_bits*240/(240+48000/frame_rate) + base_bits)/8; + redundancy_bytes = IMIN(redundancy_bytes, redundancy_bytes_cap); + /* It we can't get enough bits for redundancy to be worth it, rely on the decoder PLC. */ + if (redundancy_bytes > 4 + 8*channels) + redundancy_bytes = IMIN(257, redundancy_bytes); + else + redundancy_bytes = 0; + return redundancy_bytes; +} + +opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size, + unsigned char *data, opus_int32 out_data_bytes, int lsb_depth, + const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2, + int analysis_channels, downmix_func downmix, int float_api) +{ + void *silk_enc; + CELTEncoder *celt_enc; + int i; + int ret=0; + opus_int32 nBytes; + ec_enc enc; + int bytes_target; + int prefill=0; + int start_band = 0; + int redundancy = 0; + int redundancy_bytes = 0; /* Number of bytes to use for redundancy frame */ + int celt_to_silk = 0; + VARDECL(opus_val16, pcm_buf); + int nb_compr_bytes; + int to_celt = 0; + opus_uint32 redundant_rng = 0; + int cutoff_Hz, hp_freq_smth1; + int voice_est; /* Probability of voice in Q7 */ + opus_int32 equiv_rate; + int delay_compensation; + int frame_rate; + opus_int32 max_rate; /* Max bitrate we're allowed to use */ + int curr_bandwidth; + opus_val16 HB_gain; + opus_int32 max_data_bytes; /* Max number of bytes we're allowed to use */ + int total_buffer; + opus_val16 stereo_width; + const CELTMode *celt_mode; +#ifndef DISABLE_FLOAT_API + AnalysisInfo analysis_info; + int analysis_read_pos_bak=-1; + int analysis_read_subframe_bak=-1; + int is_silence = 0; +#endif + opus_int activity = VAD_NO_DECISION; + + VARDECL(opus_val16, tmp_prefill); + + ALLOC_STACK; + + max_data_bytes = IMIN(1276, out_data_bytes); + + st->rangeFinal = 0; + if (frame_size <= 0 || max_data_bytes <= 0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + /* Cannot encode 100 ms in 1 byte */ + if (max_data_bytes==1 && st->Fs==(frame_size*10)) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + + silk_enc = (char*)st+st->silk_enc_offset; + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + delay_compensation = 0; + else + delay_compensation = st->delay_compensation; + + lsb_depth = IMIN(lsb_depth, st->lsb_depth); + + celt_encoder_ctl(celt_enc, CELT_GET_MODE(&celt_mode)); +#ifndef DISABLE_FLOAT_API + analysis_info.valid = 0; +#ifdef FIXED_POINT + if (st->silk_mode.complexity >= 10 && st->Fs>=16000) +#else + if (st->silk_mode.complexity >= 7 && st->Fs>=16000) +#endif + { + is_silence = is_digital_silence(pcm, frame_size, st->channels, lsb_depth); + analysis_read_pos_bak = st->analysis.read_pos; + analysis_read_subframe_bak = st->analysis.read_subframe; + run_analysis(&st->analysis, celt_mode, analysis_pcm, analysis_size, frame_size, + c1, c2, analysis_channels, st->Fs, + lsb_depth, downmix, &analysis_info); + + /* Track the peak signal energy */ + if (!is_silence && analysis_info.activity_probability > DTX_ACTIVITY_THRESHOLD) + st->peak_signal_energy = MAX32(MULT16_32_Q15(QCONST16(0.999f, 15), st->peak_signal_energy), + compute_frame_energy(pcm, frame_size, st->channels, st->arch)); + } else if (st->analysis.initialized) { + tonality_analysis_reset(&st->analysis); + } +#else + (void)analysis_pcm; + (void)analysis_size; + (void)c1; + (void)c2; + (void)analysis_channels; + (void)downmix; +#endif + +#ifndef DISABLE_FLOAT_API + /* Reset voice_ratio if this frame is not silent or if analysis is disabled. + * Otherwise, preserve voice_ratio from the last non-silent frame */ + if (!is_silence) + st->voice_ratio = -1; + + if (is_silence) + { + activity = !is_silence; + } else if (analysis_info.valid) + { + activity = analysis_info.activity_probability >= DTX_ACTIVITY_THRESHOLD; + if (!activity) + { + /* Mark as active if this noise frame is sufficiently loud */ + opus_val32 noise_energy = compute_frame_energy(pcm, frame_size, st->channels, st->arch); + activity = st->peak_signal_energy < (PSEUDO_SNR_THRESHOLD * noise_energy); + } + } + + st->detected_bandwidth = 0; + if (analysis_info.valid) + { + int analysis_bandwidth; + if (st->signal_type == OPUS_AUTO) + { + float prob; + if (st->prev_mode == 0) + prob = analysis_info.music_prob; + else if (st->prev_mode == MODE_CELT_ONLY) + prob = analysis_info.music_prob_max; + else + prob = analysis_info.music_prob_min; + st->voice_ratio = (int)floor(.5+100*(1-prob)); + } + + analysis_bandwidth = analysis_info.bandwidth; + if (analysis_bandwidth<=12) + st->detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND; + else if (analysis_bandwidth<=14) + st->detected_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + else if (analysis_bandwidth<=16) + st->detected_bandwidth = OPUS_BANDWIDTH_WIDEBAND; + else if (analysis_bandwidth<=18) + st->detected_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + else + st->detected_bandwidth = OPUS_BANDWIDTH_FULLBAND; + } +#else + st->voice_ratio = -1; +#endif + + if (st->channels==2 && st->force_channels!=1) + stereo_width = compute_stereo_width(pcm, frame_size, st->Fs, &st->width_mem); + else + stereo_width = 0; + total_buffer = delay_compensation; + st->bitrate_bps = user_bitrate_to_bitrate(st, frame_size, max_data_bytes); + + frame_rate = st->Fs/frame_size; + if (!st->use_vbr) + { + int cbrBytes; + /* Multiply by 12 to make sure the division is exact. */ + int frame_rate12 = 12*st->Fs/frame_size; + /* We need to make sure that "int" values always fit in 16 bits. */ + cbrBytes = IMIN( (12*st->bitrate_bps/8 + frame_rate12/2)/frame_rate12, max_data_bytes); + st->bitrate_bps = cbrBytes*(opus_int32)frame_rate12*8/12; + /* Make sure we provide at least one byte to avoid failing. */ + max_data_bytes = IMAX(1, cbrBytes); + } + if (max_data_bytes<3 || st->bitrate_bps < 3*frame_rate*8 + || (frame_rate<50 && (max_data_bytes*frame_rate<300 || st->bitrate_bps < 2400))) + { + /*If the space is too low to do something useful, emit 'PLC' frames.*/ + int tocmode = st->mode; + int bw = st->bandwidth == 0 ? OPUS_BANDWIDTH_NARROWBAND : st->bandwidth; + int packet_code = 0; + int num_multiframes = 0; + + if (tocmode==0) + tocmode = MODE_SILK_ONLY; + if (frame_rate>100) + tocmode = MODE_CELT_ONLY; + /* 40 ms -> 2 x 20 ms if in CELT_ONLY or HYBRID mode */ + if (frame_rate==25 && tocmode!=MODE_SILK_ONLY) + { + frame_rate = 50; + packet_code = 1; + } + + /* >= 60 ms frames */ + if (frame_rate<=16) + { + /* 1 x 60 ms, 2 x 40 ms, 2 x 60 ms */ + if (out_data_bytes==1 || (tocmode==MODE_SILK_ONLY && frame_rate!=10)) + { + tocmode = MODE_SILK_ONLY; + + packet_code = frame_rate <= 12; + frame_rate = frame_rate == 12 ? 25 : 16; + } + else + { + num_multiframes = 50/frame_rate; + frame_rate = 50; + packet_code = 3; + } + } + + if(tocmode==MODE_SILK_ONLY&&bw>OPUS_BANDWIDTH_WIDEBAND) + bw=OPUS_BANDWIDTH_WIDEBAND; + else if (tocmode==MODE_CELT_ONLY&&bw==OPUS_BANDWIDTH_MEDIUMBAND) + bw=OPUS_BANDWIDTH_NARROWBAND; + else if (tocmode==MODE_HYBRID&&bw<=OPUS_BANDWIDTH_SUPERWIDEBAND) + bw=OPUS_BANDWIDTH_SUPERWIDEBAND; + + data[0] = gen_toc(tocmode, frame_rate, bw, st->stream_channels); + data[0] |= packet_code; + + ret = packet_code <= 1 ? 1 : 2; + + max_data_bytes = IMAX(max_data_bytes, ret); + + if (packet_code==3) + data[1] = num_multiframes; + + if (!st->use_vbr) + { + ret = opus_packet_pad(data, ret, max_data_bytes); + if (ret == OPUS_OK) + ret = max_data_bytes; + else + ret = OPUS_INTERNAL_ERROR; + } + RESTORE_STACK; + return ret; + } + max_rate = frame_rate*max_data_bytes*8; + + /* Equivalent 20-ms rate for mode/channel/bandwidth decisions */ + equiv_rate = compute_equiv_rate(st->bitrate_bps, st->channels, st->Fs/frame_size, + st->use_vbr, 0, st->silk_mode.complexity, st->silk_mode.packetLossPercentage); + + if (st->signal_type == OPUS_SIGNAL_VOICE) + voice_est = 127; + else if (st->signal_type == OPUS_SIGNAL_MUSIC) + voice_est = 0; + else if (st->voice_ratio >= 0) + { + voice_est = st->voice_ratio*327>>8; + /* For AUDIO, never be more than 90% confident of having speech */ + if (st->application == OPUS_APPLICATION_AUDIO) + voice_est = IMIN(voice_est, 115); + } else if (st->application == OPUS_APPLICATION_VOIP) + voice_est = 115; + else + voice_est = 48; + + if (st->force_channels!=OPUS_AUTO && st->channels == 2) + { + st->stream_channels = st->force_channels; + } else { +#ifdef FUZZING + /* Random mono/stereo decision */ + if (st->channels == 2 && (rand()&0x1F)==0) + st->stream_channels = 3-st->stream_channels; +#else + /* Rate-dependent mono-stereo decision */ + if (st->channels == 2) + { + opus_int32 stereo_threshold; + stereo_threshold = stereo_music_threshold + ((voice_est*voice_est*(stereo_voice_threshold-stereo_music_threshold))>>14); + if (st->stream_channels == 2) + stereo_threshold -= 1000; + else + stereo_threshold += 1000; + st->stream_channels = (equiv_rate > stereo_threshold) ? 2 : 1; + } else { + st->stream_channels = st->channels; + } +#endif + } + /* Update equivalent rate for channels decision. */ + equiv_rate = compute_equiv_rate(st->bitrate_bps, st->stream_channels, st->Fs/frame_size, + st->use_vbr, 0, st->silk_mode.complexity, st->silk_mode.packetLossPercentage); + + /* Allow SILK DTX if DTX is enabled but the generalized DTX cannot be used, + e.g. because of the complexity setting or sample rate. */ +#ifndef DISABLE_FLOAT_API + st->silk_mode.useDTX = st->use_dtx && !(analysis_info.valid || is_silence); +#else + st->silk_mode.useDTX = st->use_dtx; +#endif + + /* Mode selection depending on application and signal type */ + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + { + st->mode = MODE_CELT_ONLY; + } else if (st->user_forced_mode == OPUS_AUTO) + { +#ifdef FUZZING + /* Random mode switching */ + if ((rand()&0xF)==0) + { + if ((rand()&0x1)==0) + st->mode = MODE_CELT_ONLY; + else + st->mode = MODE_SILK_ONLY; + } else { + if (st->prev_mode==MODE_CELT_ONLY) + st->mode = MODE_CELT_ONLY; + else + st->mode = MODE_SILK_ONLY; + } +#else + opus_int32 mode_voice, mode_music; + opus_int32 threshold; + + /* Interpolate based on stereo width */ + mode_voice = (opus_int32)(MULT16_32_Q15(Q15ONE-stereo_width,mode_thresholds[0][0]) + + MULT16_32_Q15(stereo_width,mode_thresholds[1][0])); + mode_music = (opus_int32)(MULT16_32_Q15(Q15ONE-stereo_width,mode_thresholds[1][1]) + + MULT16_32_Q15(stereo_width,mode_thresholds[1][1])); + /* Interpolate based on speech/music probability */ + threshold = mode_music + ((voice_est*voice_est*(mode_voice-mode_music))>>14); + /* Bias towards SILK for VoIP because of some useful features */ + if (st->application == OPUS_APPLICATION_VOIP) + threshold += 8000; + + /*printf("%f %d\n", stereo_width/(float)Q15ONE, threshold);*/ + /* Hysteresis */ + if (st->prev_mode == MODE_CELT_ONLY) + threshold -= 4000; + else if (st->prev_mode>0) + threshold += 4000; + + st->mode = (equiv_rate >= threshold) ? MODE_CELT_ONLY: MODE_SILK_ONLY; + + /* When FEC is enabled and there's enough packet loss, use SILK */ + if (st->silk_mode.useInBandFEC && st->silk_mode.packetLossPercentage > (128-voice_est)>>4) + st->mode = MODE_SILK_ONLY; + /* When encoding voice and DTX is enabled but the generalized DTX cannot be used, + use SILK in order to make use of its DTX. */ + if (st->silk_mode.useDTX && voice_est > 100) + st->mode = MODE_SILK_ONLY; +#endif + + /* If max_data_bytes represents less than 6 kb/s, switch to CELT-only mode */ + if (max_data_bytes < (frame_rate > 50 ? 9000 : 6000)*frame_size / (st->Fs * 8)) + st->mode = MODE_CELT_ONLY; + } else { + st->mode = st->user_forced_mode; + } + + /* Override the chosen mode to make sure we meet the requested frame size */ + if (st->mode != MODE_CELT_ONLY && frame_size < st->Fs/100) + st->mode = MODE_CELT_ONLY; + if (st->lfe) + st->mode = MODE_CELT_ONLY; + + if (st->prev_mode > 0 && + ((st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) || + (st->mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY))) + { + redundancy = 1; + celt_to_silk = (st->mode != MODE_CELT_ONLY); + if (!celt_to_silk) + { + /* Switch to SILK/hybrid if frame size is 10 ms or more*/ + if (frame_size >= st->Fs/100) + { + st->mode = st->prev_mode; + to_celt = 1; + } else { + redundancy=0; + } + } + } + + /* When encoding multiframes, we can ask for a switch to CELT only in the last frame. This switch + * is processed above as the requested mode shouldn't interrupt stereo->mono transition. */ + if (st->stream_channels == 1 && st->prev_channels ==2 && st->silk_mode.toMono==0 + && st->mode != MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY) + { + /* Delay stereo->mono transition by two frames so that SILK can do a smooth downmix */ + st->silk_mode.toMono = 1; + st->stream_channels = 2; + } else { + st->silk_mode.toMono = 0; + } + + /* Update equivalent rate with mode decision. */ + equiv_rate = compute_equiv_rate(st->bitrate_bps, st->stream_channels, st->Fs/frame_size, + st->use_vbr, st->mode, st->silk_mode.complexity, st->silk_mode.packetLossPercentage); + + if (st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) + { + silk_EncControlStruct dummy; + silk_InitEncoder( silk_enc, st->arch, &dummy); + prefill=1; + } + + /* Automatic (rate-dependent) bandwidth selection */ + if (st->mode == MODE_CELT_ONLY || st->first || st->silk_mode.allowBandwidthSwitch) + { + const opus_int32 *voice_bandwidth_thresholds, *music_bandwidth_thresholds; + opus_int32 bandwidth_thresholds[8]; + int bandwidth = OPUS_BANDWIDTH_FULLBAND; + + if (st->channels==2 && st->force_channels!=1) + { + voice_bandwidth_thresholds = stereo_voice_bandwidth_thresholds; + music_bandwidth_thresholds = stereo_music_bandwidth_thresholds; + } else { + voice_bandwidth_thresholds = mono_voice_bandwidth_thresholds; + music_bandwidth_thresholds = mono_music_bandwidth_thresholds; + } + /* Interpolate bandwidth thresholds depending on voice estimation */ + for (i=0;i<8;i++) + { + bandwidth_thresholds[i] = music_bandwidth_thresholds[i] + + ((voice_est*voice_est*(voice_bandwidth_thresholds[i]-music_bandwidth_thresholds[i]))>>14); + } + do { + int threshold, hysteresis; + threshold = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)]; + hysteresis = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)+1]; + if (!st->first) + { + if (st->auto_bandwidth >= bandwidth) + threshold -= hysteresis; + else + threshold += hysteresis; + } + if (equiv_rate >= threshold) + break; + } while (--bandwidth>OPUS_BANDWIDTH_NARROWBAND); + /* We don't use mediumband anymore, except when explicitly requested or during + mode transitions. */ + if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + bandwidth = OPUS_BANDWIDTH_WIDEBAND; + st->bandwidth = st->auto_bandwidth = bandwidth; + /* Prevents any transition to SWB/FB until the SILK layer has fully + switched to WB mode and turned the variable LP filter off */ + if (!st->first && st->mode != MODE_CELT_ONLY && !st->silk_mode.inWBmodeWithoutVariableLP && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + } + + if (st->bandwidth>st->max_bandwidth) + st->bandwidth = st->max_bandwidth; + + if (st->user_bandwidth != OPUS_AUTO) + st->bandwidth = st->user_bandwidth; + + /* This prevents us from using hybrid at unsafe CBR/max rates */ + if (st->mode != MODE_CELT_ONLY && max_rate < 15000) + { + st->bandwidth = IMIN(st->bandwidth, OPUS_BANDWIDTH_WIDEBAND); + } + + /* Prevents Opus from wasting bits on frequencies that are above + the Nyquist rate of the input signal */ + if (st->Fs <= 24000 && st->bandwidth > OPUS_BANDWIDTH_SUPERWIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + if (st->Fs <= 16000 && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + if (st->Fs <= 12000 && st->bandwidth > OPUS_BANDWIDTH_MEDIUMBAND) + st->bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + if (st->Fs <= 8000 && st->bandwidth > OPUS_BANDWIDTH_NARROWBAND) + st->bandwidth = OPUS_BANDWIDTH_NARROWBAND; +#ifndef DISABLE_FLOAT_API + /* Use detected bandwidth to reduce the encoded bandwidth. */ + if (st->detected_bandwidth && st->user_bandwidth == OPUS_AUTO) + { + int min_detected_bandwidth; + /* Makes bandwidth detection more conservative just in case the detector + gets it wrong when we could have coded a high bandwidth transparently. + When operating in SILK/hybrid mode, we don't go below wideband to avoid + more complicated switches that require redundancy. */ + if (equiv_rate <= 18000*st->stream_channels && st->mode == MODE_CELT_ONLY) + min_detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND; + else if (equiv_rate <= 24000*st->stream_channels && st->mode == MODE_CELT_ONLY) + min_detected_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + else if (equiv_rate <= 30000*st->stream_channels) + min_detected_bandwidth = OPUS_BANDWIDTH_WIDEBAND; + else if (equiv_rate <= 44000*st->stream_channels) + min_detected_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + else + min_detected_bandwidth = OPUS_BANDWIDTH_FULLBAND; + + st->detected_bandwidth = IMAX(st->detected_bandwidth, min_detected_bandwidth); + st->bandwidth = IMIN(st->bandwidth, st->detected_bandwidth); + } +#endif + st->silk_mode.LBRR_coded = decide_fec(st->silk_mode.useInBandFEC, st->silk_mode.packetLossPercentage, + st->silk_mode.LBRR_coded, st->mode, &st->bandwidth, equiv_rate); + celt_encoder_ctl(celt_enc, OPUS_SET_LSB_DEPTH(lsb_depth)); + + /* CELT mode doesn't support mediumband, use wideband instead */ + if (st->mode == MODE_CELT_ONLY && st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + if (st->lfe) + st->bandwidth = OPUS_BANDWIDTH_NARROWBAND; + + curr_bandwidth = st->bandwidth; + + /* Chooses the appropriate mode for speech + *NEVER* switch to/from CELT-only mode here as this will invalidate some assumptions */ + if (st->mode == MODE_SILK_ONLY && curr_bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->mode = MODE_HYBRID; + if (st->mode == MODE_HYBRID && curr_bandwidth <= OPUS_BANDWIDTH_WIDEBAND) + st->mode = MODE_SILK_ONLY; + + /* Can't support higher than >60 ms frames, and >20 ms when in Hybrid or CELT-only modes */ + if ((frame_size > st->Fs/50 && (st->mode != MODE_SILK_ONLY)) || frame_size > 3*st->Fs/50) + { + int enc_frame_size; + int nb_frames; + + if (st->mode == MODE_SILK_ONLY) + { + if (frame_size == 2*st->Fs/25) /* 80 ms -> 2x 40 ms */ + enc_frame_size = st->Fs/25; + else if (frame_size == 3*st->Fs/25) /* 120 ms -> 2x 60 ms */ + enc_frame_size = 3*st->Fs/50; + else /* 100 ms -> 5x 20 ms */ + enc_frame_size = st->Fs/50; + } + else + enc_frame_size = st->Fs/50; + + nb_frames = frame_size/enc_frame_size; + +#ifndef DISABLE_FLOAT_API + if (analysis_read_pos_bak!= -1) + { + st->analysis.read_pos = analysis_read_pos_bak; + st->analysis.read_subframe = analysis_read_subframe_bak; + } +#endif + + ret = encode_multiframe_packet(st, pcm, nb_frames, enc_frame_size, data, + out_data_bytes, to_celt, lsb_depth, float_api); + + RESTORE_STACK; + return ret; + } + + /* For the first frame at a new SILK bandwidth */ + if (st->silk_bw_switch) + { + redundancy = 1; + celt_to_silk = 1; + st->silk_bw_switch = 0; + /* Do a prefill without reseting the sampling rate control. */ + prefill=2; + } + + /* If we decided to go with CELT, make sure redundancy is off, no matter what + we decided earlier. */ + if (st->mode == MODE_CELT_ONLY) + redundancy = 0; + + if (redundancy) + { + redundancy_bytes = compute_redundancy_bytes(max_data_bytes, st->bitrate_bps, frame_rate, st->stream_channels); + if (redundancy_bytes == 0) + redundancy = 0; + } + + /* printf("%d %d %d %d\n", st->bitrate_bps, st->stream_channels, st->mode, curr_bandwidth); */ + bytes_target = IMIN(max_data_bytes-redundancy_bytes, st->bitrate_bps * frame_size / (st->Fs * 8)) - 1; + + data += 1; + + ec_enc_init(&enc, data, max_data_bytes-1); + + ALLOC(pcm_buf, (total_buffer+frame_size)*st->channels, opus_val16); + OPUS_COPY(pcm_buf, &st->delay_buffer[(st->encoder_buffer-total_buffer)*st->channels], total_buffer*st->channels); + + if (st->mode == MODE_CELT_ONLY) + hp_freq_smth1 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + else + hp_freq_smth1 = ((silk_encoder*)silk_enc)->state_Fxx[0].sCmn.variable_HP_smth1_Q15; + + st->variable_HP_smth2_Q15 = silk_SMLAWB( st->variable_HP_smth2_Q15, + hp_freq_smth1 - st->variable_HP_smth2_Q15, SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF2, 16 ) ); + + /* convert from log scale to Hertz */ + cutoff_Hz = silk_log2lin( silk_RSHIFT( st->variable_HP_smth2_Q15, 8 ) ); + + if (st->application == OPUS_APPLICATION_VOIP) + { + hp_cutoff(pcm, cutoff_Hz, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs, st->arch); + } else { + dc_reject(pcm, 3, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs); + } +#ifndef FIXED_POINT + if (float_api) + { + opus_val32 sum; + sum = celt_inner_prod(&pcm_buf[total_buffer*st->channels], &pcm_buf[total_buffer*st->channels], frame_size*st->channels, st->arch); + /* This should filter out both NaNs and ridiculous signals that could + cause NaNs further down. */ + if (!(sum < 1e9f) || celt_isnan(sum)) + { + OPUS_CLEAR(&pcm_buf[total_buffer*st->channels], frame_size*st->channels); + st->hp_mem[0] = st->hp_mem[1] = st->hp_mem[2] = st->hp_mem[3] = 0; + } + } +#endif + + + /* SILK processing */ + HB_gain = Q15ONE; + if (st->mode != MODE_CELT_ONLY) + { + opus_int32 total_bitRate, celt_rate; +#ifdef FIXED_POINT + const opus_int16 *pcm_silk; +#else + VARDECL(opus_int16, pcm_silk); + ALLOC(pcm_silk, st->channels*frame_size, opus_int16); +#endif + + /* Distribute bits between SILK and CELT */ + total_bitRate = 8 * bytes_target * frame_rate; + if( st->mode == MODE_HYBRID ) { + /* Base rate for SILK */ + st->silk_mode.bitRate = compute_silk_rate_for_hybrid(total_bitRate, + curr_bandwidth, st->Fs == 50 * frame_size, st->use_vbr, st->silk_mode.LBRR_coded, + st->stream_channels); + if (!st->energy_masking) + { + /* Increasingly attenuate high band when it gets allocated fewer bits */ + celt_rate = total_bitRate - st->silk_mode.bitRate; + HB_gain = Q15ONE - SHR32(celt_exp2(-celt_rate * QCONST16(1.f/1024, 10)), 1); + } + } else { + /* SILK gets all bits */ + st->silk_mode.bitRate = total_bitRate; + } + + /* Surround masking for SILK */ + if (st->energy_masking && st->use_vbr && !st->lfe) + { + opus_val32 mask_sum=0; + opus_val16 masking_depth; + opus_int32 rate_offset; + int c; + int end = 17; + opus_int16 srate = 16000; + if (st->bandwidth == OPUS_BANDWIDTH_NARROWBAND) + { + end = 13; + srate = 8000; + } else if (st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + { + end = 15; + srate = 12000; + } + for (c=0;cchannels;c++) + { + for(i=0;ienergy_masking[21*c+i], + QCONST16(.5f, DB_SHIFT)), -QCONST16(2.0f, DB_SHIFT)); + if (mask > 0) + mask = HALF16(mask); + mask_sum += mask; + } + } + /* Conservative rate reduction, we cut the masking in half */ + masking_depth = mask_sum / end*st->channels; + masking_depth += QCONST16(.2f, DB_SHIFT); + rate_offset = (opus_int32)PSHR32(MULT16_16(srate, masking_depth), DB_SHIFT); + rate_offset = MAX32(rate_offset, -2*st->silk_mode.bitRate/3); + /* Split the rate change between the SILK and CELT part for hybrid. */ + if (st->bandwidth==OPUS_BANDWIDTH_SUPERWIDEBAND || st->bandwidth==OPUS_BANDWIDTH_FULLBAND) + st->silk_mode.bitRate += 3*rate_offset/5; + else + st->silk_mode.bitRate += rate_offset; + } + + st->silk_mode.payloadSize_ms = 1000 * frame_size / st->Fs; + st->silk_mode.nChannelsAPI = st->channels; + st->silk_mode.nChannelsInternal = st->stream_channels; + if (curr_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.desiredInternalSampleRate = 8000; + } else if (curr_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.desiredInternalSampleRate = 12000; + } else { + celt_assert( st->mode == MODE_HYBRID || curr_bandwidth == OPUS_BANDWIDTH_WIDEBAND ); + st->silk_mode.desiredInternalSampleRate = 16000; + } + if( st->mode == MODE_HYBRID ) { + /* Don't allow bandwidth reduction at lowest bitrates in hybrid mode */ + st->silk_mode.minInternalSampleRate = 16000; + } else { + st->silk_mode.minInternalSampleRate = 8000; + } + + st->silk_mode.maxInternalSampleRate = 16000; + if (st->mode == MODE_SILK_ONLY) + { + opus_int32 effective_max_rate = max_rate; + if (frame_rate > 50) + effective_max_rate = effective_max_rate*2/3; + if (effective_max_rate < 8000) + { + st->silk_mode.maxInternalSampleRate = 12000; + st->silk_mode.desiredInternalSampleRate = IMIN(12000, st->silk_mode.desiredInternalSampleRate); + } + if (effective_max_rate < 7000) + { + st->silk_mode.maxInternalSampleRate = 8000; + st->silk_mode.desiredInternalSampleRate = IMIN(8000, st->silk_mode.desiredInternalSampleRate); + } + } + + st->silk_mode.useCBR = !st->use_vbr; + + /* Call SILK encoder for the low band */ + + /* Max bits for SILK, counting ToC, redundancy bytes, and optionally redundancy. */ + st->silk_mode.maxBits = (max_data_bytes-1)*8; + if (redundancy && redundancy_bytes >= 2) + { + /* Counting 1 bit for redundancy position and 20 bits for flag+size (only for hybrid). */ + st->silk_mode.maxBits -= redundancy_bytes*8 + 1; + if (st->mode == MODE_HYBRID) + st->silk_mode.maxBits -= 20; + } + if (st->silk_mode.useCBR) + { + if (st->mode == MODE_HYBRID) + { + st->silk_mode.maxBits = IMIN(st->silk_mode.maxBits, st->silk_mode.bitRate * frame_size / st->Fs); + } + } else { + /* Constrained VBR. */ + if (st->mode == MODE_HYBRID) + { + /* Compute SILK bitrate corresponding to the max total bits available */ + opus_int32 maxBitRate = compute_silk_rate_for_hybrid(st->silk_mode.maxBits*st->Fs / frame_size, + curr_bandwidth, st->Fs == 50 * frame_size, st->use_vbr, st->silk_mode.LBRR_coded, + st->stream_channels); + st->silk_mode.maxBits = maxBitRate * frame_size / st->Fs; + } + } + + if (prefill) + { + opus_int32 zero=0; + int prefill_offset; + /* Use a smooth onset for the SILK prefill to avoid the encoder trying to encode + a discontinuity. The exact location is what we need to avoid leaving any "gap" + in the audio when mixing with the redundant CELT frame. Here we can afford to + overwrite st->delay_buffer because the only thing that uses it before it gets + rewritten is tmp_prefill[] and even then only the part after the ramp really + gets used (rather than sent to the encoder and discarded) */ + prefill_offset = st->channels*(st->encoder_buffer-st->delay_compensation-st->Fs/400); + gain_fade(st->delay_buffer+prefill_offset, st->delay_buffer+prefill_offset, + 0, Q15ONE, celt_mode->overlap, st->Fs/400, st->channels, celt_mode->window, st->Fs); + OPUS_CLEAR(st->delay_buffer, prefill_offset); +#ifdef FIXED_POINT + pcm_silk = st->delay_buffer; +#else + for (i=0;iencoder_buffer*st->channels;i++) + pcm_silk[i] = FLOAT2INT16(st->delay_buffer[i]); +#endif + silk_Encode( silk_enc, &st->silk_mode, pcm_silk, st->encoder_buffer, NULL, &zero, prefill, activity ); + /* Prevent a second switch in the real encode call. */ + st->silk_mode.opusCanSwitch = 0; + } + +#ifdef FIXED_POINT + pcm_silk = pcm_buf+total_buffer*st->channels; +#else + for (i=0;ichannels;i++) + pcm_silk[i] = FLOAT2INT16(pcm_buf[total_buffer*st->channels + i]); +#endif + ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0, activity ); + if( ret ) { + /*fprintf (stderr, "SILK encode error: %d\n", ret);*/ + /* Handle error */ + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + + /* Extract SILK internal bandwidth for signaling in first byte */ + if( st->mode == MODE_SILK_ONLY ) { + if( st->silk_mode.internalSampleRate == 8000 ) { + curr_bandwidth = OPUS_BANDWIDTH_NARROWBAND; + } else if( st->silk_mode.internalSampleRate == 12000 ) { + curr_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + } else if( st->silk_mode.internalSampleRate == 16000 ) { + curr_bandwidth = OPUS_BANDWIDTH_WIDEBAND; + } + } else { + celt_assert( st->silk_mode.internalSampleRate == 16000 ); + } + + st->silk_mode.opusCanSwitch = st->silk_mode.switchReady && !st->nonfinal_frame; + + if (nBytes==0) + { + st->rangeFinal = 0; + data[-1] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); + RESTORE_STACK; + return 1; + } + + /* FIXME: How do we allocate the redundancy for CBR? */ + if (st->silk_mode.opusCanSwitch) + { + redundancy_bytes = compute_redundancy_bytes(max_data_bytes, st->bitrate_bps, frame_rate, st->stream_channels); + redundancy = (redundancy_bytes != 0); + celt_to_silk = 0; + st->silk_bw_switch = 1; + } + } + + /* CELT processing */ + { + int endband=21; + + switch(curr_bandwidth) + { + case OPUS_BANDWIDTH_NARROWBAND: + endband = 13; + break; + case OPUS_BANDWIDTH_MEDIUMBAND: + case OPUS_BANDWIDTH_WIDEBAND: + endband = 17; + break; + case OPUS_BANDWIDTH_SUPERWIDEBAND: + endband = 19; + break; + case OPUS_BANDWIDTH_FULLBAND: + endband = 21; + break; + } + celt_encoder_ctl(celt_enc, CELT_SET_END_BAND(endband)); + celt_encoder_ctl(celt_enc, CELT_SET_CHANNELS(st->stream_channels)); + } + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX)); + if (st->mode != MODE_SILK_ONLY) + { + opus_val32 celt_pred=2; + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); + /* We may still decide to disable prediction later */ + if (st->silk_mode.reducedDependency) + celt_pred = 0; + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(celt_pred)); + + if (st->mode == MODE_HYBRID) + { + if( st->use_vbr ) { + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps-st->silk_mode.bitRate)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(0)); + } + } else { + if (st->use_vbr) + { + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(st->vbr_constraint)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps)); + } + } + } + + ALLOC(tmp_prefill, st->channels*st->Fs/400, opus_val16); + if (st->mode != MODE_SILK_ONLY && st->mode != st->prev_mode && st->prev_mode > 0) + { + OPUS_COPY(tmp_prefill, &st->delay_buffer[(st->encoder_buffer-total_buffer-st->Fs/400)*st->channels], st->channels*st->Fs/400); + } + + if (st->channels*(st->encoder_buffer-(frame_size+total_buffer)) > 0) + { + OPUS_MOVE(st->delay_buffer, &st->delay_buffer[st->channels*frame_size], st->channels*(st->encoder_buffer-frame_size-total_buffer)); + OPUS_COPY(&st->delay_buffer[st->channels*(st->encoder_buffer-frame_size-total_buffer)], + &pcm_buf[0], + (frame_size+total_buffer)*st->channels); + } else { + OPUS_COPY(st->delay_buffer, &pcm_buf[(frame_size+total_buffer-st->encoder_buffer)*st->channels], st->encoder_buffer*st->channels); + } + /* gain_fade() and stereo_fade() need to be after the buffer copying + because we don't want any of this to affect the SILK part */ + if( st->prev_HB_gain < Q15ONE || HB_gain < Q15ONE ) { + gain_fade(pcm_buf, pcm_buf, + st->prev_HB_gain, HB_gain, celt_mode->overlap, frame_size, st->channels, celt_mode->window, st->Fs); + } + st->prev_HB_gain = HB_gain; + if (st->mode != MODE_HYBRID || st->stream_channels==1) + { + if (equiv_rate > 32000) + st->silk_mode.stereoWidth_Q14 = 16384; + else if (equiv_rate < 16000) + st->silk_mode.stereoWidth_Q14 = 0; + else + st->silk_mode.stereoWidth_Q14 = 16384 - 2048*(opus_int32)(32000-equiv_rate)/(equiv_rate-14000); + } + if( !st->energy_masking && st->channels == 2 ) { + /* Apply stereo width reduction (at low bitrates) */ + if( st->hybrid_stereo_width_Q14 < (1 << 14) || st->silk_mode.stereoWidth_Q14 < (1 << 14) ) { + opus_val16 g1, g2; + g1 = st->hybrid_stereo_width_Q14; + g2 = (opus_val16)(st->silk_mode.stereoWidth_Q14); +#ifdef FIXED_POINT + g1 = g1==16384 ? Q15ONE : SHL16(g1,1); + g2 = g2==16384 ? Q15ONE : SHL16(g2,1); +#else + g1 *= (1.f/16384); + g2 *= (1.f/16384); +#endif + stereo_fade(pcm_buf, pcm_buf, g1, g2, celt_mode->overlap, + frame_size, st->channels, celt_mode->window, st->Fs); + st->hybrid_stereo_width_Q14 = st->silk_mode.stereoWidth_Q14; + } + } + + if ( st->mode != MODE_CELT_ONLY && ec_tell(&enc)+17+20*(st->mode == MODE_HYBRID) <= 8*(max_data_bytes-1)) + { + /* For SILK mode, the redundancy is inferred from the length */ + if (st->mode == MODE_HYBRID) + ec_enc_bit_logp(&enc, redundancy, 12); + if (redundancy) + { + int max_redundancy; + ec_enc_bit_logp(&enc, celt_to_silk, 1); + if (st->mode == MODE_HYBRID) + { + /* Reserve the 8 bits needed for the redundancy length, + and at least a few bits for CELT if possible */ + max_redundancy = (max_data_bytes-1)-((ec_tell(&enc)+8+3+7)>>3); + } + else + max_redundancy = (max_data_bytes-1)-((ec_tell(&enc)+7)>>3); + /* Target the same bit-rate for redundancy as for the rest, + up to a max of 257 bytes */ + redundancy_bytes = IMIN(max_redundancy, redundancy_bytes); + redundancy_bytes = IMIN(257, IMAX(2, redundancy_bytes)); + if (st->mode == MODE_HYBRID) + ec_enc_uint(&enc, redundancy_bytes-2, 256); + } + } else { + redundancy = 0; + } + + if (!redundancy) + { + st->silk_bw_switch = 0; + redundancy_bytes = 0; + } + if (st->mode != MODE_CELT_ONLY)start_band=17; + + if (st->mode == MODE_SILK_ONLY) + { + ret = (ec_tell(&enc)+7)>>3; + ec_enc_done(&enc); + nb_compr_bytes = ret; + } else { + nb_compr_bytes = (max_data_bytes-1)-redundancy_bytes; + ec_enc_shrink(&enc, nb_compr_bytes); + } + +#ifndef DISABLE_FLOAT_API + if (redundancy || st->mode != MODE_SILK_ONLY) + celt_encoder_ctl(celt_enc, CELT_SET_ANALYSIS(&analysis_info)); +#endif + if (st->mode == MODE_HYBRID) { + SILKInfo info; + info.signalType = st->silk_mode.signalType; + info.offset = st->silk_mode.offset; + celt_encoder_ctl(celt_enc, CELT_SET_SILK_INFO(&info)); + } + + /* 5 ms redundant frame for CELT->SILK */ + if (redundancy && celt_to_silk) + { + int err; + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX)); + err = celt_encode_with_ec(celt_enc, pcm_buf, st->Fs/200, data+nb_compr_bytes, redundancy_bytes, NULL); + if (err < 0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng)); + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + } + + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(start_band)); + + if (st->mode != MODE_SILK_ONLY) + { + if (st->mode != st->prev_mode && st->prev_mode > 0) + { + unsigned char dummy[2]; + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + + /* Prefilling */ + celt_encode_with_ec(celt_enc, tmp_prefill, st->Fs/400, dummy, 2, NULL); + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0)); + } + /* If false, we already busted the budget and we'll end up with a "PLC frame" */ + if (ec_tell(&enc) <= 8*nb_compr_bytes) + { + /* Set the bitrate again if it was overridden in the redundancy code above*/ + if (redundancy && celt_to_silk && st->mode==MODE_HYBRID && st->use_vbr) + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps-st->silk_mode.bitRate)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(st->use_vbr)); + ret = celt_encode_with_ec(celt_enc, pcm_buf, frame_size, NULL, nb_compr_bytes, &enc); + if (ret < 0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + /* Put CELT->SILK redundancy data in the right place. */ + if (redundancy && celt_to_silk && st->mode==MODE_HYBRID && st->use_vbr) + { + OPUS_MOVE(data+ret, data+nb_compr_bytes, redundancy_bytes); + nb_compr_bytes = nb_compr_bytes+redundancy_bytes; + } + } + } + + /* 5 ms redundant frame for SILK->CELT */ + if (redundancy && !celt_to_silk) + { + int err; + unsigned char dummy[2]; + int N2, N4; + N2 = st->Fs/200; + N4 = st->Fs/400; + + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0)); + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX)); + + if (st->mode == MODE_HYBRID) + { + /* Shrink packet to what the encoder actually used. */ + nb_compr_bytes = ret; + ec_enc_shrink(&enc, nb_compr_bytes); + } + /* NOTE: We could speed this up slightly (at the expense of code size) by just adding a function that prefills the buffer */ + celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2-N4), N4, dummy, 2, NULL); + + err = celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2), N2, data+nb_compr_bytes, redundancy_bytes, NULL); + if (err < 0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng)); + } + + + + /* Signalling the mode in the first byte */ + data--; + data[0] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); + + st->rangeFinal = enc.rng ^ redundant_rng; + + if (to_celt) + st->prev_mode = MODE_CELT_ONLY; + else + st->prev_mode = st->mode; + st->prev_channels = st->stream_channels; + st->prev_framesize = frame_size; + + st->first = 0; + + /* DTX decision */ +#ifndef DISABLE_FLOAT_API + if (st->use_dtx && (analysis_info.valid || is_silence)) + { + if (decide_dtx_mode(activity, &st->nb_no_activity_ms_Q1, 2*1000*frame_size/st->Fs)) + { + st->rangeFinal = 0; + data[0] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); + RESTORE_STACK; + return 1; + } + } else { + st->nb_no_activity_ms_Q1 = 0; + } +#endif + + /* In the unlikely case that the SILK encoder busted its target, tell + the decoder to call the PLC */ + if (ec_tell(&enc) > (max_data_bytes-1)*8) + { + if (max_data_bytes < 2) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + data[1] = 0; + ret = 1; + st->rangeFinal = 0; + } else if (st->mode==MODE_SILK_ONLY&&!redundancy) + { + /*When in LPC only mode it's perfectly + reasonable to strip off trailing zero bytes as + the required range decoder behavior is to + fill these in. This can't be done when the MDCT + modes are used because the decoder needs to know + the actual length for allocation purposes.*/ + while(ret>2&&data[ret]==0)ret--; + } + /* Count ToC and redundancy */ + ret += 1+redundancy_bytes; + if (!st->use_vbr) + { + if (opus_packet_pad(data, ret, max_data_bytes) != OPUS_OK) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + ret = max_data_bytes; + } + RESTORE_STACK; + return ret; +} + +#ifdef FIXED_POINT + +#ifndef DISABLE_FLOAT_API +opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_frame_size, + unsigned char *data, opus_int32 max_data_bytes) +{ + int i, ret; + int frame_size; + VARDECL(opus_int16, in); + ALLOC_STACK; + + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + if (frame_size <= 0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + ALLOC(in, frame_size*st->channels, opus_int16); + + for (i=0;ichannels;i++) + in[i] = FLOAT2INT16(pcm[i]); + ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16, + pcm, analysis_frame_size, 0, -2, st->channels, downmix_float, 1); + RESTORE_STACK; + return ret; +} +#endif + +opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_frame_size, + unsigned char *data, opus_int32 out_data_bytes) +{ + int frame_size; + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 16, + pcm, analysis_frame_size, 0, -2, st->channels, downmix_int, 0); +} + +#else +opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_frame_size, + unsigned char *data, opus_int32 max_data_bytes) +{ + int i, ret; + int frame_size; + VARDECL(float, in); + ALLOC_STACK; + + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + if (frame_size <= 0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + ALLOC(in, frame_size*st->channels, float); + + for (i=0;ichannels;i++) + in[i] = (1.0f/32768)*pcm[i]; + ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16, + pcm, analysis_frame_size, 0, -2, st->channels, downmix_int, 0); + RESTORE_STACK; + return ret; +} +opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_frame_size, + unsigned char *data, opus_int32 out_data_bytes) +{ + int frame_size; + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 24, + pcm, analysis_frame_size, 0, -2, st->channels, downmix_float, 1); +} +#endif + + +int opus_encoder_ctl(OpusEncoder *st, int request, ...) +{ + int ret; + CELTEncoder *celt_enc; + va_list ap; + + ret = OPUS_OK; + va_start(ap, request); + + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + + switch (request) + { + case OPUS_SET_APPLICATION_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ( (value != OPUS_APPLICATION_VOIP && value != OPUS_APPLICATION_AUDIO + && value != OPUS_APPLICATION_RESTRICTED_LOWDELAY) + || (!st->first && st->application != value)) + { + ret = OPUS_BAD_ARG; + break; + } + st->application = value; +#ifndef DISABLE_FLOAT_API + st->analysis.application = value; +#endif + } + break; + case OPUS_GET_APPLICATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->application; + } + break; + case OPUS_SET_BITRATE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value != OPUS_AUTO && value != OPUS_BITRATE_MAX) + { + if (value <= 0) + goto bad_arg; + else if (value <= 500) + value = 500; + else if (value > (opus_int32)300000*st->channels) + value = (opus_int32)300000*st->channels; + } + st->user_bitrate_bps = value; + } + break; + case OPUS_GET_BITRATE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = user_bitrate_to_bitrate(st, st->prev_framesize, 1276); + } + break; + case OPUS_SET_FORCE_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if((value<1 || value>st->channels) && value != OPUS_AUTO) + { + goto bad_arg; + } + st->force_channels = value; + } + break; + case OPUS_GET_FORCE_CHANNELS_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->force_channels; + } + break; + case OPUS_SET_MAX_BANDWIDTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) + { + goto bad_arg; + } + st->max_bandwidth = value; + if (st->max_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.maxInternalSampleRate = 8000; + } else if (st->max_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.maxInternalSampleRate = 12000; + } else { + st->silk_mode.maxInternalSampleRate = 16000; + } + } + break; + case OPUS_GET_MAX_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->max_bandwidth; + } + break; + case OPUS_SET_BANDWIDTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ((value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) && value != OPUS_AUTO) + { + goto bad_arg; + } + st->user_bandwidth = value; + if (st->user_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.maxInternalSampleRate = 8000; + } else if (st->user_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.maxInternalSampleRate = 12000; + } else { + st->silk_mode.maxInternalSampleRate = 16000; + } + } + break; + case OPUS_GET_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->bandwidth; + } + break; + case OPUS_SET_DTX_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->use_dtx = value; + } + break; + case OPUS_GET_DTX_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->use_dtx; + } + break; + case OPUS_SET_COMPLEXITY_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>10) + { + goto bad_arg; + } + st->silk_mode.complexity = value; + celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(value)); + } + break; + case OPUS_GET_COMPLEXITY_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->silk_mode.complexity; + } + break; + case OPUS_SET_INBAND_FEC_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->silk_mode.useInBandFEC = value; + } + break; + case OPUS_GET_INBAND_FEC_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->silk_mode.useInBandFEC; + } + break; + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value < 0 || value > 100) + { + goto bad_arg; + } + st->silk_mode.packetLossPercentage = value; + celt_encoder_ctl(celt_enc, OPUS_SET_PACKET_LOSS_PERC(value)); + } + break; + case OPUS_GET_PACKET_LOSS_PERC_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->silk_mode.packetLossPercentage; + } + break; + case OPUS_SET_VBR_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->use_vbr = value; + st->silk_mode.useCBR = 1-value; + } + break; + case OPUS_GET_VBR_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->use_vbr; + } + break; + case OPUS_SET_VOICE_RATIO_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<-1 || value>100) + { + goto bad_arg; + } + st->voice_ratio = value; + } + break; + case OPUS_GET_VOICE_RATIO_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->voice_ratio; + } + break; + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->vbr_constraint = value; + } + break; + case OPUS_GET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->vbr_constraint; + } + break; + case OPUS_SET_SIGNAL_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value!=OPUS_AUTO && value!=OPUS_SIGNAL_VOICE && value!=OPUS_SIGNAL_MUSIC) + { + goto bad_arg; + } + st->signal_type = value; + } + break; + case OPUS_GET_SIGNAL_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->signal_type; + } + break; + case OPUS_GET_LOOKAHEAD_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->Fs/400; + if (st->application != OPUS_APPLICATION_RESTRICTED_LOWDELAY) + *value += st->delay_compensation; + } + break; + case OPUS_GET_SAMPLE_RATE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->Fs; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 *value = va_arg(ap, opus_uint32*); + if (!value) + { + goto bad_arg; + } + *value = st->rangeFinal; + } + break; + case OPUS_SET_LSB_DEPTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<8 || value>24) + { + goto bad_arg; + } + st->lsb_depth=value; + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->lsb_depth; + } + break; + case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value != OPUS_FRAMESIZE_ARG && value != OPUS_FRAMESIZE_2_5_MS && + value != OPUS_FRAMESIZE_5_MS && value != OPUS_FRAMESIZE_10_MS && + value != OPUS_FRAMESIZE_20_MS && value != OPUS_FRAMESIZE_40_MS && + value != OPUS_FRAMESIZE_60_MS && value != OPUS_FRAMESIZE_80_MS && + value != OPUS_FRAMESIZE_100_MS && value != OPUS_FRAMESIZE_120_MS) + { + goto bad_arg; + } + st->variable_duration = value; + } + break; + case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->variable_duration; + } + break; + case OPUS_SET_PREDICTION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value > 1 || value < 0) + goto bad_arg; + st->silk_mode.reducedDependency = value; + } + break; + case OPUS_GET_PREDICTION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + goto bad_arg; + *value = st->silk_mode.reducedDependency; + } + break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + celt_encoder_ctl(celt_enc, OPUS_SET_PHASE_INVERSION_DISABLED(value)); + } + break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + celt_encoder_ctl(celt_enc, OPUS_GET_PHASE_INVERSION_DISABLED(value)); + } + break; + case OPUS_RESET_STATE: + { + void *silk_enc; + silk_EncControlStruct dummy; + char *start; + silk_enc = (char*)st+st->silk_enc_offset; +#ifndef DISABLE_FLOAT_API + tonality_analysis_reset(&st->analysis); +#endif + + start = (char*)&st->OPUS_ENCODER_RESET_START; + OPUS_CLEAR(start, sizeof(OpusEncoder) - (start - (char*)st)); + + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + silk_InitEncoder( silk_enc, st->arch, &dummy ); + st->stream_channels = st->channels; + st->hybrid_stereo_width_Q14 = 1 << 14; + st->prev_HB_gain = Q15ONE; + st->first = 1; + st->mode = MODE_HYBRID; + st->bandwidth = OPUS_BANDWIDTH_FULLBAND; + st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + } + break; + case OPUS_SET_FORCE_MODE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ((value < MODE_SILK_ONLY || value > MODE_CELT_ONLY) && value != OPUS_AUTO) + { + goto bad_arg; + } + st->user_forced_mode = value; + } + break; + case OPUS_SET_LFE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->lfe = value; + ret = celt_encoder_ctl(celt_enc, OPUS_SET_LFE(value)); + } + break; + case OPUS_SET_ENERGY_MASK_REQUEST: + { + opus_val16 *value = va_arg(ap, opus_val16*); + st->energy_masking = value; + ret = celt_encoder_ctl(celt_enc, OPUS_SET_ENERGY_MASK(value)); + } + break; + case OPUS_GET_IN_DTX_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + if (st->silk_mode.useDTX && (st->prev_mode == MODE_SILK_ONLY || st->prev_mode == MODE_HYBRID)) { + /* DTX determined by Silk. */ + silk_encoder *silk_enc = (silk_encoder*)(void *)((char*)st+st->silk_enc_offset); + *value = silk_enc->state_Fxx[0].sCmn.noSpeechCounter >= NB_SPEECH_FRAMES_BEFORE_DTX; + /* Stereo: check second channel unless only the middle channel was encoded. */ + if(*value == 1 && st->silk_mode.nChannelsInternal == 2 && silk_enc->prev_decode_only_middle == 0) { + *value = silk_enc->state_Fxx[1].sCmn.noSpeechCounter >= NB_SPEECH_FRAMES_BEFORE_DTX; + } + } +#ifndef DISABLE_FLOAT_API + else if (st->use_dtx) { + /* DTX determined by Opus. */ + *value = st->nb_no_activity_ms_Q1 >= NB_SPEECH_FRAMES_BEFORE_DTX*20*2; + } +#endif + else { + *value = 0; + } + } + break; + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (!value) + { + goto bad_arg; + } + ret = celt_encoder_ctl(celt_enc, CELT_GET_MODE(value)); + } + break; + default: + /* fprintf(stderr, "unknown opus_encoder_ctl() request: %d", request);*/ + ret = OPUS_UNIMPLEMENTED; + break; + } + va_end(ap); + return ret; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +} + +void opus_encoder_destroy(OpusEncoder *st) +{ + opus_free(st); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_multistream.c b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_multistream.c new file mode 100644 index 000000000..09c3639b7 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_multistream.c @@ -0,0 +1,92 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_multistream.h" +#include "opus.h" +#include "opus_private.h" +#include "stack_alloc.h" +#include +#include "float_cast.h" +#include "os_support.h" + + +int validate_layout(const ChannelLayout *layout) +{ + int i, max_channel; + + max_channel = layout->nb_streams+layout->nb_coupled_streams; + if (max_channel>255) + return 0; + for (i=0;inb_channels;i++) + { + if (layout->mapping[i] >= max_channel && layout->mapping[i] != 255) + return 0; + } + return 1; +} + + +int get_left_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id*2) + return i; + } + return -1; +} + +int get_right_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id*2+1) + return i; + } + return -1; +} + +int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id+layout->nb_coupled_streams) + return i; + } + return -1; +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_multistream_decoder.c b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_multistream_decoder.c new file mode 100644 index 000000000..a2837c354 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_multistream_decoder.c @@ -0,0 +1,552 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_multistream.h" +#include "opus.h" +#include "opus_private.h" +#include "stack_alloc.h" +#include +#include "float_cast.h" +#include "os_support.h" + +/* DECODER */ + +#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) +static void validate_ms_decoder(OpusMSDecoder *st) +{ + validate_layout(&st->layout); +} +#define VALIDATE_MS_DECODER(st) validate_ms_decoder(st) +#else +#define VALIDATE_MS_DECODER(st) +#endif + + +opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams) +{ + int coupled_size; + int mono_size; + + if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0; + coupled_size = opus_decoder_get_size(2); + mono_size = opus_decoder_get_size(1); + return align(sizeof(OpusMSDecoder)) + + nb_coupled_streams * align(coupled_size) + + (nb_streams-nb_coupled_streams) * align(mono_size); +} + +int opus_multistream_decoder_init( + OpusMSDecoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping +) +{ + int coupled_size; + int mono_size; + int i, ret; + char *ptr; + + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) + return OPUS_BAD_ARG; + + st->layout.nb_channels = channels; + st->layout.nb_streams = streams; + st->layout.nb_coupled_streams = coupled_streams; + + for (i=0;ilayout.nb_channels;i++) + st->layout.mapping[i] = mapping[i]; + if (!validate_layout(&st->layout)) + return OPUS_BAD_ARG; + + ptr = (char*)st + align(sizeof(OpusMSDecoder)); + coupled_size = opus_decoder_get_size(2); + mono_size = opus_decoder_get_size(1); + + for (i=0;ilayout.nb_coupled_streams;i++) + { + ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2); + if(ret!=OPUS_OK)return ret; + ptr += align(coupled_size); + } + for (;ilayout.nb_streams;i++) + { + ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1); + if(ret!=OPUS_OK)return ret; + ptr += align(mono_size); + } + return OPUS_OK; +} + + +OpusMSDecoder *opus_multistream_decoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int *error +) +{ + int ret; + OpusMSDecoder *st; + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams)); + if (st==NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping); + if (error) + *error = ret; + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + return st; +} + +static int opus_multistream_packet_validate(const unsigned char *data, + opus_int32 len, int nb_streams, opus_int32 Fs) +{ + int s; + int count; + unsigned char toc; + opus_int16 size[48]; + int samples=0; + opus_int32 packet_offset; + + for (s=0;slayout.nb_streams-1) + { + RESTORE_STACK; + return OPUS_INVALID_PACKET; + } + if (!do_plc) + { + int ret = opus_multistream_packet_validate(data, len, st->layout.nb_streams, Fs); + if (ret < 0) + { + RESTORE_STACK; + return ret; + } else if (ret > frame_size) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + } + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + opus_int32 packet_offset; + int ret; + + dec = (OpusDecoder*)ptr; + ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size); + + if (!do_plc && len<=0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + packet_offset = 0; + ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip); + if (!do_plc) + { + data += packet_offset; + len -= packet_offset; + } + if (ret <= 0) + { + RESTORE_STACK; + return ret; + } + frame_size = ret; + if (s < st->layout.nb_coupled_streams) + { + int chan, prev; + prev = -1; + /* Copy "left" audio to the channel(s) where it belongs */ + while ( (chan = get_left_channel(&st->layout, s, prev)) != -1) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, chan, + buf, 2, frame_size, user_data); + prev = chan; + } + prev = -1; + /* Copy "right" audio to the channel(s) where it belongs */ + while ( (chan = get_right_channel(&st->layout, s, prev)) != -1) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, chan, + buf+1, 2, frame_size, user_data); + prev = chan; + } + } else { + int chan, prev; + prev = -1; + /* Copy audio to the channel(s) where it belongs */ + while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, chan, + buf, 1, frame_size, user_data); + prev = chan; + } + } + } + /* Handle muted channels */ + for (c=0;clayout.nb_channels;c++) + { + if (st->layout.mapping[c] == 255) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, c, + NULL, 0, frame_size, user_data); + } + } + RESTORE_STACK; + return frame_size; +} + +#if !defined(DISABLE_FLOAT_API) +static void opus_copy_channel_out_float( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data +) +{ + float *float_dst; + opus_int32 i; + (void)user_data; + float_dst = (float*)dst; + if (src != NULL) + { + for (i=0;ilayout.nb_streams;s++) + { + OpusDecoder *dec; + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, request, &tmp); + if (ret != OPUS_OK) break; + *value ^= tmp; + } + } + break; + case OPUS_RESET_STATE: + { + int s; + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, OPUS_RESET_STATE); + if (ret != OPUS_OK) + break; + } + } + break; + case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST: + { + int s; + opus_int32 stream_id; + OpusDecoder **value; + stream_id = va_arg(ap, opus_int32); + if (stream_id<0 || stream_id >= st->layout.nb_streams) + goto bad_arg; + value = va_arg(ap, OpusDecoder**); + if (!value) + { + goto bad_arg; + } + for (s=0;slayout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + *value = (OpusDecoder*)ptr; + } + break; + case OPUS_SET_GAIN_REQUEST: + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + int s; + /* This works for int32 params */ + opus_int32 value = va_arg(ap, opus_int32); + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, request, value); + if (ret != OPUS_OK) + break; + } + } + break; + default: + ret = OPUS_UNIMPLEMENTED; + break; + } + return ret; +bad_arg: + return OPUS_BAD_ARG; +} + +int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) +{ + int ret; + va_list ap; + va_start(ap, request); + ret = opus_multistream_decoder_ctl_va_list(st, request, ap); + va_end(ap); + return ret; +} + +void opus_multistream_decoder_destroy(OpusMSDecoder *st) +{ + opus_free(st); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_multistream_encoder.c b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_multistream_encoder.c new file mode 100644 index 000000000..93204a14c --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_multistream_encoder.c @@ -0,0 +1,1328 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_multistream.h" +#include "opus.h" +#include "opus_private.h" +#include "stack_alloc.h" +#include +#include "float_cast.h" +#include "os_support.h" +#include "mathops.h" +#include "mdct.h" +#include "modes.h" +#include "bands.h" +#include "quant_bands.h" +#include "pitch.h" + +typedef struct { + int nb_streams; + int nb_coupled_streams; + unsigned char mapping[8]; +} VorbisLayout; + +/* Index is nb_channel-1*/ +static const VorbisLayout vorbis_mappings[8] = { + {1, 0, {0}}, /* 1: mono */ + {1, 1, {0, 1}}, /* 2: stereo */ + {2, 1, {0, 2, 1}}, /* 3: 1-d surround */ + {2, 2, {0, 1, 2, 3}}, /* 4: quadraphonic surround */ + {3, 2, {0, 4, 1, 2, 3}}, /* 5: 5-channel surround */ + {4, 2, {0, 4, 1, 2, 3, 5}}, /* 6: 5.1 surround */ + {4, 3, {0, 4, 1, 2, 3, 5, 6}}, /* 7: 6.1 surround */ + {5, 3, {0, 6, 1, 2, 3, 4, 5, 7}}, /* 8: 7.1 surround */ +}; + +static opus_val32 *ms_get_preemph_mem(OpusMSEncoder *st) +{ + int s; + char *ptr; + int coupled_size, mono_size; + + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + for (s=0;slayout.nb_streams;s++) + { + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + /* void* cast avoids clang -Wcast-align warning */ + return (opus_val32*)(void*)(ptr+st->layout.nb_channels*120*sizeof(opus_val32)); +} + +static opus_val32 *ms_get_window_mem(OpusMSEncoder *st) +{ + int s; + char *ptr; + int coupled_size, mono_size; + + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + for (s=0;slayout.nb_streams;s++) + { + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + /* void* cast avoids clang -Wcast-align warning */ + return (opus_val32*)(void*)ptr; +} + +static int validate_ambisonics(int nb_channels, int *nb_streams, int *nb_coupled_streams) +{ + int order_plus_one; + int acn_channels; + int nondiegetic_channels; + + if (nb_channels < 1 || nb_channels > 227) + return 0; + + order_plus_one = isqrt32(nb_channels); + acn_channels = order_plus_one * order_plus_one; + nondiegetic_channels = nb_channels - acn_channels; + + if (nondiegetic_channels != 0 && nondiegetic_channels != 2) + return 0; + + if (nb_streams) + *nb_streams = acn_channels + (nondiegetic_channels != 0); + if (nb_coupled_streams) + *nb_coupled_streams = nondiegetic_channels != 0; + return 1; +} + +static int validate_encoder_layout(const ChannelLayout *layout) +{ + int s; + for (s=0;snb_streams;s++) + { + if (s < layout->nb_coupled_streams) + { + if (get_left_channel(layout, s, -1)==-1) + return 0; + if (get_right_channel(layout, s, -1)==-1) + return 0; + } else { + if (get_mono_channel(layout, s, -1)==-1) + return 0; + } + } + return 1; +} + +static void channel_pos(int channels, int pos[8]) +{ + /* Position in the mix: 0 don't mix, 1: left, 2: center, 3:right */ + if (channels==4) + { + pos[0]=1; + pos[1]=3; + pos[2]=1; + pos[3]=3; + } else if (channels==3||channels==5||channels==6) + { + pos[0]=1; + pos[1]=2; + pos[2]=3; + pos[3]=1; + pos[4]=3; + pos[5]=0; + } else if (channels==7) + { + pos[0]=1; + pos[1]=2; + pos[2]=3; + pos[3]=1; + pos[4]=3; + pos[5]=2; + pos[6]=0; + } else if (channels==8) + { + pos[0]=1; + pos[1]=2; + pos[2]=3; + pos[3]=1; + pos[4]=3; + pos[5]=1; + pos[6]=3; + pos[7]=0; + } +} + +#if 1 +/* Computes a rough approximation of log2(2^a + 2^b) */ +static opus_val16 logSum(opus_val16 a, opus_val16 b) +{ + opus_val16 max; + opus_val32 diff; + opus_val16 frac; + static const opus_val16 diff_table[17] = { + QCONST16(0.5000000f, DB_SHIFT), QCONST16(0.2924813f, DB_SHIFT), QCONST16(0.1609640f, DB_SHIFT), QCONST16(0.0849625f, DB_SHIFT), + QCONST16(0.0437314f, DB_SHIFT), QCONST16(0.0221971f, DB_SHIFT), QCONST16(0.0111839f, DB_SHIFT), QCONST16(0.0056136f, DB_SHIFT), + QCONST16(0.0028123f, DB_SHIFT) + }; + int low; + if (a>b) + { + max = a; + diff = SUB32(EXTEND32(a),EXTEND32(b)); + } else { + max = b; + diff = SUB32(EXTEND32(b),EXTEND32(a)); + } + if (!(diff < QCONST16(8.f, DB_SHIFT))) /* inverted to catch NaNs */ + return max; +#ifdef FIXED_POINT + low = SHR32(diff, DB_SHIFT-1); + frac = SHL16(diff - SHL16(low, DB_SHIFT-1), 16-DB_SHIFT); +#else + low = (int)floor(2*diff); + frac = 2*diff - low; +#endif + return max + diff_table[low] + MULT16_16_Q15(frac, SUB16(diff_table[low+1], diff_table[low])); +} +#else +opus_val16 logSum(opus_val16 a, opus_val16 b) +{ + return log2(pow(4, a)+ pow(4, b))/2; +} +#endif + +void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *bandLogE, opus_val32 *mem, opus_val32 *preemph_mem, + int len, int overlap, int channels, int rate, opus_copy_channel_in_func copy_channel_in, int arch +) +{ + int c; + int i; + int LM; + int pos[8] = {0}; + int upsample; + int frame_size; + int freq_size; + opus_val16 channel_offset; + opus_val32 bandE[21]; + opus_val16 maskLogE[3][21]; + VARDECL(opus_val32, in); + VARDECL(opus_val16, x); + VARDECL(opus_val32, freq); + SAVE_STACK; + + upsample = resampling_factor(rate); + frame_size = len*upsample; + freq_size = IMIN(960, frame_size); + + /* LM = log2(frame_size / 120) */ + for (LM=0;LMmaxLM;LM++) + if (celt_mode->shortMdctSize<preemph, preemph_mem+c, 0); +#ifndef FIXED_POINT + { + opus_val32 sum; + sum = celt_inner_prod(in, in, frame_size+overlap, 0); + /* This should filter out both NaNs and ridiculous signals that could + cause NaNs further down. */ + if (!(sum < 1e18f) || celt_isnan(sum)) + { + OPUS_CLEAR(in, frame_size+overlap); + preemph_mem[c] = 0; + } + } +#endif + OPUS_CLEAR(bandE, 21); + for (frame=0;framemdct, in+960*frame, freq, celt_mode->window, + overlap, celt_mode->maxLM-LM, 1, arch); + if (upsample != 1) + { + int bound = freq_size/upsample; + for (i=0;i=0;i--) + bandLogE[21*c+i] = MAX16(bandLogE[21*c+i], bandLogE[21*c+i+1]-QCONST16(2.f, DB_SHIFT)); + if (pos[c]==1) + { + for (i=0;i<21;i++) + maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]); + } else if (pos[c]==3) + { + for (i=0;i<21;i++) + maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]); + } else if (pos[c]==2) + { + for (i=0;i<21;i++) + { + maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]-QCONST16(.5f, DB_SHIFT)); + maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]-QCONST16(.5f, DB_SHIFT)); + } + } +#if 0 + for (i=0;i<21;i++) + printf("%f ", bandLogE[21*c+i]); + float sum=0; + for (i=0;i<21;i++) + sum += bandLogE[21*c+i]; + printf("%f ", sum/21); +#endif + OPUS_COPY(mem+c*overlap, in+frame_size, overlap); + } + for (i=0;i<21;i++) + maskLogE[1][i] = MIN32(maskLogE[0][i],maskLogE[2][i]); + channel_offset = HALF16(celt_log2(QCONST32(2.f,14)/(channels-1))); + for (c=0;c<3;c++) + for (i=0;i<21;i++) + maskLogE[c][i] += channel_offset; +#if 0 + for (c=0;c<3;c++) + { + for (i=0;i<21;i++) + printf("%f ", maskLogE[c][i]); + } +#endif + for (c=0;cnb_streams||nb_coupled_streams<0)return 0; + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + return align(sizeof(OpusMSEncoder)) + + nb_coupled_streams * align(coupled_size) + + (nb_streams-nb_coupled_streams) * align(mono_size); +} + +opus_int32 opus_multistream_surround_encoder_get_size(int channels, int mapping_family) +{ + int nb_streams; + int nb_coupled_streams; + opus_int32 size; + + if (mapping_family==0) + { + if (channels==1) + { + nb_streams=1; + nb_coupled_streams=0; + } else if (channels==2) + { + nb_streams=1; + nb_coupled_streams=1; + } else + return 0; + } else if (mapping_family==1 && channels<=8 && channels>=1) + { + nb_streams=vorbis_mappings[channels-1].nb_streams; + nb_coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams; + } else if (mapping_family==255) + { + nb_streams=channels; + nb_coupled_streams=0; + } else if (mapping_family==2) + { + if (!validate_ambisonics(channels, &nb_streams, &nb_coupled_streams)) + return 0; + } else + return 0; + size = opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams); + if (channels>2) + { + size += channels*(120*sizeof(opus_val32) + sizeof(opus_val32)); + } + return size; +} + +static int opus_multistream_encoder_init_impl( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application, + MappingType mapping_type +) +{ + int coupled_size; + int mono_size; + int i, ret; + char *ptr; + + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) + return OPUS_BAD_ARG; + + st->arch = opus_select_arch(); + st->layout.nb_channels = channels; + st->layout.nb_streams = streams; + st->layout.nb_coupled_streams = coupled_streams; + if (mapping_type != MAPPING_TYPE_SURROUND) + st->lfe_stream = -1; + st->bitrate_bps = OPUS_AUTO; + st->application = application; + st->variable_duration = OPUS_FRAMESIZE_ARG; + for (i=0;ilayout.nb_channels;i++) + st->layout.mapping[i] = mapping[i]; + if (!validate_layout(&st->layout)) + return OPUS_BAD_ARG; + if (mapping_type == MAPPING_TYPE_SURROUND && + !validate_encoder_layout(&st->layout)) + return OPUS_BAD_ARG; + if (mapping_type == MAPPING_TYPE_AMBISONICS && + !validate_ambisonics(st->layout.nb_channels, NULL, NULL)) + return OPUS_BAD_ARG; + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + + for (i=0;ilayout.nb_coupled_streams;i++) + { + ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application); + if(ret!=OPUS_OK)return ret; + if (i==st->lfe_stream) + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1)); + ptr += align(coupled_size); + } + for (;ilayout.nb_streams;i++) + { + ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application); + if (i==st->lfe_stream) + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1)); + if(ret!=OPUS_OK)return ret; + ptr += align(mono_size); + } + if (mapping_type == MAPPING_TYPE_SURROUND) + { + OPUS_CLEAR(ms_get_preemph_mem(st), channels); + OPUS_CLEAR(ms_get_window_mem(st), channels*120); + } + st->mapping_type = mapping_type; + return OPUS_OK; +} + +int opus_multistream_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application +) +{ + return opus_multistream_encoder_init_impl(st, Fs, channels, streams, + coupled_streams, mapping, + application, MAPPING_TYPE_NONE); +} + +int opus_multistream_surround_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + unsigned char *mapping, + int application +) +{ + MappingType mapping_type; + + if ((channels>255) || (channels<1)) + return OPUS_BAD_ARG; + st->lfe_stream = -1; + if (mapping_family==0) + { + if (channels==1) + { + *streams=1; + *coupled_streams=0; + mapping[0]=0; + } else if (channels==2) + { + *streams=1; + *coupled_streams=1; + mapping[0]=0; + mapping[1]=1; + } else + return OPUS_UNIMPLEMENTED; + } else if (mapping_family==1 && channels<=8 && channels>=1) + { + int i; + *streams=vorbis_mappings[channels-1].nb_streams; + *coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams; + for (i=0;i=6) + st->lfe_stream = *streams-1; + } else if (mapping_family==255) + { + int i; + *streams=channels; + *coupled_streams=0; + for(i=0;i2 && mapping_family==1) { + mapping_type = MAPPING_TYPE_SURROUND; + } else if (mapping_family==2) + { + mapping_type = MAPPING_TYPE_AMBISONICS; + } else + { + mapping_type = MAPPING_TYPE_NONE; + } + return opus_multistream_encoder_init_impl(st, Fs, channels, *streams, + *coupled_streams, mapping, + application, mapping_type); +} + +OpusMSEncoder *opus_multistream_encoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application, + int *error +) +{ + int ret; + OpusMSEncoder *st; + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + st = (OpusMSEncoder *)opus_alloc(opus_multistream_encoder_get_size(streams, coupled_streams)); + if (st==NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_multistream_encoder_init(st, Fs, channels, streams, coupled_streams, mapping, application); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +OpusMSEncoder *opus_multistream_surround_encoder_create( + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + unsigned char *mapping, + int application, + int *error +) +{ + int ret; + opus_int32 size; + OpusMSEncoder *st; + if ((channels>255) || (channels<1)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + size = opus_multistream_surround_encoder_get_size(channels, mapping_family); + if (!size) + { + if (error) + *error = OPUS_UNIMPLEMENTED; + return NULL; + } + st = (OpusMSEncoder *)opus_alloc(size); + if (st==NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_multistream_surround_encoder_init(st, Fs, channels, mapping_family, streams, coupled_streams, mapping, application); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +static void surround_rate_allocation( + OpusMSEncoder *st, + opus_int32 *rate, + int frame_size, + opus_int32 Fs + ) +{ + int i; + opus_int32 channel_rate; + int stream_offset; + int lfe_offset; + int coupled_ratio; /* Q8 */ + int lfe_ratio; /* Q8 */ + int nb_lfe; + int nb_uncoupled; + int nb_coupled; + int nb_normal; + opus_int32 channel_offset; + opus_int32 bitrate; + int total; + + nb_lfe = (st->lfe_stream!=-1); + nb_coupled = st->layout.nb_coupled_streams; + nb_uncoupled = st->layout.nb_streams-nb_coupled-nb_lfe; + nb_normal = 2*nb_coupled + nb_uncoupled; + + /* Give each non-LFE channel enough bits per channel for coding band energy. */ + channel_offset = 40*IMAX(50, Fs/frame_size); + + if (st->bitrate_bps==OPUS_AUTO) + { + bitrate = nb_normal*(channel_offset + Fs + 10000) + 8000*nb_lfe; + } else if (st->bitrate_bps==OPUS_BITRATE_MAX) + { + bitrate = nb_normal*300000 + nb_lfe*128000; + } else { + bitrate = st->bitrate_bps; + } + + /* Give LFE some basic stream_channel allocation but never exceed 1/20 of the + total rate for the non-energy part to avoid problems at really low rate. */ + lfe_offset = IMIN(bitrate/20, 3000) + 15*IMAX(50, Fs/frame_size); + + /* We give each stream (coupled or uncoupled) a starting bitrate. + This models the main saving of coupled channels over uncoupled. */ + stream_offset = (bitrate - channel_offset*nb_normal - lfe_offset*nb_lfe)/nb_normal/2; + stream_offset = IMAX(0, IMIN(20000, stream_offset)); + + /* Coupled streams get twice the mono rate after the offset is allocated. */ + coupled_ratio = 512; + /* Should depend on the bitrate, for now we assume LFE gets 1/8 the bits of mono */ + lfe_ratio = 32; + + total = (nb_uncoupled<<8) /* mono */ + + coupled_ratio*nb_coupled /* stereo */ + + nb_lfe*lfe_ratio; + channel_rate = 256*(opus_int64)(bitrate - lfe_offset*nb_lfe - stream_offset*(nb_coupled+nb_uncoupled) - channel_offset*nb_normal)/total; + + for (i=0;ilayout.nb_streams;i++) + { + if (ilayout.nb_coupled_streams) + rate[i] = 2*channel_offset + IMAX(0, stream_offset+(channel_rate*coupled_ratio>>8)); + else if (i!=st->lfe_stream) + rate[i] = channel_offset + IMAX(0, stream_offset + channel_rate); + else + rate[i] = IMAX(0, lfe_offset+(channel_rate*lfe_ratio>>8)); + } +} + +static void ambisonics_rate_allocation( + OpusMSEncoder *st, + opus_int32 *rate, + int frame_size, + opus_int32 Fs + ) +{ + int i; + opus_int32 total_rate; + opus_int32 per_stream_rate; + + const int nb_channels = st->layout.nb_streams + st->layout.nb_coupled_streams; + + if (st->bitrate_bps==OPUS_AUTO) + { + total_rate = (st->layout.nb_coupled_streams + st->layout.nb_streams) * + (Fs+60*Fs/frame_size) + st->layout.nb_streams * (opus_int32)15000; + } else if (st->bitrate_bps==OPUS_BITRATE_MAX) + { + total_rate = nb_channels * 320000; + } else + { + total_rate = st->bitrate_bps; + } + + /* Allocate equal number of bits to Ambisonic (uncoupled) and non-diegetic + * (coupled) streams */ + per_stream_rate = total_rate / st->layout.nb_streams; + for (i = 0; i < st->layout.nb_streams; i++) + { + rate[i] = per_stream_rate; + } +} + +static opus_int32 rate_allocation( + OpusMSEncoder *st, + opus_int32 *rate, + int frame_size + ) +{ + int i; + opus_int32 rate_sum=0; + opus_int32 Fs; + char *ptr; + + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs)); + + if (st->mapping_type == MAPPING_TYPE_AMBISONICS) { + ambisonics_rate_allocation(st, rate, frame_size, Fs); + } else + { + surround_rate_allocation(st, rate, frame_size, Fs); + } + + for (i=0;ilayout.nb_streams;i++) + { + rate[i] = IMAX(rate[i], 500); + rate_sum += rate[i]; + } + return rate_sum; +} + +/* Max size in case the encoder decides to return six frames (6 x 20 ms = 120 ms) */ +#define MS_FRAME_TMP (6*1275+12) +int opus_multistream_encode_native +( + OpusMSEncoder *st, + opus_copy_channel_in_func copy_channel_in, + const void *pcm, + int analysis_frame_size, + unsigned char *data, + opus_int32 max_data_bytes, + int lsb_depth, + downmix_func downmix, + int float_api, + void *user_data +) +{ + opus_int32 Fs; + int coupled_size; + int mono_size; + int s; + char *ptr; + int tot_size; + VARDECL(opus_val16, buf); + VARDECL(opus_val16, bandSMR); + unsigned char tmp_data[MS_FRAME_TMP]; + OpusRepacketizer rp; + opus_int32 vbr; + const CELTMode *celt_mode; + opus_int32 bitrates[256]; + opus_val16 bandLogE[42]; + opus_val32 *mem = NULL; + opus_val32 *preemph_mem=NULL; + int frame_size; + opus_int32 rate_sum; + opus_int32 smallest_packet; + ALLOC_STACK; + + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + preemph_mem = ms_get_preemph_mem(st); + mem = ms_get_window_mem(st); + } + + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs)); + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_VBR(&vbr)); + opus_encoder_ctl((OpusEncoder*)ptr, CELT_GET_MODE(&celt_mode)); + + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, Fs); + if (frame_size <= 0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + /* Smallest packet the encoder can produce. */ + smallest_packet = st->layout.nb_streams*2-1; + /* 100 ms needs an extra byte per stream for the ToC. */ + if (Fs/frame_size == 10) + smallest_packet += st->layout.nb_streams; + if (max_data_bytes < smallest_packet) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + ALLOC(buf, 2*frame_size, opus_val16); + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + + ALLOC(bandSMR, 21*st->layout.nb_channels, opus_val16); + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + surround_analysis(celt_mode, pcm, bandSMR, mem, preemph_mem, frame_size, 120, st->layout.nb_channels, Fs, copy_channel_in, st->arch); + } + + /* Compute bitrate allocation between streams (this could be a lot better) */ + rate_sum = rate_allocation(st, bitrates, frame_size); + + if (!vbr) + { + if (st->bitrate_bps == OPUS_AUTO) + { + max_data_bytes = IMIN(max_data_bytes, 3*rate_sum/(3*8*Fs/frame_size)); + } else if (st->bitrate_bps != OPUS_BITRATE_MAX) + { + max_data_bytes = IMIN(max_data_bytes, IMAX(smallest_packet, + 3*st->bitrate_bps/(3*8*Fs/frame_size))); + } + } + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrates[s])); + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + opus_int32 equiv_rate; + equiv_rate = st->bitrate_bps; + if (frame_size*50 < Fs) + equiv_rate -= 60*(Fs/frame_size - 50)*st->layout.nb_channels; + if (equiv_rate > 10000*st->layout.nb_channels) + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + else if (equiv_rate > 7000*st->layout.nb_channels) + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); + else if (equiv_rate > 5000*st->layout.nb_channels) + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND)); + else + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + if (s < st->layout.nb_coupled_streams) + { + /* To preserve the spatial image, force stereo CELT on coupled streams */ + opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY)); + opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(2)); + } + } + else if (st->mapping_type == MAPPING_TYPE_AMBISONICS) { + opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY)); + } + } + + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + /* Counting ToC */ + tot_size = 0; + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + int len; + int curr_max; + int c1, c2; + int ret; + + opus_repacketizer_init(&rp); + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + { + int i; + int left, right; + left = get_left_channel(&st->layout, s, -1); + right = get_right_channel(&st->layout, s, -1); + (*copy_channel_in)(buf, 2, + pcm, st->layout.nb_channels, left, frame_size, user_data); + (*copy_channel_in)(buf+1, 2, + pcm, st->layout.nb_channels, right, frame_size, user_data); + ptr += align(coupled_size); + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + for (i=0;i<21;i++) + { + bandLogE[i] = bandSMR[21*left+i]; + bandLogE[21+i] = bandSMR[21*right+i]; + } + } + c1 = left; + c2 = right; + } else { + int i; + int chan = get_mono_channel(&st->layout, s, -1); + (*copy_channel_in)(buf, 1, + pcm, st->layout.nb_channels, chan, frame_size, user_data); + ptr += align(mono_size); + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + for (i=0;i<21;i++) + bandLogE[i] = bandSMR[21*chan+i]; + } + c1 = chan; + c2 = -1; + } + if (st->mapping_type == MAPPING_TYPE_SURROUND) + opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE)); + /* number of bytes left (+Toc) */ + curr_max = max_data_bytes - tot_size; + /* Reserve one byte for the last stream and two for the others */ + curr_max -= IMAX(0,2*(st->layout.nb_streams-s-1)-1); + /* For 100 ms, reserve an extra byte per stream for the ToC */ + if (Fs/frame_size == 10) + curr_max -= st->layout.nb_streams-s-1; + curr_max = IMIN(curr_max,MS_FRAME_TMP); + /* Repacketizer will add one or two bytes for self-delimited frames */ + if (s != st->layout.nb_streams-1) curr_max -= curr_max>253 ? 2 : 1; + if (!vbr && s == st->layout.nb_streams-1) + opus_encoder_ctl(enc, OPUS_SET_BITRATE(curr_max*(8*Fs/frame_size))); + len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth, + pcm, analysis_frame_size, c1, c2, st->layout.nb_channels, downmix, float_api); + if (len<0) + { + RESTORE_STACK; + return len; + } + /* We need to use the repacketizer to add the self-delimiting lengths + while taking into account the fact that the encoder can now return + more than one frame at a time (e.g. 60 ms CELT-only) */ + ret = opus_repacketizer_cat(&rp, tmp_data, len); + /* If the opus_repacketizer_cat() fails, then something's seriously wrong + with the encoder. */ + if (ret != OPUS_OK) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + len = opus_repacketizer_out_range_impl(&rp, 0, opus_repacketizer_get_nb_frames(&rp), + data, max_data_bytes-tot_size, s != st->layout.nb_streams-1, !vbr && s == st->layout.nb_streams-1); + data += len; + tot_size += len; + } + /*printf("\n");*/ + RESTORE_STACK; + return tot_size; +} + +#if !defined(DISABLE_FLOAT_API) +static void opus_copy_channel_in_float( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +) +{ + const float *float_src; + opus_int32 i; + (void)user_data; + float_src = (const float *)src; + for (i=0;ilayout.nb_channels, IMAX(500*st->layout.nb_channels, value)); + } + st->bitrate_bps = value; + } + break; + case OPUS_GET_BITRATE_REQUEST: + { + int s; + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = 0; + for (s=0;slayout.nb_streams;s++) + { + opus_int32 rate; + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + opus_encoder_ctl(enc, request, &rate); + *value += rate; + } + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + case OPUS_GET_VBR_REQUEST: + case OPUS_GET_APPLICATION_REQUEST: + case OPUS_GET_BANDWIDTH_REQUEST: + case OPUS_GET_COMPLEXITY_REQUEST: + case OPUS_GET_PACKET_LOSS_PERC_REQUEST: + case OPUS_GET_DTX_REQUEST: + case OPUS_GET_VOICE_RATIO_REQUEST: + case OPUS_GET_VBR_CONSTRAINT_REQUEST: + case OPUS_GET_SIGNAL_REQUEST: + case OPUS_GET_LOOKAHEAD_REQUEST: + case OPUS_GET_SAMPLE_RATE_REQUEST: + case OPUS_GET_INBAND_FEC_REQUEST: + case OPUS_GET_FORCE_CHANNELS_REQUEST: + case OPUS_GET_PREDICTION_DISABLED_REQUEST: + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + OpusEncoder *enc; + /* For int32* GET params, just query the first stream */ + opus_int32 *value = va_arg(ap, opus_int32*); + enc = (OpusEncoder*)ptr; + ret = opus_encoder_ctl(enc, request, value); + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + int s; + opus_uint32 *value = va_arg(ap, opus_uint32*); + opus_uint32 tmp; + if (!value) + { + goto bad_arg; + } + *value=0; + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_encoder_ctl(enc, request, &tmp); + if (ret != OPUS_OK) break; + *value ^= tmp; + } + } + break; + case OPUS_SET_LSB_DEPTH_REQUEST: + case OPUS_SET_COMPLEXITY_REQUEST: + case OPUS_SET_VBR_REQUEST: + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + case OPUS_SET_MAX_BANDWIDTH_REQUEST: + case OPUS_SET_BANDWIDTH_REQUEST: + case OPUS_SET_SIGNAL_REQUEST: + case OPUS_SET_APPLICATION_REQUEST: + case OPUS_SET_INBAND_FEC_REQUEST: + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + case OPUS_SET_DTX_REQUEST: + case OPUS_SET_FORCE_MODE_REQUEST: + case OPUS_SET_FORCE_CHANNELS_REQUEST: + case OPUS_SET_PREDICTION_DISABLED_REQUEST: + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + int s; + /* This works for int32 params */ + opus_int32 value = va_arg(ap, opus_int32); + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_encoder_ctl(enc, request, value); + if (ret != OPUS_OK) + break; + } + } + break; + case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST: + { + int s; + opus_int32 stream_id; + OpusEncoder **value; + stream_id = va_arg(ap, opus_int32); + if (stream_id<0 || stream_id >= st->layout.nb_streams) + goto bad_arg; + value = va_arg(ap, OpusEncoder**); + if (!value) + { + goto bad_arg; + } + for (s=0;slayout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + *value = (OpusEncoder*)ptr; + } + break; + case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->variable_duration = value; + } + break; + case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->variable_duration; + } + break; + case OPUS_RESET_STATE: + { + int s; + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + OPUS_CLEAR(ms_get_preemph_mem(st), st->layout.nb_channels); + OPUS_CLEAR(ms_get_window_mem(st), st->layout.nb_channels*120); + } + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_encoder_ctl(enc, OPUS_RESET_STATE); + if (ret != OPUS_OK) + break; + } + } + break; + default: + ret = OPUS_UNIMPLEMENTED; + break; + } + return ret; +bad_arg: + return OPUS_BAD_ARG; +} + +int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) +{ + int ret; + va_list ap; + va_start(ap, request); + ret = opus_multistream_encoder_ctl_va_list(st, request, ap); + va_end(ap); + return ret; +} + +void opus_multistream_encoder_destroy(OpusMSEncoder *st) +{ + opus_free(st); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_private.h b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_private.h new file mode 100644 index 000000000..5e2463f54 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_private.h @@ -0,0 +1,201 @@ +/* Copyright (c) 2012 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + + +#ifndef OPUS_PRIVATE_H +#define OPUS_PRIVATE_H + +#include "arch.h" +#include "opus.h" +#include "celt.h" + +#include /* va_list */ +#include /* offsetof */ + +struct OpusRepacketizer { + unsigned char toc; + int nb_frames; + const unsigned char *frames[48]; + opus_int16 len[48]; + int framesize; +}; + +typedef struct ChannelLayout { + int nb_channels; + int nb_streams; + int nb_coupled_streams; + unsigned char mapping[256]; +} ChannelLayout; + +typedef enum { + MAPPING_TYPE_NONE, + MAPPING_TYPE_SURROUND, + MAPPING_TYPE_AMBISONICS +} MappingType; + +struct OpusMSEncoder { + ChannelLayout layout; + int arch; + int lfe_stream; + int application; + int variable_duration; + MappingType mapping_type; + opus_int32 bitrate_bps; + /* Encoder states go here */ + /* then opus_val32 window_mem[channels*120]; */ + /* then opus_val32 preemph_mem[channels]; */ +}; + +struct OpusMSDecoder { + ChannelLayout layout; + /* Decoder states go here */ +}; + +int opus_multistream_encoder_ctl_va_list(struct OpusMSEncoder *st, int request, + va_list ap); +int opus_multistream_decoder_ctl_va_list(struct OpusMSDecoder *st, int request, + va_list ap); + +int validate_layout(const ChannelLayout *layout); +int get_left_channel(const ChannelLayout *layout, int stream_id, int prev); +int get_right_channel(const ChannelLayout *layout, int stream_id, int prev); +int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev); + +typedef void (*opus_copy_channel_in_func)( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +); + +typedef void (*opus_copy_channel_out_func)( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data +); + +#define MODE_SILK_ONLY 1000 +#define MODE_HYBRID 1001 +#define MODE_CELT_ONLY 1002 + +#define OPUS_SET_VOICE_RATIO_REQUEST 11018 +#define OPUS_GET_VOICE_RATIO_REQUEST 11019 + +/** Configures the encoder's expected percentage of voice + * opposed to music or other signals. + * + * @note This interface is currently more aspiration than actuality. It's + * ultimately expected to bias an automatic signal classifier, but it currently + * just shifts the static bitrate to mode mapping around a little bit. + * + * @param[in] x int: Voice percentage in the range 0-100, inclusive. + * @hideinitializer */ +#define OPUS_SET_VOICE_RATIO(x) OPUS_SET_VOICE_RATIO_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured voice ratio value, @see OPUS_SET_VOICE_RATIO + * + * @param[out] x int*: Voice percentage in the range 0-100, inclusive. + * @hideinitializer */ +#define OPUS_GET_VOICE_RATIO(x) OPUS_GET_VOICE_RATIO_REQUEST, __opus_check_int_ptr(x) + + +#define OPUS_SET_FORCE_MODE_REQUEST 11002 +#define OPUS_SET_FORCE_MODE(x) OPUS_SET_FORCE_MODE_REQUEST, __opus_check_int(x) + +typedef void (*downmix_func)(const void *, opus_val32 *, int, int, int, int, int); +void downmix_float(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C); +void downmix_int(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C); +int is_digital_silence(const opus_val16* pcm, int frame_size, int channels, int lsb_depth); + +int encode_size(int size, unsigned char *data); + +opus_int32 frame_size_select(opus_int32 frame_size, int variable_duration, opus_int32 Fs); + +opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size, + unsigned char *data, opus_int32 out_data_bytes, int lsb_depth, + const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2, + int analysis_channels, downmix_func downmix, int float_api); + +int opus_decode_native(OpusDecoder *st, const unsigned char *data, opus_int32 len, + opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited, + opus_int32 *packet_offset, int soft_clip); + +/* Make sure everything is properly aligned. */ +static OPUS_INLINE int align(int i) +{ + struct foo {char c; union { void* p; opus_int32 i; opus_val32 v; } u;}; + + unsigned int alignment = offsetof(struct foo, u); + + /* Optimizing compilers should optimize div and multiply into and + for all sensible alignment values. */ + return ((i + alignment - 1) / alignment) * alignment; +} + +int opus_packet_parse_impl(const unsigned char *data, opus_int32 len, + int self_delimited, unsigned char *out_toc, + const unsigned char *frames[48], opus_int16 size[48], + int *payload_offset, opus_int32 *packet_offset); + +opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, + unsigned char *data, opus_int32 maxlen, int self_delimited, int pad); + +int pad_frame(unsigned char *data, opus_int32 len, opus_int32 new_len); + +int opus_multistream_encode_native +( + struct OpusMSEncoder *st, + opus_copy_channel_in_func copy_channel_in, + const void *pcm, + int analysis_frame_size, + unsigned char *data, + opus_int32 max_data_bytes, + int lsb_depth, + downmix_func downmix, + int float_api, + void *user_data +); + +int opus_multistream_decode_native( + struct OpusMSDecoder *st, + const unsigned char *data, + opus_int32 len, + void *pcm, + opus_copy_channel_out_func copy_channel_out, + int frame_size, + int decode_fec, + int soft_clip, + void *user_data +); + +#endif /* OPUS_PRIVATE_H */ diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_projection_decoder.c b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_projection_decoder.c new file mode 100644 index 000000000..c2e07d5bc --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_projection_decoder.c @@ -0,0 +1,258 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mathops.h" +#include "os_support.h" +#include "opus_private.h" +#include "opus_defines.h" +#include "opus_projection.h" +#include "opus_multistream.h" +#include "mapping_matrix.h" +#include "stack_alloc.h" + +struct OpusProjectionDecoder +{ + opus_int32 demixing_matrix_size_in_bytes; + /* Encoder states go here */ +}; + +#if !defined(DISABLE_FLOAT_API) +static void opus_projection_copy_channel_out_float( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data) +{ + float *float_dst; + const MappingMatrix *matrix; + float_dst = (float *)dst; + matrix = (const MappingMatrix *)user_data; + + if (dst_channel == 0) + OPUS_CLEAR(float_dst, frame_size * dst_stride); + + if (src != NULL) + mapping_matrix_multiply_channel_out_float(matrix, src, dst_channel, + src_stride, float_dst, dst_stride, frame_size); +} +#endif + +static void opus_projection_copy_channel_out_short( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data) +{ + opus_int16 *short_dst; + const MappingMatrix *matrix; + short_dst = (opus_int16 *)dst; + matrix = (const MappingMatrix *)user_data; + if (dst_channel == 0) + OPUS_CLEAR(short_dst, frame_size * dst_stride); + + if (src != NULL) + mapping_matrix_multiply_channel_out_short(matrix, src, dst_channel, + src_stride, short_dst, dst_stride, frame_size); +} + +static MappingMatrix *get_dec_demixing_matrix(OpusProjectionDecoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (MappingMatrix*)(void*)((char*)st + + align(sizeof(OpusProjectionDecoder))); +} + +static OpusMSDecoder *get_multistream_decoder(OpusProjectionDecoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (OpusMSDecoder*)(void*)((char*)st + + align(sizeof(OpusProjectionDecoder) + + st->demixing_matrix_size_in_bytes)); +} + +opus_int32 opus_projection_decoder_get_size(int channels, int streams, + int coupled_streams) +{ + opus_int32 matrix_size; + opus_int32 decoder_size; + + matrix_size = + mapping_matrix_get_size(streams + coupled_streams, channels); + if (!matrix_size) + return 0; + + decoder_size = opus_multistream_decoder_get_size(streams, coupled_streams); + if (!decoder_size) + return 0; + + return align(sizeof(OpusProjectionDecoder)) + matrix_size + decoder_size; +} + +int opus_projection_decoder_init(OpusProjectionDecoder *st, opus_int32 Fs, + int channels, int streams, int coupled_streams, + unsigned char *demixing_matrix, opus_int32 demixing_matrix_size) +{ + int nb_input_streams; + opus_int32 expected_matrix_size; + int i, ret; + unsigned char mapping[255]; + VARDECL(opus_int16, buf); + ALLOC_STACK; + + /* Verify supplied matrix size. */ + nb_input_streams = streams + coupled_streams; + expected_matrix_size = nb_input_streams * channels * sizeof(opus_int16); + if (expected_matrix_size != demixing_matrix_size) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + /* Convert demixing matrix input into internal format. */ + ALLOC(buf, nb_input_streams * channels, opus_int16); + for (i = 0; i < nb_input_streams * channels; i++) + { + int s = demixing_matrix[2*i + 1] << 8 | demixing_matrix[2*i]; + s = ((s & 0xFFFF) ^ 0x8000) - 0x8000; + buf[i] = (opus_int16)s; + } + + /* Assign demixing matrix. */ + st->demixing_matrix_size_in_bytes = + mapping_matrix_get_size(channels, nb_input_streams); + if (!st->demixing_matrix_size_in_bytes) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + mapping_matrix_init(get_dec_demixing_matrix(st), channels, nb_input_streams, 0, + buf, demixing_matrix_size); + + /* Set trivial mapping so each input channel pairs with a matrix column. */ + for (i = 0; i < channels; i++) + mapping[i] = i; + + ret = opus_multistream_decoder_init( + get_multistream_decoder(st), Fs, channels, streams, coupled_streams, mapping); + RESTORE_STACK; + return ret; +} + +OpusProjectionDecoder *opus_projection_decoder_create( + opus_int32 Fs, int channels, int streams, int coupled_streams, + unsigned char *demixing_matrix, opus_int32 demixing_matrix_size, int *error) +{ + int size; + int ret; + OpusProjectionDecoder *st; + + /* Allocate space for the projection decoder. */ + size = opus_projection_decoder_get_size(channels, streams, coupled_streams); + if (!size) { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + st = (OpusProjectionDecoder *)opus_alloc(size); + if (!st) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + + /* Initialize projection decoder with provided settings. */ + ret = opus_projection_decoder_init(st, Fs, channels, streams, coupled_streams, + demixing_matrix, demixing_matrix_size); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +#ifdef FIXED_POINT +int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data, + opus_int32 len, opus_int16 *pcm, int frame_size, + int decode_fec) +{ + return opus_multistream_decode_native(get_multistream_decoder(st), data, len, + pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, 0, + get_dec_demixing_matrix(st)); +} +#else +int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data, + opus_int32 len, opus_int16 *pcm, int frame_size, + int decode_fec) +{ + return opus_multistream_decode_native(get_multistream_decoder(st), data, len, + pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, 1, + get_dec_demixing_matrix(st)); +} +#endif + +#ifndef DISABLE_FLOAT_API +int opus_projection_decode_float(OpusProjectionDecoder *st, const unsigned char *data, + opus_int32 len, float *pcm, int frame_size, int decode_fec) +{ + return opus_multistream_decode_native(get_multistream_decoder(st), data, len, + pcm, opus_projection_copy_channel_out_float, frame_size, decode_fec, 0, + get_dec_demixing_matrix(st)); +} +#endif + +int opus_projection_decoder_ctl(OpusProjectionDecoder *st, int request, ...) +{ + va_list ap; + int ret = OPUS_OK; + + va_start(ap, request); + ret = opus_multistream_decoder_ctl_va_list(get_multistream_decoder(st), + request, ap); + va_end(ap); + return ret; +} + +void opus_projection_decoder_destroy(OpusProjectionDecoder *st) +{ + opus_free(st); +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_projection_encoder.c b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_projection_encoder.c new file mode 100644 index 000000000..06fb2d252 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/opus_projection_encoder.c @@ -0,0 +1,468 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mathops.h" +#include "os_support.h" +#include "opus_private.h" +#include "opus_defines.h" +#include "opus_projection.h" +#include "opus_multistream.h" +#include "stack_alloc.h" +#include "mapping_matrix.h" + +struct OpusProjectionEncoder +{ + opus_int32 mixing_matrix_size_in_bytes; + opus_int32 demixing_matrix_size_in_bytes; + /* Encoder states go here */ +}; + +#if !defined(DISABLE_FLOAT_API) +static void opus_projection_copy_channel_in_float( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +) +{ + mapping_matrix_multiply_channel_in_float((const MappingMatrix*)user_data, + (const float*)src, src_stride, dst, src_channel, dst_stride, frame_size); +} +#endif + +static void opus_projection_copy_channel_in_short( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +) +{ + mapping_matrix_multiply_channel_in_short((const MappingMatrix*)user_data, + (const opus_int16*)src, src_stride, dst, src_channel, dst_stride, frame_size); +} + +static int get_order_plus_one_from_channels(int channels, int *order_plus_one) +{ + int order_plus_one_; + int acn_channels; + int nondiegetic_channels; + + /* Allowed numbers of channels: + * (1 + n)^2 + 2j, for n = 0...14 and j = 0 or 1. + */ + if (channels < 1 || channels > 227) + return OPUS_BAD_ARG; + + order_plus_one_ = isqrt32(channels); + acn_channels = order_plus_one_ * order_plus_one_; + nondiegetic_channels = channels - acn_channels; + if (nondiegetic_channels != 0 && nondiegetic_channels != 2) + return OPUS_BAD_ARG; + + if (order_plus_one) + *order_plus_one = order_plus_one_; + return OPUS_OK; +} + +static int get_streams_from_channels(int channels, int mapping_family, + int *streams, int *coupled_streams, + int *order_plus_one) +{ + if (mapping_family == 3) + { + if (get_order_plus_one_from_channels(channels, order_plus_one) != OPUS_OK) + return OPUS_BAD_ARG; + if (streams) + *streams = (channels + 1) / 2; + if (coupled_streams) + *coupled_streams = channels / 2; + return OPUS_OK; + } + return OPUS_BAD_ARG; +} + +static MappingMatrix *get_mixing_matrix(OpusProjectionEncoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (MappingMatrix *)(void*)((char*)st + + align(sizeof(OpusProjectionEncoder))); +} + +static MappingMatrix *get_enc_demixing_matrix(OpusProjectionEncoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (MappingMatrix *)(void*)((char*)st + + align(sizeof(OpusProjectionEncoder) + + st->mixing_matrix_size_in_bytes)); +} + +static OpusMSEncoder *get_multistream_encoder(OpusProjectionEncoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (OpusMSEncoder *)(void*)((char*)st + + align(sizeof(OpusProjectionEncoder) + + st->mixing_matrix_size_in_bytes + + st->demixing_matrix_size_in_bytes)); +} + +opus_int32 opus_projection_ambisonics_encoder_get_size(int channels, + int mapping_family) +{ + int nb_streams; + int nb_coupled_streams; + int order_plus_one; + int mixing_matrix_rows, mixing_matrix_cols; + int demixing_matrix_rows, demixing_matrix_cols; + opus_int32 mixing_matrix_size, demixing_matrix_size; + opus_int32 encoder_size; + int ret; + + ret = get_streams_from_channels(channels, mapping_family, &nb_streams, + &nb_coupled_streams, &order_plus_one); + if (ret != OPUS_OK) + return 0; + + if (order_plus_one == 2) + { + mixing_matrix_rows = mapping_matrix_foa_mixing.rows; + mixing_matrix_cols = mapping_matrix_foa_mixing.cols; + demixing_matrix_rows = mapping_matrix_foa_demixing.rows; + demixing_matrix_cols = mapping_matrix_foa_demixing.cols; + } + else if (order_plus_one == 3) + { + mixing_matrix_rows = mapping_matrix_soa_mixing.rows; + mixing_matrix_cols = mapping_matrix_soa_mixing.cols; + demixing_matrix_rows = mapping_matrix_soa_demixing.rows; + demixing_matrix_cols = mapping_matrix_soa_demixing.cols; + } + else if (order_plus_one == 4) + { + mixing_matrix_rows = mapping_matrix_toa_mixing.rows; + mixing_matrix_cols = mapping_matrix_toa_mixing.cols; + demixing_matrix_rows = mapping_matrix_toa_demixing.rows; + demixing_matrix_cols = mapping_matrix_toa_demixing.cols; + } + else + return 0; + + mixing_matrix_size = + mapping_matrix_get_size(mixing_matrix_rows, mixing_matrix_cols); + if (!mixing_matrix_size) + return 0; + + demixing_matrix_size = + mapping_matrix_get_size(demixing_matrix_rows, demixing_matrix_cols); + if (!demixing_matrix_size) + return 0; + + encoder_size = + opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams); + if (!encoder_size) + return 0; + + return align(sizeof(OpusProjectionEncoder)) + + mixing_matrix_size + demixing_matrix_size + encoder_size; +} + +int opus_projection_ambisonics_encoder_init(OpusProjectionEncoder *st, opus_int32 Fs, + int channels, int mapping_family, + int *streams, int *coupled_streams, + int application) +{ + MappingMatrix *mixing_matrix; + MappingMatrix *demixing_matrix; + OpusMSEncoder *ms_encoder; + int i; + int ret; + int order_plus_one; + unsigned char mapping[255]; + + if (streams == NULL || coupled_streams == NULL) { + return OPUS_BAD_ARG; + } + + if (get_streams_from_channels(channels, mapping_family, streams, + coupled_streams, &order_plus_one) != OPUS_OK) + return OPUS_BAD_ARG; + + if (mapping_family == 3) + { + /* Assign mixing matrix based on available pre-computed matrices. */ + mixing_matrix = get_mixing_matrix(st); + if (order_plus_one == 2) + { + mapping_matrix_init(mixing_matrix, mapping_matrix_foa_mixing.rows, + mapping_matrix_foa_mixing.cols, mapping_matrix_foa_mixing.gain, + mapping_matrix_foa_mixing_data, + sizeof(mapping_matrix_foa_mixing_data)); + } + else if (order_plus_one == 3) + { + mapping_matrix_init(mixing_matrix, mapping_matrix_soa_mixing.rows, + mapping_matrix_soa_mixing.cols, mapping_matrix_soa_mixing.gain, + mapping_matrix_soa_mixing_data, + sizeof(mapping_matrix_soa_mixing_data)); + } + else if (order_plus_one == 4) + { + mapping_matrix_init(mixing_matrix, mapping_matrix_toa_mixing.rows, + mapping_matrix_toa_mixing.cols, mapping_matrix_toa_mixing.gain, + mapping_matrix_toa_mixing_data, + sizeof(mapping_matrix_toa_mixing_data)); + } + else + return OPUS_BAD_ARG; + + st->mixing_matrix_size_in_bytes = mapping_matrix_get_size( + mixing_matrix->rows, mixing_matrix->cols); + if (!st->mixing_matrix_size_in_bytes) + return OPUS_BAD_ARG; + + /* Assign demixing matrix based on available pre-computed matrices. */ + demixing_matrix = get_enc_demixing_matrix(st); + if (order_plus_one == 2) + { + mapping_matrix_init(demixing_matrix, mapping_matrix_foa_demixing.rows, + mapping_matrix_foa_demixing.cols, mapping_matrix_foa_demixing.gain, + mapping_matrix_foa_demixing_data, + sizeof(mapping_matrix_foa_demixing_data)); + } + else if (order_plus_one == 3) + { + mapping_matrix_init(demixing_matrix, mapping_matrix_soa_demixing.rows, + mapping_matrix_soa_demixing.cols, mapping_matrix_soa_demixing.gain, + mapping_matrix_soa_demixing_data, + sizeof(mapping_matrix_soa_demixing_data)); + } + else if (order_plus_one == 4) + { + mapping_matrix_init(demixing_matrix, mapping_matrix_toa_demixing.rows, + mapping_matrix_toa_demixing.cols, mapping_matrix_toa_demixing.gain, + mapping_matrix_toa_demixing_data, + sizeof(mapping_matrix_toa_demixing_data)); + } + else + return OPUS_BAD_ARG; + + st->demixing_matrix_size_in_bytes = mapping_matrix_get_size( + demixing_matrix->rows, demixing_matrix->cols); + if (!st->demixing_matrix_size_in_bytes) + return OPUS_BAD_ARG; + } + else + return OPUS_UNIMPLEMENTED; + + /* Ensure matrices are large enough for desired coding scheme. */ + if (*streams + *coupled_streams > mixing_matrix->rows || + channels > mixing_matrix->cols || + channels > demixing_matrix->rows || + *streams + *coupled_streams > demixing_matrix->cols) + return OPUS_BAD_ARG; + + /* Set trivial mapping so each input channel pairs with a matrix column. */ + for (i = 0; i < channels; i++) + mapping[i] = i; + + /* Initialize multistream encoder with provided settings. */ + ms_encoder = get_multistream_encoder(st); + ret = opus_multistream_encoder_init(ms_encoder, Fs, channels, *streams, + *coupled_streams, mapping, application); + return ret; +} + +OpusProjectionEncoder *opus_projection_ambisonics_encoder_create( + opus_int32 Fs, int channels, int mapping_family, int *streams, + int *coupled_streams, int application, int *error) +{ + int size; + int ret; + OpusProjectionEncoder *st; + + /* Allocate space for the projection encoder. */ + size = opus_projection_ambisonics_encoder_get_size(channels, mapping_family); + if (!size) { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + st = (OpusProjectionEncoder *)opus_alloc(size); + if (!st) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + + /* Initialize projection encoder with provided settings. */ + ret = opus_projection_ambisonics_encoder_init(st, Fs, channels, + mapping_family, streams, coupled_streams, application); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +int opus_projection_encode(OpusProjectionEncoder *st, const opus_int16 *pcm, + int frame_size, unsigned char *data, + opus_int32 max_data_bytes) +{ + return opus_multistream_encode_native(get_multistream_encoder(st), + opus_projection_copy_channel_in_short, pcm, frame_size, data, + max_data_bytes, 16, downmix_int, 0, get_mixing_matrix(st)); +} + +#ifndef DISABLE_FLOAT_API +#ifdef FIXED_POINT +int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm, + int frame_size, unsigned char *data, + opus_int32 max_data_bytes) +{ + return opus_multistream_encode_native(get_multistream_encoder(st), + opus_projection_copy_channel_in_float, pcm, frame_size, data, + max_data_bytes, 16, downmix_float, 1, get_mixing_matrix(st)); +} +#else +int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm, + int frame_size, unsigned char *data, + opus_int32 max_data_bytes) +{ + return opus_multistream_encode_native(get_multistream_encoder(st), + opus_projection_copy_channel_in_float, pcm, frame_size, data, + max_data_bytes, 24, downmix_float, 1, get_mixing_matrix(st)); +} +#endif +#endif + +void opus_projection_encoder_destroy(OpusProjectionEncoder *st) +{ + opus_free(st); +} + +int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...) +{ + va_list ap; + MappingMatrix *demixing_matrix; + OpusMSEncoder *ms_encoder; + int ret = OPUS_OK; + + ms_encoder = get_multistream_encoder(st); + demixing_matrix = get_enc_demixing_matrix(st); + + va_start(ap, request); + switch(request) + { + case OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = + ms_encoder->layout.nb_channels * (ms_encoder->layout.nb_streams + + ms_encoder->layout.nb_coupled_streams) * sizeof(opus_int16); + } + break; + case OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = demixing_matrix->gain; + } + break; + case OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST: + { + int i, j, k, l; + int nb_input_streams; + int nb_output_streams; + unsigned char *external_char; + opus_int16 *internal_short; + opus_int32 external_size; + opus_int32 internal_size; + + /* (I/O is in relation to the decoder's perspective). */ + nb_input_streams = ms_encoder->layout.nb_streams + + ms_encoder->layout.nb_coupled_streams; + nb_output_streams = ms_encoder->layout.nb_channels; + + external_char = va_arg(ap, unsigned char *); + external_size = va_arg(ap, opus_int32); + if (!external_char) + { + goto bad_arg; + } + internal_short = mapping_matrix_get_data(demixing_matrix); + internal_size = nb_input_streams * nb_output_streams * sizeof(opus_int16); + if (external_size != internal_size) + { + goto bad_arg; + } + + /* Copy demixing matrix subset to output destination. */ + l = 0; + for (i = 0; i < nb_input_streams; i++) { + for (j = 0; j < nb_output_streams; j++) { + k = demixing_matrix->rows * i + j; + external_char[2*l] = (unsigned char)internal_short[k]; + external_char[2*l+1] = (unsigned char)(internal_short[k] >> 8); + l++; + } + } + } + break; + default: + { + ret = opus_multistream_encoder_ctl_va_list(ms_encoder, request, ap); + } + break; + } + va_end(ap); + return ret; + +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/repacketizer.c b/native/opennow-streamer/vendor/audiopus-sys/opus/src/repacketizer.c new file mode 100644 index 000000000..bda44a148 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/repacketizer.c @@ -0,0 +1,349 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus.h" +#include "opus_private.h" +#include "os_support.h" + + +int opus_repacketizer_get_size(void) +{ + return sizeof(OpusRepacketizer); +} + +OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) +{ + rp->nb_frames = 0; + return rp; +} + +OpusRepacketizer *opus_repacketizer_create(void) +{ + OpusRepacketizer *rp; + rp=(OpusRepacketizer *)opus_alloc(opus_repacketizer_get_size()); + if(rp==NULL)return NULL; + return opus_repacketizer_init(rp); +} + +void opus_repacketizer_destroy(OpusRepacketizer *rp) +{ + opus_free(rp); +} + +static int opus_repacketizer_cat_impl(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len, int self_delimited) +{ + unsigned char tmp_toc; + int curr_nb_frames,ret; + /* Set of check ToC */ + if (len<1) return OPUS_INVALID_PACKET; + if (rp->nb_frames == 0) + { + rp->toc = data[0]; + rp->framesize = opus_packet_get_samples_per_frame(data, 8000); + } else if ((rp->toc&0xFC) != (data[0]&0xFC)) + { + /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/ + return OPUS_INVALID_PACKET; + } + curr_nb_frames = opus_packet_get_nb_frames(data, len); + if(curr_nb_frames<1) return OPUS_INVALID_PACKET; + + /* Check the 120 ms maximum packet size */ + if ((curr_nb_frames+rp->nb_frames)*rp->framesize > 960) + { + return OPUS_INVALID_PACKET; + } + + ret=opus_packet_parse_impl(data, len, self_delimited, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], NULL, NULL); + if(ret<1)return ret; + + rp->nb_frames += curr_nb_frames; + return OPUS_OK; +} + +int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) +{ + return opus_repacketizer_cat_impl(rp, data, len, 0); +} + +int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) +{ + return rp->nb_frames; +} + +opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, + unsigned char *data, opus_int32 maxlen, int self_delimited, int pad) +{ + int i, count; + opus_int32 tot_size; + opus_int16 *len; + const unsigned char **frames; + unsigned char * ptr; + + if (begin<0 || begin>=end || end>rp->nb_frames) + { + /*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/ + return OPUS_BAD_ARG; + } + count = end-begin; + + len = rp->len+begin; + frames = rp->frames+begin; + if (self_delimited) + tot_size = 1 + (len[count-1]>=252); + else + tot_size = 0; + + ptr = data; + if (count==1) + { + /* Code 0 */ + tot_size += len[0]+1; + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = rp->toc&0xFC; + } else if (count==2) + { + if (len[1] == len[0]) + { + /* Code 1 */ + tot_size += 2*len[0]+1; + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = (rp->toc&0xFC) | 0x1; + } else { + /* Code 2 */ + tot_size += len[0]+len[1]+2+(len[0]>=252); + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = (rp->toc&0xFC) | 0x2; + ptr += encode_size(len[0], ptr); + } + } + if (count > 2 || (pad && tot_size < maxlen)) + { + /* Code 3 */ + int vbr; + int pad_amount=0; + + /* Restart the process for the padding case */ + ptr = data; + if (self_delimited) + tot_size = 1 + (len[count-1]>=252); + else + tot_size = 0; + vbr = 0; + for (i=1;i=252) + len[i]; + tot_size += len[count-1]; + + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = (rp->toc&0xFC) | 0x3; + *ptr++ = count | 0x80; + } else { + tot_size += count*len[0]+2; + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = (rp->toc&0xFC) | 0x3; + *ptr++ = count; + } + pad_amount = pad ? (maxlen-tot_size) : 0; + if (pad_amount != 0) + { + int nb_255s; + data[1] |= 0x40; + nb_255s = (pad_amount-1)/255; + for (i=0;inb_frames, data, maxlen, 0, 0); +} + +int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len) +{ + OpusRepacketizer rp; + opus_int32 ret; + if (len < 1) + return OPUS_BAD_ARG; + if (len==new_len) + return OPUS_OK; + else if (len > new_len) + return OPUS_BAD_ARG; + opus_repacketizer_init(&rp); + /* Moving payload to the end of the packet so we can do in-place padding */ + OPUS_MOVE(data+new_len-len, data, len); + ret = opus_repacketizer_cat(&rp, data+new_len-len, len); + if (ret != OPUS_OK) + return ret; + ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, 1); + if (ret > 0) + return OPUS_OK; + else + return ret; +} + +opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len) +{ + OpusRepacketizer rp; + opus_int32 ret; + if (len < 1) + return OPUS_BAD_ARG; + opus_repacketizer_init(&rp); + ret = opus_repacketizer_cat(&rp, data, len); + if (ret < 0) + return ret; + ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, len, 0, 0); + celt_assert(ret > 0 && ret <= len); + return ret; +} + +int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams) +{ + int s; + int count; + unsigned char toc; + opus_int16 size[48]; + opus_int32 packet_offset; + opus_int32 amount; + + if (len < 1) + return OPUS_BAD_ARG; + if (len==new_len) + return OPUS_OK; + else if (len > new_len) + return OPUS_BAD_ARG; + amount = new_len - len; + /* Seek to last stream */ + for (s=0;s +#include +#include + +#define MAX_PACKETOUT 32000 + +void usage(char *argv0) +{ + fprintf(stderr, "usage: %s [options] input_file output_file\n", argv0); +} + +static void int_to_char(opus_uint32 i, unsigned char ch[4]) +{ + ch[0] = i>>24; + ch[1] = (i>>16)&0xFF; + ch[2] = (i>>8)&0xFF; + ch[3] = i&0xFF; +} + +static opus_uint32 char_to_int(unsigned char ch[4]) +{ + return ((opus_uint32)ch[0]<<24) | ((opus_uint32)ch[1]<<16) + | ((opus_uint32)ch[2]<< 8) | (opus_uint32)ch[3]; +} + +int main(int argc, char *argv[]) +{ + int i, eof=0; + FILE *fin, *fout; + unsigned char packets[48][1500]; + int len[48]; + int rng[48]; + OpusRepacketizer *rp; + unsigned char output_packet[MAX_PACKETOUT]; + int merge = 1, split=0; + + if (argc < 3) + { + usage(argv[0]); + return EXIT_FAILURE; + } + for (i=1;i48) + { + fprintf(stderr, "-merge parameter must be less than 48.\n"); + return EXIT_FAILURE; + } + i++; + } else if (strcmp(argv[i], "-split")==0) + split = 1; + else + { + fprintf(stderr, "Unknown option: %s\n", argv[i]); + usage(argv[0]); + return EXIT_FAILURE; + } + } + fin = fopen(argv[argc-2], "r"); + if(fin==NULL) + { + fprintf(stderr, "Error opening input file: %s\n", argv[argc-2]); + return EXIT_FAILURE; + } + fout = fopen(argv[argc-1], "w"); + if(fout==NULL) + { + fprintf(stderr, "Error opening output file: %s\n", argv[argc-1]); + fclose(fin); + return EXIT_FAILURE; + } + + rp = opus_repacketizer_create(); + while (!eof) + { + int err; + int nb_packets=merge; + opus_repacketizer_init(rp); + for (i=0;i1500 || len[i]<0) + { + if (feof(fin)) + { + eof = 1; + } else { + fprintf(stderr, "Invalid payload length\n"); + fclose(fin); + fclose(fout); + return EXIT_FAILURE; + } + break; + } + if (fread(ch, 1, 4, fin)!=4) + { + if (feof(fin)) + { + eof = 1; + } else { + fprintf(stderr, "Error reading.\n"); + fclose(fin); + fclose(fout); + return EXIT_FAILURE; + } + break; + } + rng[i] = char_to_int(ch); + if (fread(packets[i], len[i], 1, fin)!=1) { + if (feof(fin)) + { + eof = 1; + } else { + fprintf(stderr, "Error reading packet of %u bytes.\n", len[i]); + fclose(fin); + fclose(fout); + return EXIT_FAILURE; + } + break; + } + err = opus_repacketizer_cat(rp, packets[i], len[i]); + if (err!=OPUS_OK) + { + fprintf(stderr, "opus_repacketizer_cat() failed: %s\n", opus_strerror(err)); + break; + } + } + nb_packets = i; + + if (eof) + break; + + if (!split) + { + err = opus_repacketizer_out(rp, output_packet, MAX_PACKETOUT); + if (err>0) { + unsigned char int_field[4]; + int_to_char(err, int_field); + if(fwrite(int_field, 1, 4, fout)!=4){ + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + int_to_char(rng[nb_packets-1], int_field); + if (fwrite(int_field, 1, 4, fout)!=4) { + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + if (fwrite(output_packet, 1, err, fout)!=(unsigned)err) { + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + /*fprintf(stderr, "out len = %d\n", err);*/ + } else { + fprintf(stderr, "opus_repacketizer_out() failed: %s\n", opus_strerror(err)); + } + } else { + int nb_frames = opus_repacketizer_get_nb_frames(rp); + for (i=0;i0) { + unsigned char int_field[4]; + int_to_char(err, int_field); + if (fwrite(int_field, 1, 4, fout)!=4) { + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + if (i==nb_frames-1) + int_to_char(rng[nb_packets-1], int_field); + else + int_to_char(0, int_field); + if (fwrite(int_field, 1, 4, fout)!=4) { + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + if (fwrite(output_packet, 1, err, fout)!=(unsigned)err) { + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + /*fprintf(stderr, "out len = %d\n", err);*/ + } else { + fprintf(stderr, "opus_repacketizer_out() failed: %s\n", opus_strerror(err)); + } + + } + } + } + + fclose(fin); + fclose(fout); + return EXIT_SUCCESS; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/src/tansig_table.h b/native/opennow-streamer/vendor/audiopus-sys/opus/src/tansig_table.h new file mode 100644 index 000000000..c76f844a7 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/src/tansig_table.h @@ -0,0 +1,45 @@ +/* This file is auto-generated by gen_tables */ + +static const float tansig_table[201] = { +0.000000f, 0.039979f, 0.079830f, 0.119427f, 0.158649f, +0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f, +0.379949f, 0.413644f, 0.446244f, 0.477700f, 0.507977f, +0.537050f, 0.564900f, 0.591519f, 0.616909f, 0.641077f, +0.664037f, 0.685809f, 0.706419f, 0.725897f, 0.744277f, +0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.821040f, +0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f, +0.885352f, 0.893698f, 0.901468f, 0.908698f, 0.915420f, +0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f, +0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.961090f, +0.964028f, 0.966747f, 0.969265f, 0.971594f, 0.973749f, +0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f, +0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f, +0.989027f, 0.989867f, 0.990642f, 0.991359f, 0.992020f, +0.992631f, 0.993196f, 0.993718f, 0.994199f, 0.994644f, +0.995055f, 0.995434f, 0.995784f, 0.996108f, 0.996407f, +0.996682f, 0.996937f, 0.997172f, 0.997389f, 0.997590f, +0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f, +0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f, +0.999000f, 0.999076f, 0.999147f, 0.999213f, 0.999273f, +0.999329f, 0.999381f, 0.999428f, 0.999472f, 0.999513f, +0.999550f, 0.999585f, 0.999617f, 0.999646f, 0.999673f, +0.999699f, 0.999722f, 0.999743f, 0.999763f, 0.999781f, +0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f, +0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f, +0.999909f, 0.999916f, 0.999923f, 0.999929f, 0.999934f, +0.999939f, 0.999944f, 0.999948f, 0.999952f, 0.999956f, +0.999959f, 0.999962f, 0.999965f, 0.999968f, 0.999970f, +0.999973f, 0.999975f, 0.999977f, 0.999978f, 0.999980f, +0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f, +0.999988f, 0.999989f, 0.999990f, 0.999990f, 0.999991f, +0.999992f, 0.999992f, 0.999993f, 0.999994f, 0.999994f, +0.999994f, 0.999995f, 0.999995f, 0.999996f, 0.999996f, +0.999996f, 0.999997f, 0.999997f, 0.999997f, 0.999997f, +0.999997f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, +0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f, +0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, +0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, +1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, +1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, +1.000000f, +}; diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/tests/meson.build b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/meson.build new file mode 100644 index 000000000..5f3ac9df3 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/meson.build @@ -0,0 +1,34 @@ +# Tests that link to libopus +opus_tests = [ + ['test_opus_api'], + ['test_opus_decode', [], 60], + ['test_opus_encode', 'opus_encode_regressions.c', 120], + ['test_opus_padding'], + ['test_opus_projection'], +] + +foreach t : opus_tests + test_name = t.get(0) + extra_srcs = t.get(1, []) + + test_kwargs = {} + if t.length() > 2 + test_kwargs += {'timeout': t[2]} + endif + + exe_kwargs = {} + # This test uses private symbols + if test_name == 'test_opus_projection' + exe_kwargs = { + 'link_with': [celt_lib, silk_lib], + 'objects': opus_lib.extract_all_objects(), + } + endif + + exe = executable(test_name, '@0@.c'.format(test_name), extra_srcs, + include_directories: opus_includes, + dependencies: [libm, opus_dep], + install: false, + kwargs: exe_kwargs) + test(test_name, exe, kwargs: test_kwargs) +endforeach diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/tests/opus_decode_fuzzer.c b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/opus_decode_fuzzer.c new file mode 100644 index 000000000..ea6ec4fd1 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/opus_decode_fuzzer.c @@ -0,0 +1,124 @@ +/* Copyright (c) 2017 Google Inc. */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "opus.h" +#include "opus_types.h" + +#define MAX_FRAME_SAMP 5760 +#define MAX_PACKET 1500 + +/* 4 bytes: packet length, 4 bytes: encoder final range */ +#define SETUP_BYTE_COUNT 8 + +#define MAX_DECODES 12 + +typedef struct { + int fs; + int channels; +} TocInfo; + +static void ParseToc(const uint8_t *toc, TocInfo *const info) { + const int samp_freqs[5] = {8000, 12000, 16000, 24000, 48000}; + const int bandwidth = opus_packet_get_bandwidth(toc); + + info->fs = samp_freqs[bandwidth - OPUS_BANDWIDTH_NARROWBAND]; + info->channels = opus_packet_get_nb_channels(toc); +} + +/* Treats the input data as concatenated packets encoded by opus_demo, + * structured as + * bytes 0..3: packet length + * bytes 4..7: encoder final range + * bytes 8+ : Opus packet, including ToC + */ +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + OpusDecoder *dec; + opus_int16 *pcm; + uint8_t *temp_data; + TocInfo toc; + int i = 0; + int err = OPUS_OK; + int num_decodes = 0; + + /* Not enough data to setup the decoder (+1 for the ToC) */ + if (size < SETUP_BYTE_COUNT + 1) { + return 0; + } + + /* Create decoder based on info from the first ToC available */ + ParseToc(&data[SETUP_BYTE_COUNT], &toc); + + dec = opus_decoder_create(toc.fs, toc.channels, &err); + if (err != OPUS_OK || dec == NULL) { + return 0; + } + + pcm = (opus_int16*) malloc(sizeof(*pcm) * MAX_FRAME_SAMP * toc.channels); + + while (i + SETUP_BYTE_COUNT < size && num_decodes++ < MAX_DECODES) { + int len, fec; + + len = (opus_uint32) data[i ] << 24 | + (opus_uint32) data[i + 1] << 16 | + (opus_uint32) data[i + 2] << 8 | + (opus_uint32) data[i + 3]; + if (len > MAX_PACKET || len < 0 || i + SETUP_BYTE_COUNT + len > size) { + break; + } + + /* Bytes 4..7 represent encoder final range, but are unused here. + * Instead, byte 4 is repurposed to determine if FEC is used. */ + fec = data[i + 4] & 1; + + if (len == 0) { + /* Lost packet */ + int frame_size; + opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&frame_size)); + (void) opus_decode(dec, NULL, len, pcm, frame_size, fec); + } else { + temp_data = (uint8_t*) malloc(len); + memcpy(temp_data, &data[i + SETUP_BYTE_COUNT], len); + + (void) opus_decode(dec, temp_data, len, pcm, MAX_FRAME_SAMP, fec); + + free(temp_data); + } + + i += SETUP_BYTE_COUNT + len; + } + + opus_decoder_destroy(dec); + free(pcm); + + return 0; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/tests/opus_decode_fuzzer.options b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/opus_decode_fuzzer.options new file mode 100644 index 000000000..e5ae71b93 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/opus_decode_fuzzer.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 1000000 diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/tests/opus_encode_regressions.c b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/opus_encode_regressions.c new file mode 100644 index 000000000..292347301 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/opus_encode_regressions.c @@ -0,0 +1,1035 @@ +/* Copyright (c) 2016 Mark Harris, Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include "opus_multistream.h" +#include "opus.h" +#include "test_opus_common.h" + + +static int celt_ec_internal_error(void) +{ + OpusMSEncoder *enc; + int err; + unsigned char data[2460]; + int streams; + int coupled_streams; + unsigned char mapping[1]; + + enc = opus_multistream_surround_encoder_create(16000, 1, 1, &streams, + &coupled_streams, mapping, OPUS_APPLICATION_VOIP, &err); + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(8)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(OPUS_AUTO)); + { + static const short pcm[320] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1792, 1799, 1799, + 1799, 1799, 1799, 1799, 1799, 1799, 1799, 1799, 1799, + 1799, 1799, 1799, 1799, 1799, 0, 25600, 1799, 1799, + 1799, 1799, 1799, 1799, 1799, 1799, 1799, 1799, 1799, + 1799, 1799, 1799, 1799, 7, 0, 255, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 32767, -1, + 0, 0, 0, 100, 0, 16384, 0, 0, 0, + 0, 0, 0, 4, 0, 0, -256, 255, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,-32768, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 128, 0, 0, 0, 0, + 0, 0, 0, 0, -256, 0, 0, 32, 0, + 0, 0, 0, 0, 0, 0, 4352, 4, 228, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5632, 0, 0, + 0, 0,-32768, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 256, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + -3944, 10500, 4285, 10459, -6474, 10204, -6539, 11601, -6824, + 13385, -7142, 13872,-11553, 13670, -7725, 13463, -6887, 7874, + -5580, 12600, -4964, 12480, 3254, 11741, -4210, 9741, -3155, + 7558, -5468, 5431, -1073, 3641, -1304, 0, -1, 343, + 26, 0, 0, 150, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1799, 1799, 1799, 1799, 1799, -2553, + 7, 1792, 1799, 1799, 1799, 1799, 1799, 1799, 1799, + 1799, 1799, 1799, 1799, -9721 + }; + err = opus_multistream_encode(enc, pcm, 320, data, 2460); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(18)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(90)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(280130)); + { + static const short pcm[160] = + { + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9526, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, 25600, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510 + }; + err = opus_multistream_encode(enc, pcm, 160, data, 2460); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(18)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(90)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(280130)); + { + static const short pcm[160] = + { + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9494, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510 + }; + err = opus_multistream_encode(enc, pcm, 160, data, 2460); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(18)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(90)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(280130)); + { + static const short pcm[160] = + { + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9479, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510 + }; + err = opus_multistream_encode(enc, pcm, 160, data, 2460); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(18)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(90)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(280130)); + { + static const short pcm[160] = + { + -9510, -9510, 1799, 1799, 1799, 1799, 1799, 1799, 1799, + 1799, 1799, 1799, 1799, 1799, 1799, 1799, 1799, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + -256, 255, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 0, 0, 0, 0, 0, 0, 0, + 4352, 4, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 148, 0, 0, 0, 0, + 5632 + }; + err = opus_multistream_encode(enc, pcm, 160, data, 2460); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(12)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(41)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(21425)); + { + static const short pcm[40] = + { + 10459, -6474, 10204, -6539, 11601, -6824, 13385, -7142, 13872, + -11553, 13670, -7725, 13463, -6887, 12482, -5580, 12600, -4964, + 12480, 3254, 11741, -4210, 9741, -3155, 7558, -5468, 5431, + -1073, 3641, -1304, 0, -1, 343, 26, 0, 0, + 0, 0, -256, 226 + }; + err = opus_multistream_encode(enc, pcm, 40, data, 2460); + assert(err > 0); + /* returns -3 */ + } + opus_multistream_encoder_destroy(enc); + return 0; +} + +static int mscbr_encode_fail10(void) +{ + OpusMSEncoder *enc; + int err; + unsigned char data[627300]; + static const unsigned char mapping[255] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101, + 102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118, + 119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135, + 136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152, + 153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169, + 170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186, + 187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203, + 204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, + 221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237, + 238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254 + }; + + enc = opus_multistream_encoder_create(8000, 255, 254, 1, mapping, + OPUS_APPLICATION_RESTRICTED_LOWDELAY, &err); + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(2)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(2)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(14)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(57)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(3642675)); + { + static const short pcm[20*255] = + { + 0 + }; + err = opus_multistream_encode(enc, pcm, 20, data, 627300); + assert(err > 0); + /* returns -1 */ + } + opus_multistream_encoder_destroy(enc); + return 0; +} + +static int mscbr_encode_fail(void) +{ + OpusMSEncoder *enc; + int err; + unsigned char data[472320]; + static const unsigned char mapping[192] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101, + 102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118, + 119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135, + 136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152, + 153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169, + 170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186, + 187,188,189,190,191 + }; + + enc = opus_multistream_encoder_create(8000, 192, 189, 3, mapping, + OPUS_APPLICATION_RESTRICTED_LOWDELAY, &err); + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(8)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(15360)); + { + static const short pcm[20*192] = + { + 0 + }; + err = opus_multistream_encode(enc, pcm, 20, data, 472320); + assert(err > 0); + /* returns -1 */ + } + opus_multistream_encoder_destroy(enc); + return 0; +} + +static int surround_analysis_uninit(void) +{ + OpusMSEncoder *enc; + int err; + unsigned char data[7380]; + int streams; + int coupled_streams; + unsigned char mapping[3]; + + enc = opus_multistream_surround_encoder_create(24000, 3, 1, &streams, + &coupled_streams, mapping, OPUS_APPLICATION_AUDIO, &err); + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(8)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(84315)); + { + static const short pcm[960*3] = + { + -6896, 4901, -6158, 4120, -5164, 3631, -4442, 3153, -4070, + 3349, -4577, 4474, -5541, 5058, -6701, 3881, -7933, 1863, + -8041, 697, -6738,-31464, 14330,-12523, 4096, -6130, 29178, + -250,-21252, 10467, 16907, -3359, -6644, 31965, 14607,-21544, + -32497, 24020, 12557,-26926,-18421, -1842, 24587, 19659, 4878, + 10954, 23060, 8907,-10215,-16179, 31772,-11825,-15590,-23089, + 17173,-25903,-17387, 11733, 4884, 10204,-16476,-14367, 516, + 20453,-16898, 20967,-23813, -20, 22011,-17167, 9459, 32499, + -25855, -523, -3883, -390, -4206, 634, -3767, 2325, -2751, + 3115, -2392, 2746, -2173, 2317, -1147, 2326, 23142, 11314, + -15350,-24529, 3026, 6146, 2150, 2476, 1105, -830, 1775, + -3425, 3674,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + 4293,-14023, 3879,-15553, 3158,-16161, 2629, 18433,-12535, + -6645,-20735,-32763,-13824,-20992, 25859, 13052, -8731, 2292, + -3860, 24049, 10225,-19220, 10478,-22294, 22773, 28137, 13816, + 30953,-25863,-24598, 16888,-14612,-28942, 20974,-27397,-18944, + -18690, 20991,-16638, 5632,-14330, 28911,-25594, 17408, 29958, + -517,-20984, -1800, 11281, 9977,-21221,-14854, 23840, -9477, + 3362,-12805,-22493, 32507, 156, 16384, -1163, 2301, -1874, + 4600, -1748, 6950, 16557, 8192, -7372, -1033, -3278, 2806, + 20275, 3317, -717, 9792, -767, 9099, -613, 8362, 5027, + 7774, 2597, 8549, 5278, 8743, 9343, 6940, 13038, 4826, + 14086, 2964, 13215, 1355, 11596, 455, 9850, -519, 10680, + -2287, 12551, -3736, 13639, -4291, 13790, -2722, 14544, -866, + 15050, -304, 22833, -1196, 13520, -2063, 13051, -2317, 13066, + -2737, 13773, -2664, 14105, -3447, 13854, 24589, 24672, -5280, + 10388, -4933, 7543, -4149, 3654, -1552, 1726, 661, 57, + 2922, -751, 3917, 8419, 3840, -5218, 3435, 5540, -1073, + 4153, -6656, 1649, -769, -7276,-13072, 6380, -7948, 20717, + 18425, 17392, 14335,-18190, -1842, 24587, 19659, 11790, 10954, + 23060, 8907,-10215,-16179, 31772,-11825,-15590,-23101, 17173, + -25903,-17387, 11733, 4884, 10192,-16627,-14367, 516, 20453, + -16898, 20967,-23813, -20, 22011,-17167, 9468, 32499,-25607, + -523, -3883, -390, -4206, 634, -3767, 2325, -2751, 3115, + -2392, 2746, -2161, 2317, -1147, 2326, 23142, 11314,-15350, + -29137, 3026,-15056, -491,-15170, -386,-16015, -641,-16505, + -930,-16206, -717,-16175, -2839,-16374, -4558,-16237, -5207, + -15903, -6421, 6373, -1403, 5431, -1073, 3641, -1304, -4495, + -769, -7276, 2856, -7870, 3314, -8730, 3964,-10183, 4011, + -11135, 3421,-11727, 2966,-12360, 2818,-13472, 3660,-13805, + 5162,-13478, 6434,-12840, 7335,-12420, 6865,-12349, 5541, + -11965, 5530,-10820, 5132, -9197, 3367, -7745, 1223, -6910, + -433, -6211, -1711, -4958, -1025, -3755, -836, -3292, -1666, + -2661,-10755, 31472,-27906, 31471, 18690, 5617, 16649, 11253, + -22516,-17674,-31990, 3575,-31479, 5883, 26121, 12890, -6612, + 12228,-11634, 523, 26136,-21496, 20745,-15868, -4100,-24826, + 23282, 22798, 491, -1774, 15075,-27373,-13094, 6417,-29487, + 14608, 10185, 16143, 22211, -8436, 4288, -8694, 2375, 3023, + 486, 1455, 128, 202, 942, -923, 2068, -1233, -717, + -1042, -2167, 32255, -4632, 310, -4458, -3639, -5258, 2106, + -6857, 2681, -7497, 2765, -6601, 1945, -5219, 19154, -4877, + 619, -5719, -1928, -6208, -121, 593, 188, 1558, -4152, + 1648, 156, 1604, -3664, -6862, -2851, -5112, -3600, -3747, + -5081, -4428, -5592, 20974,-27397,-18944,-18690, 20991,-17406, + 5632,-14330, 28911, 15934, 15934, 15934, 15934, 15934, 15934, + 15934, 15934, 15934, 15934, 15934, 15934,-25594, 17408, 29958, + -7173,-16888, 9098, -613, 8362, 675, 7774, 2597, 8549, + 5278, 8743, 9375, 6940, 13038, 4826, 14598, 7721,-24308, + -29905,-19703,-17106,-16124, -3287,-26118,-19709,-10769, 24353, + 28648, 6946, -1363, 12485, -1187, 26074,-25055, 10004,-24798, + 7204, -4581, -9678, 1554, 10553, 3102, 12193, 2443, 11955, + 1213, 10689, -1293, 921, -4173, 10709, -6049, 8815, -7128, + 8147, -8308, 6847, -2977, 4920,-11447,-22426,-11794, 3514, + -10220, 3430, -7993, 1926, -7072, 327, -7569, -608, -7605, + 3695, -6271, -1579, -4877, -1419, -3103, -2197, 128, -3904, + 3760, -5401, 4906, -6051, 4250, -6272, 3492, -6343, 3197, + -6397, 4041, -6341, 6255, -6381, 7905, 16504, 0, -6144, + 8062, -5606, 8622, -5555, -9, -1, 7423, 0, 1, + 238, 5148, 1309, 4700, 2218, 4403, 2573, 3568, 28303, + 1758, 3454, -1247, 3434, -4912, 2862, -7844, 1718,-10095, + 369,-12631, 128, -3904, 3632, -5401, 4906, -6051, 4250, + -6272, 3492, -6343, 3197, -6397, 4041, -6341, 6255, -6381, + 7905, 16504, 0, -6144, 8062, -5606, 8622, -5555, 8439, + -3382, 7398, -1170, 6132, 238, 5148, 1309, 4700, 2218, + 4403, 2573, 3568, 2703, 1758, 3454, -1247, 3434, -4912, + 2862, -7844, 1718,-10095, 369,-12631, -259,-14632, 234, + -15056, -521,-15170, -386,-16015, -641,-16505, -930,-16206, + -1209,-16146, -2839,-16374, -4558,-16218, -5207,-15903, -6421, + -15615, -6925,-14871, -6149,-13759, -5233,-12844, 18313, -4357, + -5696, 2804, 12992,-22802, -6720, -9770, -7088, -8998, 14330, + -12523, 14843, -6130, 29178, -250,-27396, 10467, 16907, -3359, + -6644, 31965, 14607,-21544,-32497, 24020, 12557,-26926, -173, + -129, -6401, -130,-25089, -3841, -4916, -3048, 224, -237, + -3969, -189, -3529, -535, -3464,-14863,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14395,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907, 0, 32512,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907, 9925, -718, 9753, -767, + 9099, -613, 8362, 675, 7774, 2597, 8549, 5278, 8743, + 9375, 6940, 13038, 4826, 14598, 7721,-24308,-29905,-19703, + -17106,-16124, -3287,-26118,-19709, 0, 24353, 28648, 10274, + -11292,-29665,-16417, 24346, 14553, 18707, 26323, -4596,-17711, + 5133, 26328, 13,-31168, 24583, 18404,-28927,-24350, 19453, + 28642, 1019,-10777, -3079, 30188, -7686, 27635,-32521,-16384, + 12528, -6386, 10986, 23827,-25880,-32752,-23321, 14605, 32231, + 780,-13849, 15119, 28647, 4888, -7705, 30750, 64, 0, + 32488, 6687,-20758, 19745, -2070,-13792, -6414, 28188, -2821, + -4585, 7168, 7444, 23557,-21998, 13064, 3345, -4086,-28915, + -8694, 32262, 8461, 27387,-12275, 12012, 23563,-18719,-28410, + 29144,-22271, -562, -9986, -5434, 12288, 5573,-16642, 32448, + 29182, 32705,-30723, 24255,-19716, 18368, -4357, -5696, 2804, + 12992,-22802,-22080, -7701, -5183, 486, -3133, -5660, -1083, + 16871,-28726,-11029,-30259, -1209,-16146, -2839,-16374, -4558, + -16218,-10523, 20697, -9500, -1316, 5431, -1073, 3641, -1304, + 1649, -769, -7276, 2856, -7870, 3314, -8730, 3964,-10183, + 4011,-11135, 3421,-11727, 21398, 32767, -1, 32486, -1, + 6301,-13071, 6380, -7948, -1, 32767, 240, 14081, -5646, + 30973, -3598,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907, 32767,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907, 8901, 9375, 6940, 13038, 4826, 14598, 7721,-24308, + -29905,-19703,-17106,-16124, -3287,-26118,-19709,-10769, 24361, + 28648, 10274,-11292,-29665,-16417, 24346, 14580, 18707, 26323, + -4440,-17711, 5133, 26328,-14579,-31008, 24583, 18404, 28417, + -24350, 19453, 28642,-32513,-10777, -3079, 30188, -7686, 27635, + -32521,-16384,-20240, -6386, 10986, 23827,-25880,-32752,-23321, + 14605, 32231, 780,-13849, 15119, 28647, 4888, -7705,-15074, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907, 8192,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14897,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -15931,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907, 26121, 12890, 2604, + 12228,-11634, 12299, 5573,-16642, 32452, 29182, 32705,-30723, + 24255,-19716, 13248,-11779, -5696, 2804, 12992,-27666,-22080, + -7701, -5183, -6682,-31464, 14330,-12523, 14843, -6130, 29178, + -18,-27396, 10467, 16907, -3359, -6644, 31965, 14607,-21544, + -32497, 24020, 12557,-26926,-18421, 706, 24587, 19659, 4878, + 10954, 23060, 8907,-10215,-22579, 31772,-11825,-15590,-23089, + 17173,-25903,-17387, 3285, 4884, 10204,-16627,-14367, 516, + 20453,-16898, 20967,-23815, -20, 22011,-17167, 9468, 32499, + -25607, -523, -3883, -390, -4206, 634, -3767, 2325, -2751, + 3115, -2392, 2746, -2173, 2317, -1147, 2326, 23142, 11314, + -15130,-29137, 3026, 6146, 2150, 2476, 1105, -830, 1775, + -3425, 3674, -5287, 4609, -7175, 4922, -9579, 4556,-12007, + 4236,-14023, 3879,-15553, 3158,-16161, 2576, 18398,-12535, + -6645,-20735,-32763,-13824,-20992, 25859, 5372, 12040, 13307, + -4355,-30213, -9, -6019, 14061,-31487,-13842, 30449, 15083, + 14088, 31205,-18678,-12830, 14090,-26138,-25337,-11541, -3254, + 27628,-22270, 30953,-16136,-30745, 20991,-17406, 5632,-14330, + 28911,-25594, 17408,-20474, 13041, -8731, 2292, -3860, 24049, + 10225,-19220, 10478, -4374, -1199, 148, -330, -74, 593, + 188, 1558, -4152, 15984, 15934, 15934, 15934, 15934, 15934, + 15934, 15934, 15934, 15934, 15934, 15934, 1598, 156, 1604, + -1163, 2278,-30018,-25821,-21763,-23776, 24066, 9502, 25866, + -25055, 10004,-24798, 7204, -4581, -9678, 1554, 10553, 3102, + 12193, 2443, 11955, 1213, 10689, -1293, 921, -4173, 8661, + -6049, 8815,-21221,-14854, 23840, -9477, 8549, 5278, 8743, + 9375, 6940, 13038, 4826, 14598, 7721,-24308,-29905,-19703, + -17106,-16124, -3287,-26118,-19709,-10769, 24361, 28648, 10274, + -11292,-29665,-16417, 24346, 14580, 18707, 26323, -4410,-17711, + 5133, 26328,-14579,-31008, 24583, 18404, 28417,-24350, 19453, + 28642,-32513,-10777, -3079, 30188, -7686, 27635,-32521,-16384, + -20240, -6386, 10986, 23827,-25880,-32752,-23321, 14605, 32231, + 780,-13849, 15119, 28647, 4888, -7705, 30750, 64, 0, + 32488, 6687,-20758, 19745, -2070, -1, -1, 28, 256, + -4608, 7168, 7444, 23557,-21998, 13064, 3345, -4086,-28915, + -8594, 32262, 8461, 27387,-12275, 12012, 23563,-18719,-28410, + 29144,-22271,-32562,-16384, 12528, -6386, 10986, 23827,-25880, + -32752,-23321, 14605, 32231, 780,-13849, 15119, 28647, 4888, + -7705, 30750, 64, 0, 32488, 6687,-20758, 19745, -2070, + -13792, -6414, 28188, -2821, -4585, 7168, 7444, 23557,-21998, + 13064, 3345, -4086,-28915, -8694, 32262, 8461, 27387,-12275, + 12012, 23563,-18719,-28410, 29144,-22271, -562, -9986, -5434, + 12288, -2107,-16643, 32452, 29182, 32705,-30723, 24255,-19716, + 18368, -4357, -5696, 2804, 12992,-22802,-22080, -7701, -5183, + 486, -3133, -5660, -1083, 16871,-28726,-11029,-30259, -1209, + -16146, -2839,-16374, -4558,-16218,-10523, 20697, -9500, -1316, + 5431, -1073, 3641, -1304, 1649, -769, -7276, 2856, -7870, + 3314, -8730, 3964,-10183, 4011,-11135, 3421,-11727, 21398, + 32767, -1, 32486, -1, -99,-13072, 6380, -7948, 4864, + 32767, 17392, 14335, -5646, 30973, -3598,-10299,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14905,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-19771,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-16443,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-15931,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907, -1,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907, 7877, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, -994, -7276, 2856, -7870, + 3314, -8730, 3964,-10183, 4011,-11135, 3421,-11727, 21398, + 32767, -1, 32486, -1, -99,-13072, 6380, -7948, 4864, + 32767, 17392, 14335, -5646, 30973, -3598,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14905,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907, 197, 0,-14977,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907, 12838, 6653, 294, + -29699,-25821,-21763,-23776, 24066, 9502, 25866,-25055, 10004, + -24798, 7204, -4581, -9678, 1554, 10553, 3102, 12193, 2443, + 11955, 1213, 10689, -1293, 921, 179, 8448, -6049, 8815, + -7128, 8147, -8308, 6847, -9889, 4920,-11447, 3174,-11794, + 3514,-10220, 3430, 16384, 1926, -7072, 327, -7537, -608, + -7605, -1169, -6397, -1579, -4877, -1419, -3103, -2197, 128, + -3904, 3632, -5401, 4906, -6051, 4250, -6272, 3492, -6343, + 3197, -6397, 4041, -6341, 6255, -6381, 7905, 16504, 0, + -6144, 8062, -5606, 8622, -5555, 8439, -3382, 7398, -1170, + 6132, 238, 5148, 1309, 4700, 2218, 4403, 2573, 3568, + 2703, 1758, 3454, -1247, 3434, -4912, 2862, -7844, 1718, + -10095, 369,-12631, -259,-14632, 234,-15056, -491,-16194, + -386,-16015, -641,-16505, -930,-16206, -1209,-16146, -2839, + -16374, -4558,-16218, -5207,-15903, -6421,-15615, -6925,-14871, + -6149,-13759, -5233,-12844, 18313, -4357, -5696, 2804, 12992, + -22802, -6720, -9770, -7088, -8998, 14330,-12523, 14843, -6130, + 29178, -250,-27396, 10467, 16907, -3359, -6644, 31965, 14607, + -21544,-32497, 24020, 12557,-26926, -173, -129, -6401, -130, + -25089, -3816, -4916, -3048, -32, -1, -3969, 256, -3529, + -535, -3464,-14863,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -1209,-16146, -2839,-16374, -4558,-16218,-10523, 20697, -9500, + -1316, 5431, -1073, 3641, -1304, 1649, -769, -7276, 2856, + -7870, 3314, -8730, 3964,-10183, 4011,-11135, 3421,-11727, + 21398, 32767, -1, 32486, -1, 6301,-13071, 6380, -7948, + -1, 32767, 240, 14081, -5646, 30973, -3598,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + 32767,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907, 8901, 9375, 6940, + 13038, 4826, 14598, 7721,-24308,-29905,-19703,-17106,-16124, + -3287,-26118,-19709,-10769, 24361, 28648, 10274,-11292,-29665, + -16417, 24346, 14580, 18707, 26323, -4440,-17711, 5133, 26328, + -14579,-31008, 24583, 18404, 28417,-24350, 19453, 28642,-32513, + -10777, -3079, 30188, -7686, 27635,-32521,-16384,-20240, -6386, + 10986, 23827,-25880,-32752,-23321, 14605, 32231, 780,-13849, + 15119, 28647, 4888, -7705,-15074,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, 8192, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14897, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-15931,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907, 26121, 12890, 2604, 12228,-11634, 12299, 5573, + -16642, 32452, 29182, 32705,-30723, 24255,-19716, 13248,-11779, + -5696, 2804, 12992,-27666,-22080, -7701, -5183, -6682,-31464, + 14330,-12523, 14843, -6130, 29178, -18,-27396, 10467, 16907, + -3359, -6644, 31965, 14607,-21544,-32497, 24020, 12557,-26926, + -18421, 706, 24587, 19659, 4878, 10954, 23060, 8907,-10215, + -22579, 31772,-11825,-15590,-23089, 17173,-25903,-17387, 3285, + 4884, 10204,-16627,-14367, 516, 20453,-16898, 20967,-23815, + -20, 22011,-17167, 9468, 32499,-25607, -523, -3883, -390, + -4206, 634, -3767, 2325, -2751, 3115, -2392, 2746, -2173, + 2317, -1147, 2326, 23142, 11314,-15130,-29137, 3026, 6146, + 2150, 2476, 1105, -830, 1775, -3425, 3674, -5287, 4609, + -7175, 4922, -9579, 4556,-12007, 4236,-14023, 3879,-15553, + 3158,-16161, 2576, 18398,-12535, -6645,-20735,-32763,-13824, + -20992, 25859, 5372, 12040, 13307, -4355,-30213, -9, -6019 + }; + err = opus_multistream_encode(enc, pcm, 960, data, 7380); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(6)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(9)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(5)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(775410)); + { + static const short pcm[1440*3] = + { + 30449, 15083, 14088, 31205,-18678,-12830, 14090,-26138,-25337, + -11541, -3254, 27628,-22270, 30953,-16136,-30745, 20991,-17406, + 5632,-14330, 28911,-25594, 17408,-20474, 13041, -8731, 2292, + -3860, 24049, 10225,-19220, 10478, -4374, -1199, 148, -330, + -74, 593, 188, 1558, -4152, 15984, 15934, 15934, 15934, + 15934, 15934, 15934, 15934, 15934, 15934, 15934, 15934, 1598, + 156, 1604, -1163, 2278,-30018,-25821,-21763,-23776, 24066, + 9502, 25866,-25055, 10004,-24798, 7204, -4581, -9678, 1554, + 10553, 3102, 12193, 2443, 11955, 1213, 10689, -1293, 921, + -4173, 8661, -6049, 8815,-21221,-14854, 23840, -9477, 8549, + 5278, 8743, 9375, 6940, 13038, 4826, 14598, 7721,-24308, + -29905,-19703,-17106,-16124, -3287,-26118,-19709,-10769, 24361, + 28648, 10274,-11292,-29665,-16417, 24346, 14580, 18707, 26323, + -4410,-17711, 5133, 26328,-14579,-31008, 24583, 18404, 28417, + -24350, 19453, 28642,-32513,-10777, -3079, 30188, -7686, 27635, + -32521,-16384,-20240, -6386, 10986, 23827,-25880,-32752,-23321, + 14605, 32231, 780,-13849, 15119, 28647, 4888, -7705, 30750, + 64, 0, 32488, 6687,-20758, 19745, -2070, -1, -1, + 28, 256, -4608, 7168, 7444, 23557,-21998, 13064, 3345, + -4086,-28915, -8594, 32262, 8461, 27387,-12275, 12012, 23563, + -18719,-28410, 29144,-22271,-32562,-16384, 12528, -6386, 10986, + 23827,-25880,-32752,-23321, 14605, 32231, 780,-13849, 15119, + 28647, 4888, -7705, 30750, 64, 0, 32488, 6687,-20758, + 19745, -2070,-13792, -6414, 28188, -2821, -4585, 7168, 7444, + 23557,-21998, 13064, 3345, -4086,-28915, -8694, 32262, 8461, + -14853,-14907,-14907,-14907,-14907, 32767,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14891,-14907,-14907,-14907, + -14907,-14907, 8901, 9375, 6940, 13038, 4826, 14598, 7721, + -24308,-29905,-19703,-17106,-16124, -3287,-26118,-19709,-10769, + 24361, 28648, 10274,-11292,-29665,-16417, 24346, 14580, 18707, + 26323, -4440,-17711, 5133, 26328,-14579,-31008, 24583, 18404, + 28417,-24350, 19453, 28642,-32513,-10777, -3079, 30188, -7686, + 27635,-32521,-16384,-20240, -6386, 10986, 23827,-25880,-32752, + -23321, 14605, 32231, 780,-13849, 15119, 28647, 4888, -7705, + -15074,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907, 8192,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14897,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-15931,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907, 26121, 12890, + 2604, 12228,-11634, 12299, 5573,-16642, 32452, 29182, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-10811,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14917,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14938,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907, -571, -9986, -58, 12542,-18491, + 32507, 12838, 6653, 294, -1, 0,-19968, 18368, -4357, + -5696, 2804, 12998,-22802,-22080, -7701, -5183, 486, -3133, + -5660, -1083, 13799,-28726,-11029, 205,-14848, 32464, -1, + -129,-13072, 6380, -7948, 20717, 18425, 17392, 14335, -5646, + 30973, -3598, 7188, -3867, 3055, -4247, 5597, -4011,-26427, + -11,-30418, 7922, 2614, 237, -5839,-27413,-17624,-29716, + -13539, 239, 20991, 18164, -4082,-16647,-27386, 19458, 20224, + 4619, 19728, -7409,-18186,-25073, 27627,-23539, -7945,-31464, + 14330,-12523,-22021, -7701, -5183, 486, -3133, -5660, -1083, + 13799,-28726,-11029, 205,-14848, 32464, -1, -129,-13072, + 6380, -7948, 20717, 18425, 17392, 14093, -5646, 30973, -3598, + 7188, -3867, 3055, 3689, -5401, 4906, -6051, 4250, -6272, + 3492, -6343, 3197, -6397, 4041, -6341, 6255, -6381, 239, + 20991, 18164, -4082,-16647,-27386, 19458, 20224, 4619, 19728, + -7409,-18186,-25073, 27627,-23539, -7945,-31464, 14330,-12523, + 14843, -6130, 30202, -250,-28420, 10467, 16907, -3359, -6644, + 31965, 3343,-11727, 2966,-12616, 3064,-13472, 6732,-12349, + 5541,-11965, 5530,-10820, -1912, -3637, 32285, -4607, 310, + -32768, 0, -5258, 2106, -6857, 2681, -5449, -3606, -6717, + -5482, -3606, -1853, 4082, -7631, -9808, -1742, -2851, -5112, + 64, -868,-13546,-13365,-13365,-13365,-13365,-13365,-13365, + -13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365, + -13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365, + -13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365, + -13365,-13365,-13365,-13365,-13365,-13365,-13365, 7883, -2316, + 9086, -3944, 10500, 4285, 10459, -6474, 10204, -6539, 11601, + -6824, 13385, -7142, 13872, -7457, 13670, -7725, 13463, -6887, + 12482, -5580, 12600, -4964, 12480, 3254, 11741, -4210,-24819, + 23282, 22798, 491, -1774, -1073, 3641, -1304, 28928, -250, + -27396, 6657, -8961, 22524, 19987, 10231, 1791, 8947,-32763, + -26385,-31227, -792,-30461, 8926, 4866, 27863, 27756, 27756, + 27756, 27756, 27756, 27756, 27756, 27756, 5630,-11070,-16136, + 20671,-11530, 27328, 8179, 5059,-31503,-24379,-19472, 17863, + -29202, 22986, -23, 8909, 8422, 10450 + }; + err = opus_multistream_encode(enc, pcm, 1440, data, 7380); + /* reads uninitialized data at src/opus_multistream_encoder.c:293 */ + assert(err > 0); + } + opus_multistream_encoder_destroy(enc); + return 0; +} + +static int ec_enc_shrink_assert(void) +{ + OpusEncoder *enc; + int err; + int data_len; + unsigned char data[2000]; + static const short pcm1[960] = { 5140 }; + static const short pcm2[2880] = + { + -256,-12033, 0, -2817, 6912, 0, -5359, 5200, 3061, + 0, -2903, 5652, -1281,-24656,-14433,-24678, 32,-29793, + 2870, 0, 4096, 5120, 5140, -234,-20230,-24673,-24633, + -24673,-24705, 0,-32768,-25444,-25444, 0,-25444,-25444, + 156,-20480, -7948, -5920, -7968, -7968, 224, 0, 20480, + 11, 20496, 13, 20496, 11,-20480, 2292,-20240, 244, + 20480, 11, 20496, 11,-20480, 244,-20240, 7156, 20456, + -246,-20243, 244, 128, 244, 20480, 11, 20496, 11, + -20480, 244,-20256, 244, 20480, 256, 0, -246, 16609, + -176, 0, 29872, -4096, -2888, 516, 2896, 4096, 2896, + -20480, -3852, -2896, -1025,-31056,-14433, 244, 1792, -256, + -12033, 0, -2817, 0, 0, -5359, 5200, 3061, 16, + -2903, 5652, -1281,-24656,-14433,-24678, 32,-29793, 2870, + 0, 4096, 5120, 5140, -234,-20230,-24673,-24633,-24673, + -24705, 0,-32768,-25444,-25444, 0,-25444,-25444, 156, + -20480, -7973, -5920, -7968, -7968, 224, 0, 20480, 11, + 20496, 11, 20496, 11,-20480, 2292,-20213, 244, 20480, + 11, 20496, 11,-24698, -2873, 0, 7, -1, 208, + -256, 244, 0, 4352, 20715, -2796, 11,-22272, 5364, + -234,-20230,-24673,-25913, 8351,-24832, 13963, 11, 0, + 16, 5140, 5652, -1281,-24656,-14433,-24673, 32671, 159, + 0,-25472,-25444, 156,-25600,-25444,-25444, 0, -2896, + -7968, -7960, -7968, -7968, 0, 0, 2896, 4096, 2896, + 4096, 2896, 0, -2896, -4088, -2896, 0, 2896, 0, + -2896, -4096, -2896, 11, 2640, -4609, -2896,-32768, -3072, + 0, 2896, 4096, 2896, 0, -2896, -4096, -2896, 0, + 80, 1, 2816, 0, 20656, 255,-20480, 116,-18192 + }; + static const short pcm3[2880] = { 0 }; + + enc = opus_encoder_create(48000, 1, OPUS_APPLICATION_AUDIO, &err); + opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); + opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(6)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(6000)); + data_len = opus_encode(enc, pcm1, 960, data, 2000); + assert(data_len > 0); + + opus_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + opus_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); + opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(15600)); + data_len = opus_encode(enc, pcm2, 2880, data, 122); + assert(data_len > 0); + + opus_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(27000)); + data_len = opus_encode(enc, pcm3, 2880, data, 122); /* assertion failure */ + assert(data_len > 0); + + opus_encoder_destroy(enc); + return 0; +} + +static int ec_enc_shrink_assert2(void) +{ + OpusEncoder *enc; + int err; + int data_len; + unsigned char data[2000]; + + enc = opus_encoder_create(48000, 1, OPUS_APPLICATION_AUDIO, &err); + opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(6)); + opus_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(26)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(27000)); + { + static const short pcm[960] = { 0 }; + data_len = opus_encode(enc, pcm, 960, data, 2000); + assert(data_len > 0); + } + opus_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + { + static const short pcm[480] = + { + 32767, 32767, 0, 0, 32767, 32767, 0, 0, 32767, 32767, + -32768, -32768, 0, 0, -32768, -32768, 0, 0, -32768, -32768 + }; + data_len = opus_encode(enc, pcm, 480, data, 19); + assert(data_len > 0); + } + opus_encoder_destroy(enc); + return 0; +} + +static int silk_gain_assert(void) +{ + OpusEncoder *enc; + int err; + int data_len; + unsigned char data[1000]; + static const short pcm1[160] = { 0 }; + static const short pcm2[960] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32767, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32767 + }; + + enc = opus_encoder_create(8000, 1, OPUS_APPLICATION_AUDIO, &err); + opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(3)); + opus_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(6000)); + data_len = opus_encode(enc, pcm1, 160, data, 1000); + assert(data_len > 0); + + opus_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(0)); + opus_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(2867)); + data_len = opus_encode(enc, pcm2, 960, data, 1000); + assert(data_len > 0); + + opus_encoder_destroy(enc); + return 0; +} + +void regression_test(void) +{ + fprintf(stderr, "Running simple tests for bugs that have been fixed previously\n"); + celt_ec_internal_error(); + mscbr_encode_fail10(); + mscbr_encode_fail(); + surround_analysis_uninit(); + ec_enc_shrink_assert(); + ec_enc_shrink_assert2(); + silk_gain_assert(); +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/tests/run_vectors.sh b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/run_vectors.sh new file mode 100755 index 000000000..dcb76cf18 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/run_vectors.sh @@ -0,0 +1,143 @@ +#!/bin/sh + +# Copyright (c) 2011-2012 Jean-Marc Valin +# +# This file is extracted from RFC6716. Please see that RFC for additional +# information. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - 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. +# +# - Neither the name of Internet Society, IETF or IETF Trust, nor the +# names of specific 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 OWNER +# 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. + +rm -f logs_mono.txt logs_mono2.txt +rm -f logs_stereo.txt logs_stereo2.txt + +if [ "$#" -ne "3" ]; then + echo "usage: run_vectors.sh " + exit 1 +fi + +CMD_PATH=$1 +VECTOR_PATH=$2 +RATE=$3 + +: ${OPUS_DEMO:=$CMD_PATH/opus_demo} +: ${OPUS_COMPARE:=$CMD_PATH/opus_compare} + +if [ -d "$VECTOR_PATH" ]; then + echo "Test vectors found in $VECTOR_PATH" +else + echo "No test vectors found" + #Don't make the test fail here because the test vectors + #will be distributed separately + exit 0 +fi + +if [ ! -x "$OPUS_COMPARE" ]; then + echo "ERROR: Compare program not found: $OPUS_COMPARE" + exit 1 +fi + +if [ -x "$OPUS_DEMO" ]; then + echo "Decoding with $OPUS_DEMO" +else + echo "ERROR: Decoder not found: $OPUS_DEMO" + exit 1 +fi + +echo "==============" +echo "Testing mono" +echo "==============" +echo + +for file in 01 02 03 04 05 06 07 08 09 10 11 12 +do + if [ -e "$VECTOR_PATH/testvector$file.bit" ]; then + echo "Testing testvector$file" + else + echo "Bitstream file not found: testvector$file.bit" + fi + if "$OPUS_DEMO" -d "$RATE" 1 "$VECTOR_PATH/testvector$file.bit" tmp.out >> logs_mono.txt 2>&1; then + echo "successfully decoded" + else + echo "ERROR: decoding failed" + exit 1 + fi + "$OPUS_COMPARE" -r "$RATE" "$VECTOR_PATH/testvector${file}.dec" tmp.out >> logs_mono.txt 2>&1 + float_ret=$? + "$OPUS_COMPARE" -r "$RATE" "$VECTOR_PATH/testvector${file}m.dec" tmp.out >> logs_mono2.txt 2>&1 + float_ret2=$? + if [ "$float_ret" -eq "0" ] || [ "$float_ret2" -eq "0" ]; then + echo "output matches reference" + else + echo "ERROR: output does not match reference" + exit 1 + fi + echo +done + +echo "==============" +echo Testing stereo +echo "==============" +echo + +for file in 01 02 03 04 05 06 07 08 09 10 11 12 +do + if [ -e "$VECTOR_PATH/testvector$file.bit" ]; then + echo "Testing testvector$file" + else + echo "Bitstream file not found: testvector$file" + fi + if "$OPUS_DEMO" -d "$RATE" 2 "$VECTOR_PATH/testvector$file.bit" tmp.out >> logs_stereo.txt 2>&1; then + echo "successfully decoded" + else + echo "ERROR: decoding failed" + exit 1 + fi + "$OPUS_COMPARE" -s -r "$RATE" "$VECTOR_PATH/testvector${file}.dec" tmp.out >> logs_stereo.txt 2>&1 + float_ret=$? + "$OPUS_COMPARE" -s -r "$RATE" "$VECTOR_PATH/testvector${file}m.dec" tmp.out >> logs_stereo2.txt 2>&1 + float_ret2=$? + if [ "$float_ret" -eq "0" ] || [ "$float_ret2" -eq "0" ]; then + echo "output matches reference" + else + echo "ERROR: output does not match reference" + exit 1 + fi + echo +done + + + +echo "All tests have passed successfully" +mono1=`grep quality logs_mono.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` +mono2=`grep quality logs_mono2.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` +echo $mono1 $mono2 | awk '{if ($2 > $1) $1 = $2; print "Average mono quality is", $1, "%"}' + +stereo1=`grep quality logs_stereo.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` +stereo2=`grep quality logs_stereo2.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` +echo $stereo1 $stereo2 | awk '{if ($2 > $1) $1 = $2; print "Average stereo quality is", $1, "%"}' diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_api.c b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_api.c new file mode 100644 index 000000000..fb385c630 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_api.c @@ -0,0 +1,1904 @@ +/* Copyright (c) 2011-2013 Xiph.Org Foundation + Written by Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +/* This tests the API presented by the libopus system. + It does not attempt to extensively exercise the codec internals. + The strategy here is to simply the API interface invariants: + That sane options are accepted, insane options are rejected, + and that nothing blows up. In particular we don't actually test + that settings are heeded by the codec (though we do check that + get after set returns a sane value when it should). Other + tests check the actual codec behavior. + In cases where its reasonable to do so we test exhaustively, + but its not reasonable to do so in all cases. + Although these tests are simple they found several library bugs + when they were initially developed. */ + +/* These tests are more sensitive if compiled with -DVALGRIND and + run inside valgrind. Malloc failure testing requires glibc. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include "arch.h" +#include "opus_multistream.h" +#include "opus.h" +#include "test_opus_common.h" + +#ifdef VALGRIND +#include +#define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y)) +#define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y)) +#else +#define VG_UNDEF(x,y) +#define VG_CHECK(x,y) +#endif + +#if defined(HAVE___MALLOC_HOOK) +#define MALLOC_FAIL +#include "os_support.h" +#include + +static const opus_int32 opus_apps[3] = {OPUS_APPLICATION_VOIP, + OPUS_APPLICATION_AUDIO,OPUS_APPLICATION_RESTRICTED_LOWDELAY}; + +void *malloc_hook(__attribute__((unused)) size_t size, + __attribute__((unused)) const void *caller) +{ + return 0; +} +#endif + +opus_int32 *null_int_ptr = (opus_int32 *)NULL; +opus_uint32 *null_uint_ptr = (opus_uint32 *)NULL; + +static const opus_int32 opus_rates[5] = {48000,24000,16000,12000,8000}; + +opus_int32 test_dec_api(void) +{ + opus_uint32 dec_final_range; + OpusDecoder *dec; + OpusDecoder *dec2; + opus_int32 i,j,cfgs; + unsigned char packet[1276]; +#ifndef DISABLE_FLOAT_API + float fbuf[960*2]; +#endif + short sbuf[960*2]; + int c,err; + + cfgs=0; + /*First test invalid configurations which should fail*/ + fprintf(stdout,"\n Decoder basic API tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); + for(c=0;c<4;c++) + { + i=opus_decoder_get_size(c); + if(((c==1||c==2)&&(i<=2048||i>1<<16))||((c!=1&&c!=2)&&i!=0))test_failed(); + fprintf(stdout," opus_decoder_get_size(%d)=%d ...............%s OK.\n",c,i,i>0?"":"...."); + cfgs++; + } + + /*Test with unsupported sample rates*/ + for(c=0;c<4;c++) + { + for(i=-7;i<=96000;i++) + { + int fs; + if((i==8000||i==12000||i==16000||i==24000||i==48000)&&(c==1||c==2))continue; + switch(i) + { + case(-5):fs=-8000;break; + case(-6):fs=INT32_MAX;break; + case(-7):fs=INT32_MIN;break; + default:fs=i; + } + err = OPUS_OK; + VG_UNDEF(&err,sizeof(err)); + dec = opus_decoder_create(fs, c, &err); + if(err!=OPUS_BAD_ARG || dec!=NULL)test_failed(); + cfgs++; + dec = opus_decoder_create(fs, c, 0); + if(dec!=NULL)test_failed(); + cfgs++; + dec=malloc(opus_decoder_get_size(2)); + if(dec==NULL)test_failed(); + err = opus_decoder_init(dec,fs,c); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + free(dec); + } + } + + VG_UNDEF(&err,sizeof(err)); + dec = opus_decoder_create(48000, 2, &err); + if(err!=OPUS_OK || dec==NULL)test_failed(); + VG_CHECK(dec,opus_decoder_get_size(2)); + cfgs++; + + fprintf(stdout," opus_decoder_create() ........................ OK.\n"); + fprintf(stdout," opus_decoder_init() .......................... OK.\n"); + + err=opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(null_uint_ptr)); + if(err != OPUS_BAD_ARG)test_failed(); + VG_UNDEF(&dec_final_range,sizeof(dec_final_range)); + err=opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range)); + if(err!=OPUS_OK)test_failed(); + VG_CHECK(&dec_final_range,sizeof(dec_final_range)); + fprintf(stdout," OPUS_GET_FINAL_RANGE ......................... OK.\n"); + cfgs++; + + err=opus_decoder_ctl(dec,OPUS_UNIMPLEMENTED); + if(err!=OPUS_UNIMPLEMENTED)test_failed(); + fprintf(stdout," OPUS_UNIMPLEMENTED ........................... OK.\n"); + cfgs++; + + err=opus_decoder_ctl(dec, OPUS_GET_BANDWIDTH(null_int_ptr)); + if(err != OPUS_BAD_ARG)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_BANDWIDTH(&i)); + if(err != OPUS_OK || i!=0)test_failed(); + fprintf(stdout," OPUS_GET_BANDWIDTH ........................... OK.\n"); + cfgs++; + + err=opus_decoder_ctl(dec, OPUS_GET_SAMPLE_RATE(null_int_ptr)); + if(err != OPUS_BAD_ARG)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_SAMPLE_RATE(&i)); + if(err != OPUS_OK || i!=48000)test_failed(); + fprintf(stdout," OPUS_GET_SAMPLE_RATE ......................... OK.\n"); + cfgs++; + + /*GET_PITCH has different execution paths depending on the previously decoded frame.*/ + err=opus_decoder_ctl(dec, OPUS_GET_PITCH(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + VG_UNDEF(packet,sizeof(packet)); + packet[0]=63<<2;packet[1]=packet[2]=0; + if(opus_decode(dec, packet, 3, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + packet[0]=1; + if(opus_decode(dec, packet, 1, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_PITCH ............................... OK.\n"); + + err=opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(null_int_ptr)); + if(err != OPUS_BAD_ARG)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&i)); + if(err != OPUS_OK || i!=960)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_LAST_PACKET_DURATION ................ OK.\n"); + + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_GAIN(&i)); + VG_CHECK(&i,sizeof(i)); + if(err != OPUS_OK || i!=0)test_failed(); + cfgs++; + err=opus_decoder_ctl(dec, OPUS_GET_GAIN(null_int_ptr)); + if(err != OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_decoder_ctl(dec, OPUS_SET_GAIN(-32769)); + if(err != OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_decoder_ctl(dec, OPUS_SET_GAIN(32768)); + if(err != OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_decoder_ctl(dec, OPUS_SET_GAIN(-15)); + if(err != OPUS_OK)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_GAIN(&i)); + VG_CHECK(&i,sizeof(i)); + if(err != OPUS_OK || i!=-15)test_failed(); + cfgs++; + fprintf(stdout," OPUS_SET_GAIN ................................ OK.\n"); + fprintf(stdout," OPUS_GET_GAIN ................................ OK.\n"); + + /*Reset the decoder*/ + dec2=malloc(opus_decoder_get_size(2)); + memcpy(dec2,dec,opus_decoder_get_size(2)); + if(opus_decoder_ctl(dec, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + if(memcmp(dec2,dec,opus_decoder_get_size(2))==0)test_failed(); + free(dec2); + fprintf(stdout," OPUS_RESET_STATE ............................. OK.\n"); + cfgs++; + + VG_UNDEF(packet,sizeof(packet)); + packet[0]=0; + if(opus_decoder_get_nb_samples(dec,packet,1)!=480)test_failed(); + if(opus_packet_get_nb_samples(packet,1,48000)!=480)test_failed(); + if(opus_packet_get_nb_samples(packet,1,96000)!=960)test_failed(); + if(opus_packet_get_nb_samples(packet,1,32000)!=320)test_failed(); + if(opus_packet_get_nb_samples(packet,1,8000)!=80)test_failed(); + packet[0]=3; + if(opus_packet_get_nb_samples(packet,1,24000)!=OPUS_INVALID_PACKET)test_failed(); + packet[0]=(63<<2)|3; + packet[1]=63; + if(opus_packet_get_nb_samples(packet,0,24000)!=OPUS_BAD_ARG)test_failed(); + if(opus_packet_get_nb_samples(packet,2,48000)!=OPUS_INVALID_PACKET)test_failed(); + if(opus_decoder_get_nb_samples(dec,packet,2)!=OPUS_INVALID_PACKET)test_failed(); + fprintf(stdout," opus_{packet,decoder}_get_nb_samples() ....... OK.\n"); + cfgs+=9; + + if(OPUS_BAD_ARG!=opus_packet_get_nb_frames(packet,0))test_failed(); + for(i=0;i<256;i++) { + int l1res[4]={1,2,2,OPUS_INVALID_PACKET}; + packet[0]=i; + if(l1res[packet[0]&3]!=opus_packet_get_nb_frames(packet,1))test_failed(); + cfgs++; + for(j=0;j<256;j++) { + packet[1]=j; + if(((packet[0]&3)!=3?l1res[packet[0]&3]:packet[1]&63)!=opus_packet_get_nb_frames(packet,2))test_failed(); + cfgs++; + } + } + fprintf(stdout," opus_packet_get_nb_frames() .................. OK.\n"); + + for(i=0;i<256;i++) { + int bw; + packet[0]=i; + bw=packet[0]>>4; + bw=OPUS_BANDWIDTH_NARROWBAND+(((((bw&7)*9)&(63-(bw&8)))+2+12*((bw&8)!=0))>>4); + if(bw!=opus_packet_get_bandwidth(packet))test_failed(); + cfgs++; + } + fprintf(stdout," opus_packet_get_bandwidth() .................. OK.\n"); + + for(i=0;i<256;i++) { + int fp3s,rate; + packet[0]=i; + fp3s=packet[0]>>3; + fp3s=((((3-(fp3s&3))*13&119)+9)>>2)*((fp3s>13)*(3-((fp3s&3)==3))+1)*25; + for(rate=0;rate<5;rate++) { + if((opus_rates[rate]*3/fp3s)!=opus_packet_get_samples_per_frame(packet,opus_rates[rate]))test_failed(); + cfgs++; + } + } + fprintf(stdout," opus_packet_get_samples_per_frame() .......... OK.\n"); + + packet[0]=(63<<2)+3; + packet[1]=49; + for(j=2;j<51;j++)packet[j]=0; + VG_UNDEF(sbuf,sizeof(sbuf)); + if(opus_decode(dec, packet, 51, sbuf, 960, 0)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + packet[0]=(63<<2); + packet[1]=packet[2]=0; + if(opus_decode(dec, packet, -1, sbuf, 960, 0)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_decode(dec, packet, 3, sbuf, 60, 0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(opus_decode(dec, packet, 3, sbuf, 480, 0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(opus_decode(dec, packet, 3, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + fprintf(stdout," opus_decode() ................................ OK.\n"); +#ifndef DISABLE_FLOAT_API + VG_UNDEF(fbuf,sizeof(fbuf)); + if(opus_decode_float(dec, packet, 3, fbuf, 960, 0)!=960)test_failed(); + cfgs++; + fprintf(stdout," opus_decode_float() .......................... OK.\n"); +#endif + +#if 0 + /*These tests are disabled because the library crashes with null states*/ + if(opus_decoder_ctl(0,OPUS_RESET_STATE) !=OPUS_INVALID_STATE)test_failed(); + if(opus_decoder_init(0,48000,1) !=OPUS_INVALID_STATE)test_failed(); + if(opus_decode(0,packet,1,outbuf,2880,0) !=OPUS_INVALID_STATE)test_failed(); + if(opus_decode_float(0,packet,1,0,2880,0) !=OPUS_INVALID_STATE)test_failed(); + if(opus_decoder_get_nb_samples(0,packet,1) !=OPUS_INVALID_STATE)test_failed(); + if(opus_packet_get_nb_frames(NULL,1) !=OPUS_BAD_ARG)test_failed(); + if(opus_packet_get_bandwidth(NULL) !=OPUS_BAD_ARG)test_failed(); + if(opus_packet_get_samples_per_frame(NULL,48000)!=OPUS_BAD_ARG)test_failed(); +#endif + opus_decoder_destroy(dec); + cfgs++; + fprintf(stdout," All decoder interface tests passed\n"); + fprintf(stdout," (%6d API invocations)\n",cfgs); + return cfgs; +} + +opus_int32 test_msdec_api(void) +{ + opus_uint32 dec_final_range; + OpusMSDecoder *dec; + OpusDecoder *streamdec; + opus_int32 i,j,cfgs; + unsigned char packet[1276]; + unsigned char mapping[256]; +#ifndef DISABLE_FLOAT_API + float fbuf[960*2]; +#endif + short sbuf[960*2]; + int a,b,c,err; + + mapping[0]=0; + mapping[1]=1; + for(i=2;i<256;i++)VG_UNDEF(&mapping[i],sizeof(unsigned char)); + + cfgs=0; + /*First test invalid configurations which should fail*/ + fprintf(stdout,"\n Multistream decoder basic API tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); + for(a=-1;a<4;a++) + { + for(b=-1;b<4;b++) + { + i=opus_multistream_decoder_get_size(a,b); + if(((a>0&&b<=a&&b>=0)&&(i<=2048||i>((1<<16)*a)))||((a<1||b>a||b<0)&&i!=0))test_failed(); + fprintf(stdout," opus_multistream_decoder_get_size(%2d,%2d)=%d %sOK.\n",a,b,i,i>0?"":"... "); + cfgs++; + } + } + + /*Test with unsupported sample rates*/ + for(c=1;c<3;c++) + { + for(i=-7;i<=96000;i++) + { + int fs; + if((i==8000||i==12000||i==16000||i==24000||i==48000)&&(c==1||c==2))continue; + switch(i) + { + case(-5):fs=-8000;break; + case(-6):fs=INT32_MAX;break; + case(-7):fs=INT32_MIN;break; + default:fs=i; + } + err = OPUS_OK; + VG_UNDEF(&err,sizeof(err)); + dec = opus_multistream_decoder_create(fs, c, 1, c-1, mapping, &err); + if(err!=OPUS_BAD_ARG || dec!=NULL)test_failed(); + cfgs++; + dec = opus_multistream_decoder_create(fs, c, 1, c-1, mapping, 0); + if(dec!=NULL)test_failed(); + cfgs++; + dec=malloc(opus_multistream_decoder_get_size(1,1)); + if(dec==NULL)test_failed(); + err = opus_multistream_decoder_init(dec,fs,c,1,c-1, mapping); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + free(dec); + } + } + + for(c=0;c<2;c++) + { + int *ret_err; + ret_err = c?0:&err; + + mapping[0]=0; + mapping[1]=1; + for(i=2;i<256;i++)VG_UNDEF(&mapping[i],sizeof(unsigned char)); + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 2, 1, 0, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + mapping[0]=mapping[1]=0; + dec = opus_multistream_decoder_create(48000, 2, 1, 0, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_OK) || dec==NULL)test_failed(); + cfgs++; + opus_multistream_decoder_destroy(dec); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 1, 4, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_OK) || dec==NULL)test_failed(); + cfgs++; + + err = opus_multistream_decoder_init(dec,48000, 1, 0, 0, mapping); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + + err = opus_multistream_decoder_init(dec,48000, 1, 1, -1, mapping); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + + opus_multistream_decoder_destroy(dec); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 2, 1, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_OK) || dec==NULL)test_failed(); + cfgs++; + opus_multistream_decoder_destroy(dec); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 255, 255, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, -1, 1, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 0, 1, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 1, -1, 2, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 1, -1, -1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 256, 255, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 256, 255, 0, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + mapping[0]=255; + mapping[1]=1; + mapping[2]=2; + dec = opus_multistream_decoder_create(48000, 3, 2, 0, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + mapping[0]=0; + mapping[1]=0; + mapping[2]=0; + dec = opus_multistream_decoder_create(48000, 3, 2, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_OK) || dec==NULL)test_failed(); + cfgs++; + opus_multistream_decoder_destroy(dec); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + mapping[0]=0; + mapping[1]=255; + mapping[2]=1; + mapping[3]=2; + mapping[4]=3; + dec = opus_multistream_decoder_create(48001, 5, 4, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + } + + VG_UNDEF(&err,sizeof(err)); + mapping[0]=0; + mapping[1]=255; + mapping[2]=1; + mapping[3]=2; + dec = opus_multistream_decoder_create(48000, 4, 2, 1, mapping, &err); + VG_CHECK(&err,sizeof(err)); + if(err!=OPUS_OK || dec==NULL)test_failed(); + cfgs++; + + fprintf(stdout," opus_multistream_decoder_create() ............ OK.\n"); + fprintf(stdout," opus_multistream_decoder_init() .............. OK.\n"); + + VG_UNDEF(&dec_final_range,sizeof(dec_final_range)); + err=opus_multistream_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range)); + if(err!=OPUS_OK)test_failed(); + VG_CHECK(&dec_final_range,sizeof(dec_final_range)); + fprintf(stdout," OPUS_GET_FINAL_RANGE ......................... OK.\n"); + cfgs++; + + streamdec=0; + VG_UNDEF(&streamdec,sizeof(streamdec)); + err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(-1,&streamdec)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(1,&streamdec)); + if(err!=OPUS_OK||streamdec==NULL)test_failed(); + VG_CHECK(streamdec,opus_decoder_get_size(1)); + cfgs++; + err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(2,&streamdec)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(0,&streamdec)); + if(err!=OPUS_OK||streamdec==NULL)test_failed(); + VG_CHECK(streamdec,opus_decoder_get_size(1)); + fprintf(stdout," OPUS_MULTISTREAM_GET_DECODER_STATE ........... OK.\n"); + cfgs++; + + for(j=0;j<2;j++) + { + OpusDecoder *od; + err=opus_multistream_decoder_ctl(dec,OPUS_MULTISTREAM_GET_DECODER_STATE(j,&od)); + if(err != OPUS_OK)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(od, OPUS_GET_GAIN(&i)); + VG_CHECK(&i,sizeof(i)); + if(err != OPUS_OK || i!=0)test_failed(); + cfgs++; + } + err=opus_multistream_decoder_ctl(dec,OPUS_SET_GAIN(15)); + if(err!=OPUS_OK)test_failed(); + fprintf(stdout," OPUS_SET_GAIN ................................ OK.\n"); + for(j=0;j<2;j++) + { + OpusDecoder *od; + err=opus_multistream_decoder_ctl(dec,OPUS_MULTISTREAM_GET_DECODER_STATE(j,&od)); + if(err != OPUS_OK)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(od, OPUS_GET_GAIN(&i)); + VG_CHECK(&i,sizeof(i)); + if(err != OPUS_OK || i!=15)test_failed(); + cfgs++; + } + fprintf(stdout," OPUS_GET_GAIN ................................ OK.\n"); + + VG_UNDEF(&i,sizeof(i)); + err=opus_multistream_decoder_ctl(dec, OPUS_GET_BANDWIDTH(&i)); + if(err != OPUS_OK || i!=0)test_failed(); + fprintf(stdout," OPUS_GET_BANDWIDTH ........................... OK.\n"); + cfgs++; + + err=opus_multistream_decoder_ctl(dec,OPUS_UNIMPLEMENTED); + if(err!=OPUS_UNIMPLEMENTED)test_failed(); + fprintf(stdout," OPUS_UNIMPLEMENTED ........................... OK.\n"); + cfgs++; + +#if 0 + /*Currently unimplemented for multistream*/ + /*GET_PITCH has different execution paths depending on the previously decoded frame.*/ + err=opus_multistream_decoder_ctl(dec, OPUS_GET_PITCH(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_multistream_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + VG_UNDEF(packet,sizeof(packet)); + packet[0]=63<<2;packet[1]=packet[2]=0; + if(opus_multistream_decode(dec, packet, 3, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_multistream_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + packet[0]=1; + if(opus_multistream_decode(dec, packet, 1, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_multistream_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_PITCH ............................... OK.\n"); +#endif + + /*Reset the decoder*/ + if(opus_multistream_decoder_ctl(dec, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + fprintf(stdout," OPUS_RESET_STATE ............................. OK.\n"); + cfgs++; + + opus_multistream_decoder_destroy(dec); + cfgs++; + VG_UNDEF(&err,sizeof(err)); + dec = opus_multistream_decoder_create(48000, 2, 1, 1, mapping, &err); + if(err!=OPUS_OK || dec==NULL)test_failed(); + cfgs++; + + packet[0]=(63<<2)+3; + packet[1]=49; + for(j=2;j<51;j++)packet[j]=0; + VG_UNDEF(sbuf,sizeof(sbuf)); + if(opus_multistream_decode(dec, packet, 51, sbuf, 960, 0)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + packet[0]=(63<<2); + packet[1]=packet[2]=0; + if(opus_multistream_decode(dec, packet, -1, sbuf, 960, 0)!=OPUS_BAD_ARG){printf("%d\n",opus_multistream_decode(dec, packet, -1, sbuf, 960, 0));test_failed();} + cfgs++; + if(opus_multistream_decode(dec, packet, 3, sbuf, -960, 0)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_multistream_decode(dec, packet, 3, sbuf, 60, 0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(opus_multistream_decode(dec, packet, 3, sbuf, 480, 0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(opus_multistream_decode(dec, packet, 3, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + fprintf(stdout," opus_multistream_decode() .................... OK.\n"); +#ifndef DISABLE_FLOAT_API + VG_UNDEF(fbuf,sizeof(fbuf)); + if(opus_multistream_decode_float(dec, packet, 3, fbuf, 960, 0)!=960)test_failed(); + cfgs++; + fprintf(stdout," opus_multistream_decode_float() .............. OK.\n"); +#endif + +#if 0 + /*These tests are disabled because the library crashes with null states*/ + if(opus_multistream_decoder_ctl(0,OPUS_RESET_STATE) !=OPUS_INVALID_STATE)test_failed(); + if(opus_multistream_decoder_init(0,48000,1) !=OPUS_INVALID_STATE)test_failed(); + if(opus_multistream_decode(0,packet,1,outbuf,2880,0) !=OPUS_INVALID_STATE)test_failed(); + if(opus_multistream_decode_float(0,packet,1,0,2880,0) !=OPUS_INVALID_STATE)test_failed(); + if(opus_multistream_decoder_get_nb_samples(0,packet,1) !=OPUS_INVALID_STATE)test_failed(); +#endif + opus_multistream_decoder_destroy(dec); + cfgs++; + fprintf(stdout," All multistream decoder interface tests passed\n"); + fprintf(stdout," (%6d API invocations)\n",cfgs); + return cfgs; +} + +#ifdef VALGRIND +#define UNDEFINE_FOR_PARSE toc=-1; \ + frames[0]=(unsigned char *)0; \ + frames[1]=(unsigned char *)0; \ + payload_offset=-1; \ + VG_UNDEF(&toc,sizeof(toc)); \ + VG_UNDEF(frames,sizeof(frames));\ + VG_UNDEF(&payload_offset,sizeof(payload_offset)); +#else +#define UNDEFINE_FOR_PARSE toc=-1; \ + frames[0]=(unsigned char *)0; \ + frames[1]=(unsigned char *)0; \ + payload_offset=-1; +#endif + +/* This test exercises the heck out of the libopus parser. + It is much larger than the parser itself in part because + it tries to hit a lot of corner cases that could never + fail with the libopus code, but might be problematic for + other implementations. */ +opus_int32 test_parse(void) +{ + opus_int32 i,j,jj,sz; + unsigned char packet[1276]; + opus_int32 cfgs,cfgs_total; + unsigned char toc; + const unsigned char *frames[48]; + short size[48]; + int payload_offset, ret; + fprintf(stdout,"\n Packet header parsing tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); + memset(packet,0,sizeof(char)*1276); + packet[0]=63<<2; + if(opus_packet_parse(packet,1,&toc,frames,0,&payload_offset)!=OPUS_BAD_ARG)test_failed(); + cfgs_total=cfgs=1; + /*code 0*/ + for(i=0;i<64;i++) + { + packet[0]=i<<2; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,4,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=1)test_failed(); + if(size[0]!=3)test_failed(); + if(frames[0]!=packet+1)test_failed(); + } + fprintf(stdout," code 0 (%2d cases) ............................ OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + /*code 1, two frames of the same size*/ + for(i=0;i<64;i++) + { + packet[0]=(i<<2)+1; + for(jj=0;jj<=1275*2+3;jj++) + { + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,jj,&toc,frames,size,&payload_offset); + cfgs++; + if((jj&1)==1 && jj<=2551) + { + /* Must pass if payload length even (packet length odd) and + size<=2551, must fail otherwise. */ + if(ret!=2)test_failed(); + if(size[0]!=size[1] || size[0]!=((jj-1)>>1))test_failed(); + if(frames[0]!=packet+1)test_failed(); + if(frames[1]!=frames[0]+size[0])test_failed(); + if((toc>>2)!=i)test_failed(); + } else if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + } + fprintf(stdout," code 1 (%6d cases) ........................ OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + /*code 2, length code overflow*/ + packet[0]=(i<<2)+2; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + packet[1]=252; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + for(j=0;j<1275;j++) + { + if(j<252)packet[1]=j; + else{packet[1]=252+(j&3);packet[2]=(j-252)>>2;} + /*Code 2, one too short*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,j+(j<252?2:3)-1,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*Code 2, one too long*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,j+(j<252?2:3)+1276,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*Code 2, second zero*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,j+(j<252?2:3),&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=2)test_failed(); + if(size[0]!=j||size[1]!=0)test_failed(); + if(frames[1]!=frames[0]+size[0])test_failed(); + if((toc>>2)!=i)test_failed(); + /*Code 2, normal*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,(j<<1)+4,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=2)test_failed(); + if(size[0]!=j||size[1]!=(j<<1)+3-j-(j<252?1:2))test_failed(); + if(frames[1]!=frames[0]+size[0])test_failed(); + if((toc>>2)!=i)test_failed(); + } + } + fprintf(stdout," code 2 (%6d cases) ........................ OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + packet[0]=(i<<2)+3; + /*code 3, length code overflow*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + fprintf(stdout," code 3 m-truncation (%2d cases) ............... OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + /*code 3, m is zero or 49-63*/ + packet[0]=(i<<2)+3; + for(jj=49;jj<=64;jj++) + { + packet[1]=0+(jj&63); /*CBR, no padding*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1275,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + packet[1]=128+(jj&63); /*VBR, no padding*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1275,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + packet[1]=64+(jj&63); /*CBR, padding*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1275,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + packet[1]=128+64+(jj&63); /*VBR, padding*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1275,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + } + fprintf(stdout," code 3 m=0,49-64 (%2d cases) ................ OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + packet[0]=(i<<2)+3; + /*code 3, m is one, cbr*/ + packet[1]=1; + for(j=0;j<1276;j++) + { + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,j+2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=1)test_failed(); + if(size[0]!=j)test_failed(); + if((toc>>2)!=i)test_failed(); + } + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1276+2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + fprintf(stdout," code 3 m=1 CBR (%2d cases) ................. OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + int frame_samp; + /*code 3, m>1 CBR*/ + packet[0]=(i<<2)+3; + frame_samp=opus_packet_get_samples_per_frame(packet,48000); + for(j=2;j<49;j++) + { + packet[1]=j; + for(sz=2;sz<((j+2)*1275);sz++) + { + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,sz,&toc,frames,size,&payload_offset); + cfgs++; + /*Must be <=120ms, must be evenly divisible, can't have frames>1275 bytes*/ + if(frame_samp*j<=5760 && (sz-2)%j==0 && (sz-2)/j<1276) + { + if(ret!=j)test_failed(); + for(jj=1;jj>2)!=i)test_failed(); + } else if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + } + /*Super jumbo packets*/ + packet[1]=5760/frame_samp; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1275*packet[1]+2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=packet[1])test_failed(); + for(jj=0;jj>2)!=i)test_failed(); + } + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+1276,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + for(j=2;j<49;j++) + { + packet[1]=128+j; + /*Length code overflow*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+j-2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + packet[2]=252; + packet[3]=0; + for(jj=4;jj<2+j;jj++)packet[jj]=0; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+j,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*One byte too short*/ + for(jj=2;jj<2+j;jj++)packet[jj]=0; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+j-2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*One byte too short thanks to length coding*/ + packet[2]=252; + packet[3]=0; + for(jj=4;jj<2+j;jj++)packet[jj]=0; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+j+252-1,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*Most expensive way of coding zeros*/ + for(jj=2;jj<2+j;jj++)packet[jj]=0; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+j-1,&toc,frames,size,&payload_offset); + cfgs++; + if(frame_samp*j<=5760){ + if(ret!=j)test_failed(); + for(jj=0;jj>2)!=i)test_failed(); + } else if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*Quasi-CBR use of mode 3*/ + for(sz=0;sz<8;sz++) + { + const int tsz[8]={50,201,403,700,1472,5110,20400,61298}; + int pos=0; + int as=(tsz[sz]+i-j-2)/j; + for(jj=0;jj>2;pos+=2;} + } + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,tsz[sz]+i,&toc,frames,size,&payload_offset); + cfgs++; + if(frame_samp*j<=5760 && as<1276 && (tsz[sz]+i-2-pos-as*(j-1))<1276){ + if(ret!=j)test_failed(); + for(jj=0;jj>2)!=i)test_failed(); + } else if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + } + } + fprintf(stdout," code 3 m=1-48 VBR (%2d cases) ............. OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + packet[0]=(i<<2)+3; + /*Padding*/ + packet[1]=128+1+64; + /*Overflow the length coding*/ + for(jj=2;jj<127;jj++)packet[jj]=255; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,127,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + + for(sz=0;sz<4;sz++) + { + const int tsz[4]={0,72,512,1275}; + for(jj=sz;jj<65025;jj+=11) + { + int pos; + for(pos=0;pos>2)!=i)test_failed(); + } else if (ret!=OPUS_INVALID_PACKET)test_failed(); + } + } + } + fprintf(stdout," code 3 padding (%2d cases) ............... OK.\n",cfgs); + cfgs_total+=cfgs; + fprintf(stdout," opus_packet_parse ............................ OK.\n"); + fprintf(stdout," All packet parsing tests passed\n"); + fprintf(stdout," (%d API invocations)\n",cfgs_total); + return cfgs_total; +} + +/* This is a helper macro for the encoder tests. + The encoder api tests all have a pattern of set-must-fail, set-must-fail, + set-must-pass, get-and-compare, set-must-pass, get-and-compare. */ +#define CHECK_SETGET(setcall,getcall,badv,badv2,goodv,goodv2,sok,gok) \ + i=(badv);\ + if(opus_encoder_ctl(enc,setcall)==OPUS_OK)test_failed();\ + i=(badv2);\ + if(opus_encoder_ctl(enc,setcall)==OPUS_OK)test_failed();\ + j=i=(goodv);\ + if(opus_encoder_ctl(enc,setcall)!=OPUS_OK)test_failed();\ + i=-12345;\ + VG_UNDEF(&i,sizeof(i)); \ + err=opus_encoder_ctl(enc,getcall);\ + if(err!=OPUS_OK || i!=j)test_failed();\ + j=i=(goodv2);\ + if(opus_encoder_ctl(enc,setcall)!=OPUS_OK)test_failed();\ + fprintf(stdout,sok);\ + i=-12345;\ + VG_UNDEF(&i,sizeof(i)); \ + err=opus_encoder_ctl(enc,getcall);\ + if(err!=OPUS_OK || i!=j)test_failed();\ + fprintf(stdout,gok);\ + cfgs+=6; + +opus_int32 test_enc_api(void) +{ + opus_uint32 enc_final_range; + OpusEncoder *enc; + opus_int32 i,j; + unsigned char packet[1276]; +#ifndef DISABLE_FLOAT_API + float fbuf[960*2]; +#endif + short sbuf[960*2]; + int c,err,cfgs; + + cfgs=0; + /*First test invalid configurations which should fail*/ + fprintf(stdout,"\n Encoder basic API tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); + for(c=0;c<4;c++) + { + i=opus_encoder_get_size(c); + if(((c==1||c==2)&&(i<=2048||i>1<<17))||((c!=1&&c!=2)&&i!=0))test_failed(); + fprintf(stdout," opus_encoder_get_size(%d)=%d ...............%s OK.\n",c,i,i>0?"":"...."); + cfgs++; + } + + /*Test with unsupported sample rates, channel counts*/ + for(c=0;c<4;c++) + { + for(i=-7;i<=96000;i++) + { + int fs; + if((i==8000||i==12000||i==16000||i==24000||i==48000)&&(c==1||c==2))continue; + switch(i) + { + case(-5):fs=-8000;break; + case(-6):fs=INT32_MAX;break; + case(-7):fs=INT32_MIN;break; + default:fs=i; + } + err = OPUS_OK; + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(fs, c, OPUS_APPLICATION_VOIP, &err); + if(err!=OPUS_BAD_ARG || enc!=NULL)test_failed(); + cfgs++; + enc = opus_encoder_create(fs, c, OPUS_APPLICATION_VOIP, 0); + if(enc!=NULL)test_failed(); + cfgs++; + opus_encoder_destroy(enc); + enc=malloc(opus_encoder_get_size(2)); + if(enc==NULL)test_failed(); + err = opus_encoder_init(enc, fs, c, OPUS_APPLICATION_VOIP); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + free(enc); + } + } + + enc = opus_encoder_create(48000, 2, OPUS_AUTO, NULL); + if(enc!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(48000, 2, OPUS_AUTO, &err); + if(err!=OPUS_BAD_ARG || enc!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_VOIP, NULL); + if(enc==NULL)test_failed(); + opus_encoder_destroy(enc); + cfgs++; + + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_RESTRICTED_LOWDELAY, &err); + if(err!=OPUS_OK || enc==NULL)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_LOOKAHEAD(&i)); + if(err!=OPUS_OK || i<0 || i>32766)test_failed(); + cfgs++; + opus_encoder_destroy(enc); + + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_AUDIO, &err); + if(err!=OPUS_OK || enc==NULL)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_LOOKAHEAD(&i)); + if(err!=OPUS_OK || i<0 || i>32766)test_failed(); + opus_encoder_destroy(enc); + cfgs++; + + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_VOIP, &err); + if(err!=OPUS_OK || enc==NULL)test_failed(); + cfgs++; + + fprintf(stdout," opus_encoder_create() ........................ OK.\n"); + fprintf(stdout," opus_encoder_init() .......................... OK.\n"); + + i=-12345; + VG_UNDEF(&i,sizeof(i)); + err=opus_encoder_ctl(enc,OPUS_GET_LOOKAHEAD(&i)); + if(err!=OPUS_OK || i<0 || i>32766)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_LOOKAHEAD(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_LOOKAHEAD ........................... OK.\n"); + + err=opus_encoder_ctl(enc,OPUS_GET_SAMPLE_RATE(&i)); + if(err!=OPUS_OK || i!=48000)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_SAMPLE_RATE(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_SAMPLE_RATE ......................... OK.\n"); + + if(opus_encoder_ctl(enc,OPUS_UNIMPLEMENTED)!=OPUS_UNIMPLEMENTED)test_failed(); + fprintf(stdout," OPUS_UNIMPLEMENTED ........................... OK.\n"); + cfgs++; + + err=opus_encoder_ctl(enc,OPUS_GET_APPLICATION(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_APPLICATION(i),OPUS_GET_APPLICATION(&i),-1,OPUS_AUTO, + OPUS_APPLICATION_AUDIO,OPUS_APPLICATION_RESTRICTED_LOWDELAY, + " OPUS_SET_APPLICATION ......................... OK.\n", + " OPUS_GET_APPLICATION ......................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_BITRATE(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_encoder_ctl(enc,OPUS_SET_BITRATE(1073741832))!=OPUS_OK)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + if(opus_encoder_ctl(enc,OPUS_GET_BITRATE(&i))!=OPUS_OK)test_failed(); + if(i>700000||i<256000)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_BITRATE(i),OPUS_GET_BITRATE(&i),-12345,0, + 500,256000, + " OPUS_SET_BITRATE ............................. OK.\n", + " OPUS_GET_BITRATE ............................. OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_FORCE_CHANNELS(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_FORCE_CHANNELS(i),OPUS_GET_FORCE_CHANNELS(&i),-1,3, + 1,OPUS_AUTO, + " OPUS_SET_FORCE_CHANNELS ...................... OK.\n", + " OPUS_GET_FORCE_CHANNELS ...................... OK.\n") + + i=-2; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))==OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_FULLBAND+1; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))==OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_NARROWBAND; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_FULLBAND; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_WIDEBAND; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_MEDIUMBAND; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + fprintf(stdout," OPUS_SET_BANDWIDTH ........................... OK.\n"); + /*We don't test if the bandwidth has actually changed. + because the change may be delayed until the encoder is advanced.*/ + i=-12345; + VG_UNDEF(&i,sizeof(i)); + err=opus_encoder_ctl(enc,OPUS_GET_BANDWIDTH(&i)); + if(err!=OPUS_OK || (i!=OPUS_BANDWIDTH_NARROWBAND&& + i!=OPUS_BANDWIDTH_MEDIUMBAND&&i!=OPUS_BANDWIDTH_WIDEBAND&& + i!=OPUS_BANDWIDTH_FULLBAND&&i!=OPUS_AUTO))test_failed(); + cfgs++; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(OPUS_AUTO))!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_BANDWIDTH(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_BANDWIDTH ........................... OK.\n"); + + i=-2; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))==OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_FULLBAND+1; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))==OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_NARROWBAND; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_FULLBAND; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_WIDEBAND; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_MEDIUMBAND; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + fprintf(stdout," OPUS_SET_MAX_BANDWIDTH ....................... OK.\n"); + /*We don't test if the bandwidth has actually changed. + because the change may be delayed until the encoder is advanced.*/ + i=-12345; + VG_UNDEF(&i,sizeof(i)); + err=opus_encoder_ctl(enc,OPUS_GET_MAX_BANDWIDTH(&i)); + if(err!=OPUS_OK || (i!=OPUS_BANDWIDTH_NARROWBAND&& + i!=OPUS_BANDWIDTH_MEDIUMBAND&&i!=OPUS_BANDWIDTH_WIDEBAND&& + i!=OPUS_BANDWIDTH_FULLBAND))test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_MAX_BANDWIDTH(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_MAX_BANDWIDTH ....................... OK.\n"); + + err=opus_encoder_ctl(enc,OPUS_GET_DTX(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_DTX(i),OPUS_GET_DTX(&i),-1,2, + 1,0, + " OPUS_SET_DTX ................................. OK.\n", + " OPUS_GET_DTX ................................. OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_COMPLEXITY(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_COMPLEXITY(i),OPUS_GET_COMPLEXITY(&i),-1,11, + 0,10, + " OPUS_SET_COMPLEXITY .......................... OK.\n", + " OPUS_GET_COMPLEXITY .......................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_INBAND_FEC(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_INBAND_FEC(i),OPUS_GET_INBAND_FEC(&i),-1,2, + 1,0, + " OPUS_SET_INBAND_FEC .......................... OK.\n", + " OPUS_GET_INBAND_FEC .......................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_PACKET_LOSS_PERC(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_PACKET_LOSS_PERC(i),OPUS_GET_PACKET_LOSS_PERC(&i),-1,101, + 100,0, + " OPUS_SET_PACKET_LOSS_PERC .................... OK.\n", + " OPUS_GET_PACKET_LOSS_PERC .................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_VBR(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_VBR(i),OPUS_GET_VBR(&i),-1,2, + 1,0, + " OPUS_SET_VBR ................................. OK.\n", + " OPUS_GET_VBR ................................. OK.\n") + +/* err=opus_encoder_ctl(enc,OPUS_GET_VOICE_RATIO(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_VOICE_RATIO(i),OPUS_GET_VOICE_RATIO(&i),-2,101, + 0,50, + " OPUS_SET_VOICE_RATIO ......................... OK.\n", + " OPUS_GET_VOICE_RATIO ......................... OK.\n")*/ + + err=opus_encoder_ctl(enc,OPUS_GET_VBR_CONSTRAINT(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_VBR_CONSTRAINT(i),OPUS_GET_VBR_CONSTRAINT(&i),-1,2, + 1,0, + " OPUS_SET_VBR_CONSTRAINT ...................... OK.\n", + " OPUS_GET_VBR_CONSTRAINT ...................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_SIGNAL(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_SIGNAL(i),OPUS_GET_SIGNAL(&i),-12345,0x7FFFFFFF, + OPUS_SIGNAL_MUSIC,OPUS_AUTO, + " OPUS_SET_SIGNAL .............................. OK.\n", + " OPUS_GET_SIGNAL .............................. OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_LSB_DEPTH(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_LSB_DEPTH(i),OPUS_GET_LSB_DEPTH(&i),7,25,16,24, + " OPUS_SET_LSB_DEPTH ........................... OK.\n", + " OPUS_GET_LSB_DEPTH ........................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_PREDICTION_DISABLED(&i)); + if(i!=0)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_PREDICTION_DISABLED(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_PREDICTION_DISABLED(i),OPUS_GET_PREDICTION_DISABLED(&i),-1,2,1,0, + " OPUS_SET_PREDICTION_DISABLED ................. OK.\n", + " OPUS_GET_PREDICTION_DISABLED ................. OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_EXPERT_FRAME_DURATION(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_2_5_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_5_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_10_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_20_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_40_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_60_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_80_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_100_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_120_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_EXPERT_FRAME_DURATION(i),OPUS_GET_EXPERT_FRAME_DURATION(&i),0,-1, + OPUS_FRAMESIZE_60_MS,OPUS_FRAMESIZE_ARG, + " OPUS_SET_EXPERT_FRAME_DURATION ............... OK.\n", + " OPUS_GET_EXPERT_FRAME_DURATION ............... OK.\n") + + /*OPUS_SET_FORCE_MODE is not tested here because it's not a public API, however the encoder tests use it*/ + + err=opus_encoder_ctl(enc,OPUS_GET_FINAL_RANGE(null_uint_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_encoder_ctl(enc,OPUS_GET_FINAL_RANGE(&enc_final_range))!=OPUS_OK)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_FINAL_RANGE ......................... OK.\n"); + + /*Reset the encoder*/ + if(opus_encoder_ctl(enc, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + cfgs++; + fprintf(stdout," OPUS_RESET_STATE ............................. OK.\n"); + + memset(sbuf,0,sizeof(short)*2*960); + VG_UNDEF(packet,sizeof(packet)); + i=opus_encode(enc, sbuf, 960, packet, sizeof(packet)); + if(i<1 || (i>(opus_int32)sizeof(packet)))test_failed(); + VG_CHECK(packet,i); + cfgs++; + fprintf(stdout," opus_encode() ................................ OK.\n"); +#ifndef DISABLE_FLOAT_API + memset(fbuf,0,sizeof(float)*2*960); + VG_UNDEF(packet,sizeof(packet)); + i=opus_encode_float(enc, fbuf, 960, packet, sizeof(packet)); + if(i<1 || (i>(opus_int32)sizeof(packet)))test_failed(); + VG_CHECK(packet,i); + cfgs++; + fprintf(stdout," opus_encode_float() .......................... OK.\n"); +#endif + +#if 0 + /*These tests are disabled because the library crashes with null states*/ + if(opus_encoder_ctl(0,OPUS_RESET_STATE) !=OPUS_INVALID_STATE)test_failed(); + if(opus_encoder_init(0,48000,1,OPUS_APPLICATION_VOIP) !=OPUS_INVALID_STATE)test_failed(); + if(opus_encode(0,sbuf,960,packet,sizeof(packet)) !=OPUS_INVALID_STATE)test_failed(); + if(opus_encode_float(0,fbuf,960,packet,sizeof(packet))!=OPUS_INVALID_STATE)test_failed(); +#endif + opus_encoder_destroy(enc); + cfgs++; + fprintf(stdout," All encoder interface tests passed\n"); + fprintf(stdout," (%d API invocations)\n",cfgs); + return cfgs; +} + +#define max_out (1276*48+48*2+2) +int test_repacketizer_api(void) +{ + int ret,cfgs,i,j,k; + OpusRepacketizer *rp; + unsigned char *packet; + unsigned char *po; + cfgs=0; + fprintf(stdout,"\n Repacketizer tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); + + packet=malloc(max_out); + if(packet==NULL)test_failed(); + memset(packet,0,max_out); + po=malloc(max_out+256); + if(po==NULL)test_failed(); + + i=opus_repacketizer_get_size(); + if(i<=0)test_failed(); + cfgs++; + fprintf(stdout," opus_repacketizer_get_size()=%d ............. OK.\n",i); + + rp=malloc(i); + rp=opus_repacketizer_init(rp); + if(rp==NULL)test_failed(); + cfgs++; + free(rp); + fprintf(stdout," opus_repacketizer_init ....................... OK.\n"); + + rp=opus_repacketizer_create(); + if(rp==NULL)test_failed(); + cfgs++; + fprintf(stdout," opus_repacketizer_create ..................... OK.\n"); + + if(opus_repacketizer_get_nb_frames(rp)!=0)test_failed(); + cfgs++; + fprintf(stdout," opus_repacketizer_get_nb_frames .............. OK.\n"); + + /*Length overflows*/ + VG_UNDEF(packet,4); + if(opus_repacketizer_cat(rp,packet,0)!=OPUS_INVALID_PACKET)test_failed(); /* Zero len */ + cfgs++; + packet[0]=1; + if(opus_repacketizer_cat(rp,packet,2)!=OPUS_INVALID_PACKET)test_failed(); /* Odd payload code 1 */ + cfgs++; + packet[0]=2; + if(opus_repacketizer_cat(rp,packet,1)!=OPUS_INVALID_PACKET)test_failed(); /* Code 2 overflow one */ + cfgs++; + packet[0]=3; + if(opus_repacketizer_cat(rp,packet,1)!=OPUS_INVALID_PACKET)test_failed(); /* Code 3 no count */ + cfgs++; + packet[0]=2; + packet[1]=255; + if(opus_repacketizer_cat(rp,packet,2)!=OPUS_INVALID_PACKET)test_failed(); /* Code 2 overflow two */ + cfgs++; + packet[0]=2; + packet[1]=250; + if(opus_repacketizer_cat(rp,packet,251)!=OPUS_INVALID_PACKET)test_failed(); /* Code 2 overflow three */ + cfgs++; + packet[0]=3; + packet[1]=0; + if(opus_repacketizer_cat(rp,packet,2)!=OPUS_INVALID_PACKET)test_failed(); /* Code 3 m=0 */ + cfgs++; + packet[1]=49; + if(opus_repacketizer_cat(rp,packet,100)!=OPUS_INVALID_PACKET)test_failed(); /* Code 3 m=49 */ + cfgs++; + packet[0]=0; + if(opus_repacketizer_cat(rp,packet,3)!=OPUS_OK)test_failed(); + cfgs++; + packet[0]=1<<2; + if(opus_repacketizer_cat(rp,packet,3)!=OPUS_INVALID_PACKET)test_failed(); /* Change in TOC */ + cfgs++; + + /* Code 0,1,3 CBR -> Code 0,1,3 CBR */ + opus_repacketizer_init(rp); + for(j=0;j<32;j++) + { + /* TOC types, test half with stereo */ + int maxi; + packet[0]=((j<<1)+(j&1))<<2; + maxi=960/opus_packet_get_samples_per_frame(packet,8000); + for(i=1;i<=maxi;i++) + { + /* Number of CBR frames in the input packets */ + int maxp; + packet[0]=((j<<1)+(j&1))<<2; + if(i>1)packet[0]+=i==2?1:3; + packet[1]=i>2?i:0; + maxp=960/(i*opus_packet_get_samples_per_frame(packet,8000)); + for(k=0;k<=(1275+75);k+=3) + { + /*Payload size*/ + opus_int32 cnt,rcnt; + if(k%i!=0)continue; /* Only testing CBR here, payload must be a multiple of the count */ + for(cnt=0;cnt0) + { + ret=opus_repacketizer_cat(rp,packet,k+(i>2?2:1)); + if((cnt<=maxp&&k<=(1275*i))?ret!=OPUS_OK:ret!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + } + rcnt=k<=(1275*i)?(cnt0) + { + int len; + len=k*rcnt+((rcnt*i)>2?2:1); + if(ret!=len)test_failed(); + if((rcnt*i)<2&&(po[0]&3)!=0)test_failed(); /* Code 0 */ + if((rcnt*i)==2&&(po[0]&3)!=1)test_failed(); /* Code 1 */ + if((rcnt*i)>2&&(((po[0]&3)!=3)||(po[1]!=rcnt*i)))test_failed(); /* Code 3 CBR */ + cfgs++; + if(opus_repacketizer_out(rp,po,len)!=len)test_failed(); + cfgs++; + if(opus_packet_unpad(po,len)!=len)test_failed(); + cfgs++; + if(opus_packet_pad(po,len,len+1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_packet_pad(po,len+1,len+256)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_packet_unpad(po,len+256)!=len)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,len,1)!=len)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,len,len+1,1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,len+1,len+256,1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,len+256,1)!=len)test_failed(); + cfgs++; + if(opus_repacketizer_out(rp,po,len-1)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(len>1) + { + if(opus_repacketizer_out(rp,po,1)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + } + if(opus_repacketizer_out(rp,po,0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + } else if (ret!=OPUS_BAD_ARG)test_failed(); /* M must not be 0 */ + } + opus_repacketizer_init(rp); + } + } + } + + /*Change in input count code, CBR out*/ + opus_repacketizer_init(rp); + packet[0]=0; + if(opus_repacketizer_cat(rp,packet,5)!=OPUS_OK)test_failed(); + cfgs++; + packet[0]+=1; + if(opus_repacketizer_cat(rp,packet,9)!=OPUS_OK)test_failed(); + cfgs++; + i=opus_repacketizer_out(rp,po,max_out); + if((i!=(4+8+2))||((po[0]&3)!=3)||((po[1]&63)!=3)||((po[1]>>7)!=0))test_failed(); + cfgs++; + i=opus_repacketizer_out_range(rp,0,1,po,max_out); + if(i!=5||(po[0]&3)!=0)test_failed(); + cfgs++; + i=opus_repacketizer_out_range(rp,1,2,po,max_out); + if(i!=5||(po[0]&3)!=0)test_failed(); + cfgs++; + + /*Change in input count code, VBR out*/ + opus_repacketizer_init(rp); + packet[0]=1; + if(opus_repacketizer_cat(rp,packet,9)!=OPUS_OK)test_failed(); + cfgs++; + packet[0]=0; + if(opus_repacketizer_cat(rp,packet,3)!=OPUS_OK)test_failed(); + cfgs++; + i=opus_repacketizer_out(rp,po,max_out); + if((i!=(2+8+2+2))||((po[0]&3)!=3)||((po[1]&63)!=3)||((po[1]>>7)!=1))test_failed(); + cfgs++; + + /*VBR in, VBR out*/ + opus_repacketizer_init(rp); + packet[0]=2; + packet[1]=4; + if(opus_repacketizer_cat(rp,packet,8)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_repacketizer_cat(rp,packet,8)!=OPUS_OK)test_failed(); + cfgs++; + i=opus_repacketizer_out(rp,po,max_out); + if((i!=(2+1+1+1+4+2+4+2))||((po[0]&3)!=3)||((po[1]&63)!=4)||((po[1]>>7)!=1))test_failed(); + cfgs++; + + /*VBR in, CBR out*/ + opus_repacketizer_init(rp); + packet[0]=2; + packet[1]=4; + if(opus_repacketizer_cat(rp,packet,10)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_repacketizer_cat(rp,packet,10)!=OPUS_OK)test_failed(); + cfgs++; + i=opus_repacketizer_out(rp,po,max_out); + if((i!=(2+4+4+4+4))||((po[0]&3)!=3)||((po[1]&63)!=4)||((po[1]>>7)!=0))test_failed(); + cfgs++; + + /*Count 0 in, VBR out*/ + for(j=0;j<32;j++) + { + /* TOC types, test half with stereo */ + int maxi,sum,rcnt; + packet[0]=((j<<1)+(j&1))<<2; + maxi=960/opus_packet_get_samples_per_frame(packet,8000); + sum=0; + rcnt=0; + opus_repacketizer_init(rp); + for(i=1;i<=maxi+2;i++) + { + int len; + ret=opus_repacketizer_cat(rp,packet,i); + if(rcnt2&&(po[1]&63)!=rcnt)test_failed(); + if(rcnt==2&&(po[0]&3)!=2)test_failed(); + if(rcnt==1&&(po[0]&3)!=0)test_failed(); + cfgs++; + if(opus_repacketizer_out(rp,po,len)!=len)test_failed(); + cfgs++; + if(opus_packet_unpad(po,len)!=len)test_failed(); + cfgs++; + if(opus_packet_pad(po,len,len+1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_packet_pad(po,len+1,len+256)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_packet_unpad(po,len+256)!=len)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,len,1)!=len)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,len,len+1,1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,len+1,len+256,1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,len+256,1)!=len)test_failed(); + cfgs++; + if(opus_repacketizer_out(rp,po,len-1)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(len>1) + { + if(opus_repacketizer_out(rp,po,1)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + } + if(opus_repacketizer_out(rp,po,0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + } + } + + po[0]='O'; + po[1]='p'; + if(opus_packet_pad(po,4,4)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,4,4,1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_packet_pad(po,4,5)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,4,5,1)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + if(opus_packet_pad(po,0,5)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,0,5,1)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_packet_unpad(po,0)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,0,1)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_packet_unpad(po,4)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,4,1)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + po[0]=0; + po[1]=0; + po[2]=0; + if(opus_packet_pad(po,5,4)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,5,4,1)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + + fprintf(stdout," opus_repacketizer_cat ........................ OK.\n"); + fprintf(stdout," opus_repacketizer_out ........................ OK.\n"); + fprintf(stdout," opus_repacketizer_out_range .................. OK.\n"); + fprintf(stdout," opus_packet_pad .............................. OK.\n"); + fprintf(stdout," opus_packet_unpad ............................ OK.\n"); + fprintf(stdout," opus_multistream_packet_pad .................. OK.\n"); + fprintf(stdout," opus_multistream_packet_unpad ................ OK.\n"); + + opus_repacketizer_destroy(rp); + cfgs++; + free(packet); + free(po); + fprintf(stdout," All repacketizer tests passed\n"); + fprintf(stdout," (%7d API invocations)\n",cfgs); + + return cfgs; +} + +#ifdef MALLOC_FAIL +/* GLIBC 2.14 declares __malloc_hook as deprecated, generating a warning + * under GCC. However, this is the cleanest way to test malloc failure + * handling in our codebase, and the lack of thread safety isn't an + * issue here. We therefore disable the warning for this function. + */ +#if OPUS_GNUC_PREREQ(4,6) +/* Save the current warning settings */ +#pragma GCC diagnostic push +#endif +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +typedef void *(*mhook)(size_t __size, __const void *); +#endif + +int test_malloc_fail(void) +{ +#ifdef MALLOC_FAIL + OpusDecoder *dec; + OpusEncoder *enc; + OpusRepacketizer *rp; + unsigned char mapping[256] = {0,1}; + OpusMSDecoder *msdec; + OpusMSEncoder *msenc; + int rate,c,app,cfgs,err,useerr; + int *ep; + mhook orig_malloc; + cfgs=0; +#endif + fprintf(stdout,"\n malloc() failure tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); +#ifdef MALLOC_FAIL + orig_malloc=__malloc_hook; + __malloc_hook=malloc_hook; + ep=(int *)opus_alloc(sizeof(int)); + if(ep!=NULL) + { + if(ep)free(ep); + __malloc_hook=orig_malloc; +#endif + fprintf(stdout," opus_decoder_create() ................... SKIPPED.\n"); + fprintf(stdout," opus_encoder_create() ................... SKIPPED.\n"); + fprintf(stdout," opus_repacketizer_create() .............. SKIPPED.\n"); + fprintf(stdout," opus_multistream_decoder_create() ....... SKIPPED.\n"); + fprintf(stdout," opus_multistream_encoder_create() ....... SKIPPED.\n"); + fprintf(stdout,"(Test only supported with GLIBC and without valgrind)\n"); + return 0; +#ifdef MALLOC_FAIL + } + for(useerr=0;useerr<2;useerr++) + { + ep=useerr?&err:0; + for(rate=0;rate<5;rate++) + { + for(c=1;c<3;c++) + { + err=1; + if(useerr) + { + VG_UNDEF(&err,sizeof(err)); + } + dec=opus_decoder_create(opus_rates[rate], c, ep); + if(dec!=NULL||(useerr&&err!=OPUS_ALLOC_FAIL)) + { + __malloc_hook=orig_malloc; + test_failed(); + } + cfgs++; + msdec=opus_multistream_decoder_create(opus_rates[rate], c, 1, c-1, mapping, ep); + if(msdec!=NULL||(useerr&&err!=OPUS_ALLOC_FAIL)) + { + __malloc_hook=orig_malloc; + test_failed(); + } + cfgs++; + for(app=0;app<3;app++) + { + if(useerr) + { + VG_UNDEF(&err,sizeof(err)); + } + enc=opus_encoder_create(opus_rates[rate], c, opus_apps[app],ep); + if(enc!=NULL||(useerr&&err!=OPUS_ALLOC_FAIL)) + { + __malloc_hook=orig_malloc; + test_failed(); + } + cfgs++; + msenc=opus_multistream_encoder_create(opus_rates[rate], c, 1, c-1, mapping, opus_apps[app],ep); + if(msenc!=NULL||(useerr&&err!=OPUS_ALLOC_FAIL)) + { + __malloc_hook=orig_malloc; + test_failed(); + } + cfgs++; + } + } + } + } + rp=opus_repacketizer_create(); + if(rp!=NULL) + { + __malloc_hook=orig_malloc; + test_failed(); + } + cfgs++; + __malloc_hook=orig_malloc; + fprintf(stdout," opus_decoder_create() ........................ OK.\n"); + fprintf(stdout," opus_encoder_create() ........................ OK.\n"); + fprintf(stdout," opus_repacketizer_create() ................... OK.\n"); + fprintf(stdout," opus_multistream_decoder_create() ............ OK.\n"); + fprintf(stdout," opus_multistream_encoder_create() ............ OK.\n"); + fprintf(stdout," All malloc failure tests passed\n"); + fprintf(stdout," (%2d API invocations)\n",cfgs); + return cfgs; +#endif +} + +#ifdef MALLOC_FAIL +#if __GNUC_PREREQ(4,6) +#pragma GCC diagnostic pop /* restore -Wdeprecated-declarations */ +#endif +#endif + +int main(int _argc, char **_argv) +{ + opus_int32 total; + const char * oversion; + if(_argc>1) + { + fprintf(stderr,"Usage: %s\n",_argv[0]); + return 1; + } + iseed=0; + + oversion=opus_get_version_string(); + if(!oversion)test_failed(); + fprintf(stderr,"Testing the %s API deterministically\n", oversion); + if(opus_strerror(-32768)==NULL)test_failed(); + if(opus_strerror(32767)==NULL)test_failed(); + if(strlen(opus_strerror(0))<1)test_failed(); + total=4; + + total+=test_dec_api(); + total+=test_msdec_api(); + total+=test_parse(); + total+=test_enc_api(); + total+=test_repacketizer_api(); + total+=test_malloc_fail(); + + fprintf(stderr,"\nAll API tests passed.\nThe libopus API was invoked %d times.\n",total); + + return 0; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_common.h b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_common.h new file mode 100644 index 000000000..d96c7d84a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_common.h @@ -0,0 +1,85 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +static OPUS_INLINE void deb2_impl(unsigned char *_t,unsigned char **_p,int _k,int _x,int _y) +{ + int i; + if(_x>2){ + if(_y<3)for(i=0;i<_y;i++)*(--*_p)=_t[i+1]; + }else{ + _t[_x]=_t[_x-_y]; + deb2_impl(_t,_p,_k,_x+1,_y); + for(i=_t[_x-_y]+1;i<_k;i++){ + _t[_x]=i; + deb2_impl(_t,_p,_k,_x+1,_x); + } + } +} + +/*Generates a De Bruijn sequence (k,2) with length k^2*/ +static OPUS_INLINE void debruijn2(int _k, unsigned char *_res) +{ + unsigned char *p; + unsigned char *t; + t=malloc(sizeof(unsigned char)*_k*2); + memset(t,0,sizeof(unsigned char)*_k*2); + p=&_res[_k*_k]; + deb2_impl(t,&p,_k,1,1); + free(t); +} + +/*MWC RNG of George Marsaglia*/ +static opus_uint32 Rz, Rw; +static OPUS_INLINE opus_uint32 fast_rand(void) +{ + Rz=36969*(Rz&65535)+(Rz>>16); + Rw=18000*(Rw&65535)+(Rw>>16); + return (Rz<<16)+Rw; +} +static opus_uint32 iseed; + +#ifdef __GNUC__ +__attribute__((noreturn)) +#elif defined(_MSC_VER) +__declspec(noreturn) +#endif +static OPUS_INLINE void _test_failed(const char *file, int line) +{ + fprintf(stderr,"\n ***************************************************\n"); + fprintf(stderr," *** A fatal error was detected. ***\n"); + fprintf(stderr," ***************************************************\n"); + fprintf(stderr,"Please report this failure and include\n"); + fprintf(stderr,"'make check SEED=%u fails %s at line %d for %s'\n",iseed,file,line,opus_get_version_string()); + fprintf(stderr,"and any relevant details about your system.\n\n"); +#if defined(_MSC_VER) + _set_abort_behavior( 0, _WRITE_ABORT_MSG); +#endif + abort(); +} +#define test_failed() _test_failed(__FILE__, __LINE__); + +void regression_test(void); diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_decode.c b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_decode.c new file mode 100644 index 000000000..2d1e2d414 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_decode.c @@ -0,0 +1,463 @@ +/* Copyright (c) 2011-2013 Xiph.Org Foundation + Written by Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#else +#include +#define getpid _getpid +#endif +#include "opus.h" +#include "test_opus_common.h" + +#define MAX_PACKET (1500) +#define MAX_FRAME_SAMP (5760) + +int test_decoder_code0(int no_fuzz) +{ + static const opus_int32 fsv[5]={48000,24000,16000,12000,8000}; + int err,skip,plen; + int out_samples,fec; + int t; + opus_int32 i; + OpusDecoder *dec[5*2]; + opus_int32 decsize; + OpusDecoder *decbak; + opus_uint32 dec_final_range1,dec_final_range2,dec_final_acc; + unsigned char *packet; + unsigned char modes[4096]; + short *outbuf_int; + short *outbuf; + + dec_final_range1=dec_final_range2=2; + + packet=malloc(sizeof(unsigned char)*MAX_PACKET); + if(packet==NULL)test_failed(); + + outbuf_int=malloc(sizeof(short)*(MAX_FRAME_SAMP+16)*2); + for(i=0;i<(MAX_FRAME_SAMP+16)*2;i++)outbuf_int[i]=32749; + outbuf=&outbuf_int[8*2]; + + fprintf(stdout," Starting %d decoders...\n",5*2); + for(t=0;t<5*2;t++) + { + int fs=fsv[t>>1]; + int c=(t&1)+1; + err=OPUS_INTERNAL_ERROR; + dec[t] = opus_decoder_create(fs, c, &err); + if(err!=OPUS_OK || dec[t]==NULL)test_failed(); + fprintf(stdout," opus_decoder_create(%5d,%d) OK. Copy ",fs,c); + { + OpusDecoder *dec2; + /*The opus state structures contain no pointers and can be freely copied*/ + dec2=(OpusDecoder *)malloc(opus_decoder_get_size(c)); + if(dec2==NULL)test_failed(); + memcpy(dec2,dec[t],opus_decoder_get_size(c)); + memset(dec[t],255,opus_decoder_get_size(c)); + opus_decoder_destroy(dec[t]); + printf("OK.\n"); + dec[t]=dec2; + } + } + + decsize=opus_decoder_get_size(1); + decbak=(OpusDecoder *)malloc(decsize); + if(decbak==NULL)test_failed(); + + for(t=0;t<5*2;t++) + { + int factor=48000/fsv[t>>1]; + for(fec=0;fec<2;fec++) + { + opus_int32 dur; + /*Test PLC on a fresh decoder*/ + out_samples = opus_decode(dec[t], 0, 0, outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed(); + if(dur!=120/factor)test_failed(); + + /*Test on a size which isn't a multiple of 2.5ms*/ + out_samples = opus_decode(dec[t], 0, 0, outbuf, 120/factor+2, fec); + if(out_samples!=OPUS_BAD_ARG)test_failed(); + + /*Test null pointer input*/ + out_samples = opus_decode(dec[t], 0, -1, outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + out_samples = opus_decode(dec[t], 0, 1, outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + out_samples = opus_decode(dec[t], 0, 10, outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + out_samples = opus_decode(dec[t], 0, fast_rand(), outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed(); + if(dur!=120/factor)test_failed(); + + /*Zero lengths*/ + out_samples = opus_decode(dec[t], packet, 0, outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + + /*Zero buffer*/ + outbuf[0]=32749; + out_samples = opus_decode(dec[t], packet, 0, outbuf, 0, fec); + if(out_samples>0)test_failed(); +#if !defined(OPUS_BUILD) && (OPUS_GNUC_PREREQ(4, 6) || (defined(__clang_major__) && __clang_major__ >= 3)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" +#endif + out_samples = opus_decode(dec[t], packet, 0, 0, 0, fec); +#if !defined(OPUS_BUILD) && (OPUS_GNUC_PREREQ(4, 6) || (defined(__clang_major__) && __clang_major__ >= 3)) +#pragma GCC diagnostic pop +#endif + if(out_samples>0)test_failed(); + if(outbuf[0]!=32749)test_failed(); + + /*Invalid lengths*/ + out_samples = opus_decode(dec[t], packet, -1, outbuf, MAX_FRAME_SAMP, fec); + if(out_samples>=0)test_failed(); + out_samples = opus_decode(dec[t], packet, INT_MIN, outbuf, MAX_FRAME_SAMP, fec); + if(out_samples>=0)test_failed(); + out_samples = opus_decode(dec[t], packet, -1, outbuf, -1, fec); + if(out_samples>=0)test_failed(); + + /*Crazy FEC values*/ + out_samples = opus_decode(dec[t], packet, 1, outbuf, MAX_FRAME_SAMP, fec?-1:2); + if(out_samples>=0)test_failed(); + + /*Reset the decoder*/ + if(opus_decoder_ctl(dec[t], OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + } + } + fprintf(stdout," dec[all] initial frame PLC OK.\n"); + + /*Count code 0 tests*/ + for(i=0;i<64;i++) + { + opus_int32 dur; + int j,expected[5*2]; + packet[0]=i<<2; + packet[1]=255; + packet[2]=255; + err=opus_packet_get_nb_channels(packet); + if(err!=(i&1)+1)test_failed(); + + for(t=0;t<5*2;t++){ + expected[t]=opus_decoder_get_nb_samples(dec[t],packet,1); + if(expected[t]>2880)test_failed(); + } + + for(j=0;j<256;j++) + { + packet[1]=j; + for(t=0;t<5*2;t++) + { + out_samples = opus_decode(dec[t], packet, 3, outbuf, MAX_FRAME_SAMP, 0); + if(out_samples!=expected[t])test_failed(); + if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed(); + if(dur!=out_samples)test_failed(); + opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1)); + if(t==0)dec_final_range2=dec_final_range1; + else if(dec_final_range1!=dec_final_range2)test_failed(); + } + } + + for(t=0;t<5*2;t++){ + int factor=48000/fsv[t>>1]; + /* The PLC is run for 6 frames in order to get better PLC coverage. */ + for(j=0;j<6;j++) + { + out_samples = opus_decode(dec[t], 0, 0, outbuf, expected[t], 0); + if(out_samples!=expected[t])test_failed(); + if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed(); + if(dur!=out_samples)test_failed(); + } + /* Run the PLC once at 2.5ms, as a simulation of someone trying to + do small drift corrections. */ + if(expected[t]!=120/factor) + { + out_samples = opus_decode(dec[t], 0, 0, outbuf, 120/factor, 0); + if(out_samples!=120/factor)test_failed(); + if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed(); + if(dur!=out_samples)test_failed(); + } + out_samples = opus_decode(dec[t], packet, 2, outbuf, expected[t]-1, 0); + if(out_samples>0)test_failed(); + } + } + fprintf(stdout," dec[all] all 2-byte prefix for length 3 and PLC, all modes (64) OK.\n"); + + if(no_fuzz) + { + fprintf(stdout," Skipping many tests which fuzz the decoder as requested.\n"); + free(decbak); + for(t=0;t<5*2;t++)opus_decoder_destroy(dec[t]); + printf(" Decoders stopped.\n"); + + err=0; + for(i=0;i<8*2;i++)err|=outbuf_int[i]!=32749; + for(i=MAX_FRAME_SAMP*2;i<(MAX_FRAME_SAMP+8)*2;i++)err|=outbuf[i]!=32749; + if(err)test_failed(); + + free(outbuf_int); + free(packet); + return 0; + } + + { + /*We only test a subset of the modes here simply because the longer + durations end up taking a long time.*/ + static const int cmodes[4]={16,20,24,28}; + static const opus_uint32 cres[4]={116290185,2172123586u,2172123586u,2172123586u}; + static const opus_uint32 lres[3]={3285687739u,1481572662,694350475}; + static const int lmodes[3]={0,4,8}; + int mode=fast_rand()%4; + + packet[0]=cmodes[mode]<<3; + dec_final_acc=0; + t=fast_rand()%10; + + for(i=0;i<65536;i++) + { + int factor=48000/fsv[t>>1]; + packet[1]=i>>8; + packet[2]=i&255; + packet[3]=255; + out_samples = opus_decode(dec[t], packet, 4, outbuf, MAX_FRAME_SAMP, 0); + if(out_samples!=120/factor)test_failed(); + opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1)); + dec_final_acc+=dec_final_range1; + } + if(dec_final_acc!=cres[mode])test_failed(); + fprintf(stdout," dec[%3d] all 3-byte prefix for length 4, mode %2d OK.\n",t,cmodes[mode]); + + mode=fast_rand()%3; + packet[0]=lmodes[mode]<<3; + dec_final_acc=0; + t=fast_rand()%10; + for(i=0;i<65536;i++) + { + int factor=48000/fsv[t>>1]; + packet[1]=i>>8; + packet[2]=i&255; + packet[3]=255; + out_samples = opus_decode(dec[t], packet, 4, outbuf, MAX_FRAME_SAMP, 0); + if(out_samples!=480/factor)test_failed(); + opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1)); + dec_final_acc+=dec_final_range1; + } + if(dec_final_acc!=lres[mode])test_failed(); + fprintf(stdout," dec[%3d] all 3-byte prefix for length 4, mode %2d OK.\n",t,lmodes[mode]); + } + + skip=fast_rand()%7; + for(i=0;i<64;i++) + { + int j,expected[5*2]; + packet[0]=i<<2; + for(t=0;t<5*2;t++)expected[t]=opus_decoder_get_nb_samples(dec[t],packet,1); + for(j=2+skip;j<1275;j+=4) + { + int jj; + for(jj=0;jj1.f)test_failed(); + if(x[j]<-1.f)test_failed(); + } + } + for(i=1;i<9;i++) + { + for (j=0;j<1024;j++) + { + x[j]=(j&255)*(1/32.f)-4.f; + } + opus_pcm_soft_clip(x,1024/i,i,s); + for (j=0;j<(1024/i)*i;j++) + { + if(x[j]>1.f)test_failed(); + if(x[j]<-1.f)test_failed(); + } + } + opus_pcm_soft_clip(x,0,1,s); + opus_pcm_soft_clip(x,1,0,s); + opus_pcm_soft_clip(x,1,1,0); + opus_pcm_soft_clip(x,1,-1,s); + opus_pcm_soft_clip(x,-1,1,s); + opus_pcm_soft_clip(0,1,1,s); + printf("OK.\n"); +} +#endif + +int main(int _argc, char **_argv) +{ + const char * oversion; + const char * env_seed; + int env_used; + + if(_argc>2) + { + fprintf(stderr,"Usage: %s []\n",_argv[0]); + return 1; + } + + env_used=0; + env_seed=getenv("SEED"); + if(_argc>1)iseed=atoi(_argv[1]); + else if(env_seed) + { + iseed=atoi(env_seed); + env_used=1; + } + else iseed=(opus_uint32)time(NULL)^(((opus_uint32)getpid()&65535)<<16); + Rw=Rz=iseed; + + oversion=opus_get_version_string(); + if(!oversion)test_failed(); + fprintf(stderr,"Testing %s decoder. Random seed: %u (%.4X)\n", oversion, iseed, fast_rand() % 65535); + if(env_used)fprintf(stderr," Random seed set from the environment (SEED=%s).\n", env_seed); + + /*Setting TEST_OPUS_NOFUZZ tells the tool not to send garbage data + into the decoders. This is helpful because garbage data + may cause the decoders to clip, which angers CLANG IOC.*/ + test_decoder_code0(getenv("TEST_OPUS_NOFUZZ")!=NULL); +#ifndef DISABLE_FLOAT_API + test_soft_clip(); +#endif + + return 0; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_encode.c b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_encode.c new file mode 100644 index 000000000..00795a1e2 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_encode.c @@ -0,0 +1,703 @@ +/* Copyright (c) 2011-2013 Xiph.Org Foundation + Written by Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#if (!defined WIN32 && !defined _WIN32) || defined(__MINGW32__) +#include +#else +#include +#define getpid _getpid +#endif +#include "opus_multistream.h" +#include "opus.h" +#include "../src/opus_private.h" +#include "test_opus_common.h" + +#define MAX_PACKET (1500) +#define SAMPLES (48000*30) +#define SSAMPLES (SAMPLES/3) +#define MAX_FRAME_SAMP (5760) +#define PI (3.141592653589793238462643f) +#define RAND_SAMPLE(a) (a[fast_rand() % sizeof(a)/sizeof(a[0])]) + +void generate_music(short *buf, opus_int32 len) +{ + opus_int32 a1,b1,a2,b2; + opus_int32 c1,c2,d1,d2; + opus_int32 i,j; + a1=b1=a2=b2=0; + c1=c2=d1=d2=0; + j=0; + /*60ms silence*/ + for(i=0;i<2880;i++)buf[i*2]=buf[i*2+1]=0; + for(i=2880;i>12)^((j>>10|j>>12)&26&j>>7)))&128)+128)<<15; + r=fast_rand();v1+=r&65535;v1-=r>>16; + r=fast_rand();v2+=r&65535;v2-=r>>16; + b1=v1-a1+((b1*61+32)>>6);a1=v1; + b2=v2-a2+((b2*61+32)>>6);a2=v2; + c1=(30*(c1+b1+d1)+32)>>6;d1=b1; + c2=(30*(c2+b2+d2)+32)>>6;d2=b2; + v1=(c1+128)>>8; + v2=(c2+128)>>8; + buf[i*2]=v1>32767?32767:(v1<-32768?-32768:v1); + buf[i*2+1]=v2>32767?32767:(v2<-32768?-32768:v2); + if(i%6==0)j++; + } +} + +#if 0 +static int save_ctr = 0; +static void int_to_char(opus_uint32 i, unsigned char ch[4]) +{ + ch[0] = i>>24; + ch[1] = (i>>16)&0xFF; + ch[2] = (i>>8)&0xFF; + ch[3] = i&0xFF; +} + +static OPUS_INLINE void save_packet(unsigned char* p, int len, opus_uint32 rng) +{ + FILE *fout; + unsigned char int_field[4]; + char name[256]; + snprintf(name,255,"test_opus_encode.%llu.%d.bit",(unsigned long long)iseed,save_ctr); + fprintf(stdout,"writing %d byte packet to %s\n",len,name); + fout=fopen(name, "wb+"); + if(fout==NULL)test_failed(); + int_to_char(len, int_field); + fwrite(int_field, 1, 4, fout); + int_to_char(rng, int_field); + fwrite(int_field, 1, 4, fout); + fwrite(p, 1, len, fout); + fclose(fout); + save_ctr++; +} +#endif + +int get_frame_size_enum(int frame_size, int sampling_rate) +{ + int frame_size_enum; + + if(frame_size==sampling_rate/400) + frame_size_enum = OPUS_FRAMESIZE_2_5_MS; + else if(frame_size==sampling_rate/200) + frame_size_enum = OPUS_FRAMESIZE_5_MS; + else if(frame_size==sampling_rate/100) + frame_size_enum = OPUS_FRAMESIZE_10_MS; + else if(frame_size==sampling_rate/50) + frame_size_enum = OPUS_FRAMESIZE_20_MS; + else if(frame_size==sampling_rate/25) + frame_size_enum = OPUS_FRAMESIZE_40_MS; + else if(frame_size==3*sampling_rate/50) + frame_size_enum = OPUS_FRAMESIZE_60_MS; + else if(frame_size==4*sampling_rate/50) + frame_size_enum = OPUS_FRAMESIZE_80_MS; + else if(frame_size==5*sampling_rate/50) + frame_size_enum = OPUS_FRAMESIZE_100_MS; + else if(frame_size==6*sampling_rate/50) + frame_size_enum = OPUS_FRAMESIZE_120_MS; + else + test_failed(); + + return frame_size_enum; +} + +int test_encode(OpusEncoder *enc, int channels, int frame_size, OpusDecoder *dec) +{ + int samp_count = 0; + opus_int16 *inbuf; + unsigned char packet[MAX_PACKET+257]; + int len; + opus_int16 *outbuf; + int out_samples; + int ret = 0; + + /* Generate input data */ + inbuf = (opus_int16*)malloc(sizeof(*inbuf)*SSAMPLES); + generate_music(inbuf, SSAMPLES/2); + + /* Allocate memory for output data */ + outbuf = (opus_int16*)malloc(sizeof(*outbuf)*MAX_FRAME_SAMP*3); + + /* Encode data, then decode for sanity check */ + do { + len = opus_encode(enc, &inbuf[samp_count*channels], frame_size, packet, MAX_PACKET); + if(len<0 || len>MAX_PACKET) { + fprintf(stderr,"opus_encode() returned %d\n",len); + ret = -1; + break; + } + + out_samples = opus_decode(dec, packet, len, outbuf, MAX_FRAME_SAMP, 0); + if(out_samples!=frame_size) { + fprintf(stderr,"opus_decode() returned %d\n",out_samples); + ret = -1; + break; + } + + samp_count += frame_size; + } while (samp_count < ((SSAMPLES/2)-MAX_FRAME_SAMP)); + + /* Clean up */ + free(inbuf); + free(outbuf); + return ret; +} + +void fuzz_encoder_settings(const int num_encoders, const int num_setting_changes) +{ + OpusEncoder *enc; + OpusDecoder *dec; + int i,j,err; + + /* Parameters to fuzz. Some values are duplicated to increase their probability of being tested. */ + int sampling_rates[5] = {8000, 12000, 16000, 24000, 48000}; + int channels[2] = {1, 2}; + int applications[3] = {OPUS_APPLICATION_AUDIO, OPUS_APPLICATION_VOIP, OPUS_APPLICATION_RESTRICTED_LOWDELAY}; + int bitrates[11] = {6000, 12000, 16000, 24000, 32000, 48000, 64000, 96000, 510000, OPUS_AUTO, OPUS_BITRATE_MAX}; + int force_channels[4] = {OPUS_AUTO, OPUS_AUTO, 1, 2}; + int use_vbr[3] = {0, 1, 1}; + int vbr_constraints[3] = {0, 1, 1}; + int complexities[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + int max_bandwidths[6] = {OPUS_BANDWIDTH_NARROWBAND, OPUS_BANDWIDTH_MEDIUMBAND, + OPUS_BANDWIDTH_WIDEBAND, OPUS_BANDWIDTH_SUPERWIDEBAND, + OPUS_BANDWIDTH_FULLBAND, OPUS_BANDWIDTH_FULLBAND}; + int signals[4] = {OPUS_AUTO, OPUS_AUTO, OPUS_SIGNAL_VOICE, OPUS_SIGNAL_MUSIC}; + int inband_fecs[3] = {0, 0, 1}; + int packet_loss_perc[4] = {0, 1, 2, 5}; + int lsb_depths[2] = {8, 24}; + int prediction_disabled[3] = {0, 0, 1}; + int use_dtx[2] = {0, 1}; + int frame_sizes_ms_x2[9] = {5, 10, 20, 40, 80, 120, 160, 200, 240}; /* x2 to avoid 2.5 ms */ + + for (i=0; i=64000?2:1)))!=OPUS_OK)test_failed(); + if(opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY((count>>2)%11))!=OPUS_OK)test_failed(); + if(opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC((fast_rand()&15)&(fast_rand()%15)))!=OPUS_OK)test_failed(); + bw=modes[j]==0?OPUS_BANDWIDTH_NARROWBAND+(fast_rand()%3): + modes[j]==1?OPUS_BANDWIDTH_SUPERWIDEBAND+(fast_rand()&1): + OPUS_BANDWIDTH_NARROWBAND+(fast_rand()%5); + if(modes[j]==2&&bw==OPUS_BANDWIDTH_MEDIUMBAND)bw+=3; + if(opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bw))!=OPUS_OK)test_failed(); + len = opus_encode(enc, &inbuf[i<<1], frame_size, packet, MAX_PACKET); + if(len<0 || len>MAX_PACKET)test_failed(); + if(opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range))!=OPUS_OK)test_failed(); + if((fast_rand()&3)==0) + { + if(opus_packet_pad(packet,len,len+1)!=OPUS_OK)test_failed(); + len++; + } + if((fast_rand()&7)==0) + { + if(opus_packet_pad(packet,len,len+256)!=OPUS_OK)test_failed(); + len+=256; + } + if((fast_rand()&3)==0) + { + len=opus_packet_unpad(packet,len); + if(len<1)test_failed(); + } + out_samples = opus_decode(dec, packet, len, &outbuf[i<<1], MAX_FRAME_SAMP, 0); + if(out_samples!=frame_size)test_failed(); + if(opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range))!=OPUS_OK)test_failed(); + if(enc_final_range!=dec_final_range)test_failed(); + /*LBRR decode*/ + out_samples = opus_decode(dec_err[0], packet, len, out2buf, frame_size, (fast_rand()&3)!=0); + if(out_samples!=frame_size)test_failed(); + out_samples = opus_decode(dec_err[1], packet, (fast_rand()&3)==0?0:len, out2buf, MAX_FRAME_SAMP, (fast_rand()&7)!=0); + if(out_samples<120)test_failed(); + i+=frame_size; + count++; + }while(i<(SSAMPLES-MAX_FRAME_SAMP)); + fprintf(stdout," Mode %s FB encode %s, %6d bps OK.\n",mstrings[modes[j]],rc==0?" VBR":rc==1?"CVBR":" CBR",rate); + } + } + + if(opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(OPUS_AUTO))!=OPUS_OK)test_failed(); + if(opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(OPUS_AUTO))!=OPUS_OK)test_failed(); + if(opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0))!=OPUS_OK)test_failed(); + if(opus_encoder_ctl(enc, OPUS_SET_DTX(0))!=OPUS_OK)test_failed(); + + for(rc=0;rc<3;rc++) + { + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_VBR(rc<2))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_VBR_CONSTRAINT(rc==1))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_VBR_CONSTRAINT(rc==1))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_INBAND_FEC(rc==0))!=OPUS_OK)test_failed(); + for(j=0;j<16;j++) + { + int rate; + int modes[16]={0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2}; + int rates[16]={4000,12000,32000,8000,16000,32000,48000,88000,4000,12000,32000,8000,16000,32000,48000,88000}; + int frame[16]={160*1,160,80,160,160,80,40,20,160*1,160,80,160,160,80,40,20}; + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_INBAND_FEC(rc==0&&j==1))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_FORCE_MODE(MODE_SILK_ONLY+modes[j]))!=OPUS_OK)test_failed(); + rate=rates[j]+fast_rand()%rates[j]; + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_DTX(fast_rand()&1))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_BITRATE(rate))!=OPUS_OK)test_failed(); + count=i=0; + do { + int len,out_samples,frame_size,loss; + opus_int32 pred; + if(opus_multistream_encoder_ctl(MSenc, OPUS_GET_PREDICTION_DISABLED(&pred))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_PREDICTION_DISABLED((int)(fast_rand()&15)<(pred?11:4)))!=OPUS_OK)test_failed(); + frame_size=frame[j]; + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_COMPLEXITY((count>>2)%11))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_PACKET_LOSS_PERC((fast_rand()&15)&(fast_rand()%15)))!=OPUS_OK)test_failed(); + if((fast_rand()&255)==0) + { + if(opus_multistream_encoder_ctl(MSenc, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + if(opus_multistream_decoder_ctl(MSdec, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + if((fast_rand()&3)!=0) + { + if(opus_multistream_decoder_ctl(MSdec_err, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + } + } + if((fast_rand()&255)==0) + { + if(opus_multistream_decoder_ctl(MSdec_err, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + } + len = opus_multistream_encode(MSenc, &inbuf[i<<1], frame_size, packet, MAX_PACKET); + if(len<0 || len>MAX_PACKET)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_GET_FINAL_RANGE(&enc_final_range))!=OPUS_OK)test_failed(); + if((fast_rand()&3)==0) + { + if(opus_multistream_packet_pad(packet,len,len+1,2)!=OPUS_OK)test_failed(); + len++; + } + if((fast_rand()&7)==0) + { + if(opus_multistream_packet_pad(packet,len,len+256,2)!=OPUS_OK)test_failed(); + len+=256; + } + if((fast_rand()&3)==0) + { + len=opus_multistream_packet_unpad(packet,len,2); + if(len<1)test_failed(); + } + out_samples = opus_multistream_decode(MSdec, packet, len, out2buf, MAX_FRAME_SAMP, 0); + if(out_samples!=frame_size*6)test_failed(); + if(opus_multistream_decoder_ctl(MSdec, OPUS_GET_FINAL_RANGE(&dec_final_range))!=OPUS_OK)test_failed(); + if(enc_final_range!=dec_final_range)test_failed(); + /*LBRR decode*/ + loss=(fast_rand()&63)==0; + out_samples = opus_multistream_decode(MSdec_err, packet, loss?0:len, out2buf, frame_size*6, (fast_rand()&3)!=0); + if(out_samples!=(frame_size*6))test_failed(); + i+=frame_size; + count++; + }while(i<(SSAMPLES/12-MAX_FRAME_SAMP)); + fprintf(stdout," Mode %s NB dual-mono MS encode %s, %6d bps OK.\n",mstrings[modes[j]],rc==0?" VBR":rc==1?"CVBR":" CBR",rate); + } + } + + bitrate_bps=512000; + fsize=fast_rand()%31; + fswitch=100; + + debruijn2(6,db62); + count=i=0; + do { + unsigned char toc; + const unsigned char *frames[48]; + short size[48]; + int payload_offset; + opus_uint32 dec_final_range2; + int jj,dec2; + int len,out_samples; + int frame_size=fsizes[db62[fsize]]; + opus_int32 offset=i%(SAMPLES-MAX_FRAME_SAMP); + + opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps)); + + len = opus_encode(enc, &inbuf[offset<<1], frame_size, packet, MAX_PACKET); + if(len<0 || len>MAX_PACKET)test_failed(); + count++; + + opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range)); + + out_samples = opus_decode(dec, packet, len, &outbuf[offset<<1], MAX_FRAME_SAMP, 0); + if(out_samples!=frame_size)test_failed(); + + opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range)); + + /* compare final range encoder rng values of encoder and decoder */ + if(dec_final_range!=enc_final_range)test_failed(); + + /* We fuzz the packet, but take care not to only corrupt the payload + Corrupted headers are tested elsewhere and we need to actually run + the decoders in order to compare them. */ + if(opus_packet_parse(packet,len,&toc,frames,size,&payload_offset)<=0)test_failed(); + if((fast_rand()&1023)==0)len=0; + for(j=(opus_int32)(frames[0]-packet);j0?packet:NULL, len, out2buf, MAX_FRAME_SAMP, 0); + if(out_samples<0||out_samples>MAX_FRAME_SAMP)test_failed(); + if((len>0&&out_samples!=frame_size))test_failed(); /*FIXME use lastframe*/ + + opus_decoder_ctl(dec_err[0], OPUS_GET_FINAL_RANGE(&dec_final_range)); + + /*randomly select one of the decoders to compare with*/ + dec2=fast_rand()%9+1; + out_samples = opus_decode(dec_err[dec2], len>0?packet:NULL, len, out2buf, MAX_FRAME_SAMP, 0); + if(out_samples<0||out_samples>MAX_FRAME_SAMP)test_failed(); /*FIXME, use factor, lastframe for loss*/ + + opus_decoder_ctl(dec_err[dec2], OPUS_GET_FINAL_RANGE(&dec_final_range2)); + if(len>0&&dec_final_range!=dec_final_range2)test_failed(); + + fswitch--; + if(fswitch<1) + { + int new_size; + fsize=(fsize+1)%36; + new_size=fsizes[db62[fsize]]; + if(new_size==960||new_size==480)fswitch=2880/new_size*(fast_rand()%19+1); + else fswitch=(fast_rand()%(2880/new_size))+1; + } + bitrate_bps=((fast_rand()%508000+4000)+bitrate_bps)>>1; + i+=frame_size; + }while(i] [-fuzz ]\n",_argv[0]); +} + +int main(int _argc, char **_argv) +{ + int args=1; + char * strtol_str=NULL; + const char * oversion; + const char * env_seed; + int env_used; + int num_encoders_to_fuzz=5; + int num_setting_changes=40; + + env_used=0; + env_seed=getenv("SEED"); + if(_argc>1) + iseed=strtol(_argv[1], &strtol_str, 10); /* the first input argument might be the seed */ + if(strtol_str!=NULL && strtol_str[0]=='\0') /* iseed is a valid number */ + args++; + else if(env_seed) { + iseed=atoi(env_seed); + env_used=1; + } + else iseed=(opus_uint32)time(NULL)^(((opus_uint32)getpid()&65535)<<16); + Rw=Rz=iseed; + + while(args<_argc) + { + if(strcmp(_argv[args], "-fuzz")==0 && _argc==(args+3)) { + num_encoders_to_fuzz=strtol(_argv[args+1], &strtol_str, 10); + if(strtol_str[0]!='\0' || num_encoders_to_fuzz<=0) { + print_usage(_argv); + return EXIT_FAILURE; + } + num_setting_changes=strtol(_argv[args+2], &strtol_str, 10); + if(strtol_str[0]!='\0' || num_setting_changes<=0) { + print_usage(_argv); + return EXIT_FAILURE; + } + args+=3; + } + else { + print_usage(_argv); + return EXIT_FAILURE; + } + } + + oversion=opus_get_version_string(); + if(!oversion)test_failed(); + fprintf(stderr,"Testing %s encoder. Random seed: %u (%.4X)\n", oversion, iseed, fast_rand() % 65535); + if(env_used)fprintf(stderr," Random seed set from the environment (SEED=%s).\n", env_seed); + + regression_test(); + + /*Setting TEST_OPUS_NOFUZZ tells the tool not to send garbage data + into the decoders. This is helpful because garbage data + may cause the decoders to clip, which angers CLANG IOC.*/ + run_test1(getenv("TEST_OPUS_NOFUZZ")!=NULL); + + /* Fuzz encoder settings online */ + if(getenv("TEST_OPUS_NOFUZZ")==NULL) { + fprintf(stderr,"Running fuzz_encoder_settings with %d encoder(s) and %d setting change(s) each.\n", + num_encoders_to_fuzz, num_setting_changes); + fuzz_encoder_settings(num_encoders_to_fuzz, num_setting_changes); + } + + fprintf(stderr,"Tests completed successfully.\n"); + + return 0; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_padding.c b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_padding.c new file mode 100644 index 000000000..c22e8f0db --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_padding.c @@ -0,0 +1,93 @@ +/* Copyright (c) 2012 Xiph.Org Foundation + Written by Jüri Aedla and Ralph Giles */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +/* Check for overflow in reading the padding length. + * http://lists.xiph.org/pipermail/opus/2012-November/001834.html + */ + +#include +#include +#include +#include "opus.h" +#include "test_opus_common.h" + +#define PACKETSIZE 16909318 +#define CHANNELS 2 +#define FRAMESIZE 5760 + +int test_overflow(void) +{ + OpusDecoder *decoder; + int result; + int error; + + unsigned char *in = malloc(PACKETSIZE); + opus_int16 *out = malloc(FRAMESIZE*CHANNELS*sizeof(*out)); + + fprintf(stderr, " Checking for padding overflow... "); + if (!in || !out) { + fprintf(stderr, "FAIL (out of memory)\n"); + return -1; + } + in[0] = 0xff; + in[1] = 0x41; + memset(in + 2, 0xff, PACKETSIZE - 3); + in[PACKETSIZE-1] = 0x0b; + + decoder = opus_decoder_create(48000, CHANNELS, &error); + result = opus_decode(decoder, in, PACKETSIZE, out, FRAMESIZE, 0); + opus_decoder_destroy(decoder); + + free(in); + free(out); + + if (result != OPUS_INVALID_PACKET) { + fprintf(stderr, "FAIL!\n"); + test_failed(); + } + + fprintf(stderr, "OK.\n"); + + return 1; +} + +int main(void) +{ + const char *oversion; + int tests = 0;; + + iseed = 0; + oversion = opus_get_version_string(); + if (!oversion) test_failed(); + fprintf(stderr, "Testing %s padding.\n", oversion); + + tests += test_overflow(); + + fprintf(stderr, "All padding tests passed.\n"); + + return 0; +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_projection.c b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_projection.c new file mode 100644 index 000000000..5f0d672c1 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/tests/test_opus_projection.c @@ -0,0 +1,394 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include "float_cast.h" +#include "opus.h" +#include "test_opus_common.h" +#include "opus_projection.h" +#include "mathops.h" +#include "../src/mapping_matrix.h" +#include "mathops.h" + +#define BUFFER_SIZE 960 +#define MAX_DATA_BYTES 32768 +#define MAX_FRAME_SAMPLES 5760 +#define ERROR_TOLERANCE 1 + +#define SIMPLE_MATRIX_SIZE 12 +#define SIMPLE_MATRIX_FRAME_SIZE 10 +#define SIMPLE_MATRIX_INPUT_SIZE 30 +#define SIMPLE_MATRIX_OUTPUT_SIZE 40 + +int assert_is_equal( + const opus_val16 *a, const opus_int16 *b, int size, opus_int16 tolerance) +{ + int i; + for (i = 0; i < size; i++) + { +#ifdef FIXED_POINT + opus_int16 val = a[i]; +#else + opus_int16 val = FLOAT2INT16(a[i]); +#endif + if (abs(val - b[i]) > tolerance) + return 1; + } + return 0; +} + +int assert_is_equal_short( + const opus_int16 *a, const opus_int16 *b, int size, opus_int16 tolerance) +{ + int i; + for (i = 0; i < size; i++) + if (abs(a[i] - b[i]) > tolerance) + return 1; + return 0; +} + +void test_simple_matrix(void) +{ + const MappingMatrix simple_matrix_params = {4, 3, 0}; + const opus_int16 simple_matrix_data[SIMPLE_MATRIX_SIZE] = {0, 32767, 0, 0, 32767, 0, 0, 0, 0, 0, 0, 32767}; + const opus_int16 input_int16[SIMPLE_MATRIX_INPUT_SIZE] = { + 32767, 0, -32768, 29491, -3277, -29491, 26214, -6554, -26214, 22938, -9830, + -22938, 19661, -13107, -19661, 16384, -16384, -16384, 13107, -19661, -13107, + 9830, -22938, -9830, 6554, -26214, -6554, 3277, -29491, -3277}; + const opus_int16 expected_output_int16[SIMPLE_MATRIX_OUTPUT_SIZE] = { + 0, 32767, 0, -32768, -3277, 29491, 0, -29491, -6554, 26214, 0, -26214, + -9830, 22938, 0, -22938, -13107, 19661, 0, -19661, -16384, 16384, 0, -16384, + -19661, 13107, 0, -13107, -22938, 9830, 0, -9830, -26214, 6554, 0, -6554, + -29491, 3277, 0, -3277}; + + int i, ret; + opus_int32 simple_matrix_size; + opus_val16 *input_val16; + opus_val16 *output_val16; + opus_int16 *output_int16; + MappingMatrix *simple_matrix; + + /* Allocate input/output buffers. */ + input_val16 = (opus_val16 *)opus_alloc(sizeof(opus_val16) * SIMPLE_MATRIX_INPUT_SIZE); + output_int16 = (opus_int16 *)opus_alloc(sizeof(opus_int16) * SIMPLE_MATRIX_OUTPUT_SIZE); + output_val16 = (opus_val16 *)opus_alloc(sizeof(opus_val16) * SIMPLE_MATRIX_OUTPUT_SIZE); + + /* Initialize matrix */ + simple_matrix_size = mapping_matrix_get_size(simple_matrix_params.rows, + simple_matrix_params.cols); + if (!simple_matrix_size) + test_failed(); + + simple_matrix = (MappingMatrix *)opus_alloc(simple_matrix_size); + mapping_matrix_init(simple_matrix, simple_matrix_params.rows, + simple_matrix_params.cols, simple_matrix_params.gain, simple_matrix_data, + sizeof(simple_matrix_data)); + + /* Copy inputs. */ + for (i = 0; i < SIMPLE_MATRIX_INPUT_SIZE; i++) + { +#ifdef FIXED_POINT + input_val16[i] = input_int16[i]; +#else + input_val16[i] = (1/32768.f)*input_int16[i]; +#endif + } + + /* _in_short */ + for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++) + output_val16[i] = 0; + for (i = 0; i < simple_matrix->rows; i++) + { + mapping_matrix_multiply_channel_in_short(simple_matrix, + input_int16, simple_matrix->cols, &output_val16[i], i, + simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE); + } + ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE); + if (ret) + test_failed(); + + /* _out_short */ + for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++) + output_int16[i] = 0; + for (i = 0; i < simple_matrix->cols; i++) + { + mapping_matrix_multiply_channel_out_short(simple_matrix, + &input_val16[i], i, simple_matrix->cols, output_int16, + simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE); + } + ret = assert_is_equal_short(output_int16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE); + if (ret) + test_failed(); + +#if !defined(DISABLE_FLOAT_API) && !defined(FIXED_POINT) + /* _in_float */ + for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++) + output_val16[i] = 0; + for (i = 0; i < simple_matrix->rows; i++) + { + mapping_matrix_multiply_channel_in_float(simple_matrix, + input_val16, simple_matrix->cols, &output_val16[i], i, + simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE); + } + ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE); + if (ret) + test_failed(); + + /* _out_float */ + for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++) + output_val16[i] = 0; + for (i = 0; i < simple_matrix->cols; i++) + { + mapping_matrix_multiply_channel_out_float(simple_matrix, + &input_val16[i], i, simple_matrix->cols, output_val16, + simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE); + } + ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE); + if (ret) + test_failed(); +#endif + + opus_free(input_val16); + opus_free(output_int16); + opus_free(output_val16); + opus_free(simple_matrix); +} + +void test_creation_arguments(const int channels, const int mapping_family) +{ + int streams; + int coupled_streams; + int enc_error; + int dec_error; + int ret; + OpusProjectionEncoder *st_enc = NULL; + OpusProjectionDecoder *st_dec = NULL; + + const opus_int32 Fs = 48000; + const int application = OPUS_APPLICATION_AUDIO; + + int order_plus_one = (int)floor(sqrt((float)channels)); + int nondiegetic_channels = channels - order_plus_one * order_plus_one; + + int is_channels_valid = 0; + int is_projection_valid = 0; + + st_enc = opus_projection_ambisonics_encoder_create(Fs, channels, + mapping_family, &streams, &coupled_streams, application, &enc_error); + if (st_enc != NULL) + { + opus_int32 matrix_size; + unsigned char *matrix; + + ret = opus_projection_encoder_ctl(st_enc, + OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, &matrix_size); + if (ret != OPUS_OK || !matrix_size) + test_failed(); + + matrix = (unsigned char *)opus_alloc(matrix_size); + ret = opus_projection_encoder_ctl(st_enc, + OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, matrix, matrix_size); + + opus_projection_encoder_destroy(st_enc); + + st_dec = opus_projection_decoder_create(Fs, channels, streams, + coupled_streams, matrix, matrix_size, &dec_error); + if (st_dec != NULL) + { + opus_projection_decoder_destroy(st_dec); + } + opus_free(matrix); + } + + is_channels_valid = (order_plus_one >= 2 && order_plus_one <= 4) && + (nondiegetic_channels == 0 || nondiegetic_channels == 2); + is_projection_valid = (enc_error == OPUS_OK && dec_error == OPUS_OK); + if (is_channels_valid ^ is_projection_valid) + { + fprintf(stderr, "Channels: %d, Family: %d\n", channels, mapping_family); + fprintf(stderr, "Order+1: %d, Non-diegetic Channels: %d\n", + order_plus_one, nondiegetic_channels); + fprintf(stderr, "Streams: %d, Coupled Streams: %d\n", + streams, coupled_streams); + test_failed(); + } +} + +void generate_music(short *buf, opus_int32 len, opus_int32 channels) +{ + opus_int32 i,j,k; + opus_int32 *a,*b,*c,*d; + a = (opus_int32 *)malloc(sizeof(opus_int32) * channels); + b = (opus_int32 *)malloc(sizeof(opus_int32) * channels); + c = (opus_int32 *)malloc(sizeof(opus_int32) * channels); + d = (opus_int32 *)malloc(sizeof(opus_int32) * channels); + memset(a, 0, sizeof(opus_int32) * channels); + memset(b, 0, sizeof(opus_int32) * channels); + memset(c, 0, sizeof(opus_int32) * channels); + memset(d, 0, sizeof(opus_int32) * channels); + j=0; + + for(i=0;i>12)^((j>>10|j>>12)&26&j>>7)))&128)+128)<<15; + r=fast_rand();v+=r&65535;v-=r>>16; + b[k]=v-a[k]+((b[k]*61+32)>>6);a[k]=v; + c[k]=(30*(c[k]+b[k]+d[k])+32)>>6;d[k]=b[k]; + v=(c[k]+128)>>8; + buf[i*channels+k]=v>32767?32767:(v<-32768?-32768:v); + if(i%6==0)j++; + } + } + + free(a); + free(b); + free(c); + free(d); +} + +void test_encode_decode(opus_int32 bitrate, opus_int32 channels, + const int mapping_family) +{ + const opus_int32 Fs = 48000; + const int application = OPUS_APPLICATION_AUDIO; + + OpusProjectionEncoder *st_enc; + OpusProjectionDecoder *st_dec; + int streams; + int coupled; + int error; + short *buffer_in; + short *buffer_out; + unsigned char data[MAX_DATA_BYTES] = { 0 }; + int len; + int out_samples; + opus_int32 matrix_size = 0; + unsigned char *matrix = NULL; + + buffer_in = (short *)malloc(sizeof(short) * BUFFER_SIZE * channels); + buffer_out = (short *)malloc(sizeof(short) * BUFFER_SIZE * channels); + + st_enc = opus_projection_ambisonics_encoder_create(Fs, channels, + mapping_family, &streams, &coupled, application, &error); + if (error != OPUS_OK) { + fprintf(stderr, + "Couldn\'t create encoder with %d channels and mapping family %d.\n", + channels, mapping_family); + free(buffer_in); + free(buffer_out); + test_failed(); + } + + error = opus_projection_encoder_ctl(st_enc, + OPUS_SET_BITRATE(bitrate * 1000 * (streams + coupled))); + if (error != OPUS_OK) + { + goto bad_cleanup; + } + + error = opus_projection_encoder_ctl(st_enc, + OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, &matrix_size); + if (error != OPUS_OK || !matrix_size) + { + goto bad_cleanup; + } + + matrix = (unsigned char *)opus_alloc(matrix_size); + error = opus_projection_encoder_ctl(st_enc, + OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, matrix, matrix_size); + + st_dec = opus_projection_decoder_create(Fs, channels, streams, coupled, + matrix, matrix_size, &error); + opus_free(matrix); + + if (error != OPUS_OK) { + fprintf(stderr, + "Couldn\'t create decoder with %d channels, %d streams " + "and %d coupled streams.\n", channels, streams, coupled); + goto bad_cleanup; + } + + generate_music(buffer_in, BUFFER_SIZE, channels); + + len = opus_projection_encode( + st_enc, buffer_in, BUFFER_SIZE, data, MAX_DATA_BYTES); + if(len<0 || len>MAX_DATA_BYTES) { + fprintf(stderr,"opus_encode() returned %d\n", len); + goto bad_cleanup; + } + + out_samples = opus_projection_decode( + st_dec, data, len, buffer_out, MAX_FRAME_SAMPLES, 0); + if(out_samples!=BUFFER_SIZE) { + fprintf(stderr,"opus_decode() returned %d\n", out_samples); + goto bad_cleanup; + } + + opus_projection_decoder_destroy(st_dec); + opus_projection_encoder_destroy(st_enc); + free(buffer_in); + free(buffer_out); + return; +bad_cleanup: + free(buffer_in); + free(buffer_out); + test_failed(); +} + +int main(int _argc, char **_argv) +{ + unsigned int i; + + (void)_argc; + (void)_argv; + + /* Test simple matrix multiplication routines. */ + test_simple_matrix(); + + /* Test full range of channels in creation arguments. */ + for (i = 0; i < 255; i++) + test_creation_arguments(i, 3); + + /* Test encode/decode pipeline. */ + test_encode_decode(64 * 18, 18, 3); + + fprintf(stderr, "All projection tests passed.\n"); + return 0; +} + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/training/rnn_dump.py b/native/opennow-streamer/vendor/audiopus-sys/opus/training/rnn_dump.py new file mode 100755 index 000000000..c312088e8 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/training/rnn_dump.py @@ -0,0 +1,66 @@ +#!/usr/bin/python + +from __future__ import print_function + +from keras.models import Sequential +from keras.models import Model +from keras.layers import Input +from keras.layers import Dense +from keras.layers import LSTM +from keras.layers import GRU +from keras.models import load_model +from keras import backend as K +import sys + +import numpy as np + +def printVector(f, vector, name): + v = np.reshape(vector, (-1)); + #print('static const float ', name, '[', len(v), '] = \n', file=f) + f.write('static const opus_int8 {}[{}] = {{\n '.format(name, len(v))) + for i in range(0, len(v)): + f.write('{}'.format(max(-128,min(127,int(round(128*v[i])))))) + if (i!=len(v)-1): + f.write(',') + else: + break; + if (i%8==7): + f.write("\n ") + else: + f.write(" ") + #print(v, file=f) + f.write('\n};\n\n') + return; + +def binary_crossentrop2(y_true, y_pred): + return K.mean(2*K.abs(y_true-0.5) * K.binary_crossentropy(y_pred, y_true), axis=-1) + + +#model = load_model(sys.argv[1], custom_objects={'binary_crossentrop2': binary_crossentrop2}) +main_input = Input(shape=(None, 25), name='main_input') +x = Dense(32, activation='tanh')(main_input) +x = GRU(24, activation='tanh', recurrent_activation='sigmoid', return_sequences=True)(x) +x = Dense(2, activation='sigmoid')(x) +model = Model(inputs=main_input, outputs=x) +model.load_weights(sys.argv[1]) + +weights = model.get_weights() + +f = open(sys.argv[2], 'w') + +f.write('/*This file is automatically generated from a Keras model*/\n\n') +f.write('#ifdef HAVE_CONFIG_H\n#include "config.h"\n#endif\n\n#include "mlp.h"\n\n') + +printVector(f, weights[0], 'layer0_weights') +printVector(f, weights[1], 'layer0_bias') +printVector(f, weights[2], 'layer1_weights') +printVector(f, weights[3], 'layer1_recur_weights') +printVector(f, weights[4], 'layer1_bias') +printVector(f, weights[5], 'layer2_weights') +printVector(f, weights[6], 'layer2_bias') + +f.write('const DenseLayer layer0 = {\n layer0_bias,\n layer0_weights,\n 25, 32, 0\n};\n\n') +f.write('const GRULayer layer1 = {\n layer1_bias,\n layer1_weights,\n layer1_recur_weights,\n 32, 24\n};\n\n') +f.write('const DenseLayer layer2 = {\n layer2_bias,\n layer2_weights,\n 24, 2, 1\n};\n\n') + +f.close() diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/training/rnn_train.py b/native/opennow-streamer/vendor/audiopus-sys/opus/training/rnn_train.py new file mode 100755 index 000000000..29bcb0346 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/training/rnn_train.py @@ -0,0 +1,177 @@ +#!/usr/bin/python3 + +from __future__ import print_function + +from keras.models import Sequential +from keras.models import Model +from keras.layers import Input +from keras.layers import Dense +from keras.layers import LSTM +from keras.layers import GRU +from keras.layers import CuDNNGRU +from keras.layers import SimpleRNN +from keras.layers import Dropout +from keras import losses +import h5py +from keras.optimizers import Adam + +from keras.constraints import Constraint +from keras import backend as K +import numpy as np + +import tensorflow as tf +from keras.backend.tensorflow_backend import set_session +config = tf.ConfigProto() +config.gpu_options.per_process_gpu_memory_fraction = 0.44 +set_session(tf.Session(config=config)) + +def binary_crossentrop2(y_true, y_pred): + return K.mean(2*K.abs(y_true-0.5) * K.binary_crossentropy(y_true, y_pred), axis=-1) + +def binary_accuracy2(y_true, y_pred): + return K.mean(K.cast(K.equal(y_true, K.round(y_pred)), 'float32') + K.cast(K.equal(y_true, 0.5), 'float32'), axis=-1) + +def quant_model(model): + weights = model.get_weights() + for k in range(len(weights)): + weights[k] = np.maximum(-128, np.minimum(127, np.round(128*weights[k])*0.0078125)) + model.set_weights(weights) + +class WeightClip(Constraint): + '''Clips the weights incident to each hidden unit to be inside a range + ''' + def __init__(self, c=2): + self.c = c + + def __call__(self, p): + return K.clip(p, -self.c, self.c) + + def get_config(self): + return {'name': self.__class__.__name__, + 'c': self.c} + +reg = 0.000001 +constraint = WeightClip(.998) + +print('Build model...') + +main_input = Input(shape=(None, 25), name='main_input') +x = Dense(32, activation='tanh', kernel_constraint=constraint, bias_constraint=constraint)(main_input) +#x = CuDNNGRU(24, return_sequences=True, kernel_constraint=constraint, recurrent_constraint=constraint, bias_constraint=constraint)(x) +x = GRU(24, recurrent_activation='sigmoid', activation='tanh', return_sequences=True, kernel_constraint=constraint, recurrent_constraint=constraint, bias_constraint=constraint)(x) +x = Dense(2, activation='sigmoid', kernel_constraint=constraint, bias_constraint=constraint)(x) +model = Model(inputs=main_input, outputs=x) + +batch_size = 2048 + +print('Loading data...') +with h5py.File('features10b.h5', 'r') as hf: + all_data = hf['data'][:] +print('done.') + +window_size = 1500 + +nb_sequences = len(all_data)//window_size +print(nb_sequences, ' sequences') +x_train = all_data[:nb_sequences*window_size, :-2] +x_train = np.reshape(x_train, (nb_sequences, window_size, 25)) + +y_train = np.copy(all_data[:nb_sequences*window_size, -2:]) +y_train = np.reshape(y_train, (nb_sequences, window_size, 2)) + +print("Marking ignores") +for s in y_train: + for e in s: + if (e[1] >= 1): + break + e[0] = 0.5 + +all_data = 0; +x_train = x_train.astype('float32') +y_train = y_train.astype('float32') + +print(len(x_train), 'train sequences. x shape =', x_train.shape, 'y shape = ', y_train.shape) + +model.load_weights('newweights10a1b_ep206.hdf5') + +#weights = model.get_weights() +#for k in range(len(weights)): +# weights[k] = np.round(128*weights[k])*0.0078125 +#model.set_weights(weights) + +# try using different optimizers and different optimizer configs +model.compile(loss=binary_crossentrop2, + optimizer=Adam(0.0001), + metrics=[binary_accuracy2]) + +print('Train...') +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=10, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep10.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=50, initial_epoch=10) +model.save("newweights10a1c_ep50.hdf5") + +model.compile(loss=binary_crossentrop2, + optimizer=Adam(0.0001), + metrics=[binary_accuracy2]) + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=100, initial_epoch=50) +model.save("newweights10a1c_ep100.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=150, initial_epoch=100) +model.save("newweights10a1c_ep150.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=200, initial_epoch=150) +model.save("newweights10a1c_ep200.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=201, initial_epoch=200) +model.save("newweights10a1c_ep201.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=202, initial_epoch=201, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep202.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=203, initial_epoch=202, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep203.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=204, initial_epoch=203, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep204.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=205, initial_epoch=204, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep205.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=206, initial_epoch=205, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep206.hdf5") + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/training/txt2hdf5.py b/native/opennow-streamer/vendor/audiopus-sys/opus/training/txt2hdf5.py new file mode 100755 index 000000000..9c602877e --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/training/txt2hdf5.py @@ -0,0 +1,12 @@ +#!/usr/bin/python + +from __future__ import print_function + +import numpy as np +import h5py +import sys + +data = np.loadtxt(sys.argv[1], dtype='float32') +h5f = h5py.File(sys.argv[2], 'w'); +h5f.create_dataset('data', data=data) +h5f.close() diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/update_version b/native/opennow-streamer/vendor/audiopus-sys/opus/update_version new file mode 100755 index 000000000..a9999918d --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/update_version @@ -0,0 +1,65 @@ +#!/bin/bash + +# Creates and updates the package_version information used by configure.ac +# (or other makefiles). When run inside a git repository it will use the +# version information that can be queried from it unless AUTO_UPDATE is set +# to 'no'. If no version is currently known it will be set to 'unknown'. +# +# If called with the argument 'release', the PACKAGE_VERSION will be updated +# even if AUTO_UPDATE=no, but the value of AUTO_UPDATE shall be preserved. +# This is used to force a version update whenever `make dist` is run. +# +# The exit status is 1 if package_version is not modified, else 0 is returned. +# +# This script should NOT be included in distributed tarballs, because if a +# parent directory contains a git repository we do not want to accidentally +# retrieve the version information from it instead. Tarballs should ship +# with only the package_version file. +# +# Ron , 2012. + +SRCDIR=$(dirname $0) + +if [ -e "$SRCDIR/package_version" ]; then + . "$SRCDIR/package_version" +fi + +if [ "$AUTO_UPDATE" = no ]; then + [ "$1" = release ] || exit 1 +else + AUTO_UPDATE=yes +fi + +# We run `git status` before describe here to ensure that we don't get a false +# -dirty from files that have been touched but are not actually altered in the +# working dir. +GIT_VERSION=$(cd "$SRCDIR" && git status > /dev/null 2>&1 \ + && git describe --tags --match 'v*' --dirty 2> /dev/null) +GIT_VERSION=${GIT_VERSION#v} + +if [ -n "$GIT_VERSION" ]; then + + [ "$GIT_VERSION" != "$PACKAGE_VERSION" ] || exit 1 + PACKAGE_VERSION="$GIT_VERSION" + +elif [ -z "$PACKAGE_VERSION" ]; then + # No current package_version and no git ... + # We really shouldn't ever get here, because this script should only be + # included in the git repository, and should usually be export-ignored. + PACKAGE_VERSION="unknown" +else + exit 1 +fi + +cat > "$SRCDIR/package_version" <<-EOF + # Automatically generated by update_version. + # This file may be sourced into a shell script or makefile. + + # Set this to 'no' if you do not wish the version information + # to be checked and updated for every build. Most people will + # never want to change this, it is an option for developers + # making frequent changes that they know will not be released. + AUTO_UPDATE=$AUTO_UPDATE + + PACKAGE_VERSION="$PACKAGE_VERSION" +EOF diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/win32/.gitignore b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/.gitignore new file mode 100644 index 000000000..c17feab73 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/.gitignore @@ -0,0 +1,26 @@ +# Visual Studio ignores +[Dd]ebug/ +[Dd]ebugDLL/ +[Dd]ebugDLL_fixed/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleaseDLL/ +[Rr]eleaseDLL_fixed/ +[Rr]eleases/ +*.manifest +*.lastbuildstate +*.lib +*.log +*.idb +*.ipdb +*.ilk +*.iobj +*.obj +*.opensdf +*.pdb +*.sdf +*.suo +*.tlog +*.vcxproj.user +*.vc.db +*.vc.opendb diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/common.props b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/common.props new file mode 100644 index 000000000..f6e920b63 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/common.props @@ -0,0 +1,82 @@ + + + + + + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + Unicode + + + true + true + false + + + false + false + true + + + + Level3 + false + false + ..\..;..\..\include;..\..\silk;..\..\celt;..\..\win32;%(AdditionalIncludeDirectories) + HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + false + + + Console + + + true + Console + + + + + Guard + ProgramDatabase + NoExtensions + false + true + false + Disabled + false + false + Disabled + MultiThreadedDebug + MultiThreadedDebugDLL + true + false + + + true + + + + + false + None + true + true + false + Speed + Fast + Precise + true + true + true + MaxSpeed + MultiThreaded + MultiThreadedDLL + 16Bytes + + + false + + + + \ No newline at end of file diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/opus.sln b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/opus.sln new file mode 100644 index 000000000..7b678e7f1 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/opus.sln @@ -0,0 +1,168 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opus", "opus.vcxproj", "{219EC965-228A-1824-174D-96449D05F88A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opus_demo", "opus_demo.vcxproj", "{016C739D-6389-43BF-8D88-24B2BF6F620F}" + ProjectSection(ProjectDependencies) = postProject + {219EC965-228A-1824-174D-96449D05F88A} = {219EC965-228A-1824-174D-96449D05F88A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_opus_api", "test_opus_api.vcxproj", "{1D257A17-D254-42E5-82D6-1C87A6EC775A}" + ProjectSection(ProjectDependencies) = postProject + {219EC965-228A-1824-174D-96449D05F88A} = {219EC965-228A-1824-174D-96449D05F88A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_opus_decode", "test_opus_decode.vcxproj", "{8578322A-1883-486B-B6FA-E0094B65C9F2}" + ProjectSection(ProjectDependencies) = postProject + {219EC965-228A-1824-174D-96449D05F88A} = {219EC965-228A-1824-174D-96449D05F88A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_opus_encode", "test_opus_encode.vcxproj", "{84DAA768-1A38-4312-BB61-4C78BB59E5B8}" + ProjectSection(ProjectDependencies) = postProject + {219EC965-228A-1824-174D-96449D05F88A} = {219EC965-228A-1824-174D-96449D05F88A} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + DebugDLL_fixed|Win32 = DebugDLL_fixed|Win32 + DebugDLL_fixed|x64 = DebugDLL_fixed|x64 + DebugDLL|Win32 = DebugDLL|Win32 + DebugDLL|x64 = DebugDLL|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + ReleaseDLL_fixed|Win32 = ReleaseDLL_fixed|Win32 + ReleaseDLL_fixed|x64 = ReleaseDLL_fixed|x64 + ReleaseDLL|Win32 = ReleaseDLL|Win32 + ReleaseDLL|x64 = ReleaseDLL|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {219EC965-228A-1824-174D-96449D05F88A}.Debug|Win32.ActiveCfg = Debug|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.Debug|Win32.Build.0 = Debug|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.Debug|x64.ActiveCfg = Debug|x64 + {219EC965-228A-1824-174D-96449D05F88A}.Debug|x64.Build.0 = Debug|x64 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL_fixed|Win32.ActiveCfg = DebugDLL_fixed|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL_fixed|Win32.Build.0 = DebugDLL_fixed|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL_fixed|x64.ActiveCfg = DebugDLL_fixed|x64 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL_fixed|x64.Build.0 = DebugDLL_fixed|x64 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {219EC965-228A-1824-174D-96449D05F88A}.Release|Win32.ActiveCfg = Release|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.Release|Win32.Build.0 = Release|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.Release|x64.ActiveCfg = Release|x64 + {219EC965-228A-1824-174D-96449D05F88A}.Release|x64.Build.0 = Release|x64 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL_fixed|Win32.ActiveCfg = ReleaseDLL_fixed|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL_fixed|Win32.Build.0 = ReleaseDLL_fixed|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL_fixed|x64.ActiveCfg = ReleaseDLL_fixed|x64 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL_fixed|x64.Build.0 = ReleaseDLL_fixed|x64 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Debug|Win32.ActiveCfg = Debug|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Debug|Win32.Build.0 = Debug|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Debug|x64.ActiveCfg = Debug|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Debug|x64.Build.0 = Debug|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL_fixed|Win32.ActiveCfg = DebugDLL_fixed|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL_fixed|Win32.Build.0 = DebugDLL_fixed|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL_fixed|x64.ActiveCfg = DebugDLL_fixed|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL_fixed|x64.Build.0 = DebugDLL_fixed|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Release|Win32.ActiveCfg = Release|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Release|Win32.Build.0 = Release|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Release|x64.ActiveCfg = Release|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Release|x64.Build.0 = Release|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL_fixed|Win32.ActiveCfg = ReleaseDLL_fixed|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL_fixed|Win32.Build.0 = ReleaseDLL_fixed|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL_fixed|x64.ActiveCfg = ReleaseDLL_fixed|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL_fixed|x64.Build.0 = ReleaseDLL_fixed|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Debug|Win32.ActiveCfg = Debug|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Debug|Win32.Build.0 = Debug|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Debug|x64.ActiveCfg = Debug|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Debug|x64.Build.0 = Debug|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL_fixed|Win32.ActiveCfg = DebugDLL_fixed|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL_fixed|Win32.Build.0 = DebugDLL_fixed|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL_fixed|x64.ActiveCfg = DebugDLL_fixed|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL_fixed|x64.Build.0 = DebugDLL_fixed|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Release|Win32.ActiveCfg = Release|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Release|Win32.Build.0 = Release|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Release|x64.ActiveCfg = Release|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Release|x64.Build.0 = Release|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL_fixed|Win32.ActiveCfg = ReleaseDLL_fixed|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL_fixed|Win32.Build.0 = ReleaseDLL_fixed|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL_fixed|x64.ActiveCfg = ReleaseDLL_fixed|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL_fixed|x64.Build.0 = ReleaseDLL_fixed|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Debug|Win32.ActiveCfg = Debug|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Debug|Win32.Build.0 = Debug|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Debug|x64.ActiveCfg = Debug|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Debug|x64.Build.0 = Debug|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL_fixed|Win32.ActiveCfg = DebugDLL_fixed|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL_fixed|Win32.Build.0 = DebugDLL_fixed|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL_fixed|x64.ActiveCfg = DebugDLL_fixed|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL_fixed|x64.Build.0 = DebugDLL_fixed|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Release|Win32.ActiveCfg = Release|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Release|Win32.Build.0 = Release|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Release|x64.ActiveCfg = Release|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Release|x64.Build.0 = Release|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL_fixed|Win32.ActiveCfg = ReleaseDLL_fixed|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL_fixed|Win32.Build.0 = ReleaseDLL_fixed|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL_fixed|x64.ActiveCfg = ReleaseDLL_fixed|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL_fixed|x64.Build.0 = ReleaseDLL_fixed|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Debug|Win32.ActiveCfg = Debug|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Debug|Win32.Build.0 = Debug|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Debug|x64.ActiveCfg = Debug|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Debug|x64.Build.0 = Debug|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL_fixed|Win32.ActiveCfg = DebugDLL_fixed|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL_fixed|Win32.Build.0 = DebugDLL_fixed|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL_fixed|x64.ActiveCfg = DebugDLL_fixed|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL_fixed|x64.Build.0 = DebugDLL_fixed|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Release|Win32.ActiveCfg = Release|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Release|Win32.Build.0 = Release|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Release|x64.ActiveCfg = Release|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Release|x64.Build.0 = Release|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL_fixed|Win32.ActiveCfg = ReleaseDLL_fixed|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL_fixed|Win32.Build.0 = ReleaseDLL_fixed|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL_fixed|x64.ActiveCfg = ReleaseDLL_fixed|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL_fixed|x64.Build.0 = ReleaseDLL_fixed|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/opus.vcxproj b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/opus.vcxproj new file mode 100644 index 000000000..34b1233c9 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/opus.vcxproj @@ -0,0 +1,399 @@ + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + Win32Proj + opus + {219EC965-228A-1824-174D-96449D05F88A} + + + + StaticLibrary + v140 + + + DynamicLibrary + v140 + + + DynamicLibrary + v140 + + + StaticLibrary + v140 + + + DynamicLibrary + v140 + + + DynamicLibrary + v140 + + + StaticLibrary + v140 + + + DynamicLibrary + v140 + + + DynamicLibrary + v140 + + + StaticLibrary + v140 + + + DynamicLibrary + v140 + + + DynamicLibrary + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\silk\fixed;..\..\silk\float;%(AdditionalIncludeDirectories) + DLL_EXPORT;%(PreprocessorDefinitions) + FIXED_POINT;%(PreprocessorDefinitions) + /arch:IA32 %(AdditionalOptions) + + + /ignore:4221 %(AdditionalOptions) + + + "$(ProjectDir)..\..\win32\genversion.bat" "$(ProjectDir)..\..\win32\version.h" PACKAGE_VERSION + Generating version.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4244;%(DisableSpecificWarnings) + + + + + + + + + + + + + + + false + + + false + + + true + + + + + + + true + + + true + + + false + + + + + + + + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/opus.vcxproj.filters b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/opus.vcxproj.filters new file mode 100644 index 000000000..8c61d6a0a --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/opus.vcxproj.filters @@ -0,0 +1,585 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/opus_demo.vcxproj b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/opus_demo.vcxproj new file mode 100644 index 000000000..f4344e532 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/opus_demo.vcxproj @@ -0,0 +1,171 @@ + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + + {219ec965-228a-1824-174d-96449d05f88a} + + + + + + + {016C739D-6389-43BF-8D88-24B2BF6F620F} + Win32Proj + opus_demo + + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/opus_demo.vcxproj.filters b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/opus_demo.vcxproj.filters new file mode 100644 index 000000000..2eb113ac8 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/opus_demo.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_api.vcxproj b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_api.vcxproj new file mode 100644 index 000000000..7cae131ba --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_api.vcxproj @@ -0,0 +1,171 @@ + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + {219ec965-228a-1824-174d-96449d05f88a} + + + + {1D257A17-D254-42E5-82D6-1C87A6EC775A} + Win32Proj + test_opus_api + + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_api.vcxproj.filters b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_api.vcxproj.filters new file mode 100644 index 000000000..383d19f71 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_api.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + \ No newline at end of file diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_decode.vcxproj b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_decode.vcxproj new file mode 100644 index 000000000..df01dca1b --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_decode.vcxproj @@ -0,0 +1,171 @@ + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + {219ec965-228a-1824-174d-96449d05f88a} + + + + {8578322A-1883-486B-B6FA-E0094B65C9F2} + Win32Proj + test_opus_api + + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_decode.vcxproj.filters b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_decode.vcxproj.filters new file mode 100644 index 000000000..3036a4e70 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_decode.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4a0dd677-931f-4728-afe5-b761149fc7eb} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + \ No newline at end of file diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_encode.vcxproj b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_encode.vcxproj new file mode 100644 index 000000000..405efee99 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_encode.vcxproj @@ -0,0 +1,172 @@ + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + {219ec965-228a-1824-174d-96449d05f88a} + + + + {84DAA768-1A38-4312-BB61-4C78BB59E5B8} + Win32Proj + test_opus_api + + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_encode.vcxproj.filters b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_encode.vcxproj.filters new file mode 100644 index 000000000..4ed3bb9e7 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/VS2015/test_opus_encode.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + {546c8d9a-103e-4f78-972b-b44e8d3c8aba} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/native/opennow-streamer/vendor/audiopus-sys/opus/win32/genversion.bat b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/genversion.bat new file mode 100644 index 000000000..1def7460b --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/opus/win32/genversion.bat @@ -0,0 +1,37 @@ +@echo off + +setlocal enableextensions enabledelayedexpansion + +for /f %%v in ('cd "%~dp0.." ^&^& git status ^>NUL 2^>NUL ^&^& git describe --tags --match "v*" --dirty 2^>NUL') do set version=%%v + +if not "%version%"=="" set version=!version:~1! && goto :gotversion + +if exist "%~dp0..\package_version" goto :getversion + +echo Git cannot be found, nor can package_version. Generating unknown version. + +set version=unknown + +goto :gotversion + +:getversion + +for /f "delims== tokens=2" %%v in (%~dps0..\package_version) do set version=%%v +set version=!version:"=! + +:gotversion + +set version=!version: =! +set version_out=#define %~2 "%version%" + +echo %version_out%> "%~1_temp" + +echo n | comp "%~1_temp" "%~1" > NUL 2> NUL + +if not errorlevel 1 goto exit + +copy /y "%~1_temp" "%~1" + +:exit + +del "%~1_temp" diff --git a/native/opennow-streamer/vendor/audiopus-sys/src/lib.rs b/native/opennow-streamer/vendor/audiopus-sys/src/lib.rs new file mode 100644 index 000000000..8f145ed38 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/src/lib.rs @@ -0,0 +1,1251 @@ +/* automatically generated by rust-bindgen 0.58.1 */ + +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + + +pub const OPUS_OK: i32 = 0; +pub const OPUS_BAD_ARG: i32 = -1; +pub const OPUS_BUFFER_TOO_SMALL: i32 = -2; +pub const OPUS_INTERNAL_ERROR: i32 = -3; +pub const OPUS_INVALID_PACKET: i32 = -4; +pub const OPUS_UNIMPLEMENTED: i32 = -5; +pub const OPUS_INVALID_STATE: i32 = -6; +pub const OPUS_ALLOC_FAIL: i32 = -7; +pub const OPUS_SET_APPLICATION_REQUEST: i32 = 4000; +pub const OPUS_GET_APPLICATION_REQUEST: i32 = 4001; +pub const OPUS_SET_BITRATE_REQUEST: i32 = 4002; +pub const OPUS_GET_BITRATE_REQUEST: i32 = 4003; +pub const OPUS_SET_MAX_BANDWIDTH_REQUEST: i32 = 4004; +pub const OPUS_GET_MAX_BANDWIDTH_REQUEST: i32 = 4005; +pub const OPUS_SET_VBR_REQUEST: i32 = 4006; +pub const OPUS_GET_VBR_REQUEST: i32 = 4007; +pub const OPUS_SET_BANDWIDTH_REQUEST: i32 = 4008; +pub const OPUS_GET_BANDWIDTH_REQUEST: i32 = 4009; +pub const OPUS_SET_COMPLEXITY_REQUEST: i32 = 4010; +pub const OPUS_GET_COMPLEXITY_REQUEST: i32 = 4011; +pub const OPUS_SET_INBAND_FEC_REQUEST: i32 = 4012; +pub const OPUS_GET_INBAND_FEC_REQUEST: i32 = 4013; +pub const OPUS_SET_PACKET_LOSS_PERC_REQUEST: i32 = 4014; +pub const OPUS_GET_PACKET_LOSS_PERC_REQUEST: i32 = 4015; +pub const OPUS_SET_DTX_REQUEST: i32 = 4016; +pub const OPUS_GET_DTX_REQUEST: i32 = 4017; +pub const OPUS_SET_VBR_CONSTRAINT_REQUEST: i32 = 4020; +pub const OPUS_GET_VBR_CONSTRAINT_REQUEST: i32 = 4021; +pub const OPUS_SET_FORCE_CHANNELS_REQUEST: i32 = 4022; +pub const OPUS_GET_FORCE_CHANNELS_REQUEST: i32 = 4023; +pub const OPUS_SET_SIGNAL_REQUEST: i32 = 4024; +pub const OPUS_GET_SIGNAL_REQUEST: i32 = 4025; +pub const OPUS_GET_LOOKAHEAD_REQUEST: i32 = 4027; +pub const OPUS_GET_SAMPLE_RATE_REQUEST: i32 = 4029; +pub const OPUS_GET_FINAL_RANGE_REQUEST: i32 = 4031; +pub const OPUS_GET_PITCH_REQUEST: i32 = 4033; +pub const OPUS_SET_GAIN_REQUEST: i32 = 4034; +pub const OPUS_GET_GAIN_REQUEST: i32 = 4045; +pub const OPUS_SET_LSB_DEPTH_REQUEST: i32 = 4036; +pub const OPUS_GET_LSB_DEPTH_REQUEST: i32 = 4037; +pub const OPUS_GET_LAST_PACKET_DURATION_REQUEST: i32 = 4039; +pub const OPUS_SET_EXPERT_FRAME_DURATION_REQUEST: i32 = 4040; +pub const OPUS_GET_EXPERT_FRAME_DURATION_REQUEST: i32 = 4041; +pub const OPUS_SET_PREDICTION_DISABLED_REQUEST: i32 = 4042; +pub const OPUS_GET_PREDICTION_DISABLED_REQUEST: i32 = 4043; +pub const OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: i32 = 4046; +pub const OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: i32 = 4047; +pub const OPUS_GET_IN_DTX_REQUEST: i32 = 4049; +pub const OPUS_AUTO: i32 = -1000; +pub const OPUS_BITRATE_MAX: i32 = -1; +pub const OPUS_APPLICATION_VOIP: i32 = 2048; +pub const OPUS_APPLICATION_AUDIO: i32 = 2049; +pub const OPUS_APPLICATION_RESTRICTED_LOWDELAY: i32 = 2051; +pub const OPUS_SIGNAL_VOICE: i32 = 3001; +pub const OPUS_SIGNAL_MUSIC: i32 = 3002; +pub const OPUS_BANDWIDTH_NARROWBAND: i32 = 1101; +pub const OPUS_BANDWIDTH_MEDIUMBAND: i32 = 1102; +pub const OPUS_BANDWIDTH_WIDEBAND: i32 = 1103; +pub const OPUS_BANDWIDTH_SUPERWIDEBAND: i32 = 1104; +pub const OPUS_BANDWIDTH_FULLBAND: i32 = 1105; +pub const OPUS_FRAMESIZE_ARG: i32 = 5000; +pub const OPUS_FRAMESIZE_2_5_MS: i32 = 5001; +pub const OPUS_FRAMESIZE_5_MS: i32 = 5002; +pub const OPUS_FRAMESIZE_10_MS: i32 = 5003; +pub const OPUS_FRAMESIZE_20_MS: i32 = 5004; +pub const OPUS_FRAMESIZE_40_MS: i32 = 5005; +pub const OPUS_FRAMESIZE_60_MS: i32 = 5006; +pub const OPUS_FRAMESIZE_80_MS: i32 = 5007; +pub const OPUS_FRAMESIZE_100_MS: i32 = 5008; +pub const OPUS_FRAMESIZE_120_MS: i32 = 5009; +pub const OPUS_RESET_STATE: i32 = 4028; +pub const OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST: i32 = 5120; +pub const OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST: i32 = 5122; +pub type opus_int32 = ::std::os::raw::c_int; +pub type opus_uint32 = ::std::os::raw::c_uint; +pub type opus_int16 = ::std::os::raw::c_short; +pub type opus_uint16 = ::std::os::raw::c_ushort; +extern "C" { + #[doc = " Converts an opus error code into a human readable string."] + #[doc = ""] + #[doc = " @param[in] error int: Error number"] + #[doc = " @returns Error string"] + pub fn opus_strerror(error: ::std::os::raw::c_int) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Gets the libopus version string."] + #[doc = ""] + #[doc = " Applications may look for the substring \"-fixed\" in the version string to"] + #[doc = " determine whether they have a fixed-point or floating-point build at"] + #[doc = " runtime."] + #[doc = ""] + #[doc = " @returns Version string"] + pub fn opus_get_version_string() -> *const ::std::os::raw::c_char; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct OpusEncoder { + _unused: [u8; 0], +} +extern "C" { + #[doc = " Gets the size of an OpusEncoder structure."] + #[doc = " @param[in] channels int: Number of channels."] + #[doc = " This must be 1 or 2."] + #[doc = " @returns The size in bytes."] + pub fn opus_encoder_get_size(channels: ::std::os::raw::c_int) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Allocates and initializes an encoder state."] + #[doc = " There are three coding modes:"] + #[doc = ""] + #[doc = " @ref OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice"] + #[doc = " signals. It enhances the input signal by high-pass filtering and"] + #[doc = " emphasizing formants and harmonics. Optionally it includes in-band"] + #[doc = " forward error correction to protect against packet loss. Use this"] + #[doc = " mode for typical VoIP applications. Because of the enhancement,"] + #[doc = " even at high bitrates the output may sound different from the input."] + #[doc = ""] + #[doc = " @ref OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most"] + #[doc = " non-voice signals like music. Use this mode for music and mixed"] + #[doc = " (music/voice) content, broadcast, and applications requiring less"] + #[doc = " than 15 ms of coding delay."] + #[doc = ""] + #[doc = " @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that"] + #[doc = " disables the speech-optimized mode in exchange for slightly reduced delay."] + #[doc = " This mode can only be set on an newly initialized or freshly reset encoder"] + #[doc = " because it changes the codec delay."] + #[doc = ""] + #[doc = " This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution)."] + #[doc = " @param [in] Fs opus_int32: Sampling rate of input signal (Hz)"] + #[doc = " This must be one of 8000, 12000, 16000,"] + #[doc = " 24000, or 48000."] + #[doc = " @param [in] channels int: Number of channels (1 or 2) in input signal"] + #[doc = " @param [in] application int: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)"] + #[doc = " @param [out] error int*: @ref opus_errorcodes"] + #[doc = " @note Regardless of the sampling rate and number channels selected, the Opus encoder"] + #[doc = " can switch to a lower audio bandwidth or number of channels if the bitrate"] + #[doc = " selected is too low. This also means that it is safe to always use 48 kHz stereo input"] + #[doc = " and let the encoder optimize the encoding."] + pub fn opus_encoder_create( + Fs: opus_int32, + channels: ::std::os::raw::c_int, + application: ::std::os::raw::c_int, + error: *mut ::std::os::raw::c_int, + ) -> *mut OpusEncoder; +} +extern "C" { + #[doc = " Initializes a previously allocated encoder state"] + #[doc = " The memory pointed to by st must be at least the size returned by opus_encoder_get_size()."] + #[doc = " This is intended for applications which use their own allocator instead of malloc."] + #[doc = " @see opus_encoder_create(),opus_encoder_get_size()"] + #[doc = " To reset a previously initialized state, use the #OPUS_RESET_STATE CTL."] + #[doc = " @param [in] st OpusEncoder*: Encoder state"] + #[doc = " @param [in] Fs opus_int32: Sampling rate of input signal (Hz)"] + #[doc = " This must be one of 8000, 12000, 16000,"] + #[doc = " 24000, or 48000."] + #[doc = " @param [in] channels int: Number of channels (1 or 2) in input signal"] + #[doc = " @param [in] application int: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY)"] + #[doc = " @retval #OPUS_OK Success or @ref opus_errorcodes"] + pub fn opus_encoder_init( + st: *mut OpusEncoder, + Fs: opus_int32, + channels: ::std::os::raw::c_int, + application: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Encodes an Opus frame."] + #[doc = " @param [in] st OpusEncoder*: Encoder state"] + #[doc = " @param [in] pcm opus_int16*: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16)"] + #[doc = " @param [in] frame_size int: Number of samples per channel in the"] + #[doc = " input signal."] + #[doc = " This must be an Opus frame size for"] + #[doc = " the encoder's sampling rate."] + #[doc = " For example, at 48 kHz the permitted"] + #[doc = " values are 120, 240, 480, 960, 1920,"] + #[doc = " and 2880."] + #[doc = " Passing in a duration of less than"] + #[doc = " 10 ms (480 samples at 48 kHz) will"] + #[doc = " prevent the encoder from using the LPC"] + #[doc = " or hybrid modes."] + #[doc = " @param [out] data unsigned char*: Output payload."] + #[doc = " This must contain storage for at"] + #[doc = " least \\a max_data_bytes."] + #[doc = " @param [in] max_data_bytes opus_int32: Size of the allocated"] + #[doc = " memory for the output"] + #[doc = " payload. This may be"] + #[doc = " used to impose an upper limit on"] + #[doc = " the instant bitrate, but should"] + #[doc = " not be used as the only bitrate"] + #[doc = " control. Use #OPUS_SET_BITRATE to"] + #[doc = " control the bitrate."] + #[doc = " @returns The length of the encoded packet (in bytes) on success or a"] + #[doc = " negative error code (see @ref opus_errorcodes) on failure."] + pub fn opus_encode( + st: *mut OpusEncoder, + pcm: *const opus_int16, + frame_size: ::std::os::raw::c_int, + data: *mut ::std::os::raw::c_uchar, + max_data_bytes: opus_int32, + ) -> opus_int32; +} +extern "C" { + #[doc = " Encodes an Opus frame from floating point input."] + #[doc = " @param [in] st OpusEncoder*: Encoder state"] + #[doc = " @param [in] pcm float*: Input in float format (interleaved if 2 channels), with a normal range of +/-1.0."] + #[doc = " Samples with a range beyond +/-1.0 are supported but will"] + #[doc = " be clipped by decoders using the integer API and should"] + #[doc = " only be used if it is known that the far end supports"] + #[doc = " extended dynamic range."] + #[doc = " length is frame_size*channels*sizeof(float)"] + #[doc = " @param [in] frame_size int: Number of samples per channel in the"] + #[doc = " input signal."] + #[doc = " This must be an Opus frame size for"] + #[doc = " the encoder's sampling rate."] + #[doc = " For example, at 48 kHz the permitted"] + #[doc = " values are 120, 240, 480, 960, 1920,"] + #[doc = " and 2880."] + #[doc = " Passing in a duration of less than"] + #[doc = " 10 ms (480 samples at 48 kHz) will"] + #[doc = " prevent the encoder from using the LPC"] + #[doc = " or hybrid modes."] + #[doc = " @param [out] data unsigned char*: Output payload."] + #[doc = " This must contain storage for at"] + #[doc = " least \\a max_data_bytes."] + #[doc = " @param [in] max_data_bytes opus_int32: Size of the allocated"] + #[doc = " memory for the output"] + #[doc = " payload. This may be"] + #[doc = " used to impose an upper limit on"] + #[doc = " the instant bitrate, but should"] + #[doc = " not be used as the only bitrate"] + #[doc = " control. Use #OPUS_SET_BITRATE to"] + #[doc = " control the bitrate."] + #[doc = " @returns The length of the encoded packet (in bytes) on success or a"] + #[doc = " negative error code (see @ref opus_errorcodes) on failure."] + pub fn opus_encode_float( + st: *mut OpusEncoder, + pcm: *const f32, + frame_size: ::std::os::raw::c_int, + data: *mut ::std::os::raw::c_uchar, + max_data_bytes: opus_int32, + ) -> opus_int32; +} +extern "C" { + #[doc = " Frees an OpusEncoder allocated by opus_encoder_create()."] + #[doc = " @param[in] st OpusEncoder*: State to be freed."] + pub fn opus_encoder_destroy(st: *mut OpusEncoder); +} +extern "C" { + #[doc = " Perform a CTL function on an Opus encoder."] + #[doc = ""] + #[doc = " Generally the request and subsequent arguments are generated"] + #[doc = " by a convenience macro."] + #[doc = " @param st OpusEncoder*: Encoder state."] + #[doc = " @param request This and all remaining parameters should be replaced by one"] + #[doc = " of the convenience macros in @ref opus_genericctls or"] + #[doc = " @ref opus_encoderctls."] + #[doc = " @see opus_genericctls"] + #[doc = " @see opus_encoderctls"] + pub fn opus_encoder_ctl( + st: *mut OpusEncoder, + request: ::std::os::raw::c_int, + ... + ) -> ::std::os::raw::c_int; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct OpusDecoder { + _unused: [u8; 0], +} +extern "C" { + #[doc = " Gets the size of an OpusDecoder structure."] + #[doc = " @param [in] channels int: Number of channels."] + #[doc = " This must be 1 or 2."] + #[doc = " @returns The size in bytes."] + pub fn opus_decoder_get_size(channels: ::std::os::raw::c_int) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Allocates and initializes a decoder state."] + #[doc = " @param [in] Fs opus_int32: Sample rate to decode at (Hz)."] + #[doc = " This must be one of 8000, 12000, 16000,"] + #[doc = " 24000, or 48000."] + #[doc = " @param [in] channels int: Number of channels (1 or 2) to decode"] + #[doc = " @param [out] error int*: #OPUS_OK Success or @ref opus_errorcodes"] + #[doc = ""] + #[doc = " Internally Opus stores data at 48000 Hz, so that should be the default"] + #[doc = " value for Fs. However, the decoder can efficiently decode to buffers"] + #[doc = " at 8, 12, 16, and 24 kHz so if for some reason the caller cannot use"] + #[doc = " data at the full sample rate, or knows the compressed data doesn't"] + #[doc = " use the full frequency range, it can request decoding at a reduced"] + #[doc = " rate. Likewise, the decoder is capable of filling in either mono or"] + #[doc = " interleaved stereo pcm buffers, at the caller's request."] + pub fn opus_decoder_create( + Fs: opus_int32, + channels: ::std::os::raw::c_int, + error: *mut ::std::os::raw::c_int, + ) -> *mut OpusDecoder; +} +extern "C" { + #[doc = " Initializes a previously allocated decoder state."] + #[doc = " The state must be at least the size returned by opus_decoder_get_size()."] + #[doc = " This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size"] + #[doc = " To reset a previously initialized state, use the #OPUS_RESET_STATE CTL."] + #[doc = " @param [in] st OpusDecoder*: Decoder state."] + #[doc = " @param [in] Fs opus_int32: Sampling rate to decode to (Hz)."] + #[doc = " This must be one of 8000, 12000, 16000,"] + #[doc = " 24000, or 48000."] + #[doc = " @param [in] channels int: Number of channels (1 or 2) to decode"] + #[doc = " @retval #OPUS_OK Success or @ref opus_errorcodes"] + pub fn opus_decoder_init( + st: *mut OpusDecoder, + Fs: opus_int32, + channels: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Decode an Opus packet."] + #[doc = " @param [in] st OpusDecoder*: Decoder state"] + #[doc = " @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss"] + #[doc = " @param [in] len opus_int32: Number of bytes in payload*"] + #[doc = " @param [out] pcm opus_int16*: Output signal (interleaved if 2 channels). length"] + #[doc = " is frame_size*channels*sizeof(opus_int16)"] + #[doc = " @param [in] frame_size Number of samples per channel of available space in \\a pcm."] + #[doc = " If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will"] + #[doc = " not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),"] + #[doc = " then frame_size needs to be exactly the duration of audio that is missing, otherwise the"] + #[doc = " decoder will not be in the optimal state to decode the next incoming packet. For the PLC and"] + #[doc = " FEC cases, frame_size must be a multiple of 2.5 ms."] + #[doc = " @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be"] + #[doc = " decoded. If no such data is available, the frame is decoded as if it were lost."] + #[doc = " @returns Number of decoded samples or @ref opus_errorcodes"] + pub fn opus_decode( + st: *mut OpusDecoder, + data: *const ::std::os::raw::c_uchar, + len: opus_int32, + pcm: *mut opus_int16, + frame_size: ::std::os::raw::c_int, + decode_fec: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Decode an Opus packet with floating point output."] + #[doc = " @param [in] st OpusDecoder*: Decoder state"] + #[doc = " @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss"] + #[doc = " @param [in] len opus_int32: Number of bytes in payload"] + #[doc = " @param [out] pcm float*: Output signal (interleaved if 2 channels). length"] + #[doc = " is frame_size*channels*sizeof(float)"] + #[doc = " @param [in] frame_size Number of samples per channel of available space in \\a pcm."] + #[doc = " If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will"] + #[doc = " not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),"] + #[doc = " then frame_size needs to be exactly the duration of audio that is missing, otherwise the"] + #[doc = " decoder will not be in the optimal state to decode the next incoming packet. For the PLC and"] + #[doc = " FEC cases, frame_size must be a multiple of 2.5 ms."] + #[doc = " @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be"] + #[doc = " decoded. If no such data is available the frame is decoded as if it were lost."] + #[doc = " @returns Number of decoded samples or @ref opus_errorcodes"] + pub fn opus_decode_float( + st: *mut OpusDecoder, + data: *const ::std::os::raw::c_uchar, + len: opus_int32, + pcm: *mut f32, + frame_size: ::std::os::raw::c_int, + decode_fec: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Perform a CTL function on an Opus decoder."] + #[doc = ""] + #[doc = " Generally the request and subsequent arguments are generated"] + #[doc = " by a convenience macro."] + #[doc = " @param st OpusDecoder*: Decoder state."] + #[doc = " @param request This and all remaining parameters should be replaced by one"] + #[doc = " of the convenience macros in @ref opus_genericctls or"] + #[doc = " @ref opus_decoderctls."] + #[doc = " @see opus_genericctls"] + #[doc = " @see opus_decoderctls"] + pub fn opus_decoder_ctl( + st: *mut OpusDecoder, + request: ::std::os::raw::c_int, + ... + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Frees an OpusDecoder allocated by opus_decoder_create()."] + #[doc = " @param[in] st OpusDecoder*: State to be freed."] + pub fn opus_decoder_destroy(st: *mut OpusDecoder); +} +extern "C" { + #[doc = " Parse an opus packet into one or more frames."] + #[doc = " Opus_decode will perform this operation internally so most applications do"] + #[doc = " not need to use this function."] + #[doc = " This function does not copy the frames, the returned pointers are pointers into"] + #[doc = " the input packet."] + #[doc = " @param [in] data char*: Opus packet to be parsed"] + #[doc = " @param [in] len opus_int32: size of data"] + #[doc = " @param [out] out_toc char*: TOC pointer"] + #[doc = " @param [out] frames char*[48] encapsulated frames"] + #[doc = " @param [out] size opus_int16[48] sizes of the encapsulated frames"] + #[doc = " @param [out] payload_offset int*: returns the position of the payload within the packet (in bytes)"] + #[doc = " @returns number of frames"] + pub fn opus_packet_parse( + data: *const ::std::os::raw::c_uchar, + len: opus_int32, + out_toc: *mut ::std::os::raw::c_uchar, + frames: *mut *const ::std::os::raw::c_uchar, + size: *mut opus_int16, + payload_offset: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Gets the bandwidth of an Opus packet."] + #[doc = " @param [in] data char*: Opus packet"] + #[doc = " @retval OPUS_BANDWIDTH_NARROWBAND Narrowband (4kHz bandpass)"] + #[doc = " @retval OPUS_BANDWIDTH_MEDIUMBAND Mediumband (6kHz bandpass)"] + #[doc = " @retval OPUS_BANDWIDTH_WIDEBAND Wideband (8kHz bandpass)"] + #[doc = " @retval OPUS_BANDWIDTH_SUPERWIDEBAND Superwideband (12kHz bandpass)"] + #[doc = " @retval OPUS_BANDWIDTH_FULLBAND Fullband (20kHz bandpass)"] + #[doc = " @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type"] + pub fn opus_packet_get_bandwidth(data: *const ::std::os::raw::c_uchar) + -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Gets the number of samples per frame from an Opus packet."] + #[doc = " @param [in] data char*: Opus packet."] + #[doc = " This must contain at least one byte of"] + #[doc = " data."] + #[doc = " @param [in] Fs opus_int32: Sampling rate in Hz."] + #[doc = " This must be a multiple of 400, or"] + #[doc = " inaccurate results will be returned."] + #[doc = " @returns Number of samples per frame."] + pub fn opus_packet_get_samples_per_frame( + data: *const ::std::os::raw::c_uchar, + Fs: opus_int32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Gets the number of channels from an Opus packet."] + #[doc = " @param [in] data char*: Opus packet"] + #[doc = " @returns Number of channels"] + #[doc = " @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type"] + pub fn opus_packet_get_nb_channels( + data: *const ::std::os::raw::c_uchar, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Gets the number of frames in an Opus packet."] + #[doc = " @param [in] packet char*: Opus packet"] + #[doc = " @param [in] len opus_int32: Length of packet"] + #[doc = " @returns Number of frames"] + #[doc = " @retval OPUS_BAD_ARG Insufficient data was passed to the function"] + #[doc = " @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type"] + pub fn opus_packet_get_nb_frames( + packet: *const ::std::os::raw::c_uchar, + len: opus_int32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Gets the number of samples of an Opus packet."] + #[doc = " @param [in] packet char*: Opus packet"] + #[doc = " @param [in] len opus_int32: Length of packet"] + #[doc = " @param [in] Fs opus_int32: Sampling rate in Hz."] + #[doc = " This must be a multiple of 400, or"] + #[doc = " inaccurate results will be returned."] + #[doc = " @returns Number of samples"] + #[doc = " @retval OPUS_BAD_ARG Insufficient data was passed to the function"] + #[doc = " @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type"] + pub fn opus_packet_get_nb_samples( + packet: *const ::std::os::raw::c_uchar, + len: opus_int32, + Fs: opus_int32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Gets the number of samples of an Opus packet."] + #[doc = " @param [in] dec OpusDecoder*: Decoder state"] + #[doc = " @param [in] packet char*: Opus packet"] + #[doc = " @param [in] len opus_int32: Length of packet"] + #[doc = " @returns Number of samples"] + #[doc = " @retval OPUS_BAD_ARG Insufficient data was passed to the function"] + #[doc = " @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type"] + pub fn opus_decoder_get_nb_samples( + dec: *const OpusDecoder, + packet: *const ::std::os::raw::c_uchar, + len: opus_int32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Applies soft-clipping to bring a float signal within the [-1,1] range. If"] + #[doc = " the signal is already in that range, nothing is done. If there are values"] + #[doc = " outside of [-1,1], then the signal is clipped as smoothly as possible to"] + #[doc = " both fit in the range and avoid creating excessive distortion in the"] + #[doc = " process."] + #[doc = " @param [in,out] pcm float*: Input PCM and modified PCM"] + #[doc = " @param [in] frame_size int Number of samples per channel to process"] + #[doc = " @param [in] channels int: Number of channels"] + #[doc = " @param [in,out] softclip_mem float*: State memory for the soft clipping process (one float per channel, initialized to zero)"] + pub fn opus_pcm_soft_clip( + pcm: *mut f32, + frame_size: ::std::os::raw::c_int, + channels: ::std::os::raw::c_int, + softclip_mem: *mut f32, + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct OpusRepacketizer { + _unused: [u8; 0], +} +extern "C" { + #[doc = " Gets the size of an OpusRepacketizer structure."] + #[doc = " @returns The size in bytes."] + pub fn opus_repacketizer_get_size() -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " (Re)initializes a previously allocated repacketizer state."] + #[doc = " The state must be at least the size returned by opus_repacketizer_get_size()."] + #[doc = " This can be used for applications which use their own allocator instead of"] + #[doc = " malloc()."] + #[doc = " It must also be called to reset the queue of packets waiting to be"] + #[doc = " repacketized, which is necessary if the maximum packet duration of 120 ms"] + #[doc = " is reached or if you wish to submit packets with a different Opus"] + #[doc = " configuration (coding mode, audio bandwidth, frame size, or channel count)."] + #[doc = " Failure to do so will prevent a new packet from being added with"] + #[doc = " opus_repacketizer_cat()."] + #[doc = " @see opus_repacketizer_create"] + #[doc = " @see opus_repacketizer_get_size"] + #[doc = " @see opus_repacketizer_cat"] + #[doc = " @param rp OpusRepacketizer*: The repacketizer state to"] + #[doc = " (re)initialize."] + #[doc = " @returns A pointer to the same repacketizer state that was passed in."] + pub fn opus_repacketizer_init(rp: *mut OpusRepacketizer) -> *mut OpusRepacketizer; +} +extern "C" { + #[doc = " Allocates memory and initializes the new repacketizer with"] + #[doc = " opus_repacketizer_init()."] + pub fn opus_repacketizer_create() -> *mut OpusRepacketizer; +} +extern "C" { + #[doc = " Frees an OpusRepacketizer allocated by"] + #[doc = " opus_repacketizer_create()."] + #[doc = " @param[in] rp OpusRepacketizer*: State to be freed."] + pub fn opus_repacketizer_destroy(rp: *mut OpusRepacketizer); +} +extern "C" { + #[doc = " Add a packet to the current repacketizer state."] + #[doc = " This packet must match the configuration of any packets already submitted"] + #[doc = " for repacketization since the last call to opus_repacketizer_init()."] + #[doc = " This means that it must have the same coding mode, audio bandwidth, frame"] + #[doc = " size, and channel count."] + #[doc = " This can be checked in advance by examining the top 6 bits of the first"] + #[doc = " byte of the packet, and ensuring they match the top 6 bits of the first"] + #[doc = " byte of any previously submitted packet."] + #[doc = " The total duration of audio in the repacketizer state also must not exceed"] + #[doc = " 120 ms, the maximum duration of a single packet, after adding this packet."] + #[doc = ""] + #[doc = " The contents of the current repacketizer state can be extracted into new"] + #[doc = " packets using opus_repacketizer_out() or opus_repacketizer_out_range()."] + #[doc = ""] + #[doc = " In order to add a packet with a different configuration or to add more"] + #[doc = " audio beyond 120 ms, you must clear the repacketizer state by calling"] + #[doc = " opus_repacketizer_init()."] + #[doc = " If a packet is too large to add to the current repacketizer state, no part"] + #[doc = " of it is added, even if it contains multiple frames, some of which might"] + #[doc = " fit."] + #[doc = " If you wish to be able to add parts of such packets, you should first use"] + #[doc = " another repacketizer to split the packet into pieces and add them"] + #[doc = " individually."] + #[doc = " @see opus_repacketizer_out_range"] + #[doc = " @see opus_repacketizer_out"] + #[doc = " @see opus_repacketizer_init"] + #[doc = " @param rp OpusRepacketizer*: The repacketizer state to which to"] + #[doc = " add the packet."] + #[doc = " @param[in] data const unsigned char*: The packet data."] + #[doc = " The application must ensure"] + #[doc = " this pointer remains valid"] + #[doc = " until the next call to"] + #[doc = " opus_repacketizer_init() or"] + #[doc = " opus_repacketizer_destroy()."] + #[doc = " @param len opus_int32: The number of bytes in the packet data."] + #[doc = " @returns An error code indicating whether or not the operation succeeded."] + #[doc = " @retval #OPUS_OK The packet's contents have been added to the repacketizer"] + #[doc = " state."] + #[doc = " @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC sequence,"] + #[doc = " the packet's TOC sequence was not compatible"] + #[doc = " with previously submitted packets (because"] + #[doc = " the coding mode, audio bandwidth, frame size,"] + #[doc = " or channel count did not match), or adding"] + #[doc = " this packet would increase the total amount of"] + #[doc = " audio stored in the repacketizer state to more"] + #[doc = " than 120 ms."] + pub fn opus_repacketizer_cat( + rp: *mut OpusRepacketizer, + data: *const ::std::os::raw::c_uchar, + len: opus_int32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Construct a new packet from data previously submitted to the repacketizer"] + #[doc = " state via opus_repacketizer_cat()."] + #[doc = " @param rp OpusRepacketizer*: The repacketizer state from which to"] + #[doc = " construct the new packet."] + #[doc = " @param begin int: The index of the first frame in the current"] + #[doc = " repacketizer state to include in the output."] + #[doc = " @param end int: One past the index of the last frame in the"] + #[doc = " current repacketizer state to include in the"] + #[doc = " output."] + #[doc = " @param[out] data const unsigned char*: The buffer in which to"] + #[doc = " store the output packet."] + #[doc = " @param maxlen opus_int32: The maximum number of bytes to store in"] + #[doc = " the output buffer. In order to guarantee"] + #[doc = " success, this should be at least"] + #[doc = " 1276 for a single frame,"] + #[doc = " or for multiple frames,"] + #[doc = " 1277*(end-begin)."] + #[doc = " However, 1*(end-begin) plus"] + #[doc = " the size of all packet data submitted to"] + #[doc = " the repacketizer since the last call to"] + #[doc = " opus_repacketizer_init() or"] + #[doc = " opus_repacketizer_create() is also"] + #[doc = " sufficient, and possibly much smaller."] + #[doc = " @returns The total size of the output packet on success, or an error code"] + #[doc = " on failure."] + #[doc = " @retval #OPUS_BAD_ARG [begin,end) was an invalid range of"] + #[doc = " frames (begin < 0, begin >= end, or end >"] + #[doc = " opus_repacketizer_get_nb_frames())."] + #[doc = " @retval #OPUS_BUFFER_TOO_SMALL \\a maxlen was insufficient to contain the"] + #[doc = " complete output packet."] + pub fn opus_repacketizer_out_range( + rp: *mut OpusRepacketizer, + begin: ::std::os::raw::c_int, + end: ::std::os::raw::c_int, + data: *mut ::std::os::raw::c_uchar, + maxlen: opus_int32, + ) -> opus_int32; +} +extern "C" { + #[doc = " Return the total number of frames contained in packet data submitted to"] + #[doc = " the repacketizer state so far via opus_repacketizer_cat() since the last"] + #[doc = " call to opus_repacketizer_init() or opus_repacketizer_create()."] + #[doc = " This defines the valid range of packets that can be extracted with"] + #[doc = " opus_repacketizer_out_range() or opus_repacketizer_out()."] + #[doc = " @param rp OpusRepacketizer*: The repacketizer state containing the"] + #[doc = " frames."] + #[doc = " @returns The total number of frames contained in the packet data submitted"] + #[doc = " to the repacketizer state."] + pub fn opus_repacketizer_get_nb_frames(rp: *mut OpusRepacketizer) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Construct a new packet from data previously submitted to the repacketizer"] + #[doc = " state via opus_repacketizer_cat()."] + #[doc = " This is a convenience routine that returns all the data submitted so far"] + #[doc = " in a single packet."] + #[doc = " It is equivalent to calling"] + #[doc = " @code"] + #[doc = " opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp),"] + #[doc = " data, maxlen)"] + #[doc = " @endcode"] + #[doc = " @param rp OpusRepacketizer*: The repacketizer state from which to"] + #[doc = " construct the new packet."] + #[doc = " @param[out] data const unsigned char*: The buffer in which to"] + #[doc = " store the output packet."] + #[doc = " @param maxlen opus_int32: The maximum number of bytes to store in"] + #[doc = " the output buffer. In order to guarantee"] + #[doc = " success, this should be at least"] + #[doc = " 1277*opus_repacketizer_get_nb_frames(rp)."] + #[doc = " However,"] + #[doc = " 1*opus_repacketizer_get_nb_frames(rp)"] + #[doc = " plus the size of all packet data"] + #[doc = " submitted to the repacketizer since the"] + #[doc = " last call to opus_repacketizer_init() or"] + #[doc = " opus_repacketizer_create() is also"] + #[doc = " sufficient, and possibly much smaller."] + #[doc = " @returns The total size of the output packet on success, or an error code"] + #[doc = " on failure."] + #[doc = " @retval #OPUS_BUFFER_TOO_SMALL \\a maxlen was insufficient to contain the"] + #[doc = " complete output packet."] + pub fn opus_repacketizer_out( + rp: *mut OpusRepacketizer, + data: *mut ::std::os::raw::c_uchar, + maxlen: opus_int32, + ) -> opus_int32; +} +extern "C" { + #[doc = " Pads a given Opus packet to a larger size (possibly changing the TOC sequence)."] + #[doc = " @param[in,out] data const unsigned char*: The buffer containing the"] + #[doc = " packet to pad."] + #[doc = " @param len opus_int32: The size of the packet."] + #[doc = " This must be at least 1."] + #[doc = " @param new_len opus_int32: The desired size of the packet after padding."] + #[doc = " This must be at least as large as len."] + #[doc = " @returns an error code"] + #[doc = " @retval #OPUS_OK \\a on success."] + #[doc = " @retval #OPUS_BAD_ARG \\a len was less than 1 or new_len was less than len."] + #[doc = " @retval #OPUS_INVALID_PACKET \\a data did not contain a valid Opus packet."] + pub fn opus_packet_pad( + data: *mut ::std::os::raw::c_uchar, + len: opus_int32, + new_len: opus_int32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Remove all padding from a given Opus packet and rewrite the TOC sequence to"] + #[doc = " minimize space usage."] + #[doc = " @param[in,out] data const unsigned char*: The buffer containing the"] + #[doc = " packet to strip."] + #[doc = " @param len opus_int32: The size of the packet."] + #[doc = " This must be at least 1."] + #[doc = " @returns The new size of the output packet on success, or an error code"] + #[doc = " on failure."] + #[doc = " @retval #OPUS_BAD_ARG \\a len was less than 1."] + #[doc = " @retval #OPUS_INVALID_PACKET \\a data did not contain a valid Opus packet."] + pub fn opus_packet_unpad(data: *mut ::std::os::raw::c_uchar, len: opus_int32) -> opus_int32; +} +extern "C" { + #[doc = " Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence)."] + #[doc = " @param[in,out] data const unsigned char*: The buffer containing the"] + #[doc = " packet to pad."] + #[doc = " @param len opus_int32: The size of the packet."] + #[doc = " This must be at least 1."] + #[doc = " @param new_len opus_int32: The desired size of the packet after padding."] + #[doc = " This must be at least 1."] + #[doc = " @param nb_streams opus_int32: The number of streams (not channels) in the packet."] + #[doc = " This must be at least as large as len."] + #[doc = " @returns an error code"] + #[doc = " @retval #OPUS_OK \\a on success."] + #[doc = " @retval #OPUS_BAD_ARG \\a len was less than 1."] + #[doc = " @retval #OPUS_INVALID_PACKET \\a data did not contain a valid Opus packet."] + pub fn opus_multistream_packet_pad( + data: *mut ::std::os::raw::c_uchar, + len: opus_int32, + new_len: opus_int32, + nb_streams: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to"] + #[doc = " minimize space usage."] + #[doc = " @param[in,out] data const unsigned char*: The buffer containing the"] + #[doc = " packet to strip."] + #[doc = " @param len opus_int32: The size of the packet."] + #[doc = " This must be at least 1."] + #[doc = " @param nb_streams opus_int32: The number of streams (not channels) in the packet."] + #[doc = " This must be at least 1."] + #[doc = " @returns The new size of the output packet on success, or an error code"] + #[doc = " on failure."] + #[doc = " @retval #OPUS_BAD_ARG \\a len was less than 1 or new_len was less than len."] + #[doc = " @retval #OPUS_INVALID_PACKET \\a data did not contain a valid Opus packet."] + pub fn opus_multistream_packet_unpad( + data: *mut ::std::os::raw::c_uchar, + len: opus_int32, + nb_streams: ::std::os::raw::c_int, + ) -> opus_int32; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct OpusMSEncoder { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct OpusMSDecoder { + _unused: [u8; 0], +} +extern "C" { + #[doc = " Gets the size of an OpusMSEncoder structure."] + #[doc = " @param streams int: The total number of streams to encode from the"] + #[doc = " input."] + #[doc = " This must be no more than 255."] + #[doc = " @param coupled_streams int: Number of coupled (2 channel) streams"] + #[doc = " to encode."] + #[doc = " This must be no larger than the total"] + #[doc = " number of streams."] + #[doc = " Additionally, The total number of"] + #[doc = " encoded channels (streams +"] + #[doc = " coupled_streams) must be no"] + #[doc = " more than 255."] + #[doc = " @returns The size in bytes on success, or a negative error code"] + #[doc = " (see @ref opus_errorcodes) on error."] + pub fn opus_multistream_encoder_get_size( + streams: ::std::os::raw::c_int, + coupled_streams: ::std::os::raw::c_int, + ) -> opus_int32; +} +extern "C" { + pub fn opus_multistream_surround_encoder_get_size( + channels: ::std::os::raw::c_int, + mapping_family: ::std::os::raw::c_int, + ) -> opus_int32; +} +extern "C" { + #[doc = " Allocates and initializes a multistream encoder state."] + #[doc = " Call opus_multistream_encoder_destroy() to release"] + #[doc = " this object when finished."] + #[doc = " @param Fs opus_int32: Sampling rate of the input signal (in Hz)."] + #[doc = " This must be one of 8000, 12000, 16000,"] + #[doc = " 24000, or 48000."] + #[doc = " @param channels int: Number of channels in the input signal."] + #[doc = " This must be at most 255."] + #[doc = " It may be greater than the number of"] + #[doc = " coded channels (streams +"] + #[doc = " coupled_streams)."] + #[doc = " @param streams int: The total number of streams to encode from the"] + #[doc = " input."] + #[doc = " This must be no more than the number of channels."] + #[doc = " @param coupled_streams int: Number of coupled (2 channel) streams"] + #[doc = " to encode."] + #[doc = " This must be no larger than the total"] + #[doc = " number of streams."] + #[doc = " Additionally, The total number of"] + #[doc = " encoded channels (streams +"] + #[doc = " coupled_streams) must be no"] + #[doc = " more than the number of input channels."] + #[doc = " @param[in] mapping const unsigned char[channels]: Mapping from"] + #[doc = " encoded channels to input channels, as described in"] + #[doc = " @ref opus_multistream. As an extra constraint, the"] + #[doc = " multistream encoder does not allow encoding coupled"] + #[doc = " streams for which one channel is unused since this"] + #[doc = " is never a good idea."] + #[doc = " @param application int: The target encoder application."] + #[doc = " This must be one of the following:"] + #[doc = "
"] + #[doc = "
#OPUS_APPLICATION_VOIP
"] + #[doc = "
Process signal for improved speech intelligibility.
"] + #[doc = "
#OPUS_APPLICATION_AUDIO
"] + #[doc = "
Favor faithfulness to the original input.
"] + #[doc = "
#OPUS_APPLICATION_RESTRICTED_LOWDELAY
"] + #[doc = "
Configure the minimum possible coding delay by disabling certain modes"] + #[doc = " of operation.
"] + #[doc = "
"] + #[doc = " @param[out] error int *: Returns #OPUS_OK on success, or an error"] + #[doc = " code (see @ref opus_errorcodes) on"] + #[doc = " failure."] + pub fn opus_multistream_encoder_create( + Fs: opus_int32, + channels: ::std::os::raw::c_int, + streams: ::std::os::raw::c_int, + coupled_streams: ::std::os::raw::c_int, + mapping: *const ::std::os::raw::c_uchar, + application: ::std::os::raw::c_int, + error: *mut ::std::os::raw::c_int, + ) -> *mut OpusMSEncoder; +} +extern "C" { + pub fn opus_multistream_surround_encoder_create( + Fs: opus_int32, + channels: ::std::os::raw::c_int, + mapping_family: ::std::os::raw::c_int, + streams: *mut ::std::os::raw::c_int, + coupled_streams: *mut ::std::os::raw::c_int, + mapping: *mut ::std::os::raw::c_uchar, + application: ::std::os::raw::c_int, + error: *mut ::std::os::raw::c_int, + ) -> *mut OpusMSEncoder; +} +extern "C" { + #[doc = " Initialize a previously allocated multistream encoder state."] + #[doc = " The memory pointed to by \\a st must be at least the size returned by"] + #[doc = " opus_multistream_encoder_get_size()."] + #[doc = " This is intended for applications which use their own allocator instead of"] + #[doc = " malloc."] + #[doc = " To reset a previously initialized state, use the #OPUS_RESET_STATE CTL."] + #[doc = " @see opus_multistream_encoder_create"] + #[doc = " @see opus_multistream_encoder_get_size"] + #[doc = " @param st OpusMSEncoder*: Multistream encoder state to initialize."] + #[doc = " @param Fs opus_int32: Sampling rate of the input signal (in Hz)."] + #[doc = " This must be one of 8000, 12000, 16000,"] + #[doc = " 24000, or 48000."] + #[doc = " @param channels int: Number of channels in the input signal."] + #[doc = " This must be at most 255."] + #[doc = " It may be greater than the number of"] + #[doc = " coded channels (streams +"] + #[doc = " coupled_streams)."] + #[doc = " @param streams int: The total number of streams to encode from the"] + #[doc = " input."] + #[doc = " This must be no more than the number of channels."] + #[doc = " @param coupled_streams int: Number of coupled (2 channel) streams"] + #[doc = " to encode."] + #[doc = " This must be no larger than the total"] + #[doc = " number of streams."] + #[doc = " Additionally, The total number of"] + #[doc = " encoded channels (streams +"] + #[doc = " coupled_streams) must be no"] + #[doc = " more than the number of input channels."] + #[doc = " @param[in] mapping const unsigned char[channels]: Mapping from"] + #[doc = " encoded channels to input channels, as described in"] + #[doc = " @ref opus_multistream. As an extra constraint, the"] + #[doc = " multistream encoder does not allow encoding coupled"] + #[doc = " streams for which one channel is unused since this"] + #[doc = " is never a good idea."] + #[doc = " @param application int: The target encoder application."] + #[doc = " This must be one of the following:"] + #[doc = "
"] + #[doc = "
#OPUS_APPLICATION_VOIP
"] + #[doc = "
Process signal for improved speech intelligibility.
"] + #[doc = "
#OPUS_APPLICATION_AUDIO
"] + #[doc = "
Favor faithfulness to the original input.
"] + #[doc = "
#OPUS_APPLICATION_RESTRICTED_LOWDELAY
"] + #[doc = "
Configure the minimum possible coding delay by disabling certain modes"] + #[doc = " of operation.
"] + #[doc = "
"] + #[doc = " @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)"] + #[doc = " on failure."] + pub fn opus_multistream_encoder_init( + st: *mut OpusMSEncoder, + Fs: opus_int32, + channels: ::std::os::raw::c_int, + streams: ::std::os::raw::c_int, + coupled_streams: ::std::os::raw::c_int, + mapping: *const ::std::os::raw::c_uchar, + application: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn opus_multistream_surround_encoder_init( + st: *mut OpusMSEncoder, + Fs: opus_int32, + channels: ::std::os::raw::c_int, + mapping_family: ::std::os::raw::c_int, + streams: *mut ::std::os::raw::c_int, + coupled_streams: *mut ::std::os::raw::c_int, + mapping: *mut ::std::os::raw::c_uchar, + application: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Encodes a multistream Opus frame."] + #[doc = " @param st OpusMSEncoder*: Multistream encoder state."] + #[doc = " @param[in] pcm const opus_int16*: The input signal as interleaved"] + #[doc = " samples."] + #[doc = " This must contain"] + #[doc = " frame_size*channels"] + #[doc = " samples."] + #[doc = " @param frame_size int: Number of samples per channel in the input"] + #[doc = " signal."] + #[doc = " This must be an Opus frame size for the"] + #[doc = " encoder's sampling rate."] + #[doc = " For example, at 48 kHz the permitted values"] + #[doc = " are 120, 240, 480, 960, 1920, and 2880."] + #[doc = " Passing in a duration of less than 10 ms"] + #[doc = " (480 samples at 48 kHz) will prevent the"] + #[doc = " encoder from using the LPC or hybrid modes."] + #[doc = " @param[out] data unsigned char*: Output payload."] + #[doc = " This must contain storage for at"] + #[doc = " least \\a max_data_bytes."] + #[doc = " @param [in] max_data_bytes opus_int32: Size of the allocated"] + #[doc = " memory for the output"] + #[doc = " payload. This may be"] + #[doc = " used to impose an upper limit on"] + #[doc = " the instant bitrate, but should"] + #[doc = " not be used as the only bitrate"] + #[doc = " control. Use #OPUS_SET_BITRATE to"] + #[doc = " control the bitrate."] + #[doc = " @returns The length of the encoded packet (in bytes) on success or a"] + #[doc = " negative error code (see @ref opus_errorcodes) on failure."] + pub fn opus_multistream_encode( + st: *mut OpusMSEncoder, + pcm: *const opus_int16, + frame_size: ::std::os::raw::c_int, + data: *mut ::std::os::raw::c_uchar, + max_data_bytes: opus_int32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Encodes a multistream Opus frame from floating point input."] + #[doc = " @param st OpusMSEncoder*: Multistream encoder state."] + #[doc = " @param[in] pcm const float*: The input signal as interleaved"] + #[doc = " samples with a normal range of"] + #[doc = " +/-1.0."] + #[doc = " Samples with a range beyond +/-1.0"] + #[doc = " are supported but will be clipped by"] + #[doc = " decoders using the integer API and"] + #[doc = " should only be used if it is known"] + #[doc = " that the far end supports extended"] + #[doc = " dynamic range."] + #[doc = " This must contain"] + #[doc = " frame_size*channels"] + #[doc = " samples."] + #[doc = " @param frame_size int: Number of samples per channel in the input"] + #[doc = " signal."] + #[doc = " This must be an Opus frame size for the"] + #[doc = " encoder's sampling rate."] + #[doc = " For example, at 48 kHz the permitted values"] + #[doc = " are 120, 240, 480, 960, 1920, and 2880."] + #[doc = " Passing in a duration of less than 10 ms"] + #[doc = " (480 samples at 48 kHz) will prevent the"] + #[doc = " encoder from using the LPC or hybrid modes."] + #[doc = " @param[out] data unsigned char*: Output payload."] + #[doc = " This must contain storage for at"] + #[doc = " least \\a max_data_bytes."] + #[doc = " @param [in] max_data_bytes opus_int32: Size of the allocated"] + #[doc = " memory for the output"] + #[doc = " payload. This may be"] + #[doc = " used to impose an upper limit on"] + #[doc = " the instant bitrate, but should"] + #[doc = " not be used as the only bitrate"] + #[doc = " control. Use #OPUS_SET_BITRATE to"] + #[doc = " control the bitrate."] + #[doc = " @returns The length of the encoded packet (in bytes) on success or a"] + #[doc = " negative error code (see @ref opus_errorcodes) on failure."] + pub fn opus_multistream_encode_float( + st: *mut OpusMSEncoder, + pcm: *const f32, + frame_size: ::std::os::raw::c_int, + data: *mut ::std::os::raw::c_uchar, + max_data_bytes: opus_int32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Frees an OpusMSEncoder allocated by"] + #[doc = " opus_multistream_encoder_create()."] + #[doc = " @param st OpusMSEncoder*: Multistream encoder state to be freed."] + pub fn opus_multistream_encoder_destroy(st: *mut OpusMSEncoder); +} +extern "C" { + #[doc = " Perform a CTL function on a multistream Opus encoder."] + #[doc = ""] + #[doc = " Generally the request and subsequent arguments are generated by a"] + #[doc = " convenience macro."] + #[doc = " @param st OpusMSEncoder*: Multistream encoder state."] + #[doc = " @param request This and all remaining parameters should be replaced by one"] + #[doc = " of the convenience macros in @ref opus_genericctls,"] + #[doc = " @ref opus_encoderctls, or @ref opus_multistream_ctls."] + #[doc = " @see opus_genericctls"] + #[doc = " @see opus_encoderctls"] + #[doc = " @see opus_multistream_ctls"] + pub fn opus_multistream_encoder_ctl( + st: *mut OpusMSEncoder, + request: ::std::os::raw::c_int, + ... + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Gets the size of an OpusMSDecoder structure."] + #[doc = " @param streams int: The total number of streams coded in the"] + #[doc = " input."] + #[doc = " This must be no more than 255."] + #[doc = " @param coupled_streams int: Number streams to decode as coupled"] + #[doc = " (2 channel) streams."] + #[doc = " This must be no larger than the total"] + #[doc = " number of streams."] + #[doc = " Additionally, The total number of"] + #[doc = " coded channels (streams +"] + #[doc = " coupled_streams) must be no"] + #[doc = " more than 255."] + #[doc = " @returns The size in bytes on success, or a negative error code"] + #[doc = " (see @ref opus_errorcodes) on error."] + pub fn opus_multistream_decoder_get_size( + streams: ::std::os::raw::c_int, + coupled_streams: ::std::os::raw::c_int, + ) -> opus_int32; +} +extern "C" { + #[doc = " Allocates and initializes a multistream decoder state."] + #[doc = " Call opus_multistream_decoder_destroy() to release"] + #[doc = " this object when finished."] + #[doc = " @param Fs opus_int32: Sampling rate to decode at (in Hz)."] + #[doc = " This must be one of 8000, 12000, 16000,"] + #[doc = " 24000, or 48000."] + #[doc = " @param channels int: Number of channels to output."] + #[doc = " This must be at most 255."] + #[doc = " It may be different from the number of coded"] + #[doc = " channels (streams +"] + #[doc = " coupled_streams)."] + #[doc = " @param streams int: The total number of streams coded in the"] + #[doc = " input."] + #[doc = " This must be no more than 255."] + #[doc = " @param coupled_streams int: Number of streams to decode as coupled"] + #[doc = " (2 channel) streams."] + #[doc = " This must be no larger than the total"] + #[doc = " number of streams."] + #[doc = " Additionally, The total number of"] + #[doc = " coded channels (streams +"] + #[doc = " coupled_streams) must be no"] + #[doc = " more than 255."] + #[doc = " @param[in] mapping const unsigned char[channels]: Mapping from"] + #[doc = " coded channels to output channels, as described in"] + #[doc = " @ref opus_multistream."] + #[doc = " @param[out] error int *: Returns #OPUS_OK on success, or an error"] + #[doc = " code (see @ref opus_errorcodes) on"] + #[doc = " failure."] + pub fn opus_multistream_decoder_create( + Fs: opus_int32, + channels: ::std::os::raw::c_int, + streams: ::std::os::raw::c_int, + coupled_streams: ::std::os::raw::c_int, + mapping: *const ::std::os::raw::c_uchar, + error: *mut ::std::os::raw::c_int, + ) -> *mut OpusMSDecoder; +} +extern "C" { + #[doc = " Intialize a previously allocated decoder state object."] + #[doc = " The memory pointed to by \\a st must be at least the size returned by"] + #[doc = " opus_multistream_encoder_get_size()."] + #[doc = " This is intended for applications which use their own allocator instead of"] + #[doc = " malloc."] + #[doc = " To reset a previously initialized state, use the #OPUS_RESET_STATE CTL."] + #[doc = " @see opus_multistream_decoder_create"] + #[doc = " @see opus_multistream_deocder_get_size"] + #[doc = " @param st OpusMSEncoder*: Multistream encoder state to initialize."] + #[doc = " @param Fs opus_int32: Sampling rate to decode at (in Hz)."] + #[doc = " This must be one of 8000, 12000, 16000,"] + #[doc = " 24000, or 48000."] + #[doc = " @param channels int: Number of channels to output."] + #[doc = " This must be at most 255."] + #[doc = " It may be different from the number of coded"] + #[doc = " channels (streams +"] + #[doc = " coupled_streams)."] + #[doc = " @param streams int: The total number of streams coded in the"] + #[doc = " input."] + #[doc = " This must be no more than 255."] + #[doc = " @param coupled_streams int: Number of streams to decode as coupled"] + #[doc = " (2 channel) streams."] + #[doc = " This must be no larger than the total"] + #[doc = " number of streams."] + #[doc = " Additionally, The total number of"] + #[doc = " coded channels (streams +"] + #[doc = " coupled_streams) must be no"] + #[doc = " more than 255."] + #[doc = " @param[in] mapping const unsigned char[channels]: Mapping from"] + #[doc = " coded channels to output channels, as described in"] + #[doc = " @ref opus_multistream."] + #[doc = " @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)"] + #[doc = " on failure."] + pub fn opus_multistream_decoder_init( + st: *mut OpusMSDecoder, + Fs: opus_int32, + channels: ::std::os::raw::c_int, + streams: ::std::os::raw::c_int, + coupled_streams: ::std::os::raw::c_int, + mapping: *const ::std::os::raw::c_uchar, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Decode a multistream Opus packet."] + #[doc = " @param st OpusMSDecoder*: Multistream decoder state."] + #[doc = " @param[in] data const unsigned char*: Input payload."] + #[doc = " Use a NULL"] + #[doc = " pointer to indicate packet"] + #[doc = " loss."] + #[doc = " @param len opus_int32: Number of bytes in payload."] + #[doc = " @param[out] pcm opus_int16*: Output signal, with interleaved"] + #[doc = " samples."] + #[doc = " This must contain room for"] + #[doc = " frame_size*channels"] + #[doc = " samples."] + #[doc = " @param frame_size int: The number of samples per channel of"] + #[doc = " available space in \\a pcm."] + #[doc = " If this is less than the maximum packet duration"] + #[doc = " (120 ms; 5760 for 48kHz), this function will not be capable"] + #[doc = " of decoding some packets. In the case of PLC (data==NULL)"] + #[doc = " or FEC (decode_fec=1), then frame_size needs to be exactly"] + #[doc = " the duration of audio that is missing, otherwise the"] + #[doc = " decoder will not be in the optimal state to decode the"] + #[doc = " next incoming packet. For the PLC and FEC cases, frame_size"] + #[doc = " must be a multiple of 2.5 ms."] + #[doc = " @param decode_fec int: Flag (0 or 1) to request that any in-band"] + #[doc = " forward error correction data be decoded."] + #[doc = " If no such data is available, the frame is"] + #[doc = " decoded as if it were lost."] + #[doc = " @returns Number of samples decoded on success or a negative error code"] + #[doc = " (see @ref opus_errorcodes) on failure."] + pub fn opus_multistream_decode( + st: *mut OpusMSDecoder, + data: *const ::std::os::raw::c_uchar, + len: opus_int32, + pcm: *mut opus_int16, + frame_size: ::std::os::raw::c_int, + decode_fec: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Decode a multistream Opus packet with floating point output."] + #[doc = " @param st OpusMSDecoder*: Multistream decoder state."] + #[doc = " @param[in] data const unsigned char*: Input payload."] + #[doc = " Use a NULL"] + #[doc = " pointer to indicate packet"] + #[doc = " loss."] + #[doc = " @param len opus_int32: Number of bytes in payload."] + #[doc = " @param[out] pcm opus_int16*: Output signal, with interleaved"] + #[doc = " samples."] + #[doc = " This must contain room for"] + #[doc = " frame_size*channels"] + #[doc = " samples."] + #[doc = " @param frame_size int: The number of samples per channel of"] + #[doc = " available space in \\a pcm."] + #[doc = " If this is less than the maximum packet duration"] + #[doc = " (120 ms; 5760 for 48kHz), this function will not be capable"] + #[doc = " of decoding some packets. In the case of PLC (data==NULL)"] + #[doc = " or FEC (decode_fec=1), then frame_size needs to be exactly"] + #[doc = " the duration of audio that is missing, otherwise the"] + #[doc = " decoder will not be in the optimal state to decode the"] + #[doc = " next incoming packet. For the PLC and FEC cases, frame_size"] + #[doc = " must be a multiple of 2.5 ms."] + #[doc = " @param decode_fec int: Flag (0 or 1) to request that any in-band"] + #[doc = " forward error correction data be decoded."] + #[doc = " If no such data is available, the frame is"] + #[doc = " decoded as if it were lost."] + #[doc = " @returns Number of samples decoded on success or a negative error code"] + #[doc = " (see @ref opus_errorcodes) on failure."] + pub fn opus_multistream_decode_float( + st: *mut OpusMSDecoder, + data: *const ::std::os::raw::c_uchar, + len: opus_int32, + pcm: *mut f32, + frame_size: ::std::os::raw::c_int, + decode_fec: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Perform a CTL function on a multistream Opus decoder."] + #[doc = ""] + #[doc = " Generally the request and subsequent arguments are generated by a"] + #[doc = " convenience macro."] + #[doc = " @param st OpusMSDecoder*: Multistream decoder state."] + #[doc = " @param request This and all remaining parameters should be replaced by one"] + #[doc = " of the convenience macros in @ref opus_genericctls,"] + #[doc = " @ref opus_decoderctls, or @ref opus_multistream_ctls."] + #[doc = " @see opus_genericctls"] + #[doc = " @see opus_decoderctls"] + #[doc = " @see opus_multistream_ctls"] + pub fn opus_multistream_decoder_ctl( + st: *mut OpusMSDecoder, + request: ::std::os::raw::c_int, + ... + ) -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " Frees an OpusMSDecoder allocated by"] + #[doc = " opus_multistream_decoder_create()."] + #[doc = " @param st OpusMSDecoder: Multistream decoder state to be freed."] + pub fn opus_multistream_decoder_destroy(st: *mut OpusMSDecoder); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn access_symbols() { + unsafe { + opus_get_version_string(); + opus_encoder_get_size(0); + } + } +} diff --git a/native/opennow-streamer/vendor/audiopus-sys/src/wrapper.h b/native/opennow-streamer/vendor/audiopus-sys/src/wrapper.h new file mode 100644 index 000000000..a04539112 --- /dev/null +++ b/native/opennow-streamer/vendor/audiopus-sys/src/wrapper.h @@ -0,0 +1 @@ +#include "../opus/include/opus_multistream.h" diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/.github/workflows/build.yml b/native/opennow-streamer/vendor/ffmpeg-sys-next/.github/workflows/build.yml new file mode 100644 index 000000000..b18f9f5f4 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/.github/workflows/build.yml @@ -0,0 +1,107 @@ +name: build +on: + push: + branches: + - master + pull_request: + schedule: + - cron: "0 0 * * *" +jobs: + build-test-lint: + name: FFmpeg ${{ matrix.ffmpeg_version }} - bindgen, test, and lint + runs-on: ubuntu-latest + container: jrottenberg/ffmpeg:${{ matrix.ffmpeg_version }}-ubuntu + strategy: + matrix: + ffmpeg_version: + ["3.3", "3.4", "4.0", "4.1", "4.2", "4.3", "4.4", "5.0", "5.1", "6.0"] + fail-fast: false + env: + CARGO_PROFILE_DEV_BUILD_OVERRIDE_DEBUG: true + FEATURES: avcodec,avdevice,avfilter,avformat,postproc,swresample,swscale + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: | + apt update + apt install -y --no-install-recommends clang curl pkg-config ca-certificates + - name: Set up Rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: stable + override: true + components: rustfmt, clippy + - name: Build + run: | + cargo build --features $FEATURES + - name: Test + run: | + cargo test --features $FEATURES + - name: Lint + run: | + cargo clippy --features $FEATURES -- -D warnings + + # While this issue persists in the ffmpeg docker hub https://github.com/jrottenberg/ffmpeg/issues/418 + # manually download ffmpeg sources and link + # seems like the docker image is somehow conflicting with the github action's ubuntu version + build-test-lint-7-1: + name: FFmpeg ${{ matrix.ffmpeg_version }} - bindgen, test, and lint + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + ffmpeg_version: ["6.1", "7.0", "7.1", "8.0", "8.1", "9.0"] + env: + CARGO_PROFILE_DEV_BUILD_OVERRIDE_DEBUG: true + FEATURES: avcodec,avdevice,avfilter,avformat,swresample,swscale #,postproc + FFMPEG_DIR: /home/runner/work/rust-ffmpeg-sys/rust-ffmpeg-sys/ffmpeg-${{ matrix.ffmpeg_version }}-linux-clang-default + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: | + sudo apt update + sudo apt install -y --no-install-recommends clang curl pkg-config xz-utils + curl -L https://sourceforge.net/projects/avbuild/files/linux/ffmpeg-${{ matrix.ffmpeg_version }}-linux-clang-default.tar.xz/download -o ffmpeg.tar.xz + tar -xf ffmpeg.tar.xz + pwd + - name: Set up Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + components: rustfmt, clippy + - name: Build + run: | + cargo build --features $FEATURES + - name: Test + run: | + cargo test --features $FEATURES + - name: Lint + run: | + cargo clippy --features $FEATURES -- -D warnings + + latest-ffmpeg-build-static: + name: Manually fetch, build, and link static ffmpeg + runs-on: ubuntu-latest + env: + FEATURES: build,static,build-lib-x264,build-license-gpl,avcodec,avdevice,avfilter,avformat,swresample,swscale #,postproc + steps: + - uses: actions/checkout@v2 + - name: Set up Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + components: rustfmt, clippy + - name: Check format + run: | + cargo fmt --all -- --check + - name: Install dependencies + run: | + sudo apt update + sudo apt install -y --no-install-recommends clang curl pkg-config ca-certificates llvm pkg-config curl libssl-dev yasm nasm libx264-dev + + - name: Build and statically link latest ffmpeg + run: | + cargo build --features $FEATURES -vv + cargo test --features $FEATURES diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/.gitignore b/native/opennow-streamer/vendor/ffmpeg-sys-next/.gitignore new file mode 100644 index 000000000..907911999 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/.gitignore @@ -0,0 +1,3 @@ +target +Cargo.lock +/tmp diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/Cargo.toml b/native/opennow-streamer/vendor/ffmpeg-sys-next/Cargo.toml new file mode 100644 index 000000000..162294e82 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/Cargo.toml @@ -0,0 +1,144 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2024" +name = "ffmpeg-sys-next" +version = "9.0.0" +authors = [ + "meh. ", + "Zhiming Wang ", +] +build = "build.rs" +links = "ffmpeg" +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "FFI bindings to FFmpeg" +readme = "README.md" +keywords = [ + "audio", + "video", +] +license = "WTFPL" +repository = "https://github.com/zmwangx/rust-ffmpeg-sys" + +[features] +avcodec = [] +avdevice = ["avformat"] +avfilter = [] +avformat = ["avcodec"] +avresample = [] +build = ["static"] +build-amf = ["build"] +build-audiotoolbox = ["build"] +build-drm = ["build"] +build-lib-aacplus = ["build"] +build-lib-ass = ["build"] +build-lib-avs = ["build"] +build-lib-celt = ["build"] +build-lib-d3d11va = ["build"] +build-lib-dav1d = ["build"] +build-lib-dcadec = ["build"] +build-lib-dxva2 = ["build"] +build-lib-faac = ["build"] +build-lib-fdk-aac = ["build"] +build-lib-fontconfig = ["build"] +build-lib-freebidi = ["build"] +build-lib-freetype = ["build"] +build-lib-frei0r = ["build"] +build-lib-gnutls = ["build"] +build-lib-gsm = ["build"] +build-lib-ilbc = ["build"] +build-lib-kvazaar = ["build"] +build-lib-ladspa = ["build"] +build-lib-libmfx = ["build"] +build-lib-mp3lame = ["build"] +build-lib-opencore-amrnb = ["build"] +build-lib-opencore-amrwb = ["build"] +build-lib-opencv = ["build"] +build-lib-openh264 = ["build"] +build-lib-openjpeg = ["build"] +build-lib-openssl = ["build"] +build-lib-opus = ["build"] +build-lib-schroedinger = ["build"] +build-lib-shine = ["build"] +build-lib-smbclient = ["build"] +build-lib-snappy = ["build"] +build-lib-speex = ["build"] +build-lib-ssh = ["build"] +build-lib-stagefright-h264 = ["build"] +build-lib-theora = ["build"] +build-lib-twolame = ["build"] +build-lib-utvideo = ["build"] +build-lib-vmaf = ["build"] +build-lib-vo-aacenc = ["build"] +build-lib-vo-amrwbenc = ["build"] +build-lib-vorbis = ["build"] +build-lib-vpx = ["build"] +build-lib-wavpack = ["build"] +build-lib-webp = ["build"] +build-lib-x264 = ["build"] +build-lib-x265 = ["build"] +build-lib-xvid = ["build"] +build-license-gpl = ["build"] +build-license-nonfree = ["build"] +build-license-version3 = ["build"] +build-mediacodec = ["build"] +build-nvenc = ["build"] +build-nvdec = ["build"] +build-nvidia = ["build"] +build-pic = ["build"] +build-portable = ["build"] +build-vaapi = ["build"] +build-videotoolbox = ["build"] +build-vulkan = ["build"] +build-zlib = ["build"] +default = [ + "avcodec", + "avdevice", + "avfilter", + "avformat", + "swresample", + "swscale", +] +non-exhaustive-enums = [] +postproc = [] +static = [] +swresample = [] +swscale = [] + +[lib] +name = "ffmpeg_sys_next" +path = "src/lib.rs" +doctest = false + +[dependencies.libc] +version = "0.2" + +[build-dependencies.bindgen] +version = "0.72" +features = ["runtime"] +default-features = false + +[build-dependencies.cc] +version = "1.3" + +[build-dependencies.num_cpus] +version = "1.17" + +[build-dependencies.pkg-config] +version = "0.3" + +[target.'cfg(target_env = "msvc")'.build-dependencies.vcpkg] +version = "0.2" diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/Cargo.toml.orig b/native/opennow-streamer/vendor/ffmpeg-sys-next/Cargo.toml.orig new file mode 100644 index 000000000..206de9f33 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/Cargo.toml.orig @@ -0,0 +1,126 @@ +[package] +name = "ffmpeg-sys-next" +version = "9.0.0" +build = "build.rs" +links = "ffmpeg" +edition = "2024" + +authors = ["meh. ", "Zhiming Wang "] +license = "WTFPL" + +description = "FFI bindings to FFmpeg" +repository = "https://github.com/zmwangx/rust-ffmpeg-sys" +keywords = ["audio", "video"] + +[lib] +# Disable doctests as a workaround for https://github.com/rust-lang/rust-bindgen/issues/1313 +doctest = false + +[dependencies] +libc = "0.2" + +[build-dependencies] +num_cpus = "1.17" +cc = "1.3" +pkg-config = "0.3" +bindgen = { version = "0.72", default-features = false, features = ["runtime"] } + +[target.'cfg(target_env = "msvc")'.build-dependencies] +vcpkg = "0.2" + +[features] +default = ["avcodec", "avdevice", "avfilter", "avformat", "swresample", "swscale"] + +static = [] +build = ["static"] + +# mark enums in generated bindings as #[non_exhaustive] +non-exhaustive-enums = [] + +# licensing +build-license-gpl = ["build"] +build-license-nonfree = ["build"] +build-license-version3 = ["build"] + +# misc +build-portable = ["build"] +build-drm = ["build"] +build-nvenc = ["build"] +build-nvdec = ["build"] +build-pic = ["build"] +build-zlib = ["build"] + +# ssl +build-lib-gnutls = ["build"] +build-lib-openssl = ["build"] + +# filters +build-lib-fontconfig = ["build"] +build-lib-frei0r = ["build"] +build-lib-ladspa = ["build"] +build-lib-ass = ["build"] +build-lib-freetype = ["build"] +build-lib-freebidi = ["build"] +build-lib-opencv = ["build"] +build-lib-vmaf = ["build"] + +# encoders/decoders +build-lib-aacplus = ["build"] +build-lib-celt = ["build"] +build-lib-dav1d = ["build"] +build-lib-dcadec = ["build"] +build-lib-faac = ["build"] +build-lib-fdk-aac = ["build"] +build-lib-gsm = ["build"] +build-lib-ilbc = ["build"] +build-lib-kvazaar = ["build"] +build-lib-mp3lame = ["build"] +build-lib-opencore-amrnb = ["build"] +build-lib-opencore-amrwb = ["build"] +build-lib-openh264 = ["build"] +build-lib-openjpeg = ["build"] +build-lib-opus = ["build"] +build-lib-schroedinger = ["build"] +build-lib-shine = ["build"] +build-lib-snappy = ["build"] +build-lib-speex = ["build"] +build-lib-stagefright-h264 = ["build"] +build-lib-theora = ["build"] +build-lib-twolame = ["build"] +build-lib-utvideo = ["build"] +build-lib-vo-aacenc = ["build"] +build-lib-vo-amrwbenc = ["build"] +build-lib-vorbis = ["build"] +build-lib-vpx = ["build"] +build-lib-wavpack = ["build"] +build-lib-webp = ["build"] +build-lib-x264 = ["build"] +build-lib-x265 = ["build"] +build-lib-avs = ["build"] +build-lib-xvid = ["build"] + +# hardware accelleration +build-videotoolbox = ["build"] +build-audiotoolbox = ["build"] +build-vaapi = ["build"] +build-lib-d3d11va = ["build"] +build-lib-dxva2 = ["build"] +build-nvidia = ["build"] +build-lib-libmfx = ["build"] +build-mediacodec = ["build"] +build-amf = ["build"] +build-vulkan = ["build"] + +# protocols +build-lib-smbclient = ["build"] +build-lib-ssh = ["build"] + +# components +avcodec = [] +avdevice = ["avformat"] +avfilter = [] +avformat = ["avcodec"] +avresample = [] +postproc = [] +swresample = [] +swscale = [] diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/README.md b/native/opennow-streamer/vendor/ffmpeg-sys-next/README.md new file mode 100644 index 000000000..b8f00c7a1 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/README.md @@ -0,0 +1,40 @@ +[![ffmpeg-sys-next on crates.io](https://img.shields.io/crates/v/ffmpeg-sys-next?cacheSeconds=3600)](https://crates.io/crates/ffmpeg-sys-next) +[![build](https://github.com/zmwangx/rust-ffmpeg-sys/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/zmwangx/rust-ffmpeg-sys/actions) + +This is a fork of the abandoned [ffmpeg-sys](https://github.com/meh/rust-ffmpeg-sys) crate. You can find this crate as [ffmpeg-sys-next](https://crates.io/crates/ffmpeg-sys-next) on crates.io. + +This crate contains low level bindings to FFmpeg. You're probably interested in the high level bindings instead: [ffmpeg-next](https://github.com/zmwangx/rust-ffmpeg). + +A word on versioning: major and minor versions track major and minor versions of FFmpeg, e.g. 4.2.x of this crate has been updated to support the 4.2.x series of FFmpeg. Patch level is reserved for bug fixes of this crate and does not track FFmpeg patch versions. + +## Feature flags + +In addition to feature flags declared in `Cargo.toml`, this crate performs various compile-time version and feature detections and exposes the results in additional flags. These flags are briefly documented below; run `cargo build -vv` to view more details. + +- `ffmpeg__` flags (new in v4.3.2), e.g. `ffmpeg_4_4`, indicating the FFmpeg installation being compiled against is at least version `.`. Currently available: + + - `ffmpeg_3_0` + - `ffmpeg_3_1` + - `ffmpeg_3_2` + - `ffmpeg_3_3` + - `ffmpeg_3_4` + - `ffmpeg_4_0` + - `ffmpeg_4_1` + - `ffmpeg_4_2` + - `ffmpeg_4_3` + - `ffmpeg_4_4` + - `ffmpeg_5_0` + - `ffmpeg_5_1` + - `ffmpeg_6_0` + - `ffmpeg_6_1` + - `ffmpeg_7_0` + - `ffmpeg_7_1` + - `ffmpeg_8_0` + - `ffmpeg_8_1` + - `ffmpeg_9_0` + +- `avcodec_version_greater_than__` (new in v4.3.2), e.g., `avcodec_version_greater_than_58_90`. The name should be self-explanatory. + +- `ff_api_`, e.g. `ff_api_vaapi`, corresponding to whether their respective uppercase deprecation guards evaluate to true. + +- `ff_api__is_defined`, e.g. `ff_api_vappi_is_defined`, similar to above except these are enabled as long as the corresponding deprecation guards are defined. diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/build.rs b/native/opennow-streamer/vendor/ffmpeg-sys-next/build.rs new file mode 100644 index 000000000..09cd4ad01 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/build.rs @@ -0,0 +1,1917 @@ +extern crate bindgen; +extern crate cc; +extern crate num_cpus; +extern crate pkg_config; + +use std::env; +use std::fmt::Write as FmtWrite; +use std::fs::{self, File}; +use std::io::{self, BufRead, BufReader, Write}; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::str; + +use bindgen::callbacks::{ + EnumVariantCustomBehavior, EnumVariantValue, IntKind, MacroParsingBehavior, ParseCallbacks, +}; + +#[derive(Debug)] +struct Library { + name: &'static str, + is_feature: bool, +} + +impl Library { + fn feature_name(&self) -> Option { + if self.is_feature { + Some("CARGO_FEATURE_".to_string() + &self.name.to_uppercase()) + } else { + None + } + } +} + +static LIBRARIES: &[Library] = &[ + Library { + name: "avcodec", + is_feature: true, + }, + Library { + name: "avdevice", + is_feature: true, + }, + Library { + name: "avfilter", + is_feature: true, + }, + Library { + name: "avformat", + is_feature: true, + }, + Library { + name: "avresample", + is_feature: true, + }, + Library { + name: "avutil", + is_feature: false, + }, + Library { + name: "postproc", + is_feature: true, + }, + Library { + name: "swresample", + is_feature: true, + }, + Library { + name: "swscale", + is_feature: true, + }, +]; + +#[derive(Debug)] +struct Callbacks; + +impl ParseCallbacks for Callbacks { + fn int_macro(&self, _name: &str, value: i64) -> Option { + let ch_layout_prefix = "AV_CH_"; + let codec_cap_prefix = "AV_CODEC_CAP_"; + let codec_flag_prefix = "AV_CODEC_FLAG_"; + let error_max_size = "AV_ERROR_MAX_STRING_SIZE"; + + if _name.starts_with(ch_layout_prefix) { + Some(IntKind::ULongLong) + } else if value >= i32::MIN as i64 + && value <= i32::MAX as i64 + && (_name.starts_with(codec_cap_prefix) || _name.starts_with(codec_flag_prefix)) + { + Some(IntKind::UInt) + } else if _name == error_max_size { + Some(IntKind::Custom { + name: "usize", + is_signed: false, + }) + } else if value >= i32::MIN as i64 && value <= i32::MAX as i64 { + Some(IntKind::Int) + } else { + None + } + } + + fn enum_variant_behavior( + &self, + _enum_name: Option<&str>, + original_variant_name: &str, + _variant_value: EnumVariantValue, + ) -> Option { + let dummy_codec_id_prefix = "AV_CODEC_ID_FIRST_"; + if original_variant_name.starts_with(dummy_codec_id_prefix) { + Some(EnumVariantCustomBehavior::Constify) + } else { + None + } + } + + // https://github.com/rust-lang/rust-bindgen/issues/687#issuecomment-388277405 + fn will_parse_macro(&self, name: &str) -> MacroParsingBehavior { + use MacroParsingBehavior::*; + + match name { + "FP_INFINITE" => Ignore, + "FP_NAN" => Ignore, + "FP_NORMAL" => Ignore, + "FP_SUBNORMAL" => Ignore, + "FP_ZERO" => Ignore, + _ => Default, + } + } +} + +fn version() -> String { + let major: u8 = env::var("CARGO_PKG_VERSION_MAJOR") + .unwrap() + .parse() + .unwrap(); + let minor: u8 = env::var("CARGO_PKG_VERSION_MINOR") + .unwrap() + .parse() + .unwrap(); + + format!("{major}.{minor}") +} + +fn output() -> PathBuf { + PathBuf::from(env::var("OUT_DIR").unwrap()) +} + +fn source() -> PathBuf { + output().join(format!("ffmpeg-{}", version())) +} + +fn search() -> PathBuf { + let mut absolute = env::current_dir().unwrap(); + absolute.push(output()); + absolute.push("dist"); + + absolute +} + +fn fetch() -> io::Result<()> { + let output_base_path = output(); + let clone_dest_dir = format!("ffmpeg-{}", version()); + let _ = std::fs::remove_dir_all(output_base_path.join(&clone_dest_dir)); + let status = Command::new("git") + .current_dir(&output_base_path) + .args(if cfg!(target_os = "windows") { + vec!["-c", "core.autocrlf=false"] + } else { + vec![] + }) + .arg("clone") + .arg("--depth=1") + .arg("-b") + .arg(format!("release/{}", version())) + .arg("https://github.com/FFmpeg/FFmpeg") + .arg(&clone_dest_dir) + .status()?; + + if status.success() { + Ok(()) + } else { + Err(io::Error::other("fetch failed")) + } +} + +fn switch(configure: &mut Command, feature: &str, name: &str) { + let arg = if env::var("CARGO_FEATURE_".to_string() + feature).is_ok() { + "--enable-" + } else { + "--disable-" + }; + configure.arg(arg.to_string() + name); +} + +fn is_apple_simulator() -> bool { + env::var("CARGO_CFG_TARGET_VENDOR").unwrap_or_default() == "apple" + && (env::var("CARGO_CFG_TARGET_ABI").unwrap_or_default() == "sim" + || env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default() == "x86_64") +} + +fn apple_sdk_name(target_os: &str, is_sim: bool) -> Option<&'static str> { + match (target_os, is_sim) { + ("macos", _) => Some("macosx"), + ("ios", true) => Some("iphonesimulator"), + ("ios", false) => Some("iphoneos"), + ("tvos", true) => Some("appletvsimulator"), + ("tvos", false) => Some("appletvos"), + _ => None, + } +} + +/// Returns the `-m*-version-min=` cflags for cross-compiling to Apple platforms. +fn apple_version_min_cflag(target_os: &str, is_sim: bool) -> Option<&'static str> { + match (target_os, is_sim) { + ("ios", true) => Some("-mios-simulator-version-min=11.0"), + ("ios", false) => Some("-mios-version-min=11.0"), + ("macos", _) => Some("-mmacosx-version-min=10.11"), + ("tvos", true) => Some("-mappletvsimulator-version-min=13.0"), + ("tvos", false) => Some("-mappletvos-version-min=13.0"), + _ => None, + } +} + +fn get_ffmpeg_target_os() -> String { + let cargo_target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + match cargo_target_os.as_str() { + "ios" | "tvos" => "darwin".to_string(), + _ => cargo_target_os, + } +} + +/// Find the sysroot required for a cross compilation by ffmpeg **and** bindgen +/// @see https://github.com/rust-lang/rust-bindgen/issues/1229 +fn find_sysroot() -> Option { + if env::var("CARGO_FEATURE_BUILD").is_err() || env::var("HOST") == env::var("TARGET") { + return None; + } + + if let Ok(sysroot) = env::var("SYSROOT") { + return Some(sysroot.to_string()); + } + + if matches!( + env::var("CARGO_CFG_TARGET_OS").as_deref(), + Ok("ios") | Ok("tvos") + ) { + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + let sdk = apple_sdk_name(&target_os, is_apple_simulator()).unwrap(); + let xcode_output = Command::new("xcrun") + .args(["--sdk", sdk, "--show-sdk-path"]) + .output() + .expect("failed to run xcrun"); + + if !xcode_output.status.success() { + panic!( + "Failed to run xcrun to get the {} sysroot, please install xcode tools or provide sysroot using $SYSROOT env. Error: {}", + sdk, + String::from_utf8_lossy(&xcode_output.stderr) + ); + } + + let string = String::from_utf8(xcode_output.stdout) + .expect("Failed to parse xcrun output") + .replace("\n", ""); + + if !Path::new(&string).exists() { + panic!("xcrun returned invalid sysroot path: {}", string); + } + + return Some(string); + } + + if env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("android") { + let sysroot_path = env::var("CARGO_NDK_SYSROOT_PATH").expect("Missing android sysroot path. For android cross compilation please use cargo-ndk which exposes all the required NDK paths throught env variables."); + + if !Path::new(&sysroot_path).exists() { + panic!("Android sysroot path does not exists: {}", sysroot_path); + } + + return Some(sysroot_path); + } + + println!("cargo:warning=Detected cross compilation but sysroot not provided"); + None +} + +/// Validate a CPU flag value (e.g. from FFMPEG_MARCH/FFMPEG_MTUNE) before passing +/// it to the compiler, to prevent arbitrary string injection. +fn validated_cpu_flag(var: &str, value: String) -> String { + if value.is_empty() { + return value; // omit the flag + } + let valid = !value.starts_with('-') + && value + .chars() + .all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '.' | '+' | '_')); + if !valid { + panic!( + "Invalid {} value {:?}: only ASCII letters, digits and '-._+' are allowed \ + (e.g. native, x86-64-v3, armv8.2-a+crc)", + var, value + ); + } + value +} + +fn build(sysroot: Option<&str>) -> io::Result<()> { + let source_dir = source(); + if cfg!(target_os = "windows") { + let path = env::var("PATH").unwrap_or_default(); + let mut paths = env::split_paths(&path).collect::>(); + paths.push(source_dir.clone()); + let new_path = env::join_paths(paths).unwrap(); + + let include = env::var("INCLUDE").unwrap_or_default(); + let mut includes = env::split_paths(&include).collect::>(); + includes.push(source_dir.clone()); + let new_include = env::join_paths(includes).unwrap(); + + unsafe { + env::set_var("PATH", &new_path); + env::set_var("INCLUDE", &new_include); + } + } + + // Command's path is not relative to command's current_dir + let configure_path = source_dir.join("configure"); + assert!(configure_path.exists()); + let mut configure = if cfg!(target_os = "windows") { + if Command::new("sh") + .arg("-c") + .arg("echo ok") + .output() + .is_err() + { + return Err(io::Error::other( + "Failed to find 'sh.exe', which is required for building FFmpeg", + )); + } + + let mut configure = Command::new("sh"); + configure.arg(configure_path); + if cfg!(target_env = "msvc") { + configure.arg("--toolchain=msvc"); + } + + configure + } else { + Command::new(&configure_path) + }; + + configure.current_dir(&source_dir); + if env::var("CARGO_FEATURE_BUILD_VULKAN").is_ok() + || env::var("CARGO_FEATURE_BUILD_NVDEC").is_ok() + { + let bundled_include = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("bundled-headers") + .join("include"); + let inherited = env::var("CFLAGS").unwrap_or_default(); + let bundled_pkgconfig = bundled_include + .parent() + .unwrap() + .join("lib") + .join("pkgconfig"); + let inherited_pkgconfig = env::var("PKG_CONFIG_PATH").unwrap_or_default(); + configure.env( + "CFLAGS", + format!("-I{} {inherited}", bundled_include.to_string_lossy()), + ); + configure.env( + "PKG_CONFIG_PATH", + format!( + "{}:{inherited_pkgconfig}", + bundled_pkgconfig.to_string_lossy() + ), + ); + println!( + "cargo:rerun-if-changed={}", + bundled_include.to_string_lossy() + ); + } + configure.arg(format!("--prefix={}", search().to_string_lossy())); + + let target = env::var("TARGET").unwrap(); + let host = env::var("HOST").unwrap(); + if target != host { + configure.arg("--enable-cross-compile"); + + // Rust targets are subtly different than naming scheme for compiler prefixes. + // The cc crate has the messy logic of guessing a working prefix, + // and this is a messy way of reusing that logic. + let cc = cc::Build::new(); + + // Apple-clang needs this, -arch is not enough. + let target_flag = format!("--target={target}"); + if cc.is_flag_supported(&target_flag).unwrap_or(false) { + configure.arg(format!("--extra-cflags={target_flag}")); + configure.arg(format!("--extra-ldflags={target_flag}")); + } + + configure.arg(format!( + "--arch={}", + env::var("CARGO_CFG_TARGET_ARCH").unwrap() + )); + configure.arg(format!("--target-os={}", get_ffmpeg_target_os())); + + // cross-prefix won't work for android because they use different compiler for every + // platform version, so we provide direct compiler paths manually instead + if env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("android") { + let compiler = cc.get_compiler(); + if let Some(compiler_name) = compiler.path().file_stem().and_then(|s| s.to_str()) { + if let Some(suffix_pos) = compiler_name.rfind('-') { + let prefix = compiler_name[0..suffix_pos].trim_end_matches("-wr"); // "wr-c++" compiler + + configure.arg(format!("--cross-prefix={prefix}-")); + } + } else { + eprintln!( + "warning: Could not determine cross-compiler prefix from path: {:?}", + compiler.path() + ); + } + } + } else { + // Determine -march/-mtune flags for the compiler. + // Priority: env vars > build-portable feature > default (native) + println!("cargo:rerun-if-env-changed=FFMPEG_MARCH"); + println!("cargo:rerun-if-env-changed=FFMPEG_MTUNE"); + + let march_env = env::var("FFMPEG_MARCH").ok(); + let mtune_env = env::var("FFMPEG_MTUNE").ok(); + + let (march, mtune) = if march_env.is_some() || mtune_env.is_some() { + // Env vars take highest priority. Empty string means omit the flag. + // Validate the values to prevent arbitrary string injection. + ( + validated_cpu_flag( + "FFMPEG_MARCH", + march_env.unwrap_or_else(|| "native".to_string()), + ), + validated_cpu_flag( + "FFMPEG_MTUNE", + mtune_env.unwrap_or_else(|| "native".to_string()), + ), + ) + } else if cfg!(feature = "build-portable") { + // Omit both flags so the compiler uses its baseline target. + (String::new(), String::new()) + } else { + // Default: tune for the host architecture. + ("native".to_string(), "native".to_string()) + }; + + let mut parts = Vec::new(); + if !march.is_empty() { + parts.push(format!("-march={march}")); + } + if !mtune.is_empty() { + parts.push(format!("-mtune={mtune}")); + } + if !parts.is_empty() { + configure.arg(format!("--extra-cflags={}", parts.join(" "))); + } + } + + if env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("windows") { + // essential librareis on windowsw + println!("cargo:rustc-link-lib=dylib=ole32"); + println!("cargo:rustc-link-lib=dylib=oleaut32"); + println!("cargo:rustc-link-lib=dylib=gdi32"); + println!("cargo:rustc-link-lib=dylib=user32"); + println!("cargo:rustc-link-lib=dylib=vfw32"); + println!("cargo:rustc-link-lib=dylib=strmiids"); + println!("cargo:rustc-link-lib=dylib=bcrypt"); + println!("cargo:rustc-link-lib=dylib=shlwapi"); + println!("cargo:rustc-link-lib=dylib=shell32"); + } + + // for ios/tvos it is required to provide sysroot for both configure and bindgen + // for macos the easiest way is to run xcrun, for other platform we support $SYSROOT var + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + let is_sim = is_apple_simulator(); + + if matches!(target_os.as_str(), "ios" | "tvos") { + let sdk = apple_sdk_name(&target_os, is_sim).unwrap(); + let sysroot = sysroot.unwrap_or_else(|| panic!("The sysroot is required for {} cross compilation, make sure to have available xcode or provide the $SYSROOT env var", target_os)); + configure.arg(format!("--sysroot={sysroot}")); + + let cc = Command::new("xcrun") + .args(["--sdk", sdk, "-f", "clang"]) + .output() + .expect("failed to run xcrun") + .stdout; + + configure.arg(format!( + "--cc={}", + str::from_utf8(&cc) + .expect("Failed to parse xcrun output") + .trim() + )); + } + + if env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("android") { + // cargo ndk auto populates rust env variables for android cross compilation + // so we can just leverage the same compiler path and cflags for ffmpeg build + let android_cc_raw_path = env::var(format!("CC_{target}")).expect("Missing CC path for android. Make sure to use cargo-ndk for adnrdoic cross compilation"); + let android_cc_path = Path::new(&android_cc_raw_path); + if !android_cc_path.exists() { + panic!("Android CC path does not exists: {}", android_cc_raw_path); + } + configure.arg(format!("--cc={android_cc_raw_path}")); + + for tool in ["nm", "strip"] { + configure.arg(format!( + "--{tool}={}", + android_cc_path + .join("..") + .join(format!("llvm-{tool}")) + .canonicalize() + .unwrap_or_else(|_| panic!("failed to resolve a path to android {}", tool)) + .display() + )); + } + + if let Ok(android_target_flags) = env::var(format!("CFLAGS_{target}")).as_deref() { + configure.arg(format!("--extra-cflags={android_target_flags}")); + configure.arg(format!("--extra-ldflags={android_target_flags}")); + } + + if matches!( + env::var("CARGO_CFG_TARGET_ARCH").as_deref(), + Ok("x86_64") | Ok("x86") + ) { + // x86 asm contains position dependent code (relocations) + configure.arg("--disable-asm"); + } + + // https://github.com/Javernaut/ffmpeg-android-maker/blob/master/scripts/ffmpeg/build.sh#L30 + // configure.arg(--extra-ldflags=-WL,-z,max-page-size=16384"); + // required for android + configure.arg("--extra-cflags=-fPIC"); + } + + // control debug build + if env::var("DEBUG").is_ok() { + configure.arg("--enable-debug"); + configure.arg("--disable-stripping"); + } else { + configure.arg("--disable-debug"); + configure.arg("--enable-stripping"); + configure.arg("--extra-cflags=-03 -ffast-math -funroll-loops"); + #[cfg(not(target_os = "windows"))] + configure.arg("--extra-ldflags=-flto"); + } + + // make it static + configure.arg("--enable-static"); + configure.arg("--disable-shared"); + // windows includes threading in the standard library + #[cfg(not(target_env = "msvc"))] + { + configure.arg("--enable-pthreads"); + } + + // position independent code + configure.arg("--enable-pic"); + + // stop autodetected libraries enabling themselves, causing linking errors + configure.arg("--disable-autodetect"); + + // do not build programs since we don't need them + configure.arg("--disable-programs"); + + // do not generate documentation + configure.arg("--disable-doc"); + + macro_rules! enable { + ($conf:expr, $feat:expr, $name:expr) => { + if env::var(concat!("CARGO_FEATURE_", $feat)).is_ok() { + $conf.arg(concat!("--enable-", $name)); + } + }; + } + + // macro_rules! disable { + // ($conf:expr, $feat:expr, $name:expr) => ( + // if env::var(concat!("CARGO_FEATURE_", $feat)).is_err() { + // $conf.arg(concat!("--disable-", $name)); + // } + // ) + // } + + // the binary using ffmpeg-sys must comply with GPL + switch(&mut configure, "BUILD_LICENSE_GPL", "gpl"); + + // the binary using ffmpeg-sys must comply with (L)GPLv3 + switch(&mut configure, "BUILD_LICENSE_VERSION3", "version3"); + + // the binary using ffmpeg-sys cannot be redistributed + switch(&mut configure, "BUILD_LICENSE_NONFREE", "nonfree"); + + let ffmpeg_major_version: u32 = env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap(); + + // configure building libraries based on features + for lib in LIBRARIES + .iter() + .filter(|lib| lib.is_feature) + .filter(|lib| !(lib.name == "avresample" && ffmpeg_major_version >= 5)) + .filter(|lib| !(lib.name == "postproc" && ffmpeg_major_version >= 8)) + { + switch(&mut configure, &lib.name.to_uppercase(), lib.name); + } + + // configure external SSL libraries + enable!(configure, "BUILD_LIB_GNUTLS", "gnutls"); + enable!(configure, "BUILD_LIB_OPENSSL", "openssl"); + + // configure external filters + enable!(configure, "BUILD_LIB_FONTCONFIG", "fontconfig"); + enable!(configure, "BUILD_LIB_FREI0R", "frei0r"); + enable!(configure, "BUILD_LIB_LADSPA", "ladspa"); + enable!(configure, "BUILD_LIB_ASS", "libass"); + enable!(configure, "BUILD_LIB_FREETYPE", "libfreetype"); + enable!(configure, "BUILD_LIB_FRIBIDI", "libfribidi"); + enable!(configure, "BUILD_LIB_OPENCV", "libopencv"); + enable!(configure, "BUILD_LIB_VMAF", "libvmaf"); + + // configure external encoders/decoders + enable!(configure, "BUILD_LIB_AACPLUS", "libaacplus"); + enable!(configure, "BUILD_LIB_CELT", "libcelt"); + enable!(configure, "BUILD_LIB_DCADEC", "libdcadec"); + enable!(configure, "BUILD_LIB_DAV1D", "libdav1d"); + enable!(configure, "BUILD_LIB_FAAC", "libfaac"); + enable!(configure, "BUILD_LIB_FDK_AAC", "libfdk-aac"); + enable!(configure, "BUILD_LIB_GSM", "libgsm"); + enable!(configure, "BUILD_LIB_ILBC", "libilbc"); + enable!(configure, "BUILD_LIB_VAZAAR", "libvazaar"); + enable!(configure, "BUILD_LIB_MP3LAME", "libmp3lame"); + enable!(configure, "BUILD_LIB_OPENCORE_AMRNB", "libopencore-amrnb"); + enable!(configure, "BUILD_LIB_OPENCORE_AMRWB", "libopencore-amrwb"); + enable!(configure, "BUILD_LIB_OPENH264", "libopenh264"); + enable!(configure, "BUILD_LIB_OPENH265", "libopenh265"); + enable!(configure, "BUILD_LIB_OPENJPEG", "libopenjpeg"); + enable!(configure, "BUILD_LIB_OPUS", "libopus"); + enable!(configure, "BUILD_LIB_SCHROEDINGER", "libschroedinger"); + enable!(configure, "BUILD_LIB_SHINE", "libshine"); + enable!(configure, "BUILD_LIB_SNAPPY", "libsnappy"); + enable!(configure, "BUILD_LIB_SPEEX", "libspeex"); + enable!( + configure, + "BUILD_LIB_STAGEFRIGHT_H264", + "libstagefright-h264" + ); + enable!(configure, "BUILD_LIB_THEORA", "libtheora"); + enable!(configure, "BUILD_LIB_TWOLAME", "libtwolame"); + enable!(configure, "BUILD_LIB_UTVIDEO", "libutvideo"); + enable!(configure, "BUILD_LIB_VO_AACENC", "libvo-aacenc"); + enable!(configure, "BUILD_LIB_VO_AMRWBENC", "libvo-amrwbenc"); + enable!(configure, "BUILD_LIB_VORBIS", "libvorbis"); + enable!(configure, "BUILD_LIB_VPX", "libvpx"); + enable!(configure, "BUILD_LIB_WAVPACK", "libwavpack"); + enable!(configure, "BUILD_LIB_WEBP", "libwebp"); + enable!(configure, "BUILD_LIB_X264", "libx264"); + enable!(configure, "BUILD_LIB_X265", "libx265"); + enable!(configure, "BUILD_LIB_XAVS", "libxavs"); + enable!(configure, "BUILD_LIB_XVID", "libxvid"); + + // make sure to only enable related hw acceleration features for a correct + // target os. This allows to leave allows cargo features enable and control + // ffmpeg compilation using target only + + // Apple VideoToolbox (iOS, macOS, and tvOS) + if env::var("CARGO_FEATURE_BUILD_VIDEOTOOLBOX").is_ok() + && matches!(target_os.as_str(), "ios" | "macos" | "tvos") + { + configure.arg("--enable-videotoolbox"); + + if target != host + && let Some(flag) = apple_version_min_cflag(&target_os, is_sim) + { + configure.arg(format!("--extra-cflags={flag}")); + } + } + + // Apple audio hw acceleration API (iOS, macOS, and tvOS) + if env::var("CARGO_FEATURE_BUILD_AUDIOTOOLBOX").is_ok() + && matches!(target_os.as_str(), "ios" | "macos" | "tvos") + { + configure.arg("--enable-audiotoolbox"); + + if target != host + && let Some(flag) = apple_version_min_cflag(&target_os, is_sim) + { + configure.arg(format!("--extra-cflags={flag}")); + } + } + + // Linux video acceleration API (VAAPI) + if env::var("CARGO_FEATURE_BUILD_VAAPI").is_ok() && matches!(target_os.as_str(), "linux") { + configure.arg("--enable-vaapi"); + } + + if env::var("CARGO_FEATURE_BUILD_LIB_D3D11VA").is_ok() + && matches!(target_os.as_str(), "windows") + { + configure.arg("--enable-d3d11va"); + } + + // DirectX Video Acceleration 2 (Windows only) + if env::var("CARGO_FEATURE_BUILD_LIB_DXVA2").is_ok() && matches!(target_os.as_str(), "windows") + { + configure.arg("--enable-dxva2"); + } + + // NVIDIA NVDEC acceleration without a CUDA toolkit dependency. FFmpeg + // loads CUDA and nvcuvid from the installed driver at runtime. + if env::var("CARGO_FEATURE_BUILD_NVDEC").is_ok() + && matches!(target_os.as_str(), "linux" | "windows") + { + configure.arg("--enable-ffnvcodec"); + configure.arg("--enable-cuda"); + configure.arg("--enable-cuvid"); + configure.arg("--enable-nvdec"); + } + + // NVIDIA NVENC/NVDEC acceleration (Linux and Windows) + if env::var("CARGO_FEATURE_BUILD_NVIDIA").is_ok() + && matches!(target_os.as_str(), "linux" | "windows") + { + configure.arg("--enable-libnpp"); + configure.arg("--enable-cuda-nvcc"); + configure.arg("--enable-cuvid"); + configure.arg("--enable-nvenc"); + configure.arg("--enable-cuda-llvm"); + + let cuda_path = env::var("CUDA_PATH").unwrap_or(if target_os == "linux" { + "/usr/local/cuda".to_string() + } else { + "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA".to_string() + }); + println!("cargo:rustc-link-arg=-L{cuda_path}/lib64"); + println!("cargo:rustc-link-arg=-I{cuda_path}/include"); + + // Additional configuration may be needed for CUDA toolkit path + // This could be provided as an environment variable + if let Ok(cuda_path) = env::var("CUDA_PATH") { + configure.arg(format!("--cuda-path={cuda_path}")); + } + } + + // Intel Quick Sync Video (Linux and Windows) + if env::var("CARGO_FEATURE_BUILD_LIB_LIBMFX").is_ok() + && matches!(target_os.as_str(), "linux" | "windows") + { + configure.arg("--enable-libmfx"); + } + + // Android MediaCodec (Android only) + if env::var("CARGO_FEATURE_BUILD_MEDIACODEC").is_ok() && target_os == "android" { + configure.arg("--enable-mediacodec"); + configure.arg("--enable-jni"); + + // Add common MediaCodec decoders + configure.arg("--enable-decoder=h264_mediacodec"); + configure.arg("--enable-decoder=hevc_mediacodec"); + configure.arg("--enable-decoder=vp8_mediacodec"); + configure.arg("--enable-decoder=vp9_mediacodec"); + configure.arg("--enable-decoder=av1_mediacodec"); + } + + // AMD Advanced Media Framework (Linux and Windows) + if env::var("CARGO_FEATURE_BUILD_AMF").is_ok() + && matches!(target_os.as_str(), "linux" | "windows") + && matches!( + env::var("CARGO_FEATURE_TARGET_ARCH").as_deref(), + Ok("x86_64") + ) + { + configure.arg("--enable-amf"); + } + + enable!(configure, "BUILD_VULKAN", "vulkan"); + + // other external libraries + enable!(configure, "BUILD_LIB_DRM", "libdrm"); + enable!(configure, "BUILD_NVENC", "nvenc"); + + // configure external protocols + enable!(configure, "BUILD_LIB_SMBCLIENT", "libsmbclient"); + enable!(configure, "BUILD_LIB_SSH", "libssh"); + + // configure misc build options + enable!(configure, "BUILD_PIC", "pic"); + + // skip all the warnings from output as they can significantly slow down the build + // time on platforms like mac which spawns thousands of nullabilty complieance warnings + configure.arg("--extra-cflags=-w"); + + // run ./configure + let output = configure + .output() + .unwrap_or_else(|_| panic!("{:?} failed", configure)); + if !output.status.success() { + println!( + "configure stdout: {}", + String::from_utf8_lossy(&output.stdout) + ); + println!( + "configure stderr: {}", + String::from_utf8_lossy(&output.stderr) + ); + + return Err(io::Error::other(format!( + "configure failed {}", + String::from_utf8_lossy(&output.stderr) + ))); + } + + // run make + if !Command::new("make") + .arg("-j") + .arg(num_cpus::get().to_string()) + .current_dir(source()) + .status()? + .success() + { + return Err(io::Error::other("make failed")); + } + + // run make install + if !Command::new("make") + .current_dir(source()) + .arg("install") + .status()? + .success() + { + return Err(io::Error::other("make install failed")); + } + + Ok(()) +} + +#[cfg(not(target_env = "msvc"))] +fn try_vcpkg(_statik: bool) -> Option> { + None +} + +#[cfg(target_env = "msvc")] +fn try_vcpkg(statik: bool) -> Option> { + if !statik { + unsafe { + env::set_var("VCPKGRS_DYNAMIC", "1"); + } + } + + vcpkg::find_package("ffmpeg") + .map_err(|e| { + println!("Could not find ffmpeg with vcpkg: {}", e); + }) + .map(|library| library.include_paths) + .ok() +} + +fn check_features( + include_paths: Vec, + infos: &[(&'static str, Option<&'static str>, &'static str)], +) { + let mut includes_code = String::new(); + let mut main_code = String::new(); + + for &(header, feature, var) in infos { + if let Some(feature) = feature + && env::var(format!("CARGO_FEATURE_{}", feature.to_uppercase())).is_err() + { + continue; + } + + let include = format!("#include <{header}>"); + if !includes_code.contains(&include) { + includes_code.push_str(&include); + includes_code.push('\n'); + } + let _ = write!( + includes_code, + r#" + #ifndef {var}_is_defined + #ifndef {var} + #define {var} 0 + #define {var}_is_defined 0 + #else + #define {var}_is_defined 1 + #endif + #endif + "# + ); + + let _ = write!( + main_code, + r#"printf("[{var}]%d%d\n", {var}, {var}_is_defined); + "# + ); + } + + let version_check_info = [("avcodec", 56, 64, 0, 108)]; + for &(lib, begin_version_major, end_version_major, begin_version_minor, end_version_minor) in + version_check_info.iter() + { + for version_major in begin_version_major..end_version_major { + for version_minor in begin_version_minor..end_version_minor { + let _ = write!( + main_code, + r#"printf("[{lib}_version_greater_than_{version_major}_{version_minor}]%d\n", LIB{lib_uppercase}_VERSION_MAJOR > {version_major} || (LIB{lib_uppercase}_VERSION_MAJOR == {version_major} && LIB{lib_uppercase}_VERSION_MINOR > {version_minor})); + "#, + lib = lib, + lib_uppercase = lib.to_uppercase(), + version_major = version_major, + version_minor = version_minor + ); + } + } + } + + let out_dir = output(); + + write!( + File::create(out_dir.join("check.c")).expect("Failed to create file"), + r#" + #include + {includes_code} + + int main() + {{ + {main_code} + return 0; + }} + "# + ) + .expect("Write failed"); + + let executable = out_dir.join(if cfg!(windows) { "check.exe" } else { "check" }); + let mut compiler = cc::Build::new() + .target(&env::var("HOST").unwrap()) // don't cross-compile this + .get_compiler() + .to_command(); + + for dir in include_paths { + compiler.arg("-I"); + compiler.arg(dir.to_string_lossy().into_owned()); + } + if !compiler + .current_dir(&out_dir) + .arg("-o") + .arg(&executable) + .arg("check.c") + .status() + .expect("Command failed") + .success() + { + panic!("Compile failed"); + } + + let check_output = Command::new(out_dir.join(&executable)) + .current_dir(&out_dir) + .output() + .expect("Check failed"); + if !check_output.status.success() { + panic!( + "{} failed: {}\n{}", + executable.display(), + String::from_utf8_lossy(&check_output.stdout), + String::from_utf8_lossy(&check_output.stderr) + ); + } + + let stdout = str::from_utf8(&check_output.stdout).unwrap(); + + println!("stdout of {}={}", executable.display(), stdout); + + for &(_, feature, var) in infos { + if let Some(feature) = feature + && env::var(format!("CARGO_FEATURE_{}", feature.to_uppercase())).is_err() + { + continue; + } + // Here so the features are listed for rust-ffmpeg at build time. Does + // NOT represent activated features, just features that exist (hence the + // lack of "=true" at the end) + println!(r#"cargo:{var}="#); + + let var_str = format!("[{var}]"); + let pos = var_str.len() + + stdout + .find(&var_str) + .unwrap_or_else(|| panic!("Variable '{}' not found in stdout output", var_str)); + if &stdout[pos..pos + 1] == "1" { + println!(r#"cargo:rustc-cfg=feature="{}""#, var.to_lowercase()); + println!(r#"cargo:{}=true"#, var.to_lowercase()); + } + + // Also find out if defined or not (useful for cases where only the definition of a macro + // can be used as distinction) + if &stdout[pos + 1..pos + 2] == "1" { + println!( + r#"cargo:rustc-cfg=feature="{}_is_defined""#, + var.to_lowercase() + ); + println!(r#"cargo:{}_is_defined=true"#, var.to_lowercase()); + } + } + + for &(lib, begin_version_major, end_version_major, begin_version_minor, end_version_minor) in + version_check_info.iter() + { + for version_major in begin_version_major..end_version_major { + for version_minor in begin_version_minor..end_version_minor { + let search_str = + format!("[{lib}_version_greater_than_{version_major}_{version_minor}]"); + let pos = stdout + .find(&search_str) + .expect("Variable not found in output") + + search_str.len(); + + if &stdout[pos..pos + 1] == "1" { + println!( + r#"cargo:rustc-cfg=feature="{}""#, + &search_str[1..(search_str.len() - 1)] + ); + println!(r#"cargo:{}=true"#, &search_str[1..(search_str.len() - 1)]); + } + } + } + } + + let ffmpeg_lavc_versions = [ + ("ffmpeg_3_0", 57, 24), + ("ffmpeg_3_1", 57, 48), + ("ffmpeg_3_2", 57, 64), + ("ffmpeg_3_3", 57, 89), + ("ffmpeg_3_4", 57, 107), + ("ffmpeg_4_0", 58, 18), + ("ffmpeg_4_1", 58, 35), + ("ffmpeg_4_2", 58, 54), + ("ffmpeg_4_3", 58, 91), + ("ffmpeg_4_4", 58, 100), + ("ffmpeg_5_0", 59, 18), + ("ffmpeg_5_1", 59, 37), + ("ffmpeg_6_0", 60, 3), + ("ffmpeg_6_1", 60, 31), + ("ffmpeg_7_0", 61, 3), + ("ffmpeg_7_1", 61, 19), + ("ffmpeg_8_0", 62, 8), + ("ffmpeg_8_1", 62, 28), + ("ffmpeg_9_0", 63, 1), + ]; + for &(ffmpeg_version_flag, lavc_version_major, lavc_version_minor) in + ffmpeg_lavc_versions.iter() + { + let search_str = format!( + "[avcodec_version_greater_than_{lavc_version_major}_{lavc_version_minor}]", + lavc_version_major = lavc_version_major, + lavc_version_minor = lavc_version_minor - 1 + ); + let pos = stdout + .find(&search_str) + .expect("Variable not found in output") + + search_str.len(); + println!( + r#"cargo:rustc-check-cfg=cfg(feature, values("{}"))"#, + ffmpeg_version_flag + ); + if &stdout[pos..pos + 1] == "1" { + println!(r#"cargo:rustc-cfg=feature="{ffmpeg_version_flag}""#); + println!(r#"cargo:{ffmpeg_version_flag}=true"#); + } else { + println!(r#"cargo:{ffmpeg_version_flag}="#); + } + } +} + +fn search_include(include_paths: &[PathBuf], header: &str) -> String { + for dir in include_paths { + let include = dir.join(header); + if fs::metadata(&include).is_ok() { + if let Some(path_str) = include.as_path().to_str() { + return path_str.to_string(); + } + // Fall back to lossy conversion if path contains non-UTF8 characters + return include.to_string_lossy().to_string(); + } + } + format!("/usr/include/{header}") +} + +fn maybe_search_include(include_paths: &[PathBuf], header: &str) -> Option { + let path = search_include(include_paths, header); + if fs::metadata(&path).is_ok() { + Some(path) + } else { + None + } +} + +fn link_to_libraries(statik: bool, target_os: &str) { + let ffmpeg_ty = if statik { "static" } else { "dylib" }; + for lib in LIBRARIES { + let feat_is_enabled = lib.feature_name().and_then(|f| env::var(f).ok()).is_some(); + if !lib.is_feature || feat_is_enabled { + println!("cargo:rustc-link-lib={}={}", ffmpeg_ty, lib.name); + } + } + // Keep GNU ld from dropping libraries whose symbols it thinks are unused. + // Apple's ld and MSVC's link.exe reject the option and don't drop them + // anyway, so skip it there. + if !matches!( + target_os, + "macos" | "ios" | "tvos" | "watchos" | "visionos" | "windows" + ) { + println!("cargo:rustc-link-arg=-Wl,--no-as-needed"); + } + if env::var("CARGO_FEATURE_BUILD_ZLIB").is_ok() && target_os == "linux" { + println!("cargo:rustc-link-lib=z"); + } +} + +fn main() { + println!("cargo:rerun-if-env-changed=FFMPEG_DIR"); + + let statik = env::var("CARGO_FEATURE_STATIC").is_ok(); + let ffmpeg_major_version: u32 = env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap(); + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + + let sysroot = find_sysroot(); + let include_paths: Vec = if env::var("CARGO_FEATURE_BUILD").is_ok() { + println!( + "cargo:rustc-link-search=native={}", + search().join("lib").to_string_lossy() + ); + link_to_libraries(statik, &target_os); + if fs::metadata(search().join("lib").join("libavutil.a")).is_err() { + fs::create_dir_all(output()).expect("failed to create build directory"); + fetch().unwrap(); + build(sysroot.as_deref()).unwrap(); + } + + // Check additional required libraries. + { + let config_mak = source().join("ffbuild/config.mak"); + let file = File::open(config_mak).unwrap(); + let reader = BufReader::new(file); + let extra_linker_args = reader + .lines() + .filter_map(|line| { + let line = line.as_ref().ok()?; + + if line.starts_with("EXTRALIBS") { + Some( + line.split('=') + .next_back() + .unwrap() + .split(' ') + .map(|s| s.to_string()) + .collect::>(), + ) + } else { + None + } + }) + .flatten() + .collect::>(); + + extra_linker_args + .iter() + .filter(|flag| flag.starts_with("-l")) + .map(|lib| &lib[2..]) + .for_each(|lib| println!("cargo:rustc-link-lib={lib}")); + + extra_linker_args + .iter() + .filter(|v| v.starts_with("-L")) + .map(|flag| { + let path = &flag[2..]; + if path.starts_with('/') { + PathBuf::from(path) + } else { + source().join(path) + } + }) + .for_each(|lib_search_path| { + println!( + "cargo:rustc-link-search=native={}", + lib_search_path.to_string_lossy() + ); + }) + } + + vec![search().join("include")] + } + // Use prebuilt library + else if let Ok(ffmpeg_dir) = env::var("FFMPEG_DIR") { + let ffmpeg_dir = PathBuf::from(ffmpeg_dir); + if ffmpeg_dir.join("lib/amd64").exists() + && env::var("CARGO_CFG_TARGET_ARCH").as_deref() == Ok("x86_64") + { + println!( + "cargo:rustc-link-search=native={}", + ffmpeg_dir.join("lib/amd64").to_string_lossy() + ); + } else if ffmpeg_dir.join("lib/armhf").exists() + && env::var("CARGO_CFG_TARGET_ARCH").as_deref() == Ok("arm") + { + println!( + "cargo:rustc-link-search=native={}", + ffmpeg_dir.join("lib/armhf").to_string_lossy() + ); + } else if ffmpeg_dir.join("lib/arm64").exists() + && env::var("CARGO_CFG_TARGET_ARCH").as_deref() == Ok("aarch64") + { + println!( + "cargo:rustc-link-search=native={}", + ffmpeg_dir.join("lib/arm64").to_string_lossy() + ); + } else { + println!( + "cargo:rustc-link-search=native={}", + ffmpeg_dir.join("lib").to_string_lossy() + ); + } + link_to_libraries(statik, &target_os); + vec![ffmpeg_dir.join("include")] + } else if let Some(paths) = try_vcpkg(statik) { + // vcpkg doesn't detect the "system" dependencies + if statik { + if cfg!(feature = "avcodec") || cfg!(feature = "avdevice") { + println!("cargo:rustc-link-lib=ole32"); + } + + if cfg!(feature = "avformat") { + println!("cargo:rustc-link-lib=secur32"); + println!("cargo:rustc-link-lib=ws2_32"); + } + + // avutil dependencies + println!("cargo:rustc-link-lib=bcrypt"); + println!("cargo:rustc-link-lib=user32"); + } + + paths + } + // Fallback to pkg-config + else { + let avutil_result = pkg_config::Config::new().statik(statik).probe("libavutil"); + + if let Err(e) = avutil_result { + eprintln!("error: FFmpeg not found."); + eprintln!(); + eprintln!("FFmpeg libraries could not be found using any of the following methods:"); + eprintln!(" 1. FFMPEG_DIR environment variable (not set)"); + eprintln!(" 2. vcpkg package manager (ffmpeg package not found)"); + eprintln!(" 3. pkg-config (libavutil not found: {})", e); + eprintln!(); + eprintln!("To fix this, please do one of the following:"); + eprintln!(" - Set FFMPEG_DIR to point to your FFmpeg installation directory"); + eprintln!(" - Install FFmpeg via vcpkg: vcpkg install ffmpeg"); + eprintln!(" - Install FFmpeg and ensure pkg-config can find it"); + eprintln!(" - Enable the 'build' feature to compile FFmpeg from source"); + std::process::exit(1); + } + + let mut libs = vec![ + ("libavformat", "AVFORMAT"), + ("libavfilter", "AVFILTER"), + ("libavdevice", "AVDEVICE"), + ("libswscale", "SWSCALE"), + ("libswresample", "SWRESAMPLE"), + ]; + if ffmpeg_major_version < 5 { + libs.push(("libavresample", "AVRESAMPLE")); + } + + for (lib_name, env_variable_name) in libs.iter() { + if env::var(format!("CARGO_FEATURE_{env_variable_name}")).is_ok() + && let Err(e) = pkg_config::Config::new().statik(statik).probe(lib_name) + { + eprintln!("error: FFmpeg library {} not found: {}", lib_name, e); + eprintln!(); + eprintln!( + "The {} library is required but could not be found.", + lib_name + ); + eprintln!("Please ensure FFmpeg is installed with all required components."); + std::process::exit(1); + } + } + + match pkg_config::Config::new().statik(statik).probe("libavcodec") { + Ok(lib) => lib.include_paths, + Err(e) => { + eprintln!("error: FFmpeg library libavcodec not found: {}", e); + eprintln!(); + eprintln!("The libavcodec library is required but could not be found."); + eprintln!("Please ensure FFmpeg is installed with all required components."); + std::process::exit(1); + } + } + }; + + if statik + && matches!( + env::var("CARGO_CFG_TARGET_OS").as_deref(), + Ok("macos") | Ok("ios") | Ok("tvos") + ) + { + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + + // Frameworks available on all Apple platforms (macOS, iOS, tvOS) + let frameworks = vec![ + "AudioToolbox", + "AVFoundation", + "CoreFoundation", + "CoreGraphics", + "CoreMedia", + "CoreServices", + "CoreVideo", + "Foundation", + "QuartzCore", + "Security", + "VideoToolbox", + ]; + for f in &frameworks { + println!("cargo:rustc-link-lib=framework={f}"); + } + + // Frameworks only available on macOS + if target_os == "macos" { + let macos_frameworks = vec![ + "AppKit", + "OpenCL", + "OpenGL", + "QTKit", + "VideoDecodeAcceleration", + ]; + for f in &macos_frameworks { + println!("cargo:rustc-link-lib=framework={f}"); + } + } + } + + check_features( + include_paths.clone(), + &[ + ("libavutil/avutil.h", None, "FF_API_OLD_AVOPTIONS"), + ("libavutil/avutil.h", None, "FF_API_PIX_FMT"), + ("libavutil/avutil.h", None, "FF_API_CONTEXT_SIZE"), + ("libavutil/avutil.h", None, "FF_API_PIX_FMT_DESC"), + ("libavutil/avutil.h", None, "FF_API_AV_REVERSE"), + ("libavutil/avutil.h", None, "FF_API_AUDIOCONVERT"), + ("libavutil/avutil.h", None, "FF_API_CPU_FLAG_MMX2"), + ("libavutil/avutil.h", None, "FF_API_LLS_PRIVATE"), + ("libavutil/avutil.h", None, "FF_API_AVFRAME_LAVC"), + ("libavutil/avutil.h", None, "FF_API_VDPAU"), + ( + "libavutil/avutil.h", + None, + "FF_API_GET_CHANNEL_LAYOUT_COMPAT", + ), + ("libavutil/avutil.h", None, "FF_API_XVMC"), + ("libavutil/avutil.h", None, "FF_API_OPT_TYPE_METADATA"), + ("libavutil/avutil.h", None, "FF_API_DLOG"), + ("libavutil/avutil.h", None, "FF_API_HMAC"), + ("libavutil/avutil.h", None, "FF_API_VAAPI"), + ("libavutil/avutil.h", None, "FF_API_PKT_PTS"), + ("libavutil/avutil.h", None, "FF_API_ERROR_FRAME"), + ("libavutil/avutil.h", None, "FF_API_FRAME_QP"), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_VIMA_DECODER", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_REQUEST_CHANNELS", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_OLD_DECODE_AUDIO", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_OLD_ENCODE_AUDIO", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_OLD_ENCODE_VIDEO", + ), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_CODEC_ID"), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_AUDIO_CONVERT", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_AVCODEC_RESAMPLE", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_DEINTERLACE", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_DESTRUCT_PACKET", + ), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_GET_BUFFER"), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_MISSING_SAMPLE", + ), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_LOWRES"), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_CAP_VDPAU"), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_BUFS_VDPAU"), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_VOXWARE"), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_SET_DIMENSIONS", + ), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_DEBUG_MV"), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_AC_VLC"), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_OLD_MSMPEG4", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_ASPECT_EXTENDED", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_THREAD_OPAQUE", + ), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_CODEC_PKT"), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_ARCH_ALPHA"), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_ERROR_RATE"), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_QSCALE_TYPE", + ), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_MB_TYPE"), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_MAX_BFRAMES", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_NEG_LINESIZES", + ), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_EMU_EDGE"), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_ARCH_SH4"), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_ARCH_SPARC"), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_UNUSED_MEMBERS", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_IDCT_XVIDMMX", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_INPUT_PRESERVED", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_NORMALIZE_AQP", + ), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_GMC"), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_MV0"), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_CODEC_NAME"), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_AFD"), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_VISMV"), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_DV_FRAME_PROFILE", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_AUDIOENC_DELAY", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_VAAPI_CONTEXT", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_AVCTX_TIMEBASE", + ), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_MPV_OPT"), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_STREAM_CODEC_TAG", + ), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_QUANT_BIAS"), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_RC_STRATEGY", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_CODED_FRAME", + ), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_MOTION_EST"), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_WITHOUT_PREFIX", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_CONVERGENCE_DURATION", + ), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_PRIVATE_OPT", + ), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_CODER_TYPE"), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_RTP_CALLBACK", + ), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_STAT_BITS"), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_VBV_DELAY"), + ( + "libavcodec/avcodec.h", + Some("avcodec"), + "FF_API_SIDEDATA_ONLY_PKT", + ), + ("libavcodec/avcodec.h", Some("avcodec"), "FF_API_AVPICTURE"), + ( + "libavformat/avformat.h", + Some("avformat"), + "FF_API_LAVF_BITEXACT", + ), + ( + "libavformat/avformat.h", + Some("avformat"), + "FF_API_LAVF_FRAC", + ), + ( + "libavformat/avformat.h", + Some("avformat"), + "FF_API_URL_FEOF", + ), + ( + "libavformat/avformat.h", + Some("avformat"), + "FF_API_PROBESIZE_32", + ), + ( + "libavformat/avformat.h", + Some("avformat"), + "FF_API_LAVF_AVCTX", + ), + ( + "libavformat/avformat.h", + Some("avformat"), + "FF_API_OLD_OPEN_CALLBACKS", + ), + ( + "libavfilter/avfilter.h", + Some("avfilter"), + "FF_API_AVFILTERPAD_PUBLIC", + ), + ( + "libavfilter/avfilter.h", + Some("avfilter"), + "FF_API_FOO_COUNT", + ), + ( + "libavfilter/avfilter.h", + Some("avfilter"), + "FF_API_OLD_FILTER_OPTS", + ), + ( + "libavfilter/avfilter.h", + Some("avfilter"), + "FF_API_OLD_FILTER_OPTS_ERROR", + ), + ( + "libavfilter/avfilter.h", + Some("avfilter"), + "FF_API_AVFILTER_OPEN", + ), + ( + "libavfilter/avfilter.h", + Some("avfilter"), + "FF_API_OLD_FILTER_REGISTER", + ), + ( + "libavfilter/avfilter.h", + Some("avfilter"), + "FF_API_OLD_GRAPH_PARSE", + ), + ( + "libavfilter/avfilter.h", + Some("avfilter"), + "FF_API_NOCONST_GET_NAME", + ), + ( + "libavresample/avresample.h", + Some("avresample"), + "FF_API_RESAMPLE_CLOSE_OPEN", + ), + ( + "libswscale/swscale.h", + Some("swscale"), + "FF_API_SWS_CPU_CAPS", + ), + ("libswscale/swscale.h", Some("swscale"), "FF_API_ARCH_BFIN"), + ], + ); + + let clang_includes = include_paths + .iter() + .map(|include| format!("-I{}", include.to_string_lossy())); + + println!("cargo:rerun-if-changed=hwcontext_wrapper.h"); + println!("cargo:rerun-if-changed=hwcontext_stubs/vulkan/vulkan.h"); + println!("cargo:rerun-if-changed=hwcontext_stubs/VideoToolbox/VideoToolbox.h"); + println!("cargo:rerun-if-changed=hwcontext_stubs/va/va.h"); + println!("cargo:rerun-if-changed=hwcontext_stubs/mfxvideo.h"); + println!("cargo:rerun-if-changed=hwcontext_stubs/mfx/mfxvideo.h"); + + // SDK shims (vulkan/, VideoToolbox/, va/, mfxvideo.h) used by hwcontext_wrapper.h. + let hwcontext_stub_dir = format!( + "-I{}/hwcontext_stubs", + env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR") + ); + + // The bindgen::Builder is the main entry point + // to bindgen, and lets you build up options for + // the resulting bindings. + let mut builder = bindgen::Builder::default() + // Shim dir first, so our stubs win over the real SDK headers on the path (by design, to avoid generating bindings for full SDKs). + .clang_arg(&hwcontext_stub_dir) + .clang_args(clang_includes) + .ctypes_prefix("libc") + // https://github.com/rust-lang/rust-bindgen/issues/550 + .blocklist_type("max_align_t") + .blocklist_function("_.*") + // Blocklist functions with u128 in signature. + // https://github.com/zmwangx/rust-ffmpeg-sys/issues/1 + // https://github.com/rust-lang/rust-bindgen/issues/1549 + .blocklist_function("acoshl") + .blocklist_function("acosl") + .blocklist_function("asinhl") + .blocklist_function("asinl") + .blocklist_function("atan2l") + .blocklist_function("atanhl") + .blocklist_function("atanl") + .blocklist_function("cbrtl") + .blocklist_function("ceill") + .blocklist_function("copysignl") + .blocklist_function("coshl") + .blocklist_function("cosl") + .blocklist_function("dreml") + .blocklist_function("ecvt_r") + .blocklist_function("erfcl") + .blocklist_function("erfl") + .blocklist_function("exp2l") + .blocklist_function("expl") + .blocklist_function("expm1l") + .blocklist_function("fabsl") + .blocklist_function("fcvt_r") + .blocklist_function("fdiml") + .blocklist_function("finitel") + .blocklist_function("floorl") + .blocklist_function("fmal") + .blocklist_function("fmaxl") + .blocklist_function("fminl") + .blocklist_function("fmodl") + .blocklist_function("frexpl") + .blocklist_function("gammal") + .blocklist_function("hypotl") + .blocklist_function("ilogbl") + .blocklist_function("isinfl") + .blocklist_function("isnanl") + .blocklist_function("j0l") + .blocklist_function("j1l") + .blocklist_function("jnl") + .blocklist_function("ldexpl") + .blocklist_function("lgammal") + .blocklist_function("lgammal_r") + .blocklist_function("llrintl") + .blocklist_function("llroundl") + .blocklist_function("log10l") + .blocklist_function("log1pl") + .blocklist_function("log2l") + .blocklist_function("logbl") + .blocklist_function("logl") + .blocklist_function("lrintl") + .blocklist_function("lroundl") + .blocklist_function("modfl") + .blocklist_function("nanl") + .blocklist_function("nearbyintl") + .blocklist_function("nextafterl") + .blocklist_function("nexttoward") + .blocklist_function("nexttowardf") + .blocklist_function("nexttowardl") + .blocklist_function("powl") + .blocklist_function("qecvt") + .blocklist_function("qecvt_r") + .blocklist_function("qfcvt") + .blocklist_function("qfcvt_r") + .blocklist_function("qgcvt") + .blocklist_function("remainderl") + .blocklist_function("remquol") + .blocklist_function("rintl") + .blocklist_function("roundl") + .blocklist_function("scalbl") + .blocklist_function("scalblnl") + .blocklist_function("scalbnl") + .blocklist_function("significandl") + .blocklist_function("sinhl") + .blocklist_function("sinl") + .blocklist_function("sqrtl") + .blocklist_function("strtold") + .blocklist_function("tanhl") + .blocklist_function("tanl") + .blocklist_function("tgammal") + .blocklist_function("truncl") + .blocklist_function("y0l") + .blocklist_function("y1l") + .blocklist_function("ynl") + .opaque_type("__mingw_ldbl_type_t") + .default_enum_style(bindgen::EnumVariation::Rust { + non_exhaustive: env::var("CARGO_FEATURE_NON_EXHAUSTIVE_ENUMS").is_ok(), + }) + .prepend_enum_name(false) + .wrap_unsafe_ops(true) + .derive_eq(true) + .size_t_is_usize(true) + .parse_callbacks(Box::new(Callbacks)); + + if let Some(sysroot) = sysroot.as_deref() { + builder = builder.clang_arg(format!("--sysroot={sysroot}")); + } + + // The input headers we would like to generate + // bindings for. + if env::var("CARGO_FEATURE_AVCODEC").is_ok() { + builder = builder + .header(search_include(&include_paths, "libavcodec/avcodec.h")) + .header(search_include(&include_paths, "libavcodec/dv_profile.h")) + .header(search_include(&include_paths, "libavcodec/vorbis_parser.h")); + + let bsf_path = search_include(&include_paths, "libavcodec/bsf.h"); + if std::path::Path::new(&bsf_path).exists() { + builder = builder.header(bsf_path); + } + + if ffmpeg_major_version < 5 { + builder = builder.header(search_include(&include_paths, "libavcodec/vaapi.h")); + } + if ffmpeg_major_version < 8 + && let Some(avfft_path) = maybe_search_include(&include_paths, "libavcodec/avfft.h") + { + builder = builder.header(avfft_path); + } + } + + if env::var("CARGO_FEATURE_AVDEVICE").is_ok() { + builder = builder.header(search_include(&include_paths, "libavdevice/avdevice.h")); + } + + if env::var("CARGO_FEATURE_AVFILTER").is_ok() { + builder = builder + .header(search_include(&include_paths, "libavfilter/buffersink.h")) + .header(search_include(&include_paths, "libavfilter/buffersrc.h")) + .header(search_include(&include_paths, "libavfilter/avfilter.h")); + } + + if env::var("CARGO_FEATURE_AVFORMAT").is_ok() { + builder = builder + .header(search_include(&include_paths, "libavformat/avformat.h")) + .header(search_include(&include_paths, "libavformat/avio.h")); + } + + if env::var("CARGO_FEATURE_AVRESAMPLE").is_ok() { + builder = builder.header(search_include(&include_paths, "libavresample/avresample.h")); + } + + builder = builder + .header(search_include(&include_paths, "libavutil/adler32.h")) + .header(search_include(&include_paths, "libavutil/aes.h")) + .header(search_include(&include_paths, "libavutil/audio_fifo.h")) + .header(search_include(&include_paths, "libavutil/base64.h")) + .header(search_include(&include_paths, "libavutil/blowfish.h")) + .header(search_include(&include_paths, "libavutil/bprint.h")) + .header(search_include(&include_paths, "libavutil/buffer.h")) + .header(search_include(&include_paths, "libavutil/camellia.h")) + .header(search_include(&include_paths, "libavutil/cast5.h")) + .header(search_include(&include_paths, "libavutil/channel_layout.h")) + // Here until https://github.com/rust-lang/rust-bindgen/issues/2192 / + // https://github.com/rust-lang/rust-bindgen/issues/258 is fixed. + .header("channel_layout_fixed.h") + .header(search_include(&include_paths, "libavutil/cpu.h")) + .header(search_include(&include_paths, "libavutil/crc.h")) + .header(search_include(&include_paths, "libavutil/dict.h")) + .header(search_include(&include_paths, "libavutil/display.h")) + .header(search_include(&include_paths, "libavutil/downmix_info.h")) + .header(search_include(&include_paths, "libavutil/error.h")) + .header(search_include(&include_paths, "libavutil/eval.h")) + .header(search_include(&include_paths, "libavutil/fifo.h")) + .header(search_include(&include_paths, "libavutil/file.h")) + .header(search_include(&include_paths, "libavutil/frame.h")) + .header(search_include(&include_paths, "libavutil/hash.h")) + .header(search_include(&include_paths, "libavutil/hmac.h")) + .header(search_include(&include_paths, "libavutil/hwcontext.h")) + .header(search_include(&include_paths, "libavutil/imgutils.h")) + .header(search_include(&include_paths, "libavutil/lfg.h")) + .header(search_include(&include_paths, "libavutil/log.h")) + .header(search_include(&include_paths, "libavutil/lzo.h")) + .header(search_include(&include_paths, "libavutil/macros.h")) + .header(search_include(&include_paths, "libavutil/mathematics.h")) + .header(search_include(&include_paths, "libavutil/md5.h")) + .header(search_include(&include_paths, "libavutil/mem.h")) + .header(search_include(&include_paths, "libavutil/motion_vector.h")) + .header(search_include(&include_paths, "libavutil/murmur3.h")) + .header(search_include(&include_paths, "libavutil/opt.h")) + .header(search_include(&include_paths, "libavutil/parseutils.h")) + .header(search_include(&include_paths, "libavutil/pixdesc.h")) + .header(search_include(&include_paths, "libavutil/pixfmt.h")) + .header(search_include(&include_paths, "libavutil/random_seed.h")) + .header(search_include(&include_paths, "libavutil/rational.h")) + .header(search_include(&include_paths, "libavutil/replaygain.h")) + .header(search_include(&include_paths, "libavutil/ripemd.h")) + .header(search_include(&include_paths, "libavutil/samplefmt.h")) + .header(search_include(&include_paths, "libavutil/sha.h")) + .header(search_include(&include_paths, "libavutil/sha512.h")) + .header(search_include(&include_paths, "libavutil/stereo3d.h")) + .header(search_include(&include_paths, "libavutil/avstring.h")) + .header(search_include(&include_paths, "libavutil/threadmessage.h")) + .header(search_include(&include_paths, "libavutil/time.h")) + .header(search_include(&include_paths, "libavutil/timecode.h")) + .header(search_include(&include_paths, "libavutil/twofish.h")) + .header(search_include(&include_paths, "libavutil/avutil.h")) + .header(search_include(&include_paths, "libavutil/xtea.h")); + + let raw_color_params_path = search_include(&include_paths, "libavutil/raw_color_params.h"); + if std::path::Path::new(&raw_color_params_path).exists() { + builder = builder.header(raw_color_params_path); + } + + if env::var("CARGO_FEATURE_POSTPROC").is_ok() { + let postproc_path = search_include(&include_paths, "libpostproc/postprocess.h"); + if std::path::Path::new(&postproc_path).exists() { + builder = builder.header(postproc_path); + } + } + + if env::var("CARGO_FEATURE_SWRESAMPLE").is_ok() { + builder = builder.header(search_include(&include_paths, "libswresample/swresample.h")); + } + + if env::var("CARGO_FEATURE_SWSCALE").is_ok() { + builder = builder.header(search_include(&include_paths, "libswscale/swscale.h")); + } + + if let Some(hwcontext_drm_header) = + maybe_search_include(&include_paths, "libavutil/hwcontext_drm.h") + { + builder = builder.header(hwcontext_drm_header); + } + + // Per-API hwcontext structs (CUDA, D3D11/12, VideoToolbox, MediaCodec, + // Vulkan, VAAPI, QSV) all bind through one wrapper. + builder = builder.header("hwcontext_wrapper.h"); + + // Finish the builder and generate the bindings. + let bindings = builder + .generate() + // Unwrap the Result and panic on failure. + .expect("Unable to generate bindings"); + + // Write the bindings to the $OUT_DIR/bindings.rs file. + bindings + .write_to_file(output().join("bindings.rs")) + .expect("Couldn't write bindings!"); +} diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/NV_CODEC_HEADERS_README b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/NV_CODEC_HEADERS_README new file mode 100644 index 000000000..1f30b11c7 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/NV_CODEC_HEADERS_README @@ -0,0 +1,7 @@ +FFmpeg version of headers required to interface with NVIDIA codec APIs. + +Corresponds to Video Codec SDK version 13.1.15. + +Minimum required driver versions: +Linux: 610.0 or newer +Windows: 610.0 or newer \ No newline at end of file diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/VULKAN_HEADERS_LICENSE.md b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/VULKAN_HEADERS_LICENSE.md new file mode 100644 index 000000000..17cf4a17d --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/VULKAN_HEADERS_LICENSE.md @@ -0,0 +1,19 @@ +Copyright 2015-2026 The Khronos Group Inc. + +Files in this repository fall under one of these licenses: + +- `Apache-2.0` +- `MIT` + +Note: With the exception of `parse_dependency.py`, which is based on an +external file, files using the `MIT` license also fall under `Apache-2.0`. +Example: + +``` +SPDX-License-Identifier: Apache-2.0 OR MIT +``` + +Full license text of these licenses is available at: + + * Apache-2.0: https://opensource.org/licenses/Apache-2.0 + * MIT: https://opensource.org/licenses/MIT diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/ffnvcodec/dynlink_cuda.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/ffnvcodec/dynlink_cuda.h new file mode 100644 index 000000000..25077cdf3 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/ffnvcodec/dynlink_cuda.h @@ -0,0 +1,551 @@ +/* + * This copyright notice applies to this header file only: + * + * Copyright (c) 2016 + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the software, and to permit persons to whom the + * software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#if !defined(FFNV_DYNLINK_CUDA_H) && !defined(CUDA_VERSION) +#define FFNV_DYNLINK_CUDA_H + +#include +#include + +#define CUDA_VERSION 7050 + +#if defined(_WIN32) || defined(__CYGWIN__) +#define CUDAAPI __stdcall +#else +#define CUDAAPI +#endif + +#define CU_CTX_SCHED_BLOCKING_SYNC 4 + +typedef int CUdevice; +#if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) || defined(__LP64__) || defined(__aarch64__) +typedef unsigned long long CUdeviceptr; +#else +typedef unsigned int CUdeviceptr; +#endif +typedef unsigned long long CUtexObject; + +typedef struct CUarray_st *CUarray; +typedef struct CUctx_st *CUcontext; +typedef struct CUstream_st *CUstream; +typedef struct CUevent_st *CUevent; +typedef struct CUfunc_st *CUfunction; +typedef struct CUmod_st *CUmodule; +typedef struct CUmipmappedArray_st *CUmipmappedArray; +typedef struct CUgraphicsResource_st *CUgraphicsResource; +typedef struct CUextMemory_st *CUexternalMemory; +typedef struct CUextSemaphore_st *CUexternalSemaphore; +typedef struct CUeglStreamConnection_st *CUeglStreamConnection; + +typedef struct CUlinkState_st *CUlinkState; + +typedef enum cudaError_enum { + CUDA_SUCCESS = 0, + CUDA_ERROR_INVALID_VALUE = 1, + CUDA_ERROR_NOT_READY = 600, + CUDA_ERROR_LAUNCH_TIMEOUT = 702, + CUDA_ERROR_UNKNOWN = 999 +} CUresult; + +/** + * Device properties (subset) + */ +typedef enum CUdevice_attribute_enum { + CU_DEVICE_ATTRIBUTE_CLOCK_RATE = 13, + CU_DEVICE_ATTRIBUTE_TEXTURE_ALIGNMENT = 14, + CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT = 16, + CU_DEVICE_ATTRIBUTE_INTEGRATED = 18, + CU_DEVICE_ATTRIBUTE_CAN_MAP_HOST_MEMORY = 19, + CU_DEVICE_ATTRIBUTE_COMPUTE_MODE = 20, + CU_DEVICE_ATTRIBUTE_CONCURRENT_KERNELS = 31, + CU_DEVICE_ATTRIBUTE_PCI_BUS_ID = 33, + CU_DEVICE_ATTRIBUTE_PCI_DEVICE_ID = 34, + CU_DEVICE_ATTRIBUTE_TCC_DRIVER = 35, + CU_DEVICE_ATTRIBUTE_MEMORY_CLOCK_RATE = 36, + CU_DEVICE_ATTRIBUTE_GLOBAL_MEMORY_BUS_WIDTH = 37, + CU_DEVICE_ATTRIBUTE_ASYNC_ENGINE_COUNT = 40, + CU_DEVICE_ATTRIBUTE_UNIFIED_ADDRESSING = 41, + CU_DEVICE_ATTRIBUTE_PCI_DOMAIN_ID = 50, + CU_DEVICE_ATTRIBUTE_TEXTURE_PITCH_ALIGNMENT = 51, + CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR = 75, + CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR = 76, + CU_DEVICE_ATTRIBUTE_MANAGED_MEMORY = 83, + CU_DEVICE_ATTRIBUTE_MULTI_GPU_BOARD = 84, + CU_DEVICE_ATTRIBUTE_MULTI_GPU_BOARD_GROUP_ID = 85, +} CUdevice_attribute; + +typedef enum CUarray_format_enum { + CU_AD_FORMAT_UNSIGNED_INT8 = 0x01, + CU_AD_FORMAT_UNSIGNED_INT16 = 0x02, + CU_AD_FORMAT_UNSIGNED_INT32 = 0x03, + CU_AD_FORMAT_SIGNED_INT8 = 0x08, + CU_AD_FORMAT_SIGNED_INT16 = 0x09, + CU_AD_FORMAT_SIGNED_INT32 = 0x0a, + CU_AD_FORMAT_HALF = 0x10, + CU_AD_FORMAT_FLOAT = 0x20, + CU_AD_FORMAT_NV12 = 0xb0, + CU_AD_FORMAT_P016 = 0xa1, + CU_AD_FORMAT_NV16 = 0xa2, + CU_AD_FORMAT_P216 = 0xa4, + CU_AD_FORMAT_YUV444_8BIT_SEMIPLANAR = 0xb4, + CU_AD_FORMAT_YUV444_16BIT_SEMIPLANAR = 0xb5, + CU_AD_FORMAT_UINT8_PLANAR_420 = 0x59, + CU_AD_FORMAT_UINT16_PLANAR_420 = 0x5a, + CU_AD_FORMAT_UINT8_PLANAR_422 = 0x5b, + CU_AD_FORMAT_UINT16_PLANAR_422 = 0x5c, + CU_AD_FORMAT_UINT8_PLANAR_444 = 0x5d, + CU_AD_FORMAT_UINT16_PLANAR_444 = 0x5e, +} CUarray_format; + +typedef enum CUmemorytype_enum { + CU_MEMORYTYPE_HOST = 1, + CU_MEMORYTYPE_DEVICE = 2, + CU_MEMORYTYPE_ARRAY = 3 +} CUmemorytype; + +typedef enum CUlimit_enum { + CU_LIMIT_STACK_SIZE = 0, + CU_LIMIT_PRINTF_FIFO_SIZE = 1, + CU_LIMIT_MALLOC_HEAP_SIZE = 2, + CU_LIMIT_DEV_RUNTIME_SYNC_DEPTH = 3, + CU_LIMIT_DEV_RUNTIME_PENDING_LAUNCH_COUNT = 4 +} CUlimit; + +typedef enum CUresourcetype_enum { + CU_RESOURCE_TYPE_ARRAY = 0x00, + CU_RESOURCE_TYPE_MIPMAPPED_ARRAY = 0x01, + CU_RESOURCE_TYPE_LINEAR = 0x02, + CU_RESOURCE_TYPE_PITCH2D = 0x03 +} CUresourcetype; + +typedef enum CUaddress_mode_enum { + CU_TR_ADDRESS_MODE_WRAP = 0, + CU_TR_ADDRESS_MODE_CLAMP = 1, + CU_TR_ADDRESS_MODE_MIRROR = 2, + CU_TR_ADDRESS_MODE_BORDER = 3 +} CUaddress_mode; + +typedef enum CUfilter_mode_enum { + CU_TR_FILTER_MODE_POINT = 0, + CU_TR_FILTER_MODE_LINEAR = 1 +} CUfilter_mode; + +typedef enum CUgraphicsRegisterFlags_enum { + CU_GRAPHICS_REGISTER_FLAGS_NONE = 0, + CU_GRAPHICS_REGISTER_FLAGS_READ_ONLY = 1, + CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD = 2, + CU_GRAPHICS_REGISTER_FLAGS_SURFACE_LDST = 4, + CU_GRAPHICS_REGISTER_FLAGS_TEXTURE_GATHER = 8 +} CUgraphicsRegisterFlags; + +typedef enum CUexternalMemoryHandleType_enum { + CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD = 1, + CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32 = 2, + CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT = 3, + CU_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP = 4, + CU_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE = 5, +} CUexternalMemoryHandleType; + +typedef enum CUexternalSemaphoreHandleType_enum { + CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD = 1, + CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32 = 2, + CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT = 3, + CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE = 4, + CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_FD = 9, + CU_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TIMELINE_SEMAPHORE_WIN32 = 10, +} CUexternalSemaphoreHandleType; + +typedef enum CUjit_option_enum +{ + CU_JIT_MAX_REGISTERS = 0, + CU_JIT_THREADS_PER_BLOCK = 1, + CU_JIT_WALL_TIME = 2, + CU_JIT_INFO_LOG_BUFFER = 3, + CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES = 4, + CU_JIT_ERROR_LOG_BUFFER = 5, + CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES = 6, + CU_JIT_OPTIMIZATION_LEVEL = 7, + CU_JIT_TARGET_FROM_CUCONTEXT = 8, + CU_JIT_TARGET = 9, + CU_JIT_FALLBACK_STRATEGY = 10, + CU_JIT_GENERATE_DEBUG_INFO = 11, + CU_JIT_LOG_VERBOSE = 12, + CU_JIT_GENERATE_LINE_INFO = 13, + CU_JIT_CACHE_MODE = 14, + CU_JIT_NEW_SM3X_OPT = 15, + CU_JIT_FAST_COMPILE = 16, + CU_JIT_GLOBAL_SYMBOL_NAMES = 17, + CU_JIT_GLOBAL_SYMBOL_ADDRESSES = 18, + CU_JIT_GLOBAL_SYMBOL_COUNT = 19, + CU_JIT_NUM_OPTIONS +} CUjit_option; + +typedef enum CUjitInputType_enum +{ + CU_JIT_INPUT_CUBIN = 0, + CU_JIT_INPUT_PTX = 1, + CU_JIT_INPUT_FATBINARY = 2, + CU_JIT_INPUT_OBJECT = 3, + CU_JIT_INPUT_LIBRARY = 4, + CU_JIT_NUM_INPUT_TYPES +} CUjitInputType; + +typedef enum CUeglFrameType +{ + CU_EGL_FRAME_TYPE_ARRAY = 0, + CU_EGL_FRAME_TYPE_PITCH = 1, +} CUeglFrameType; + +typedef enum CUeglColorFormat +{ + CU_EGL_COLOR_FORMAT_YUV420_PLANAR = 0x00, + CU_EGL_COLOR_FORMAT_YUV420_SEMIPLANAR = 0x01, + CU_EGL_COLOR_FORMAT_YVU420_SEMIPLANAR = 0x15, + CU_EGL_COLOR_FORMAT_Y10V10U10_420_SEMIPLANAR = 0x17, + CU_EGL_COLOR_FORMAT_Y12V12U12_420_SEMIPLANAR = 0x19, +} CUeglColorFormat; + +typedef enum CUd3d11DeviceList_enum +{ + CU_D3D11_DEVICE_LIST_ALL = 1, + CU_D3D11_DEVICE_LIST_CURRENT_FRAME = 2, + CU_D3D11_DEVICE_LIST_NEXT_FRAME = 3, +} CUd3d11DeviceList; + +#ifndef CU_UUID_HAS_BEEN_DEFINED +#define CU_UUID_HAS_BEEN_DEFINED +typedef struct CUuuid_st { + char bytes[16]; +} CUuuid; +#endif + +typedef struct CUDA_MEMCPY2D_st { + size_t srcXInBytes; + size_t srcY; + CUmemorytype srcMemoryType; + const void *srcHost; + CUdeviceptr srcDevice; + CUarray srcArray; + size_t srcPitch; + + size_t dstXInBytes; + size_t dstY; + CUmemorytype dstMemoryType; + void *dstHost; + CUdeviceptr dstDevice; + CUarray dstArray; + size_t dstPitch; + + size_t WidthInBytes; + size_t Height; +} CUDA_MEMCPY2D; + +typedef struct CUDA_RESOURCE_DESC_st { + CUresourcetype resType; + union { + struct { + CUarray hArray; + } array; + struct { + CUmipmappedArray hMipmappedArray; + } mipmap; + struct { + CUdeviceptr devPtr; + CUarray_format format; + unsigned int numChannels; + size_t sizeInBytes; + } linear; + struct { + CUdeviceptr devPtr; + CUarray_format format; + unsigned int numChannels; + size_t width; + size_t height; + size_t pitchInBytes; + } pitch2D; + struct { + int reserved[32]; + } reserved; + } res; + unsigned int flags; +} CUDA_RESOURCE_DESC; + +typedef struct CUDA_TEXTURE_DESC_st { + CUaddress_mode addressMode[3]; + CUfilter_mode filterMode; + unsigned int flags; + unsigned int maxAnisotropy; + CUfilter_mode mipmapFilterMode; + float mipmapLevelBias; + float minMipmapLevelClamp; + float maxMipmapLevelClamp; + float borderColor[4]; + int reserved[12]; +} CUDA_TEXTURE_DESC; + +/* Unused type */ +typedef struct CUDA_RESOURCE_VIEW_DESC_st CUDA_RESOURCE_VIEW_DESC; + +typedef unsigned int GLenum; +typedef unsigned int GLuint; +/* + * Prefix type name to avoid collisions. Clients using these types + * will include the real headers with real definitions. + */ +typedef int32_t ffnv_EGLint; +typedef void *ffnv_EGLStreamKHR; + +typedef enum CUGLDeviceList_enum { + CU_GL_DEVICE_LIST_ALL = 1, + CU_GL_DEVICE_LIST_CURRENT_FRAME = 2, + CU_GL_DEVICE_LIST_NEXT_FRAME = 3, +} CUGLDeviceList; + +typedef struct CUDA_EXTERNAL_MEMORY_HANDLE_DESC_st { + CUexternalMemoryHandleType type; + union { + int fd; + struct { + void *handle; + const void *name; + } win32; + } handle; + unsigned long long size; + unsigned int flags; + unsigned int reserved[16]; +} CUDA_EXTERNAL_MEMORY_HANDLE_DESC; + +typedef struct CUDA_EXTERNAL_MEMORY_BUFFER_DESC_st { + unsigned long long offset; + unsigned long long size; + unsigned int flags; + unsigned int reserved[16]; +} CUDA_EXTERNAL_MEMORY_BUFFER_DESC; + +typedef struct CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC_st { + CUexternalSemaphoreHandleType type; + union { + int fd; + struct { + void *handle; + const void *name; + } win32; + } handle; + unsigned int flags; + unsigned int reserved[16]; +} CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC; + +typedef struct CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS_st { + struct { + struct { + unsigned long long value; + } fence; + unsigned int reserved[16]; + } params; + unsigned int flags; + unsigned int reserved[16]; +} CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS; + +typedef CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS; + +typedef struct CUDA_ARRAY_DESCRIPTOR_st { + size_t Width; + size_t Height; + + CUarray_format Format; + unsigned int NumChannels; +} CUDA_ARRAY_DESCRIPTOR; + +#define CUDA_ARRAY3D_SURFACE_LDST 0x02 +#define CUDA_ARRAY3D_VIDEO_ENCODE_DECODE 0x100 + +typedef struct CUDA_ARRAY3D_DESCRIPTOR_st { + size_t Width; + size_t Height; + size_t Depth; + + CUarray_format Format; + unsigned int NumChannels; + unsigned int Flags; +} CUDA_ARRAY3D_DESCRIPTOR; + +typedef struct CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC_st { + unsigned long long offset; + CUDA_ARRAY3D_DESCRIPTOR arrayDesc; + unsigned int numLevels; + unsigned int reserved[16]; +} CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC; + +#define CU_EGL_FRAME_MAX_PLANES 3 +typedef struct CUeglFrame_st { + union { + CUarray pArray[CU_EGL_FRAME_MAX_PLANES]; + void* pPitch[CU_EGL_FRAME_MAX_PLANES]; + } frame; + unsigned int width; + unsigned int height; + unsigned int depth; + unsigned int pitch; + unsigned int planeCount; + unsigned int numChannels; + CUeglFrameType frameType; + CUeglColorFormat eglColorFormat; + CUarray_format cuFormat; +} CUeglFrame; + +#define CU_STREAM_DEFAULT 0 +#define CU_STREAM_NON_BLOCKING 1 + +#define CU_EVENT_DEFAULT 0 +#define CU_EVENT_BLOCKING_SYNC 1 +#define CU_EVENT_DISABLE_TIMING 2 + +#define CU_EVENT_WAIT_DEFAULT 0 +#define CU_EVENT_WAIT_EXTERNAL 1 + +#define CU_TRSF_READ_AS_INTEGER 1 + +typedef void CUDAAPI CUstreamCallback(CUstream hStream, CUresult status, void *userdata); +typedef void CUDAAPI CUhostFn(void *userData); + +typedef CUresult CUDAAPI tcuInit(unsigned int Flags); +typedef CUresult CUDAAPI tcuDriverGetVersion(int *driverVersion); +typedef CUresult CUDAAPI tcuDeviceGetCount(int *count); +typedef CUresult CUDAAPI tcuDeviceGet(CUdevice *device, int ordinal); +typedef CUresult CUDAAPI tcuDeviceGetAttribute(int *pi, CUdevice_attribute attrib, CUdevice dev); +typedef CUresult CUDAAPI tcuDeviceGetName(char *name, int len, CUdevice dev); +typedef CUresult CUDAAPI tcuDeviceGetUuid(CUuuid *uuid, CUdevice dev); +typedef CUresult CUDAAPI tcuDeviceGetUuid_v2(CUuuid *uuid, CUdevice dev); +typedef CUresult CUDAAPI tcuDeviceGetLuid(char* luid, unsigned int* deviceNodeMask, CUdevice dev); +typedef CUresult CUDAAPI tcuDeviceGetByPCIBusId(CUdevice* dev, const char* pciBusId); +typedef CUresult CUDAAPI tcuDeviceGetPCIBusId(char* pciBusId, int len, CUdevice dev); +typedef CUresult CUDAAPI tcuDeviceComputeCapability(int *major, int *minor, CUdevice dev); +typedef CUresult CUDAAPI tcuCtxCreate_v2(CUcontext *pctx, unsigned int flags, CUdevice dev); +typedef CUresult CUDAAPI tcuCtxSynchronize(void); +typedef CUresult CUDAAPI tcuCtxGetStreamPriorityRange(int *leastPriority, int *greatestPriority); +typedef CUresult CUDAAPI tcuCtxGetCurrent(CUcontext *pctx); +typedef CUresult CUDAAPI tcuCtxSetLimit(CUlimit limit, size_t value); +typedef CUresult CUDAAPI tcuCtxPushCurrent_v2(CUcontext pctx); +typedef CUresult CUDAAPI tcuCtxPopCurrent_v2(CUcontext *pctx); +typedef CUresult CUDAAPI tcuCtxDestroy_v2(CUcontext ctx); +typedef CUresult CUDAAPI tcuMemAlloc_v2(CUdeviceptr *dptr, size_t bytesize); +typedef CUresult CUDAAPI tcuMemAllocPitch_v2(CUdeviceptr *dptr, size_t *pPitch, size_t WidthInBytes, size_t Height, unsigned int ElementSizeBytes); +typedef CUresult CUDAAPI tcuMemAllocManaged(CUdeviceptr *dptr, size_t bytesize, unsigned int flags); +typedef CUresult CUDAAPI tcuMemsetD8Async(CUdeviceptr dstDevice, unsigned char uc, size_t N, CUstream hStream); +typedef CUresult CUDAAPI tcuMemsetD16Async(CUdeviceptr dstDevice, unsigned short us, size_t N, CUstream hStream); +typedef CUresult CUDAAPI tcuMemsetD32Async(CUdeviceptr dstDevice, unsigned int ui, size_t N, CUstream hStream); +typedef CUresult CUDAAPI tcuMemsetD2D8Async(CUdeviceptr dstDevice, size_t dstPitch, unsigned char uc, size_t Width, size_t Height, CUstream hStream); +typedef CUresult CUDAAPI tcuMemsetD2D16Async(CUdeviceptr dstDevice, size_t dstPitch, unsigned short us, size_t Width, size_t Height, CUstream hStream); +typedef CUresult CUDAAPI tcuMemsetD2D32Async(CUdeviceptr dstDevice, size_t dstPitch, unsigned int ui, size_t Width, size_t Height, CUstream hStream); +typedef CUresult CUDAAPI tcuMemFree_v2(CUdeviceptr dptr); +typedef CUresult CUDAAPI tcuMemHostAlloc(void **pp, size_t bytesize, unsigned int flags); +typedef CUresult CUDAAPI tcuMemFreeHost(void *p); +typedef CUresult CUDAAPI tcuMemAllocAsync(CUdeviceptr *dptr, size_t bytesize, CUstream hStream); +typedef CUresult CUDAAPI tcuMemFreeAsync(CUdeviceptr dptr, CUstream hStream); +typedef CUresult CUDAAPI tcuMemcpy(CUdeviceptr dst, CUdeviceptr src, size_t bytesize); +typedef CUresult CUDAAPI tcuMemcpyAsync(CUdeviceptr dst, CUdeviceptr src, size_t bytesize, CUstream hStream); +typedef CUresult CUDAAPI tcuMemcpy2D_v2(const CUDA_MEMCPY2D *pcopy); +typedef CUresult CUDAAPI tcuMemcpy2DAsync_v2(const CUDA_MEMCPY2D *pcopy, CUstream hStream); +typedef CUresult CUDAAPI tcuMemcpyHtoD_v2(CUdeviceptr dstDevice, const void *srcHost, size_t ByteCount); +typedef CUresult CUDAAPI tcuMemcpyHtoDAsync_v2(CUdeviceptr dstDevice, const void *srcHost, size_t ByteCount, CUstream hStream); +typedef CUresult CUDAAPI tcuMemcpyDtoH_v2(void *dstHost, CUdeviceptr srcDevice, size_t ByteCount); +typedef CUresult CUDAAPI tcuMemcpyDtoHAsync_v2(void *dstHost, CUdeviceptr srcDevice, size_t ByteCount, CUstream hStream); +typedef CUresult CUDAAPI tcuMemcpyDtoD_v2(CUdeviceptr dstDevice, CUdeviceptr srcDevice, size_t ByteCount); +typedef CUresult CUDAAPI tcuMemcpyDtoDAsync_v2(CUdeviceptr dstDevice, CUdeviceptr srcDevice, size_t ByteCount, CUstream hStream); +typedef CUresult CUDAAPI tcuGetErrorName(CUresult error, const char** pstr); +typedef CUresult CUDAAPI tcuGetErrorString(CUresult error, const char** pstr); +typedef CUresult CUDAAPI tcuCtxGetDevice(CUdevice *device); + +typedef CUresult CUDAAPI tcuDevicePrimaryCtxRetain(CUcontext *pctx, CUdevice dev); +typedef CUresult CUDAAPI tcuDevicePrimaryCtxRelease(CUdevice dev); +typedef CUresult CUDAAPI tcuDevicePrimaryCtxSetFlags(CUdevice dev, unsigned int flags); +typedef CUresult CUDAAPI tcuDevicePrimaryCtxGetState(CUdevice dev, unsigned int *flags, int *active); +typedef CUresult CUDAAPI tcuDevicePrimaryCtxReset(CUdevice dev); + +typedef CUresult CUDAAPI tcuStreamCreate(CUstream *phStream, unsigned int flags); +typedef CUresult CUDAAPI tcuStreamCreateWithPriority(CUstream *phStream, unsigned int flags, int priority); +typedef CUresult CUDAAPI tcuStreamQuery(CUstream hStream); +typedef CUresult CUDAAPI tcuStreamSynchronize(CUstream hStream); +typedef CUresult CUDAAPI tcuStreamDestroy_v2(CUstream hStream); +typedef CUresult CUDAAPI tcuStreamAddCallback(CUstream hStream, CUstreamCallback *callback, void *userdata, unsigned int flags); +typedef CUresult CUDAAPI tcuStreamWaitEvent(CUstream hStream, CUevent hEvent, unsigned int flags); +typedef CUresult CUDAAPI tcuEventCreate(CUevent *phEvent, unsigned int flags); +typedef CUresult CUDAAPI tcuEventDestroy_v2(CUevent hEvent); +typedef CUresult CUDAAPI tcuEventSynchronize(CUevent hEvent); +typedef CUresult CUDAAPI tcuEventQuery(CUevent hEvent); +typedef CUresult CUDAAPI tcuEventRecord(CUevent hEvent, CUstream hStream); + +typedef CUresult CUDAAPI tcuLaunchKernel(CUfunction f, unsigned int gridDimX, unsigned int gridDimY, unsigned int gridDimZ, unsigned int blockDimX, unsigned int blockDimY, unsigned int blockDimZ, unsigned int sharedMemBytes, CUstream hStream, void** kernelParams, void** extra); +typedef CUresult CUDAAPI tcuLaunchHostFunc(CUstream hStream, CUhostFn *fn, void *userData); + +typedef CUresult CUDAAPI tcuLinkCreate(unsigned int numOptions, CUjit_option* options, void** optionValues, CUlinkState* stateOut); +typedef CUresult CUDAAPI tcuLinkAddData(CUlinkState state, CUjitInputType type, void* data, size_t size, const char* name, unsigned int numOptions, CUjit_option* options, void** optionValues); +typedef CUresult CUDAAPI tcuLinkComplete(CUlinkState state, void** cubinOut, size_t* sizeOut); +typedef CUresult CUDAAPI tcuLinkDestroy(CUlinkState state); +typedef CUresult CUDAAPI tcuModuleLoadData(CUmodule* module, const void* image); +typedef CUresult CUDAAPI tcuModuleUnload(CUmodule hmod); +typedef CUresult CUDAAPI tcuModuleGetFunction(CUfunction* hfunc, CUmodule hmod, const char* name); +typedef CUresult CUDAAPI tcuModuleGetGlobal(CUdeviceptr *dptr, size_t *bytes, CUmodule hmod, const char* name); +typedef CUresult CUDAAPI tcuTexObjectCreate(CUtexObject* pTexObject, const CUDA_RESOURCE_DESC* pResDesc, const CUDA_TEXTURE_DESC* pTexDesc, const CUDA_RESOURCE_VIEW_DESC* pResViewDesc); +typedef CUresult CUDAAPI tcuTexObjectDestroy(CUtexObject texObject); + +typedef CUresult CUDAAPI tcuGLGetDevices_v2(unsigned int* pCudaDeviceCount, CUdevice* pCudaDevices, unsigned int cudaDeviceCount, CUGLDeviceList deviceList); +typedef CUresult CUDAAPI tcuGraphicsGLRegisterImage(CUgraphicsResource* pCudaResource, GLuint image, GLenum target, unsigned int Flags); +typedef CUresult CUDAAPI tcuGraphicsUnregisterResource(CUgraphicsResource resource); +typedef CUresult CUDAAPI tcuGraphicsMapResources(unsigned int count, CUgraphicsResource* resources, CUstream hStream); +typedef CUresult CUDAAPI tcuGraphicsUnmapResources(unsigned int count, CUgraphicsResource* resources, CUstream hStream); +typedef CUresult CUDAAPI tcuGraphicsSubResourceGetMappedArray(CUarray* pArray, CUgraphicsResource resource, unsigned int arrayIndex, unsigned int mipLevel); +typedef CUresult CUDAAPI tcuGraphicsResourceGetMappedPointer(CUdeviceptr *devPtrOut, size_t *sizeOut, CUgraphicsResource resource); + +typedef CUresult CUDAAPI tcuImportExternalMemory(CUexternalMemory* extMem_out, const CUDA_EXTERNAL_MEMORY_HANDLE_DESC* memHandleDesc); +typedef CUresult CUDAAPI tcuDestroyExternalMemory(CUexternalMemory extMem); +typedef CUresult CUDAAPI tcuExternalMemoryGetMappedBuffer(CUdeviceptr* devPtr, CUexternalMemory extMem, const CUDA_EXTERNAL_MEMORY_BUFFER_DESC* bufferDesc); +typedef CUresult CUDAAPI tcuExternalMemoryGetMappedMipmappedArray(CUmipmappedArray* mipmap, CUexternalMemory extMem, const CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC* mipmapDesc); +typedef CUresult CUDAAPI tcuMipmappedArrayGetLevel(CUarray* pLevelArray, CUmipmappedArray hMipmappedArray, unsigned int level); +typedef CUresult CUDAAPI tcuMipmappedArrayDestroy(CUmipmappedArray hMipmappedArray); + +typedef CUresult CUDAAPI tcuImportExternalSemaphore(CUexternalSemaphore* extSem_out, const CUDA_EXTERNAL_SEMAPHORE_HANDLE_DESC* semHandleDesc); +typedef CUresult CUDAAPI tcuDestroyExternalSemaphore(CUexternalSemaphore extSem); +typedef CUresult CUDAAPI tcuSignalExternalSemaphoresAsync(const CUexternalSemaphore* extSemArray, const CUDA_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS* paramsArray, unsigned int numExtSems, CUstream stream); +typedef CUresult CUDAAPI tcuWaitExternalSemaphoresAsync(const CUexternalSemaphore* extSemArray, const CUDA_EXTERNAL_SEMAPHORE_WAIT_PARAMS* paramsArray, unsigned int numExtSems, CUstream stream); + +typedef CUresult CUDAAPI tcuArrayCreate(CUarray *pHandle, const CUDA_ARRAY_DESCRIPTOR* pAllocateArray); +typedef CUresult CUDAAPI tcuArray3DCreate(CUarray *pHandle, const CUDA_ARRAY3D_DESCRIPTOR* pAllocateArray); +typedef CUresult CUDAAPI tcuArrayDestroy(CUarray hArray); +typedef CUresult CUDAAPI tcuArray3DGetDescriptor(CUDA_ARRAY3D_DESCRIPTOR *pArrayDescriptor, CUarray hArray); +typedef CUresult CUDAAPI tcuArrayGetPlane(CUarray *pPlaneArray, CUarray hArray, unsigned int planeIdx); + +typedef CUresult CUDAAPI tcuEGLStreamProducerConnect(CUeglStreamConnection* conn, ffnv_EGLStreamKHR stream, ffnv_EGLint width, ffnv_EGLint height); +typedef CUresult CUDAAPI tcuEGLStreamProducerDisconnect(CUeglStreamConnection* conn); +typedef CUresult CUDAAPI tcuEGLStreamConsumerDisconnect(CUeglStreamConnection* conn); +typedef CUresult CUDAAPI tcuEGLStreamProducerPresentFrame(CUeglStreamConnection* conn, CUeglFrame eglframe, CUstream* pStream); +typedef CUresult CUDAAPI tcuEGLStreamProducerReturnFrame(CUeglStreamConnection* conn, CUeglFrame* eglframe, CUstream* pStream); + +typedef CUresult CUDAAPI tcuD3D11GetDevice(CUdevice *device, void *dxgiAdapter); +typedef CUresult CUDAAPI tcuD3D11GetDevices(unsigned int *deviceCountOut, CUdevice *devices, unsigned int deviceCount, void *d3d11device, CUd3d11DeviceList listType); +typedef CUresult CUDAAPI tcuGraphicsD3D11RegisterResource(CUgraphicsResource *cudaResourceOut, void *d3d11Resource, unsigned int flags); +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/ffnvcodec/dynlink_cuviddec.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/ffnvcodec/dynlink_cuviddec.h new file mode 100644 index 000000000..54e3bec90 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/ffnvcodec/dynlink_cuviddec.h @@ -0,0 +1,1368 @@ +/* + * This copyright notice applies to this header file only: + * + * Copyright (c) 2010-2026 NVIDIA Corporation + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the software, and to permit persons to whom the + * software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/*****************************************************************************************************/ +//! \file cuviddec.h +//! NVDECODE API provides video decoding interface to NVIDIA GPU devices. +//! This file contains constants, structure definitions and function prototypes used for decoding. +/*****************************************************************************************************/ + +#if !defined(__CUDA_VIDEO_H__) +#define __CUDA_VIDEO_H__ + +#if defined(_WIN64) || defined(__LP64__) || defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) +#if (CUDA_VERSION >= 3020) && (!defined(CUDA_FORCE_API_VERSION) || (CUDA_FORCE_API_VERSION >= 3020)) +#define __CUVID_DEVPTR64 +#endif +#endif + +#define NVDECAPI_MAJOR_VERSION 13 +#define NVDECAPI_MINOR_VERSION 1 + +#define NVDECAPI_VERSION (NVDECAPI_MAJOR_VERSION | (NVDECAPI_MINOR_VERSION << 24)) + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +#if defined(__CYGWIN__) +typedef unsigned int tcu_ulong; +#else +typedef unsigned long tcu_ulong; +#endif + +typedef void *CUvideodecoder; +typedef struct _CUcontextlock_st *CUvideoctxlock; +typedef long long CUvideotimestamp; + +/********************************************************************************************/ +//! \enum cuvidMaxNumRegisterDecodeSurfaces +//! Maximum number of decode surfaces that can be registered via cuvidRegisterDecodeSurfaces +/********************************************************************************************/ +typedef enum cuvidMaxNumRegisterDecodeSurfaces_enum { + MAX_NUM_REGISTERED_DECODE_SURFACES = 32 +} cuvidMaxNumRegisterDecodeSurfaces; + +/*********************************************************************************/ +//! \enum cudaVideoCodec +//! Video codec enums +//! These enums are used in CUVIDDECODECREATEINFO and CUVIDDECODECAPS structures +/*********************************************************************************/ +typedef enum cudaVideoCodec_enum { + cudaVideoCodec_MPEG1=0, /**< MPEG1 */ + cudaVideoCodec_MPEG2, /**< MPEG2 */ + cudaVideoCodec_MPEG4, /**< MPEG4 */ + cudaVideoCodec_VC1, /**< VC1 */ + cudaVideoCodec_H264, /**< H264 */ + cudaVideoCodec_JPEG, /**< JPEG */ + cudaVideoCodec_H264_SVC, /**< H264-SVC */ + cudaVideoCodec_H264_MVC, /**< H264-MVC */ + cudaVideoCodec_HEVC, /**< HEVC */ + cudaVideoCodec_VP8, /**< VP8 */ + cudaVideoCodec_VP9, /**< VP9 */ + cudaVideoCodec_AV1, /**< AV1 */ + cudaVideoCodec_NumCodecs, /**< Max codecs */ + // Uncompressed YUV + cudaVideoCodec_YUV420 = (('I'<<24)|('Y'<<16)|('U'<<8)|('V')), /**< Y,U,V (4:2:0) */ + cudaVideoCodec_YV12 = (('Y'<<24)|('V'<<16)|('1'<<8)|('2')), /**< Y,V,U (4:2:0) */ + cudaVideoCodec_NV12 = (('N'<<24)|('V'<<16)|('1'<<8)|('2')), /**< Y,UV (4:2:0) */ + cudaVideoCodec_YUYV = (('Y'<<24)|('U'<<16)|('Y'<<8)|('V')), /**< YUYV/YUY2 (4:2:2) */ + cudaVideoCodec_UYVY = (('U'<<24)|('Y'<<16)|('V'<<8)|('Y')) /**< UYVY (4:2:2) */ +} cudaVideoCodec; + +/********************************************************************************************/ +//! \enum cudaVideoSurfaceFormat +//! Video surface format enums used for output format and storage layout of decoded output. +//! These enums are used in CUVIDDECODECREATEINFO structure +/********************************************************************************************/ +typedef enum cudaVideoSurfaceFormat_enum { + cudaVideoSurfaceFormat_NV12=0, /**< Semi-Planar YUV [Y plane followed by interleaved UV plane] + with pitched linear storage layout of pixels. */ + cudaVideoSurfaceFormat_P016=1, /**< 16 bit Semi-Planar YUV [Y plane followed by interleaved UV plane] + with pitched linear storage layout of pixels. + Can be used for 10 bit(6LSB bits 0), 12 bit (4LSB bits 0) */ + cudaVideoSurfaceFormat_YUV444=2, /**< Planar YUV [Y plane followed by U and V planes] + with pitched linear storage layout of pixels. */ + cudaVideoSurfaceFormat_YUV444_16Bit=3, /**< 16 bit Planar YUV [Y plane followed by U and V planes] + with pitched linear storage layout of pixels. + Can be used for 10 bit(6LSB bits 0), 12 bit (4LSB bits 0) */ + cudaVideoSurfaceFormat_NV16=4, /**< Semi-Planar YUV 422 [Y plane followed by interleaved UV plane] + with pitched linear storage layout of pixels. */ + cudaVideoSurfaceFormat_P216=5, /**< 16 bit Semi-Planar YUV 422[Y plane followed by interleaved UV plane] + with pitched linear storage layout of pixels. + Can be used for 10 bit(6LSB bits 0), 12 bit (4LSB bits 0) */ + cudaVideoSurfaceFormat_NV12_Opaque=6, /**< Semi-Planar YUV [Y plane followed by interleaved UV plane] + with opaque storage layout of pixels in memory allocated as CUDA array. */ + cudaVideoSurfaceFormat_P016_Opaque=7, /**< 16 bit Semi-Planar YUV [Y plane followed by interleaved UV plane] + with opaque storage layout of pixels in memory allocated as CUDA array. + Can be used for 10 bit(6LSB bits 0), 12 bit (4LSB bits 0) */ + cudaVideoSurfaceFormat_YUV444_Opaque=8, /**< Semi-Planar YUV [Y plane followed by U and V planes] + with opaque storage layout of pixels in memory allocated as CUDA array. */ + cudaVideoSurfaceFormat_YUV444_16Bit_Opaque=9, /**< 16 bit Semi-Planar YUV [Y plane followed by U and V planes] + with opaque storage layout of pixels in memory allocated as CUDA array. + Can be used for 10 bit(6LSB bits 0), 12 bit (4LSB bits 0) */ + cudaVideoSurfaceFormat_NV16_Opaque=10, /**< Semi-Planar YUV 422 [Y plane followed by interleaved UV plane] + with opaque storage layout of pixels in memory allocated as CUDA array. */ + cudaVideoSurfaceFormat_P216_Opaque=11 /**< 16 bit Semi-Planar YUV 422[Y plane followed by interleaved UV plane] + with opaque storage layout of pixels in memory allocated as CUDA array. + Can be used for 10 bit(6LSB bits 0), 12 bit (4LSB bits 0) */ +} cudaVideoSurfaceFormat; + +/******************************************************************************************************************/ +//! \enum cudaVideoDeinterlaceMode +//! Deinterlacing mode enums +//! These enums are used in CUVIDDECODECREATEINFO structure +//! Use cudaVideoDeinterlaceMode_Weave for progressive content and for content that doesn't need deinterlacing +//! cudaVideoDeinterlaceMode_Adaptive needs more video memory than other DImodes +/******************************************************************************************************************/ +typedef enum cudaVideoDeinterlaceMode_enum { + cudaVideoDeinterlaceMode_Weave=0, /**< Weave both fields (no deinterlacing) */ + cudaVideoDeinterlaceMode_Bob, /**< Drop one field */ + cudaVideoDeinterlaceMode_Adaptive /**< Adaptive deinterlacing */ +} cudaVideoDeinterlaceMode; + +/**************************************************************************************************************/ +//! \enum cudaVideoChromaFormat +//! Chroma format enums +//! These enums are used in CUVIDDECODECREATEINFO and CUVIDDECODECAPS structures +/**************************************************************************************************************/ +typedef enum cudaVideoChromaFormat_enum { + cudaVideoChromaFormat_Monochrome=0, /**< MonoChrome */ + cudaVideoChromaFormat_420, /**< YUV 4:2:0 */ + cudaVideoChromaFormat_422, /**< YUV 4:2:2 */ + cudaVideoChromaFormat_444 /**< YUV 4:4:4 */ +} cudaVideoChromaFormat; + +/*************************************************************************************************************/ +//! \enum cudaVideoCreateFlags +//! Decoder flag enums to select preferred decode path +//! cudaVideoCreate_Default and cudaVideoCreate_PreferCUVID are most optimized, use these whenever possible +/*************************************************************************************************************/ +typedef enum cudaVideoCreateFlags_enum { + cudaVideoCreate_Default = 0x00, /**< Default operation mode: use dedicated video engines */ + cudaVideoCreate_PreferCUDA = 0x01, /**< Use CUDA-based decoder (requires valid vidLock object for multi-threading) */ + cudaVideoCreate_PreferDXVA = 0x02, /**< Go through DXVA internally if possible (requires D3D9 interop) */ + cudaVideoCreate_PreferCUVID = 0x04 /**< Use dedicated video engines directly */ +} cudaVideoCreateFlags; + + +/*************************************************************************/ +//! \enum cuvidDecodeStatus +//! Decode status enums +//! These enums are used in CUVIDGETDECODESTATUS structure +/*************************************************************************/ +typedef enum cuvidDecodeStatus_enum +{ + cuvidDecodeStatus_Invalid = 0, // Decode status is not valid + cuvidDecodeStatus_InProgress = 1, // Decode is in progress + cuvidDecodeStatus_Success = 2, // Decode is completed without any errors + // 3 to 7 enums are reserved for future use + cuvidDecodeStatus_Error = 8, // Decode is completed with an error (error is not concealed) + cuvidDecodeStatus_Error_Concealed = 9, // Decode is completed with an error and error is concealed +} cuvidDecodeStatus; + +/**************************************************************************************************************/ +//! \struct CUVIDDECODESTATSHEADER; +//! This structure contains header information related to the decode stats buffer of a frame +/**************************************************************************************************************/ +typedef struct _CUVIDDECODESTATSHEADER +{ + unsigned char bIsStatsPresent : 1; // Flag to indicate whether decode stats dump is present or not. + unsigned char bIsMV1Valid : 1; // Flag to indicate if MV1 is valid (set to 1 if valid) + unsigned char reserved1 : 6; // Reserved : shall be set to 0 + unsigned char reserved2[3]; // Reserved : shall be set to 0 + unsigned int mbCount; // Total number of 16x16 blocks in current frame + unsigned int size; // Size of decode stats data of all blocks (for sanity check) + unsigned int reserved3[5]; // Reserved : shall be set to 0 +} CUVIDDECODESTATSHEADER; + +/**************************************************************************************************************/ +//! \struct CUVIDDECODESTATS; +//! This structure contains per 16x16 block decode statistics data. +//! The decode stats buffer contains one such structure per 16x16 block. +//! The data in the main buffer has one CUVIDDECODESTATSHEADER followed by 16x16 block data saved in +//! raster scan order. +/**************************************************************************************************************/ +typedef struct _CUVIDDECODESTATS +{ + unsigned char qp_luma; /**< Quantization Parameter for luma component. + For H.264/HEVC: QP'Y + Bitdepth-QP-ScaleFactor + Bitdepth-QP-ScaleFactor = 0 for 8-bit content + = 12 for 10-bit content + = 24 for 12-bit content */ + unsigned char qp_invalid : 1; /**< 0: Qp Valid, 1: QP is invalid */ + unsigned char cu_type : 3; /**< Coding Unit type: + 0: Intra-coded block + 1: Inter-coded block + 2: Skip block + 3: PCM block + 7: Invalid block */ + unsigned char reserved1 : 4; /**< Reserved for alignment/future use, set to zero */ + unsigned char reserved2[2]; /**< Reserved for alignment/future use, set to zero */ + short mv0_x; /**< First motion vector X component. + H.264: Forward motion vector if valid, otherwise backward motion vector + HEVC : Forward motion vector */ + short mv0_y; /**< First motion vector Y component. + H.264: Forward motion vector if valid, otherwise backward motion vector + HEVC : Forward motion vector */ + short mv1_x; /**< Second motion vector X component. + H.264: Unused (set to 0) + HEVC : Backward motion vector */ + short mv1_y; /**< Second motion vector Y component. + H.264: Unused (set to 0) + HEVC : Backward motion vector */ +} CUVIDDECODESTATS; + +typedef enum cuvidDecodeFeature_enum +{ + cuvidDecodeFeature_DecStats = 0, /**< IN: enable decode stats output, if supported */ +} cuvidDecodeFeature; + +/**************************************************************************************************************/ +//! \struct CUVIDDECODECAPS; +//! This structure is used in cuvidGetDecoderCaps API +/**************************************************************************************************************/ +typedef struct _CUVIDDECODECAPS +{ + cudaVideoCodec eCodecType; /**< IN: cudaVideoCodec_XXX */ + cudaVideoChromaFormat eChromaFormat; /**< IN: cudaVideoChromaFormat_XXX */ + unsigned int nBitDepthMinus8; /**< IN: The Value "BitDepth minus 8" */ + unsigned int reserved1[3]; /**< Reserved for future use - set to zero */ + + unsigned char bIsSupported; /**< OUT: 1 if codec supported, 0 if not supported */ + unsigned char nNumNVDECs; /**< OUT: Number of NVDECs that can support IN params */ + unsigned short nOutputFormatMask; /**< OUT: each bit represents corresponding cudaVideoSurfaceFormat enum */ + unsigned int nMaxWidth; /**< OUT: Max supported coded width in pixels */ + unsigned int nMaxHeight; /**< OUT: Max supported coded height in pixels */ + unsigned int nMaxMBCount; /**< OUT: Max supported macroblock count + CodedWidth*CodedHeight/256 must be <= nMaxMBCount */ + unsigned short nMinWidth; /**< OUT: Min supported coded width in pixels */ + unsigned short nMinHeight; /**< OUT: Min supported coded height in pixels */ + unsigned char bIsHistogramSupported; /**< OUT: 1 if Y component histogram output is supported, 0 if not + Note: histogram is computed on original picture data before + any post-processing like scaling, cropping, etc. is applied */ + unsigned char nCounterBitDepth; /**< OUT: histogram counter bit depth */ + unsigned short nMaxHistogramBins; /**< OUT: Max number of histogram bins */ + unsigned char bIsDecodeStatsSupported; /**< OUT: 1 if decode statistics are supported, 0 otherwise */ + unsigned char reserved4[3]; /* Reserved for future use - set to zero */ + unsigned int reserved3[9]; /**< Reserved for future use - set to zero */ +} CUVIDDECODECAPS; + +/**************************************************************************************************************/ +//! \struct CUVIDDECODECREATEINFO +//! This structure is used in cuvidCreateDecoder API +/**************************************************************************************************************/ +typedef struct _CUVIDDECODECREATEINFO +{ + tcu_ulong ulWidth; /**< IN: Coded sequence width in pixels */ + tcu_ulong ulHeight; /**< IN: Coded sequence height in pixels */ + tcu_ulong ulNumDecodeSurfaces; /**< IN: Maximum number of internal decode surfaces */ + cudaVideoCodec CodecType; /**< IN: cudaVideoCodec_XXX */ + cudaVideoChromaFormat ChromaFormat; /**< IN: cudaVideoChromaFormat_XXX */ + tcu_ulong ulCreationFlags; /**< IN: Decoder creation flags (cudaVideoCreateFlags_XXX) */ + tcu_ulong bitDepthMinus8; /**< IN: The value "BitDepth minus 8" */ + tcu_ulong ulIntraDecodeOnly; /**< IN: Set 1 only if video has all intra frames (default value is 0). This will + optimize video memory for Intra frames only decoding. The support is limited + to specific codecs - H264, HEVC, VP9, the flag will be ignored for codecs which + are not supported. However decoding might fail if the flag is enabled in case + of supported codecs for regular bit streams having P and/or B frames. */ + tcu_ulong ulMaxWidth; /**< IN: Coded sequence max width in pixels used with reconfigure Decoder */ + tcu_ulong ulMaxHeight; /**< IN: Coded sequence max height in pixels used with reconfigure Decoder */ + tcu_ulong Reserved1; /**< Reserved for future use - set to zero */ + /** + * IN: area of the frame that should be displayed + */ + struct { + short left; + short top; + short right; + short bottom; + } display_area; + + cudaVideoSurfaceFormat OutputFormat; /**< IN: cudaVideoSurfaceFormat_XXX */ + cudaVideoDeinterlaceMode DeinterlaceMode; /**< IN: cudaVideoDeinterlaceMode_XXX */ + tcu_ulong ulTargetWidth; /**< IN: Post-processed output width (Should be aligned to 2) */ + tcu_ulong ulTargetHeight; /**< IN: Post-processed output height (Should be aligned to 2) */ + tcu_ulong ulNumOutputSurfaces; /**< IN: Maximum number of output surfaces simultaneously mapped. + Must be set to 0 when using externally allocated memory for output.*/ + + CUvideoctxlock vidLock; /**< IN: If non-NULL, context lock used for synchronizing ownership of + the cuda context. Needed for cudaVideoCreate_PreferCUDA decode */ + /** + * IN: target rectangle in the output frame (for aspect ratio conversion) + * if a null rectangle is specified, {0,0,ulTargetWidth,ulTargetHeight} will be used + */ + struct { + short left; + short top; + short right; + short bottom; + } target_rect; + + tcu_ulong enableHistogram; /**< IN: enable histogram output, if supported */ + tcu_ulong enableDecodeFeatures; /**< IN: bitwise OR of different features in cuvidDecodeFeature*/ + tcu_ulong Reserved2[3]; /**< Reserved for future use - set to zero */ +} CUVIDDECODECREATEINFO; + +/**************************************************************************************************************/ +//! \struct CUVIDREGISTERDECODESURFACESINFO +//! This structure is used in cuvidRegisterDecodeSurfaces API +/**************************************************************************************************************/ +typedef struct _CUVIDREGISTERDECODESURFACESINFO +{ + unsigned int ulNumDecodeSurfaces; /**< IN: Number of decode surfaces to register */ + unsigned int reserved[31]; /**< Reserved for future use - set to zero */ + CUarray *pDecodeSurfaces; /**< IN: List of decode surfaces to register */ + CUdeviceptr *pDecodeStatsSurfaces; /**< IN: List of decode stats surfaces to register */ + void *pReserved[30]; /**< Reserved for future use - set to zero */ +} CUVIDREGISTERDECODESURFACESINFO; + +/*********************************************************/ +//! \struct CUVIDH264DPBENTRY +//! H.264 DPB entry +//! This structure is used in CUVIDH264PICPARAMS structure +/*********************************************************/ +typedef struct _CUVIDH264DPBENTRY +{ + int PicIdx; /**< picture index of reference frame */ + int FrameIdx; /**< frame_num(short-term) or LongTermFrameIdx(long-term) */ + int is_long_term; /**< 0=short term reference, 1=long term reference */ + int not_existing; /**< non-existing reference frame (corresponding PicIdx should be set to -1) */ + int used_for_reference; /**< 0=unused, 1=top_field, 2=bottom_field, 3=both_fields */ + int FieldOrderCnt[2]; /**< field order count of top and bottom fields */ +} CUVIDH264DPBENTRY; + +/************************************************************/ +//! \struct CUVIDH264MVCEXT +//! H.264 MVC picture parameters ext +//! This structure is used in CUVIDH264PICPARAMS structure +/************************************************************/ +typedef struct _CUVIDH264MVCEXT +{ + int num_views_minus1; /**< Max number of coded views minus 1 in video : Range - 0 to 1023 */ + int view_id; /**< view identifier */ + unsigned char inter_view_flag; /**< 1 if used for inter-view prediction, 0 if not */ + unsigned char num_inter_view_refs_l0; /**< number of inter-view ref pics in RefPicList0 */ + unsigned char num_inter_view_refs_l1; /**< number of inter-view ref pics in RefPicList1 */ + unsigned char MVCReserved8Bits; /**< Reserved bits */ + int InterViewRefsL0[16]; /**< view id of the i-th view component for inter-view prediction in RefPicList0 */ + int InterViewRefsL1[16]; /**< view id of the i-th view component for inter-view prediction in RefPicList1 */ +} CUVIDH264MVCEXT; + +/*********************************************************/ +//! \struct CUVIDH264SVCEXT +//! H.264 SVC picture parameters ext +//! This structure is used in CUVIDH264PICPARAMS structure +/*********************************************************/ +typedef struct _CUVIDH264SVCEXT +{ + unsigned char profile_idc; + unsigned char level_idc; + unsigned char DQId; + unsigned char DQIdMax; + unsigned char disable_inter_layer_deblocking_filter_idc; + unsigned char ref_layer_chroma_phase_y_plus1; + signed char inter_layer_slice_alpha_c0_offset_div2; + signed char inter_layer_slice_beta_offset_div2; + + unsigned short DPBEntryValidFlag; + unsigned char inter_layer_deblocking_filter_control_present_flag; + unsigned char extended_spatial_scalability_idc; + unsigned char adaptive_tcoeff_level_prediction_flag; + unsigned char slice_header_restriction_flag; + unsigned char chroma_phase_x_plus1_flag; + unsigned char chroma_phase_y_plus1; + + unsigned char tcoeff_level_prediction_flag; + unsigned char constrained_intra_resampling_flag; + unsigned char ref_layer_chroma_phase_x_plus1_flag; + unsigned char store_ref_base_pic_flag; + unsigned char Reserved8BitsA; + unsigned char Reserved8BitsB; + + short scaled_ref_layer_left_offset; + short scaled_ref_layer_top_offset; + short scaled_ref_layer_right_offset; + short scaled_ref_layer_bottom_offset; + unsigned short Reserved16Bits; + struct _CUVIDPICPARAMS *pNextLayer; /**< Points to the picparams for the next layer to be decoded. + Linked list ends at the target layer. */ + int bRefBaseLayer; /**< whether to store ref base pic */ +} CUVIDH264SVCEXT; + +/******************************************************/ +//! \struct CUVIDH264PICPARAMS +//! H.264 picture parameters +//! This structure is used in CUVIDPICPARAMS structure +/******************************************************/ +typedef struct _CUVIDH264PICPARAMS +{ + // SPS + int log2_max_frame_num_minus4; + int pic_order_cnt_type; + int log2_max_pic_order_cnt_lsb_minus4; + int delta_pic_order_always_zero_flag; + int frame_mbs_only_flag; + int direct_8x8_inference_flag; + int num_ref_frames; + unsigned char residual_colour_transform_flag; + unsigned char bit_depth_luma_minus8; + unsigned char bit_depth_chroma_minus8; + unsigned char qpprime_y_zero_transform_bypass_flag; + // PPS + int entropy_coding_mode_flag; + int pic_order_present_flag; + int num_ref_idx_l0_active_minus1; + int num_ref_idx_l1_active_minus1; + int weighted_pred_flag; + int weighted_bipred_idc; + int pic_init_qp_minus26; + int deblocking_filter_control_present_flag; + int redundant_pic_cnt_present_flag; + int transform_8x8_mode_flag; + int MbaffFrameFlag; + int constrained_intra_pred_flag; + int chroma_qp_index_offset; + int second_chroma_qp_index_offset; + int ref_pic_flag; + int frame_num; + int CurrFieldOrderCnt[2]; + // DPB + CUVIDH264DPBENTRY dpb[16]; // List of reference frames within the DPB + // Quantization Matrices (raster-order) + unsigned char WeightScale4x4[6][16]; + unsigned char WeightScale8x8[2][64]; + // FMO/ASO + unsigned char fmo_aso_enable; + unsigned char num_slice_groups_minus1; + unsigned char slice_group_map_type; + signed char pic_init_qs_minus26; + unsigned int slice_group_change_rate_minus1; + union + { + unsigned long long slice_group_map_addr; + const unsigned char *pMb2SliceGroupMap; + } fmo; + unsigned int mb_adaptive_frame_field_flag : 2; // bit 0 represent SPS flag mb_adaptive_frame_field_flag + // if bit 1 is not set, flag is ignored. Bit 1 is set to maintain backward compatibility + unsigned int Reserved1 : 30; + unsigned int Reserved[11]; + // SVC/MVC + union + { + CUVIDH264MVCEXT mvcext; + CUVIDH264SVCEXT svcext; + }; +} CUVIDH264PICPARAMS; + + +/********************************************************/ +//! \struct CUVIDMPEG2PICPARAMS +//! MPEG-2 picture parameters +//! This structure is used in CUVIDPICPARAMS structure +/********************************************************/ +typedef struct _CUVIDMPEG2PICPARAMS +{ + int ForwardRefIdx; // Picture index of forward reference (P/B-frames) + int BackwardRefIdx; // Picture index of backward reference (B-frames) + int picture_coding_type; + int full_pel_forward_vector; + int full_pel_backward_vector; + int f_code[2][2]; + int intra_dc_precision; + int frame_pred_frame_dct; + int concealment_motion_vectors; + int q_scale_type; + int intra_vlc_format; + int alternate_scan; + int top_field_first; + // Quantization matrices (raster order) + unsigned char QuantMatrixIntra[64]; + unsigned char QuantMatrixInter[64]; +} CUVIDMPEG2PICPARAMS; + +// MPEG-4 has VOP types instead of Picture types +#define I_VOP 0 +#define P_VOP 1 +#define B_VOP 2 +#define S_VOP 3 + +/*******************************************************/ +//! \struct CUVIDMPEG4PICPARAMS +//! MPEG-4 picture parameters +//! This structure is used in CUVIDPICPARAMS structure +/*******************************************************/ +typedef struct _CUVIDMPEG4PICPARAMS +{ + int ForwardRefIdx; // Picture index of forward reference (P/B-frames) + int BackwardRefIdx; // Picture index of backward reference (B-frames) + // VOL + int video_object_layer_width; + int video_object_layer_height; + int vop_time_increment_bitcount; + int top_field_first; + int resync_marker_disable; + int quant_type; + int quarter_sample; + int short_video_header; + int divx_flags; + // VOP + int vop_coding_type; + int vop_coded; + int vop_rounding_type; + int alternate_vertical_scan_flag; + int interlaced; + int vop_fcode_forward; + int vop_fcode_backward; + int trd[2]; + int trb[2]; + // Quantization matrices (raster order) + unsigned char QuantMatrixIntra[64]; + unsigned char QuantMatrixInter[64]; + int gmc_enabled; +} CUVIDMPEG4PICPARAMS; + +/********************************************************/ +//! \struct CUVIDVC1PICPARAMS +//! VC1 picture parameters +//! This structure is used in CUVIDPICPARAMS structure +/********************************************************/ +typedef struct _CUVIDVC1PICPARAMS +{ + int ForwardRefIdx; /**< Picture index of forward reference (P/B-frames) */ + int BackwardRefIdx; /**< Picture index of backward reference (B-frames) */ + int FrameWidth; /**< Actual frame width */ + int FrameHeight; /**< Actual frame height */ + // PICTURE + int intra_pic_flag; /**< Set to 1 for I,BI frames */ + int ref_pic_flag; /**< Set to 1 for I,P frames */ + int progressive_fcm; /**< Progressive frame */ + // SEQUENCE + int profile; + int postprocflag; + int pulldown; + int interlace; + int tfcntrflag; + int finterpflag; + int psf; + int multires; + int syncmarker; + int rangered; + int maxbframes; + // ENTRYPOINT + int panscan_flag; + int refdist_flag; + int extended_mv; + int dquant; + int vstransform; + int loopfilter; + int fastuvmc; + int overlap; + int quantizer; + int extended_dmv; + int range_mapy_flag; + int range_mapy; + int range_mapuv_flag; + int range_mapuv; + int rangeredfrm; // range reduction state +} CUVIDVC1PICPARAMS; + +/***********************************************************/ +//! \struct CUVIDJPEGPICPARAMS +//! JPEG picture parameters +//! This structure is used in CUVIDPICPARAMS structure +/***********************************************************/ +typedef struct _CUVIDJPEGPICPARAMS +{ + unsigned char numComponents; + unsigned char bitDepth; + unsigned char quantizationTableSelector[4]; + unsigned int scanOffset[4]; + unsigned int scanSize[4]; + + unsigned short restartInterval; + unsigned char componentIdentifier[4]; + + unsigned char hasQMatrix; + unsigned char hasHuffman; + unsigned short quantvals[4][64]; + + unsigned char bits_ac[4][16]; + unsigned char table_ac[4][256]; // there can only be max of 162 ac symbols + + unsigned char bits_dc[4][16]; + unsigned char table_dc[4][256]; // there can only be max of 12 dc symbols +} CUVIDJPEGPICPARAMS; + + +/*******************************************************/ +//! \struct CUVIDHEVCPICPARAMS +//! HEVC picture parameters +//! This structure is used in CUVIDPICPARAMS structure +/*******************************************************/ +typedef struct _CUVIDHEVCPICPARAMS +{ + // sps + int pic_width_in_luma_samples; + int pic_height_in_luma_samples; + unsigned char log2_min_luma_coding_block_size_minus3; + unsigned char log2_diff_max_min_luma_coding_block_size; + unsigned char log2_min_transform_block_size_minus2; + unsigned char log2_diff_max_min_transform_block_size; + unsigned char pcm_enabled_flag; + unsigned char log2_min_pcm_luma_coding_block_size_minus3; + unsigned char log2_diff_max_min_pcm_luma_coding_block_size; + unsigned char pcm_sample_bit_depth_luma_minus1; + + unsigned char pcm_sample_bit_depth_chroma_minus1; + unsigned char pcm_loop_filter_disabled_flag; + unsigned char strong_intra_smoothing_enabled_flag; + unsigned char max_transform_hierarchy_depth_intra; + unsigned char max_transform_hierarchy_depth_inter; + unsigned char amp_enabled_flag; + unsigned char separate_colour_plane_flag; + unsigned char log2_max_pic_order_cnt_lsb_minus4; + + unsigned char num_short_term_ref_pic_sets; + unsigned char long_term_ref_pics_present_flag; + unsigned char num_long_term_ref_pics_sps; + unsigned char sps_temporal_mvp_enabled_flag; + unsigned char sample_adaptive_offset_enabled_flag; + unsigned char scaling_list_enable_flag; + unsigned char IrapPicFlag; + unsigned char IdrPicFlag; + + unsigned char bit_depth_luma_minus8; + unsigned char bit_depth_chroma_minus8; + //sps/pps extension fields + unsigned char log2_max_transform_skip_block_size_minus2; + unsigned char log2_sao_offset_scale_luma; + unsigned char log2_sao_offset_scale_chroma; + unsigned char high_precision_offsets_enabled_flag; + + // MV-HEVC related fields + unsigned char mv_hevc_enable; + unsigned char nuh_layer_id; + unsigned char default_ref_layers_active_flag; + unsigned char NumDirectRefLayers; + unsigned char max_one_active_ref_layer_flag; + unsigned char poc_lsb_not_present_flag; + unsigned char NumActiveRefLayerPics0; + unsigned char NumActiveRefLayerPics1; + unsigned char reserved1[2]; + + // pps + unsigned char dependent_slice_segments_enabled_flag; + unsigned char slice_segment_header_extension_present_flag; + unsigned char sign_data_hiding_enabled_flag; + unsigned char cu_qp_delta_enabled_flag; + unsigned char diff_cu_qp_delta_depth; + signed char init_qp_minus26; + signed char pps_cb_qp_offset; + signed char pps_cr_qp_offset; + + unsigned char constrained_intra_pred_flag; + unsigned char weighted_pred_flag; + unsigned char weighted_bipred_flag; + unsigned char transform_skip_enabled_flag; + unsigned char transquant_bypass_enabled_flag; + unsigned char entropy_coding_sync_enabled_flag; + unsigned char log2_parallel_merge_level_minus2; + unsigned char num_extra_slice_header_bits; + + unsigned char loop_filter_across_tiles_enabled_flag; + unsigned char loop_filter_across_slices_enabled_flag; + unsigned char output_flag_present_flag; + unsigned char num_ref_idx_l0_default_active_minus1; + unsigned char num_ref_idx_l1_default_active_minus1; + unsigned char lists_modification_present_flag; + unsigned char cabac_init_present_flag; + unsigned char pps_slice_chroma_qp_offsets_present_flag; + + unsigned char deblocking_filter_override_enabled_flag; + unsigned char pps_deblocking_filter_disabled_flag; + signed char pps_beta_offset_div2; + signed char pps_tc_offset_div2; + unsigned char tiles_enabled_flag; + unsigned char uniform_spacing_flag; + unsigned char num_tile_columns_minus1; + unsigned char num_tile_rows_minus1; + + unsigned short column_width_minus1[21]; + unsigned short row_height_minus1[21]; + + // sps and pps extension HEVC-main 444 + unsigned char sps_range_extension_flag; + unsigned char transform_skip_rotation_enabled_flag; + unsigned char transform_skip_context_enabled_flag; + unsigned char implicit_rdpcm_enabled_flag; + + unsigned char explicit_rdpcm_enabled_flag; + unsigned char extended_precision_processing_flag; + unsigned char intra_smoothing_disabled_flag; + unsigned char persistent_rice_adaptation_enabled_flag; + + unsigned char cabac_bypass_alignment_enabled_flag; + unsigned char pps_range_extension_flag; + unsigned char cross_component_prediction_enabled_flag; + unsigned char chroma_qp_offset_list_enabled_flag; + + unsigned char diff_cu_chroma_qp_offset_depth; + unsigned char chroma_qp_offset_list_len_minus1; + signed char cb_qp_offset_list[6]; + + signed char cr_qp_offset_list[6]; + unsigned char reserved2[2]; + + unsigned int reserved3[8]; + + // RefPicSets + int NumBitsForShortTermRPSInSlice; + int NumDeltaPocsOfRefRpsIdx; + int NumPocTotalCurr; + int NumPocStCurrBefore; + int NumPocStCurrAfter; + int NumPocLtCurr; + int CurrPicOrderCntVal; + int RefPicIdx[16]; // [refpic] Indices of valid reference pictures (-1 if unused for reference) + int PicOrderCntVal[16]; // [refpic] + unsigned char IsLongTerm[16]; // [refpic] 0=not a long-term reference, 1=long-term reference + unsigned char RefPicSetStCurrBefore[8]; // [0..NumPocStCurrBefore-1] -> refpic (0..15) + unsigned char RefPicSetStCurrAfter[8]; // [0..NumPocStCurrAfter-1] -> refpic (0..15) + unsigned char RefPicSetLtCurr[8]; // [0..NumPocLtCurr-1] -> refpic (0..15) + unsigned char RefPicSetInterLayer0[8]; + unsigned char RefPicSetInterLayer1[8]; + unsigned int reserved4[12]; + + // scaling lists (diag order) + unsigned char ScalingList4x4[6][16]; // [matrixId][i] + unsigned char ScalingList8x8[6][64]; // [matrixId][i] + unsigned char ScalingList16x16[6][64]; // [matrixId][i] + unsigned char ScalingList32x32[2][64]; // [matrixId][i] + unsigned char ScalingListDCCoeff16x16[6]; // [matrixId] + unsigned char ScalingListDCCoeff32x32[2]; // [matrixId] +} CUVIDHEVCPICPARAMS; + + +/***********************************************************/ +//! \struct CUVIDVP8PICPARAMS +//! VP8 picture parameters +//! This structure is used in CUVIDPICPARAMS structure +/***********************************************************/ +typedef struct _CUVIDVP8PICPARAMS +{ + int width; + int height; + unsigned int first_partition_size; + //Frame Indexes + unsigned char LastRefIdx; + unsigned char GoldenRefIdx; + unsigned char AltRefIdx; + union { + struct { + unsigned char frame_type : 1; /**< 0 = KEYFRAME, 1 = INTERFRAME */ + unsigned char version : 3; + unsigned char show_frame : 1; + unsigned char update_mb_segmentation_data : 1; /**< Must be 0 if segmentation is not enabled */ + unsigned char Reserved2Bits : 2; + }vp8_frame_tag; + unsigned char wFrameTagFlags; + }; + unsigned char Reserved1[4]; + unsigned int Reserved2[3]; +} CUVIDVP8PICPARAMS; + +/***********************************************************/ +//! \struct CUVIDVP9PICPARAMS +//! VP9 picture parameters +//! This structure is used in CUVIDPICPARAMS structure +/***********************************************************/ +typedef struct _CUVIDVP9PICPARAMS +{ + unsigned int width; + unsigned int height; + + //Frame Indices + unsigned char LastRefIdx; + unsigned char GoldenRefIdx; + unsigned char AltRefIdx; + unsigned char colorSpace; + + unsigned short profile : 3; + unsigned short frameContextIdx : 2; + unsigned short frameType : 1; + unsigned short showFrame : 1; + unsigned short errorResilient : 1; + unsigned short frameParallelDecoding : 1; + unsigned short subSamplingX : 1; + unsigned short subSamplingY : 1; + unsigned short intraOnly : 1; + unsigned short allow_high_precision_mv : 1; + unsigned short refreshEntropyProbs : 1; + unsigned short reserved2Bits : 2; + + unsigned short reserved16Bits; + + unsigned char refFrameSignBias[4]; + + unsigned char bitDepthMinus8Luma; + unsigned char bitDepthMinus8Chroma; + unsigned char loopFilterLevel; + unsigned char loopFilterSharpness; + + unsigned char modeRefLfEnabled; + unsigned char log2_tile_columns; + unsigned char log2_tile_rows; + + unsigned char segmentEnabled : 1; + unsigned char segmentMapUpdate : 1; + unsigned char segmentMapTemporalUpdate : 1; + unsigned char segmentFeatureMode : 1; + unsigned char reserved4Bits : 4; + + + unsigned char segmentFeatureEnable[8][4]; + short segmentFeatureData[8][4]; + unsigned char mb_segment_tree_probs[7]; + unsigned char segment_pred_probs[3]; + unsigned char reservedSegment16Bits[2]; + + int qpYAc; + int qpYDc; + int qpChDc; + int qpChAc; + + unsigned int activeRefIdx[3]; + unsigned int resetFrameContext; + unsigned int mcomp_filter_type; + unsigned int mbRefLfDelta[4]; + unsigned int mbModeLfDelta[2]; + unsigned int frameTagSize; + unsigned int offsetToDctParts; + unsigned int reserved128Bits[4]; + +} CUVIDVP9PICPARAMS; + +/***********************************************************/ +//! \struct CUVIDAV1PICPARAMS +//! AV1 picture parameters +//! This structure is used in CUVIDPICPARAMS structure +/***********************************************************/ +typedef struct _CUVIDAV1PICPARAMS +{ + unsigned int width; // coded width, if superres enabled then it is upscaled width + unsigned int height; // coded height + unsigned int frame_offset; // defined as order_hint in AV1 specification + int decodePicIdx; // decoded output pic index, if film grain enabled, it will keep decoded (without film grain) output + // It can be used as reference frame for future frames + + // sequence header + unsigned int profile : 3; // 0 = profile0, 1 = profile1, 2 = profile2 + unsigned int use_128x128_superblock : 1; // superblock size 0:64x64, 1: 128x128 + unsigned int subsampling_x : 1; // (subsampling_x, _y) 1,1 = 420, 1,0 = 422, 0,0 = 444 + unsigned int subsampling_y : 1; + unsigned int mono_chrome : 1; // for monochrome content, mono_chrome = 1 and (subsampling_x, _y) should be 1,1 + unsigned int bit_depth_minus8 : 4; // bit depth minus 8 + unsigned int enable_filter_intra : 1; // tool enable in seq level, 0 : disable 1: frame header control + unsigned int enable_intra_edge_filter : 1; // intra edge filtering process, 0 : disable 1: enabled + unsigned int enable_interintra_compound : 1; // interintra, 0 : not present 1: present + unsigned int enable_masked_compound : 1; // 1: mode info for inter blocks may contain the syntax element compound_type. + // 0: syntax element compound_type will not be present + unsigned int enable_dual_filter : 1; // vertical and horiz filter selection, 1: enable and 0: disable + unsigned int enable_order_hint : 1; // order hint, and related tools, 1: enable and 0: disable + unsigned int order_hint_bits_minus1 : 3; // is used to compute OrderHintBits + unsigned int enable_jnt_comp : 1; // joint compound modes, 1: enable and 0: disable + unsigned int enable_superres : 1; // superres in seq level, 0 : disable 1: frame level control + unsigned int enable_cdef : 1; // cdef filtering in seq level, 0 : disable 1: frame level control + unsigned int enable_restoration : 1; // loop restoration filtering in seq level, 0 : disable 1: frame level control + unsigned int enable_fgs : 1; // defined as film_grain_params_present in AV1 specification + unsigned int reserved0_7bits : 7; // reserved bits; must be set to 0 + + // frame header + unsigned int frame_type : 2 ; // 0:Key frame, 1:Inter frame, 2:intra only, 3:s-frame + unsigned int show_frame : 1 ; // show_frame = 1 implies that frame should be immediately output once decoded + unsigned int disable_cdf_update : 1; // CDF update during symbol decoding, 1: disabled, 0: enabled + unsigned int allow_screen_content_tools : 1; // 1: intra blocks may use palette encoding, 0: palette encoding is never used + unsigned int force_integer_mv : 1; // 1: motion vectors will always be integers, 0: can contain fractional bits + unsigned int coded_denom : 3; // coded_denom of the superres scale as specified in AV1 specification + unsigned int allow_intrabc : 1; // 1: intra block copy may be used, 0: intra block copy is not allowed + unsigned int allow_high_precision_mv : 1; // 1/8 precision mv enable + unsigned int interp_filter : 3; // interpolation filter. Refer to section 6.8.9 of the AV1 specification Version 1.0.0 with Errata 1 + unsigned int switchable_motion_mode : 1; // defined as is_motion_mode_switchable in AV1 specification + unsigned int use_ref_frame_mvs : 1; // 1: current frame can use the previous frame mv information, 0: will not use. + unsigned int disable_frame_end_update_cdf : 1; // 1: indicates that the end of frame CDF update is disabled + unsigned int delta_q_present : 1; // quantizer index delta values are present in the block level + unsigned int delta_q_res : 2; // left shift which should be applied to decoded quantizer index delta values + unsigned int using_qmatrix : 1; // 1: quantizer matrix will be used to compute quantizers + unsigned int coded_lossless : 1; // 1: all segments use lossless coding + unsigned int use_superres : 1; // 1: superres enabled for frame + unsigned int tx_mode : 2; // 0: ONLY4x4,1:LARGEST,2:SELECT + unsigned int reference_mode : 1; // 0: SINGLE, 1: SELECT + unsigned int allow_warped_motion : 1; // 1: allow_warped_motion may be present, 0: allow_warped_motion will not be present + unsigned int reduced_tx_set : 1; // 1: frame is restricted to subset of the full set of transform types, 0: no such restriction + unsigned int skip_mode : 1; // 1: most of the mode info is skipped, 0: mode info is not skipped + unsigned int reserved1_3bits : 3; // reserved bits; must be set to 0 + + // tiling info + unsigned int num_tile_cols : 8; // number of tiles across the frame., max is 64 + unsigned int num_tile_rows : 8; // number of tiles down the frame., max is 64 + unsigned int context_update_tile_id : 16; // specifies which tile to use for the CDF update + unsigned short tile_widths[64]; // Width of each column in superblocks + unsigned short tile_heights[64]; // height of each row in superblocks + + // CDEF - refer to section 6.10.14 of the AV1 specification Version 1.0.0 with Errata 1 + unsigned char cdef_damping_minus_3 : 2; // controls the amount of damping in the deringing filter + unsigned char cdef_bits : 2; // the number of bits needed to specify which CDEF filter to apply + unsigned char reserved2_4bits : 4; // reserved bits; must be set to 0 + unsigned char cdef_y_strength[8]; // 0-3 bits: y_pri_strength, 4-7 bits y_sec_strength + unsigned char cdef_uv_strength[8]; // 0-3 bits: uv_pri_strength, 4-7 bits uv_sec_strength + + // SkipModeFrames + unsigned char SkipModeFrame0 : 4; // specifies the frames to use for compound prediction when skip_mode is equal to 1. + unsigned char SkipModeFrame1 : 4; + + // qp information - refer to section 6.8.11 of the AV1 specification Version 1.0.0 with Errata 1 + unsigned char base_qindex; // indicates the base frame qindex. Defined as base_q_idx in AV1 specification + char qp_y_dc_delta_q; // indicates the Y DC quantizer relative to base_q_idx. Defined as DeltaQYDc in AV1 specification + char qp_u_dc_delta_q; // indicates the U DC quantizer relative to base_q_idx. Defined as DeltaQUDc in AV1 specification + char qp_v_dc_delta_q; // indicates the V DC quantizer relative to base_q_idx. Defined as DeltaQVDc in AV1 specification + char qp_u_ac_delta_q; // indicates the U AC quantizer relative to base_q_idx. Defined as DeltaQUAc in AV1 specification + char qp_v_ac_delta_q; // indicates the V AC quantizer relative to base_q_idx. Defined as DeltaQVAc in AV1 specification + unsigned char qm_y; // specifies the level in the quantizer matrix that should be used for luma plane decoding + unsigned char qm_u; // specifies the level in the quantizer matrix that should be used for chroma U plane decoding + unsigned char qm_v; // specifies the level in the quantizer matrix that should be used for chroma V plane decoding + + // segmentation - refer to section 6.8.13 of the AV1 specification Version 1.0.0 with Errata 1 + unsigned char segmentation_enabled : 1; // 1 indicates that this frame makes use of the segmentation tool + unsigned char segmentation_update_map : 1; // 1 indicates that the segmentation map are updated during the decoding of this frame + unsigned char segmentation_update_data : 1; // 1 indicates that new parameters are about to be specified for each segment + unsigned char segmentation_temporal_update : 1; // 1 indicates that the updates to the segmentation map are coded relative to the existing segmentation map + unsigned char reserved3_4bits : 4; // reserved bits; must be set to 0 + short segmentation_feature_data[8][8]; // specifies the feature data for a segment feature + unsigned char segmentation_feature_mask[8]; // indicates that the corresponding feature is unused or feature value is coded + + // loopfilter - refer to section 6.8.10 of the AV1 specification Version 1.0.0 with Errata 1 + unsigned char loop_filter_level[2]; // contains loop filter strength values + unsigned char loop_filter_level_u; // loop filter strength value of U plane + unsigned char loop_filter_level_v; // loop filter strength value of V plane + unsigned char loop_filter_sharpness; // indicates the sharpness level + char loop_filter_ref_deltas[8]; // contains the adjustment needed for the filter level based on the chosen reference frame + char loop_filter_mode_deltas[2]; // contains the adjustment needed for the filter level based on the chosen mode + unsigned char loop_filter_delta_enabled : 1; // indicates that the filter level depends on the mode and reference frame used to predict a block + unsigned char loop_filter_delta_update : 1; // indicates that additional syntax elements are present that specify which mode and + // reference frame deltas are to be updated + unsigned char delta_lf_present : 1; // specifies whether loop filter delta values are present in the block level + unsigned char delta_lf_res : 2; // specifies the left shift to apply to the decoded loop filter values + unsigned char delta_lf_multi : 1; // separate loop filter deltas for Hy,Vy,U,V edges + unsigned char reserved4_2bits : 2; // reserved bits; must be set to 0 + + // restoration - refer to section 6.10.15 of the AV1 specification Version 1.0.0 with Errata 1 + unsigned char lr_unit_size[3]; // specifies the size of loop restoration units: 0: 32, 1: 64, 2: 128, 3: 256 + unsigned char lr_type[3] ; // used to compute FrameRestorationType + + // reference frames + unsigned char primary_ref_frame; // specifies which reference frame contains the CDF values and other state that should be + // loaded at the start of the frame + unsigned char ref_frame_map[8]; // frames in dpb that can be used as reference for current or future frames + + unsigned char temporal_layer_id : 4; // temporal layer id + unsigned char spatial_layer_id : 4; // spatial layer id + + unsigned char reserved5_32bits[4]; // reserved bits; must be set to 0 + + // ref frame list + struct + { + unsigned int width; + unsigned int height; + unsigned char index; + unsigned char reserved24Bits[3]; // reserved bits; must be set to 0 + } ref_frame[7]; // frames used as reference frame for current frame. + + // global motion + struct { + unsigned char invalid : 1; + unsigned char wmtype : 2; // defined as GmType in AV1 specification + unsigned char reserved5Bits : 5; // reserved bits; must be set to 0 + char reserved24Bits[3]; // reserved bits; must be set to 0 + int wmmat[6]; // defined as gm_params[] in AV1 specification + } global_motion[7]; // global motion params for reference frames + + // film grain params - refer to section 6.8.20 of the AV1 specification Version 1.0.0 with Errata 1 + unsigned short apply_grain : 1; + unsigned short overlap_flag : 1; + unsigned short scaling_shift_minus8 : 2; + unsigned short chroma_scaling_from_luma : 1; + unsigned short ar_coeff_lag : 2; + unsigned short ar_coeff_shift_minus6 : 2; + unsigned short grain_scale_shift : 2; + unsigned short clip_to_restricted_range : 1; + unsigned short reserved6_4bits : 4; // reserved bits; must be set to 0 + unsigned char num_y_points; + unsigned char scaling_points_y[14][2]; + unsigned char num_cb_points; + unsigned char scaling_points_cb[10][2]; + unsigned char num_cr_points; + unsigned char scaling_points_cr[10][2]; + unsigned char reserved7_8bits; // reserved bits; must be set to 0 + unsigned short random_seed; + short ar_coeffs_y[24]; + short ar_coeffs_cb[25]; + short ar_coeffs_cr[25]; + unsigned char cb_mult; + unsigned char cb_luma_mult; + short cb_offset; + unsigned char cr_mult; + unsigned char cr_luma_mult; + short cr_offset; + + int reserved[7]; // reserved bits; must be set to 0 +} CUVIDAV1PICPARAMS; + +/******************************************************************************************/ +//! \struct CUVIDPICPARAMS +//! Picture parameters for decoding +//! This structure is used in cuvidDecodePicture API +//! IN for cuvidDecodePicture +/******************************************************************************************/ +typedef struct _CUVIDPICPARAMS +{ + int PicWidthInMbs; /**< IN: Coded frame size in macroblocks */ + int FrameHeightInMbs; /**< IN: Coded frame height in macroblocks */ + int CurrPicIdx; /**< IN: Output index of the current picture */ + int field_pic_flag; /**< IN: 0=frame picture, 1=field picture */ + int bottom_field_flag; /**< IN: 0=top field, 1=bottom field (ignored if field_pic_flag=0) */ + int second_field; /**< IN: Second field of a complementary field pair */ + // Bitstream data + unsigned int nBitstreamDataLen; /**< IN: Number of bytes in bitstream data buffer */ + const unsigned char *pBitstreamData; /**< IN: Ptr to bitstream data for this picture (slice-layer) */ + unsigned int nNumSlices; /**< IN: Number of slices in this picture */ + const unsigned int *pSliceDataOffsets; /**< IN: nNumSlices entries, contains offset of each slice within + the bitstream data buffer */ + int ref_pic_flag; /**< IN: This picture is a reference picture */ + int intra_pic_flag; /**< IN: This picture is entirely intra coded */ + CUvideotimestamp timestamp; /**< IN: Presentation time stamp */ + unsigned int Reserved[28]; /**< Reserved for future use */ + // IN: Codec-specific data + union { + CUVIDMPEG2PICPARAMS mpeg2; /**< Also used for MPEG-1 */ + CUVIDH264PICPARAMS h264; + CUVIDVC1PICPARAMS vc1; + CUVIDMPEG4PICPARAMS mpeg4; + CUVIDJPEGPICPARAMS jpeg; + CUVIDHEVCPICPARAMS hevc; + CUVIDVP8PICPARAMS vp8; + CUVIDVP9PICPARAMS vp9; + CUVIDAV1PICPARAMS av1; + unsigned int CodecReserved[1024]; + } CodecSpecific; +} CUVIDPICPARAMS; + +/***************************************************************************************/ +//! \struct CUVIDPROCPARAMSEXT +//! Extended processing parameters for video frame post-processing +//! This structure extends CUVIDPROCPARAMS with additional fields +//! and is used in cuvidMapVideoFrame API when certain features are required +/***************************************************************************************/ +typedef struct _CUVIDPROCPARAMSEXT +{ + unsigned int decode_stats_size; /**< OUT: Size of decode stats buffer in bytes. + When stats are present: sizeof(CUVIDDECODESTATSHEADER) + mbCount * sizeof(CUVIDDECODESTATS) + When no valid stats: 0 */ + unsigned int reserved1[31]; /**< Reserved for future use (set to zero) */ + unsigned long long *decode_stats_dptr; /**< IN: Pointer to a CUdeviceptr variable that will receive the GPU memory address + containing decode statistics. The allocated GPU buffer contains: + - CUVIDDECODESTATSHEADER (statistics header) + - Array of CUVIDDECODESTATS structures (one per 16x16 block in raster scan order) + Valid only when decode_stats_size > 0. */ + void *reserved_ptr[15]; /**< Reserved for future use (set to zero) */ +} CUVIDPROCPARAMSEXT; + + +/******************************************************/ +//! \struct CUVIDPROCPARAMS +//! Picture parameters for postprocessing +//! This structure is used in cuvidMapVideoFrame API +/******************************************************/ +typedef struct _CUVIDPROCPARAMS +{ + int progressive_frame; /**< IN: Input is progressive (deinterlace_mode will be ignored) */ + int second_field; /**< IN: Output the second field (ignored if deinterlace mode is Weave) */ + int top_field_first; /**< IN: Input frame is top field first (1st field is top, 2nd field is bottom) */ + int unpaired_field; /**< IN: Input only contains one field (2nd field is invalid) */ + // The fields below are used for raw YUV input + unsigned int reserved_flags; /**< Reserved for future use (set to zero) */ + unsigned int reserved_zero; /**< Reserved (set to zero) */ + unsigned long long raw_input_dptr; /**< IN: Input CUdeviceptr for raw YUV extensions */ + unsigned int raw_input_pitch; /**< IN: pitch in bytes of raw YUV input (should be aligned appropriately) */ + unsigned int raw_input_format; /**< IN: Input YUV format (cudaVideoCodec_enum) */ + unsigned long long raw_output_dptr; /**< IN: Output CUdeviceptr for raw YUV extensions */ + unsigned int raw_output_pitch; /**< IN: pitch in bytes of raw YUV output (should be aligned to 4 bytes) */ + unsigned int Reserved1; /**< Reserved for future use (set to zero) */ + CUstream output_stream; /**< IN: stream object used by cuvidMapVideoFrame */ + unsigned int Reserved[46]; /**< Reserved for future use (set to zero) */ + unsigned long long *histogram_dptr; /**< OUT: Output CUdeviceptr for histogram extensions */ + CUVIDPROCPARAMSEXT *pCuvidProcExt; /**< Extension of CUVIDPROCPARAMS */ +} CUVIDPROCPARAMS; + +/*********************************************************************************************************/ +//! \struct CUVIDGETDECODESTATUS +//! Struct for reporting decode status. +//! This structure is used in cuvidGetDecodeStatus API. +/*********************************************************************************************************/ +typedef struct _CUVIDGETDECODESTATUS +{ + cuvidDecodeStatus decodeStatus; + unsigned int reserved[31]; + void *pReserved[8]; +} CUVIDGETDECODESTATUS; + +/****************************************************/ +//! \struct CUVIDRECONFIGUREDECODERINFO +//! Struct for decoder reset +//! This structure is used in cuvidReconfigureDecoder() API +/****************************************************/ +typedef struct _CUVIDRECONFIGUREDECODERINFO +{ + unsigned int ulWidth; /**< IN: Coded sequence width in pixels, MUST be < = ulMaxWidth defined at CUVIDDECODECREATEINFO */ + unsigned int ulHeight; /**< IN: Coded sequence height in pixels, MUST be < = ulMaxHeight defined at CUVIDDECODECREATEINFO */ + unsigned int ulTargetWidth; /**< IN: Post processed output width */ + unsigned int ulTargetHeight; /**< IN: Post Processed output height */ + unsigned int ulNumDecodeSurfaces; /**< IN: Maximum number of internal decode surfaces */ + unsigned int reserved1[12]; /**< Reserved for future use. Set to Zero */ + /** + * IN: Area of frame to be displayed. Use-case : Source Cropping + */ + struct { + short left; + short top; + short right; + short bottom; + } display_area; + /** + * IN: Target Rectangle in the OutputFrame. Use-case : Aspect ratio Conversion + */ + struct { + short left; + short top; + short right; + short bottom; + } target_rect; + unsigned int reserved2[11]; /**< Reserved for future use. Set to Zero */ +} CUVIDRECONFIGUREDECODERINFO; + + +/***********************************************************************************************************/ +//! VIDEO_DECODER +//! +//! In order to minimize decode latencies, there should be always at least 2 pictures in the decode +//! queue at any time, in order to make sure that all decode engines are always busy. +//! +//! Overall data flow for output path with pitch-linear layout: +//! - cuvidGetDecoderCaps(...) +//! - cuvidCreateDecoder(...) +//! - For each picture: +//! + cuvidDecodePicture(N) +//! + cuvidMapVideoFrame(N-4) +//! + do some processing in cuda +//! + cuvidUnmapVideoFrame(N-4) +//! + cuvidDecodePicture(N+1) +//! + cuvidMapVideoFrame(N-3) +//! + ... +//! - cuvidDestroyDecoder(...) +//! +//! Overall data flow for output path with opaque layout: +//! - cuvidGetDecoderCaps(...) +//! - cuvidCreateDecoder(...) +//! - cuvidRegisterDecodeSurfaces(...) +//! - For each picture: +//! + cuvidDecodePictureAsync(N, cudaStream) +//! + do some cuda processing in cudaStream +//! + cuvidDecodePictureAsync(N+1, cudaStream) +//! + ... +//! - cuvidDestroyDecoder(...) +//! +//! NOTE: +//! - When the cuda context is created from a D3D device, the D3D device must also be created +//! with the D3DCREATE_MULTITHREADED flag. +//! - There is a limit to how many pictures can be mapped simultaneously (ulNumOutputSurfaces) +//! - cuvidDecodePicture/cuvidDecodePictureAsync may block the calling thread if there are +//! too many pictures pending in the decode queue. +/***********************************************************************************************************/ + + +/**********************************************************************************************************************/ +//! \fn CUresult CUDAAPI cuvidGetDecoderCaps(CUVIDDECODECAPS *pdc) +//! Queries decode capabilities of NVDEC-HW based on CodecType, ChromaFormat and BitDepthMinus8 parameters. +//! 1. Application fills IN parameters CodecType, ChromaFormat and BitDepthMinus8 of CUVIDDECODECAPS structure +//! 2. On calling cuvidGetDecoderCaps, driver fills OUT parameters if the IN parameters are supported +//! If IN parameters passed to the driver are not supported by NVDEC-HW, then all OUT params are set to 0. +//! E.g. on Geforce GTX 960: +//! App fills - eCodecType = cudaVideoCodec_H264; eChromaFormat = cudaVideoChromaFormat_420; nBitDepthMinus8 = 0; +//! Given IN parameters are supported, hence driver fills: bIsSupported = 1; nMinWidth = 48; nMinHeight = 16; +//! nMaxWidth = 4096; nMaxHeight = 4096; nMaxMBCount = 65536; +//! CodedWidth*CodedHeight/256 must be less than or equal to nMaxMBCount +/**********************************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidGetDecoderCaps(CUVIDDECODECAPS *pdc); + +/*****************************************************************************************************/ +//! \fn CUresult CUDAAPI cuvidCreateDecoder(CUvideodecoder *phDecoder, CUVIDDECODECREATEINFO *pdci) +//! Create the decoder object based on pdci. A handle to the created decoder is returned +/*****************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidCreateDecoder(CUvideodecoder *phDecoder, CUVIDDECODECREATEINFO *pdci); + +/*****************************************************************************************************/ +//! \fn CUresult CUDAAPI cuvidDestroyDecoder(CUvideodecoder hDecoder) +//! Destroy the decoder object +/*****************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidDestroyDecoder(CUvideodecoder hDecoder); + +/*****************************************************************************************************************************/ +//! \fn CUresult CUDAAPI cuvidRegisterDecodeSurfaces(CUvideodecoder hDecoder, CUVIDREGISTERDECODESURFACESINFO *pDecSurfInfo) +//! Registers decode output surfaces for the decoder object based on pDecSurfInfo +/*****************************************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidRegisterDecodeSurfaces(CUvideodecoder hDecoder, CUVIDREGISTERDECODESURFACESINFO *pDecSurfInfo); + +/**********************************************************************************************************************/ +//! \fn CUresult CUDAAPI cuvidDecodePictureAsync(CUvideodecoder hDecoder, CUVIDPICPARAMS *pPicParams, CUstream strm) +//! Decode a single picture (field or frame) such that the decode operation is synchronized +//! in the given CUstream object. +//! Kicks off HW decoding +/**********************************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidDecodePictureAsync(CUvideodecoder hDecoder, CUVIDPICPARAMS *pPicParams, CUstream strm); + +/*****************************************************************************************************/ +//! \fn CUresult CUDAAPI cuvidDecodePicture(CUvideodecoder hDecoder, CUVIDPICPARAMS *pPicParams) +//! Decode a single picture (field or frame) +//! Kicks off HW decoding +/*****************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidDecodePicture(CUvideodecoder hDecoder, CUVIDPICPARAMS *pPicParams); + +/************************************************************************************************************/ +//! \fn CUresult CUDAAPI cuvidGetDecodeStatus(CUvideodecoder hDecoder, int nPicIdx); +//! Get the decode status for frame corresponding to nPicIdx +//! API is supported for Turing and above generation GPUs. +//! API is currently supported for HEVC, H264 and JPEG codecs. +//! API returns CUDA_ERROR_NOT_SUPPORTED error code for unsupported GPU or codec. +/************************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidGetDecodeStatus(CUvideodecoder hDecoder, int nPicIdx, CUVIDGETDECODESTATUS* pDecodeStatus); + +/*********************************************************************************************************/ +//! \fn CUresult CUDAAPI cuvidReconfigureDecoder(CUvideodecoder hDecoder, CUVIDRECONFIGUREDECODERINFO *pDecReconfigParams) +//! Used to reuse single decoder for multiple clips. Currently supports resolution change, resize params, display area +//! params, target area params change for same codec. Must be called during CUVIDPARSERPARAMS::pfnSequenceCallback +/*********************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidReconfigureDecoder(CUvideodecoder hDecoder, CUVIDRECONFIGUREDECODERINFO *pDecReconfigParams); + + +#if !defined(__CUVID_DEVPTR64) || defined(__CUVID_INTERNAL) +/************************************************************************************************************************/ +//! \fn CUresult CUDAAPI cuvidMapVideoFrame(CUvideodecoder hDecoder, int nPicIdx, unsigned int *pDevPtr, +//! unsigned int *pPitch, CUVIDPROCPARAMS *pVPP); +//! Post-process and map video frame corresponding to nPicIdx for use in cuda. Returns cuda device pointer and associated +//! pitch of the video frame +/************************************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidMapVideoFrame(CUvideodecoder hDecoder, int nPicIdx, + unsigned int *pDevPtr, unsigned int *pPitch, + CUVIDPROCPARAMS *pVPP); + +/*****************************************************************************************************/ +//! \fn CUresult CUDAAPI cuvidUnmapVideoFrame(CUvideodecoder hDecoder, unsigned int DevPtr) +//! Unmap a previously mapped video frame +/*****************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidUnmapVideoFrame(CUvideodecoder hDecoder, unsigned int DevPtr); +#endif + +/****************************************************************************************************************************/ +//! \fn CUresult CUDAAPI cuvidMapVideoFrame64(CUvideodecoder hDecoder, int nPicIdx, unsigned long long *pDevPtr, +//! unsigned int * pPitch, CUVIDPROCPARAMS *pVPP); +//! Post-process and map video frame corresponding to nPicIdx for use in cuda. Returns cuda device pointer and associated +//! pitch of the video frame +/****************************************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidMapVideoFrame64(CUvideodecoder hDecoder, int nPicIdx, unsigned long long *pDevPtr, + unsigned int *pPitch, CUVIDPROCPARAMS *pVPP); + +/**************************************************************************************************/ +//! \fn CUresult CUDAAPI cuvidUnmapVideoFrame64(CUvideodecoder hDecoder, unsigned long long DevPtr); +//! Unmap a previously mapped video frame +/**************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidUnmapVideoFrame64(CUvideodecoder hDecoder, unsigned long long DevPtr); + +#if defined(__CUVID_DEVPTR64) && !defined(__CUVID_INTERNAL) +#define tcuvidMapVideoFrame tcuvidMapVideoFrame64 +#define tcuvidUnmapVideoFrame tcuvidUnmapVideoFrame64 +#endif + + + +/********************************************************************************************************************/ +//! +//! Context-locking: to facilitate multi-threaded implementations, the following 4 functions +//! provide a simple mutex-style host synchronization. If a non-NULL context is specified +//! in CUVIDDECODECREATEINFO, the codec library will acquire the mutex associated with the given +//! context before making any cuda calls. +//! A multi-threaded application could create a lock associated with a context handle so that +//! multiple threads can safely share the same cuda context: +//! - use cuCtxPopCurrent immediately after context creation in order to create a 'floating' context +//! that can be passed to cuvidCtxLockCreate. +//! - When using a floating context, all cuda calls should only be made within a cuvidCtxLock/cuvidCtxUnlock section. +//! +//! NOTE: This is a safer alternative to cuCtxPushCurrent and cuCtxPopCurrent, and is not related to video +//! decoder in any way (implemented as a critical section associated with cuCtx{Push|Pop}Current calls). +/********************************************************************************************************************/ + +/********************************************************************************************************************/ +//! \fn CUresult CUDAAPI cuvidCtxLockCreate(CUvideoctxlock *pLock, CUcontext ctx) +//! This API is used to create CtxLock object +/********************************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidCtxLockCreate(CUvideoctxlock *pLock, CUcontext ctx); + +/********************************************************************************************************************/ +//! \fn CUresult CUDAAPI cuvidCtxLockDestroy(CUvideoctxlock lck) +//! This API is used to free CtxLock object +/********************************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidCtxLockDestroy(CUvideoctxlock lck); + +/********************************************************************************************************************/ +//! \fn CUresult CUDAAPI cuvidCtxLock(CUvideoctxlock lck, unsigned int reserved_flags) +//! This API is used to acquire ctxlock +/********************************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidCtxLock(CUvideoctxlock lck, unsigned int reserved_flags); + +/********************************************************************************************************************/ +//! \fn CUresult CUDAAPI cuvidCtxUnlock(CUvideoctxlock lck, unsigned int reserved_flags) +//! This API is used to release ctxlock +/********************************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidCtxUnlock(CUvideoctxlock lck, unsigned int reserved_flags); + +/**********************************************************************************************/ + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif // __CUDA_VIDEO_H__ diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/ffnvcodec/dynlink_loader.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/ffnvcodec/dynlink_loader.h new file mode 100644 index 000000000..1be0dbf59 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/ffnvcodec/dynlink_loader.h @@ -0,0 +1,514 @@ +/* + * This copyright notice applies to this header file only: + * + * Copyright (c) 2016 + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the software, and to permit persons to whom the + * software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef FFNV_CUDA_DYNLINK_LOADER_H +#define FFNV_CUDA_DYNLINK_LOADER_H + +#include + +#include "dynlink_cuda.h" +#include "dynlink_nvcuvid.h" +#include "nvEncodeAPI.h" + +#if defined(_WIN32) && (!defined(FFNV_LOAD_FUNC) || !defined(FFNV_SYM_FUNC) || !defined(FFNV_LIB_HANDLE)) +# include +#endif + +#ifndef FFNV_LIB_HANDLE +# if defined(_WIN32) +# define FFNV_LIB_HANDLE HMODULE +# else +# define FFNV_LIB_HANDLE void* +# endif +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) +# define CUDA_LIBNAME "nvcuda.dll" +# define NVCUVID_LIBNAME "nvcuvid.dll" +# if defined(_WIN64) || defined(__CYGWIN64__) +# if defined(_M_ARM64) || defined(__aarch64__) +# define NVENC_LIBNAME "nvEncodeAPI.dll" +# else +# define NVENC_LIBNAME "nvEncodeAPI64.dll" +# endif +# else +# define NVENC_LIBNAME "nvEncodeAPI.dll" +# endif +#else +# define CUDA_LIBNAME "libcuda.so.1" +# define NVCUVID_LIBNAME "libnvcuvid.so.1" +# define NVENC_LIBNAME "libnvidia-encode.so.1" +#endif + +#if !defined(FFNV_LOAD_FUNC) || !defined(FFNV_SYM_FUNC) +# ifdef _WIN32 +# define FFNV_LOAD_FUNC(path) LoadLibrary(TEXT(path)) +# define FFNV_SYM_FUNC(lib, sym) GetProcAddress((lib), (sym)) +# define FFNV_FREE_FUNC(lib) FreeLibrary(lib) +# else +# include +# define FFNV_LOAD_FUNC(path) dlopen((path), RTLD_LAZY) +# define FFNV_SYM_FUNC(lib, sym) dlsym((lib), (sym)) +# define FFNV_FREE_FUNC(lib) dlclose(lib) +# endif +#endif + +#if !defined(FFNV_LOG_FUNC) || !defined(FFNV_DEBUG_LOG_FUNC) +# include +# define FFNV_LOG_FUNC(logctx, msg, ...) fprintf(stderr, (msg), __VA_ARGS__) +# define FFNV_DEBUG_LOG_FUNC(logctx, msg, ...) +#endif + +#define LOAD_LIBRARY(l, path) \ + do { \ + if (!((l) = FFNV_LOAD_FUNC(path))) { \ + FFNV_LOG_FUNC(logctx, "Cannot load %s\n", path); \ + ret = -1; \ + goto error; \ + } \ + FFNV_DEBUG_LOG_FUNC(logctx, "Loaded lib: %s\n", path); \ + } while (0) + +#define LOAD_SYMBOL(fun, tp, symbol) \ + do { \ + if (!((f->fun) = (tp*)FFNV_SYM_FUNC(f->lib, symbol))) { \ + FFNV_LOG_FUNC(logctx, "Cannot load %s\n", symbol); \ + ret = -1; \ + goto error; \ + } \ + FFNV_DEBUG_LOG_FUNC(logctx, "Loaded sym: %s\n", symbol); \ + } while (0) + +#define LOAD_SYMBOL_OPT(fun, tp, symbol) \ + do { \ + if (!((f->fun) = (tp*)FFNV_SYM_FUNC(f->lib, symbol))) { \ + FFNV_DEBUG_LOG_FUNC(logctx, "Cannot load optional %s\n", symbol); \ + } else { \ + FFNV_DEBUG_LOG_FUNC(logctx, "Loaded sym: %s\n", symbol); \ + } \ + } while (0) + +#define GENERIC_LOAD_FUNC_PREAMBLE(T, n, N) \ + T *f; \ + int ret; \ + \ + n##_free_functions(functions); \ + \ + f = *functions = (T*)calloc(1, sizeof(*f)); \ + if (!f) \ + return -1; \ + \ + LOAD_LIBRARY(f->lib, N); + +#define GENERIC_LOAD_FUNC_FINALE(n) \ + return 0; \ +error: \ + n##_free_functions(functions); \ + return ret; + +#define GENERIC_FREE_FUNC() \ + if (!functions) \ + return; \ + if (*functions && (*functions)->lib) \ + FFNV_FREE_FUNC((*functions)->lib); \ + free(*functions); \ + *functions = NULL; + +#ifdef FFNV_DYNLINK_CUDA_H +typedef struct CudaFunctions { + tcuInit *cuInit; + tcuDriverGetVersion *cuDriverGetVersion; + tcuDeviceGetCount *cuDeviceGetCount; + tcuDeviceGet *cuDeviceGet; + tcuDeviceGetAttribute *cuDeviceGetAttribute; + tcuDeviceGetName *cuDeviceGetName; + tcuDeviceGetUuid *cuDeviceGetUuid; + tcuDeviceGetUuid_v2 *cuDeviceGetUuid_v2; + tcuDeviceGetLuid *cuDeviceGetLuid; + tcuDeviceGetByPCIBusId *cuDeviceGetByPCIBusId; + tcuDeviceGetPCIBusId *cuDeviceGetPCIBusId; + tcuDeviceComputeCapability *cuDeviceComputeCapability; + tcuCtxCreate_v2 *cuCtxCreate; + tcuCtxSynchronize *cuCtxSynchronize; + tcuCtxGetStreamPriorityRange *cuCtxGetStreamPriorityRange; + tcuCtxGetCurrent *cuCtxGetCurrent; + tcuCtxSetLimit *cuCtxSetLimit; + tcuCtxPushCurrent_v2 *cuCtxPushCurrent; + tcuCtxPopCurrent_v2 *cuCtxPopCurrent; + tcuCtxDestroy_v2 *cuCtxDestroy; + tcuMemAlloc_v2 *cuMemAlloc; + tcuMemAllocPitch_v2 *cuMemAllocPitch; + tcuMemAllocManaged *cuMemAllocManaged; + tcuMemsetD8Async *cuMemsetD8Async; + tcuMemsetD16Async *cuMemsetD16Async; + tcuMemsetD32Async *cuMemsetD32Async; + tcuMemsetD2D8Async *cuMemsetD2D8Async; + tcuMemsetD2D16Async *cuMemsetD2D16Async; + tcuMemsetD2D32Async *cuMemsetD2D32Async; + tcuMemFree_v2 *cuMemFree; + tcuMemHostAlloc *cuMemHostAlloc; + tcuMemFreeHost *cuMemFreeHost; + tcuMemAllocAsync *cuMemAllocAsync; + tcuMemFreeAsync *cuMemFreeAsync; + tcuMemcpy *cuMemcpy; + tcuMemcpyAsync *cuMemcpyAsync; + tcuMemcpy2D_v2 *cuMemcpy2D; + tcuMemcpy2DAsync_v2 *cuMemcpy2DAsync; + tcuMemcpyHtoD_v2 *cuMemcpyHtoD; + tcuMemcpyHtoDAsync_v2 *cuMemcpyHtoDAsync; + tcuMemcpyDtoH_v2 *cuMemcpyDtoH; + tcuMemcpyDtoHAsync_v2 *cuMemcpyDtoHAsync; + tcuMemcpyDtoD_v2 *cuMemcpyDtoD; + tcuMemcpyDtoDAsync_v2 *cuMemcpyDtoDAsync; + tcuGetErrorName *cuGetErrorName; + tcuGetErrorString *cuGetErrorString; + tcuCtxGetDevice *cuCtxGetDevice; + + tcuDevicePrimaryCtxRetain *cuDevicePrimaryCtxRetain; + tcuDevicePrimaryCtxRelease *cuDevicePrimaryCtxRelease; + tcuDevicePrimaryCtxSetFlags *cuDevicePrimaryCtxSetFlags; + tcuDevicePrimaryCtxGetState *cuDevicePrimaryCtxGetState; + tcuDevicePrimaryCtxReset *cuDevicePrimaryCtxReset; + + tcuStreamCreate *cuStreamCreate; + tcuStreamCreateWithPriority *cuStreamCreateWithPriority; + tcuStreamQuery *cuStreamQuery; + tcuStreamSynchronize *cuStreamSynchronize; + tcuStreamDestroy_v2 *cuStreamDestroy; + tcuStreamAddCallback *cuStreamAddCallback; + tcuStreamWaitEvent *cuStreamWaitEvent; + tcuEventCreate *cuEventCreate; + tcuEventDestroy_v2 *cuEventDestroy; + tcuEventSynchronize *cuEventSynchronize; + tcuEventQuery *cuEventQuery; + tcuEventRecord *cuEventRecord; + + tcuLaunchKernel *cuLaunchKernel; + tcuLaunchHostFunc *cuLaunchHostFunc; + tcuLinkCreate *cuLinkCreate; + tcuLinkAddData *cuLinkAddData; + tcuLinkComplete *cuLinkComplete; + tcuLinkDestroy *cuLinkDestroy; + tcuModuleLoadData *cuModuleLoadData; + tcuModuleUnload *cuModuleUnload; + tcuModuleGetFunction *cuModuleGetFunction; + tcuModuleGetGlobal *cuModuleGetGlobal; + tcuTexObjectCreate *cuTexObjectCreate; + tcuTexObjectDestroy *cuTexObjectDestroy; + + tcuGLGetDevices_v2 *cuGLGetDevices; + tcuGraphicsGLRegisterImage *cuGraphicsGLRegisterImage; + tcuGraphicsUnregisterResource *cuGraphicsUnregisterResource; + tcuGraphicsMapResources *cuGraphicsMapResources; + tcuGraphicsUnmapResources *cuGraphicsUnmapResources; + tcuGraphicsSubResourceGetMappedArray *cuGraphicsSubResourceGetMappedArray; + tcuGraphicsResourceGetMappedPointer *cuGraphicsResourceGetMappedPointer; + + tcuImportExternalMemory *cuImportExternalMemory; + tcuDestroyExternalMemory *cuDestroyExternalMemory; + tcuExternalMemoryGetMappedBuffer *cuExternalMemoryGetMappedBuffer; + tcuExternalMemoryGetMappedMipmappedArray *cuExternalMemoryGetMappedMipmappedArray; + tcuMipmappedArrayDestroy *cuMipmappedArrayDestroy; + + tcuMipmappedArrayGetLevel *cuMipmappedArrayGetLevel; + + tcuImportExternalSemaphore *cuImportExternalSemaphore; + tcuDestroyExternalSemaphore *cuDestroyExternalSemaphore; + tcuSignalExternalSemaphoresAsync *cuSignalExternalSemaphoresAsync; + tcuWaitExternalSemaphoresAsync *cuWaitExternalSemaphoresAsync; + + tcuArrayCreate *cuArrayCreate; + tcuArray3DCreate *cuArray3DCreate; + tcuArrayDestroy *cuArrayDestroy; + tcuArray3DGetDescriptor *cuArray3DGetDescriptor; + tcuArrayGetPlane *cuArrayGetPlane; + + tcuEGLStreamProducerConnect *cuEGLStreamProducerConnect; + tcuEGLStreamProducerDisconnect *cuEGLStreamProducerDisconnect; + tcuEGLStreamConsumerDisconnect *cuEGLStreamConsumerDisconnect; + tcuEGLStreamProducerPresentFrame *cuEGLStreamProducerPresentFrame; + tcuEGLStreamProducerReturnFrame *cuEGLStreamProducerReturnFrame; + +#if defined(_WIN32) || defined(__CYGWIN__) + tcuD3D11GetDevice *cuD3D11GetDevice; + tcuD3D11GetDevices *cuD3D11GetDevices; + tcuGraphicsD3D11RegisterResource *cuGraphicsD3D11RegisterResource; +#endif + + FFNV_LIB_HANDLE lib; +} CudaFunctions; +#else +typedef struct CudaFunctions CudaFunctions; +#endif + +typedef struct CuvidFunctions { + tcuvidGetDecoderCaps *cuvidGetDecoderCaps; + tcuvidCreateDecoder *cuvidCreateDecoder; + tcuvidDestroyDecoder *cuvidDestroyDecoder; + tcuvidRegisterDecodeSurfaces *cuvidRegisterDecodeSurfaces; + tcuvidDecodePictureAsync *cuvidDecodePictureAsync; + tcuvidDecodePicture *cuvidDecodePicture; + tcuvidGetDecodeStatus *cuvidGetDecodeStatus; + tcuvidReconfigureDecoder *cuvidReconfigureDecoder; + tcuvidMapVideoFrame *cuvidMapVideoFrame; + tcuvidUnmapVideoFrame *cuvidUnmapVideoFrame; + tcuvidCtxLockCreate *cuvidCtxLockCreate; + tcuvidCtxLockDestroy *cuvidCtxLockDestroy; + tcuvidCtxLock *cuvidCtxLock; + tcuvidCtxUnlock *cuvidCtxUnlock; + +#if !defined(__APPLE__) + tcuvidCreateVideoSource *cuvidCreateVideoSource; + tcuvidCreateVideoSourceW *cuvidCreateVideoSourceW; + tcuvidDestroyVideoSource *cuvidDestroyVideoSource; + tcuvidSetVideoSourceState *cuvidSetVideoSourceState; + tcuvidGetVideoSourceState *cuvidGetVideoSourceState; + tcuvidGetSourceVideoFormat *cuvidGetSourceVideoFormat; + tcuvidGetSourceAudioFormat *cuvidGetSourceAudioFormat; +#endif + tcuvidCreateVideoParser *cuvidCreateVideoParser; + tcuvidParseVideoData *cuvidParseVideoData; + tcuvidDestroyVideoParser *cuvidDestroyVideoParser; + + FFNV_LIB_HANDLE lib; +} CuvidFunctions; + +typedef NVENCSTATUS NVENCAPI tNvEncodeAPICreateInstance(NV_ENCODE_API_FUNCTION_LIST *functionList); +typedef NVENCSTATUS NVENCAPI tNvEncodeAPIGetMaxSupportedVersion(uint32_t* version); + +typedef struct NvencFunctions { + tNvEncodeAPICreateInstance *NvEncodeAPICreateInstance; + tNvEncodeAPIGetMaxSupportedVersion *NvEncodeAPIGetMaxSupportedVersion; + + FFNV_LIB_HANDLE lib; +} NvencFunctions; + +#ifdef FFNV_DYNLINK_CUDA_H +static inline void cuda_free_functions(CudaFunctions **functions) +{ + GENERIC_FREE_FUNC(); +} +#endif + +static inline void cuvid_free_functions(CuvidFunctions **functions) +{ + GENERIC_FREE_FUNC(); +} + +static inline void nvenc_free_functions(NvencFunctions **functions) +{ + GENERIC_FREE_FUNC(); +} + +#ifdef FFNV_DYNLINK_CUDA_H +static inline int cuda_load_functions(CudaFunctions **functions, void *logctx) +{ + GENERIC_LOAD_FUNC_PREAMBLE(CudaFunctions, cuda, CUDA_LIBNAME); + + LOAD_SYMBOL(cuInit, tcuInit, "cuInit"); + LOAD_SYMBOL(cuDriverGetVersion, tcuDriverGetVersion, "cuDriverGetVersion"); + LOAD_SYMBOL(cuDeviceGetCount, tcuDeviceGetCount, "cuDeviceGetCount"); + LOAD_SYMBOL(cuDeviceGet, tcuDeviceGet, "cuDeviceGet"); + LOAD_SYMBOL(cuDeviceGetAttribute, tcuDeviceGetAttribute, "cuDeviceGetAttribute"); + LOAD_SYMBOL(cuDeviceGetName, tcuDeviceGetName, "cuDeviceGetName"); + LOAD_SYMBOL(cuDeviceComputeCapability, tcuDeviceComputeCapability, "cuDeviceComputeCapability"); + LOAD_SYMBOL(cuCtxCreate, tcuCtxCreate_v2, "cuCtxCreate_v2"); + LOAD_SYMBOL(cuCtxSynchronize, tcuCtxSynchronize, "cuCtxSynchronize"); + LOAD_SYMBOL(cuCtxGetStreamPriorityRange, tcuCtxGetStreamPriorityRange, "cuCtxGetStreamPriorityRange"); + LOAD_SYMBOL(cuCtxGetCurrent, tcuCtxGetCurrent, "cuCtxGetCurrent"); + LOAD_SYMBOL(cuCtxSetLimit, tcuCtxSetLimit, "cuCtxSetLimit"); + LOAD_SYMBOL(cuCtxPushCurrent, tcuCtxPushCurrent_v2, "cuCtxPushCurrent_v2"); + LOAD_SYMBOL(cuCtxPopCurrent, tcuCtxPopCurrent_v2, "cuCtxPopCurrent_v2"); + LOAD_SYMBOL(cuCtxDestroy, tcuCtxDestroy_v2, "cuCtxDestroy_v2"); + LOAD_SYMBOL(cuMemAlloc, tcuMemAlloc_v2, "cuMemAlloc_v2"); + LOAD_SYMBOL(cuMemAllocPitch, tcuMemAllocPitch_v2, "cuMemAllocPitch_v2"); + LOAD_SYMBOL(cuMemAllocManaged, tcuMemAllocManaged, "cuMemAllocManaged"); + LOAD_SYMBOL(cuMemsetD8Async, tcuMemsetD8Async, "cuMemsetD8Async"); + LOAD_SYMBOL(cuMemsetD16Async, tcuMemsetD16Async, "cuMemsetD16Async"); + LOAD_SYMBOL(cuMemsetD32Async, tcuMemsetD32Async, "cuMemsetD32Async"); + LOAD_SYMBOL(cuMemsetD2D8Async, tcuMemsetD2D8Async, "cuMemsetD2D8Async"); + LOAD_SYMBOL(cuMemsetD2D16Async, tcuMemsetD2D16Async, "cuMemsetD2D16Async"); + LOAD_SYMBOL(cuMemsetD2D32Async, tcuMemsetD2D32Async, "cuMemsetD2D32Async"); + LOAD_SYMBOL(cuMemFree, tcuMemFree_v2, "cuMemFree_v2"); + LOAD_SYMBOL(cuMemHostAlloc, tcuMemHostAlloc, "cuMemHostAlloc"); + LOAD_SYMBOL(cuMemFreeHost, tcuMemFreeHost, "cuMemFreeHost"); + LOAD_SYMBOL(cuMemAllocAsync, tcuMemAllocAsync, "cuMemAllocAsync"); + LOAD_SYMBOL(cuMemFreeAsync, tcuMemFreeAsync, "cuMemFreeAsync"); + LOAD_SYMBOL(cuMemcpy, tcuMemcpy, "cuMemcpy"); + LOAD_SYMBOL(cuMemcpyAsync, tcuMemcpyAsync, "cuMemcpyAsync"); + LOAD_SYMBOL(cuMemcpy2D, tcuMemcpy2D_v2, "cuMemcpy2D_v2"); + LOAD_SYMBOL(cuMemcpy2DAsync, tcuMemcpy2DAsync_v2, "cuMemcpy2DAsync_v2"); + LOAD_SYMBOL(cuMemcpyHtoD, tcuMemcpyHtoD_v2, "cuMemcpyHtoD_v2"); + LOAD_SYMBOL(cuMemcpyHtoDAsync, tcuMemcpyHtoDAsync_v2, "cuMemcpyHtoDAsync_v2"); + LOAD_SYMBOL(cuMemcpyDtoH, tcuMemcpyDtoH_v2, "cuMemcpyDtoH_v2"); + LOAD_SYMBOL(cuMemcpyDtoHAsync, tcuMemcpyDtoHAsync_v2, "cuMemcpyDtoHAsync_v2"); + LOAD_SYMBOL(cuMemcpyDtoD, tcuMemcpyDtoD_v2, "cuMemcpyDtoD_v2"); + LOAD_SYMBOL(cuMemcpyDtoDAsync, tcuMemcpyDtoDAsync_v2, "cuMemcpyDtoDAsync_v2"); + LOAD_SYMBOL(cuGetErrorName, tcuGetErrorName, "cuGetErrorName"); + LOAD_SYMBOL(cuGetErrorString, tcuGetErrorString, "cuGetErrorString"); + LOAD_SYMBOL(cuCtxGetDevice, tcuCtxGetDevice, "cuCtxGetDevice"); + + LOAD_SYMBOL(cuDevicePrimaryCtxRetain, tcuDevicePrimaryCtxRetain, "cuDevicePrimaryCtxRetain"); + LOAD_SYMBOL(cuDevicePrimaryCtxRelease, tcuDevicePrimaryCtxRelease, "cuDevicePrimaryCtxRelease"); + LOAD_SYMBOL(cuDevicePrimaryCtxSetFlags, tcuDevicePrimaryCtxSetFlags, "cuDevicePrimaryCtxSetFlags"); + LOAD_SYMBOL(cuDevicePrimaryCtxGetState, tcuDevicePrimaryCtxGetState, "cuDevicePrimaryCtxGetState"); + LOAD_SYMBOL(cuDevicePrimaryCtxReset, tcuDevicePrimaryCtxReset, "cuDevicePrimaryCtxReset"); + + LOAD_SYMBOL(cuStreamCreate, tcuStreamCreate, "cuStreamCreate"); + LOAD_SYMBOL(cuStreamCreateWithPriority, tcuStreamCreateWithPriority, "cuStreamCreateWithPriority"); + LOAD_SYMBOL(cuStreamQuery, tcuStreamQuery, "cuStreamQuery"); + LOAD_SYMBOL(cuStreamSynchronize, tcuStreamSynchronize, "cuStreamSynchronize"); + LOAD_SYMBOL(cuStreamDestroy, tcuStreamDestroy_v2, "cuStreamDestroy_v2"); + LOAD_SYMBOL(cuStreamAddCallback, tcuStreamAddCallback, "cuStreamAddCallback"); + LOAD_SYMBOL(cuStreamWaitEvent, tcuStreamWaitEvent, "cuStreamWaitEvent"); + LOAD_SYMBOL(cuEventCreate, tcuEventCreate, "cuEventCreate"); + LOAD_SYMBOL(cuEventDestroy, tcuEventDestroy_v2, "cuEventDestroy_v2"); + LOAD_SYMBOL(cuEventSynchronize, tcuEventSynchronize, "cuEventSynchronize"); + LOAD_SYMBOL(cuEventQuery, tcuEventQuery, "cuEventQuery"); + LOAD_SYMBOL(cuEventRecord, tcuEventRecord, "cuEventRecord"); + + LOAD_SYMBOL(cuLaunchKernel, tcuLaunchKernel, "cuLaunchKernel"); + LOAD_SYMBOL(cuLaunchHostFunc, tcuLaunchHostFunc, "cuLaunchHostFunc"); + LOAD_SYMBOL(cuLinkCreate, tcuLinkCreate, "cuLinkCreate"); + LOAD_SYMBOL(cuLinkAddData, tcuLinkAddData, "cuLinkAddData"); + LOAD_SYMBOL(cuLinkComplete, tcuLinkComplete, "cuLinkComplete"); + LOAD_SYMBOL(cuLinkDestroy, tcuLinkDestroy, "cuLinkDestroy"); + LOAD_SYMBOL(cuModuleLoadData, tcuModuleLoadData, "cuModuleLoadData"); + LOAD_SYMBOL(cuModuleUnload, tcuModuleUnload, "cuModuleUnload"); + LOAD_SYMBOL(cuModuleGetFunction, tcuModuleGetFunction, "cuModuleGetFunction"); + LOAD_SYMBOL(cuModuleGetGlobal, tcuModuleGetGlobal, "cuModuleGetGlobal"); + LOAD_SYMBOL(cuTexObjectCreate, tcuTexObjectCreate, "cuTexObjectCreate"); + LOAD_SYMBOL(cuTexObjectDestroy, tcuTexObjectDestroy, "cuTexObjectDestroy"); + + LOAD_SYMBOL(cuGLGetDevices, tcuGLGetDevices_v2, "cuGLGetDevices_v2"); + LOAD_SYMBOL(cuGraphicsGLRegisterImage, tcuGraphicsGLRegisterImage, "cuGraphicsGLRegisterImage"); + LOAD_SYMBOL(cuGraphicsUnregisterResource, tcuGraphicsUnregisterResource, "cuGraphicsUnregisterResource"); + LOAD_SYMBOL(cuGraphicsMapResources, tcuGraphicsMapResources, "cuGraphicsMapResources"); + LOAD_SYMBOL(cuGraphicsUnmapResources, tcuGraphicsUnmapResources, "cuGraphicsUnmapResources"); + LOAD_SYMBOL(cuGraphicsSubResourceGetMappedArray, tcuGraphicsSubResourceGetMappedArray, "cuGraphicsSubResourceGetMappedArray"); + LOAD_SYMBOL(cuGraphicsResourceGetMappedPointer, tcuGraphicsResourceGetMappedPointer, "cuGraphicsResourceGetMappedPointer_v2"); + + LOAD_SYMBOL_OPT(cuDeviceGetUuid, tcuDeviceGetUuid, "cuDeviceGetUuid"); + LOAD_SYMBOL_OPT(cuDeviceGetUuid_v2, tcuDeviceGetUuid_v2, "cuDeviceGetUuid_v2"); + LOAD_SYMBOL_OPT(cuDeviceGetLuid, tcuDeviceGetLuid, "cuDeviceGetLuid"); + LOAD_SYMBOL_OPT(cuDeviceGetByPCIBusId, tcuDeviceGetByPCIBusId, "cuDeviceGetByPCIBusId"); + LOAD_SYMBOL_OPT(cuDeviceGetPCIBusId, tcuDeviceGetPCIBusId, "cuDeviceGetPCIBusId"); + LOAD_SYMBOL_OPT(cuImportExternalMemory, tcuImportExternalMemory, "cuImportExternalMemory"); + LOAD_SYMBOL_OPT(cuDestroyExternalMemory, tcuDestroyExternalMemory, "cuDestroyExternalMemory"); + LOAD_SYMBOL_OPT(cuExternalMemoryGetMappedBuffer, tcuExternalMemoryGetMappedBuffer, "cuExternalMemoryGetMappedBuffer"); + LOAD_SYMBOL_OPT(cuExternalMemoryGetMappedMipmappedArray, tcuExternalMemoryGetMappedMipmappedArray, "cuExternalMemoryGetMappedMipmappedArray"); + LOAD_SYMBOL_OPT(cuMipmappedArrayGetLevel, tcuMipmappedArrayGetLevel, "cuMipmappedArrayGetLevel"); + LOAD_SYMBOL_OPT(cuMipmappedArrayDestroy, tcuMipmappedArrayDestroy, "cuMipmappedArrayDestroy"); + + LOAD_SYMBOL_OPT(cuImportExternalSemaphore, tcuImportExternalSemaphore, "cuImportExternalSemaphore"); + LOAD_SYMBOL_OPT(cuDestroyExternalSemaphore, tcuDestroyExternalSemaphore, "cuDestroyExternalSemaphore"); + LOAD_SYMBOL_OPT(cuSignalExternalSemaphoresAsync, tcuSignalExternalSemaphoresAsync, "cuSignalExternalSemaphoresAsync"); + LOAD_SYMBOL_OPT(cuWaitExternalSemaphoresAsync, tcuWaitExternalSemaphoresAsync, "cuWaitExternalSemaphoresAsync"); + + LOAD_SYMBOL(cuArrayCreate, tcuArrayCreate, "cuArrayCreate_v2"); + LOAD_SYMBOL(cuArray3DCreate, tcuArray3DCreate, "cuArray3DCreate_v2"); + LOAD_SYMBOL(cuArrayDestroy, tcuArrayDestroy, "cuArrayDestroy"); + LOAD_SYMBOL(cuArray3DGetDescriptor, tcuArray3DGetDescriptor, "cuArray3DGetDescriptor_v2"); + LOAD_SYMBOL_OPT(cuArrayGetPlane, tcuArrayGetPlane, "cuArrayGetPlane"); + + LOAD_SYMBOL_OPT(cuEGLStreamProducerConnect, tcuEGLStreamProducerConnect, "cuEGLStreamProducerConnect"); + LOAD_SYMBOL_OPT(cuEGLStreamProducerDisconnect, tcuEGLStreamProducerDisconnect, "cuEGLStreamProducerDisconnect"); + LOAD_SYMBOL_OPT(cuEGLStreamConsumerDisconnect, tcuEGLStreamConsumerDisconnect, "cuEGLStreamConsumerDisconnect"); + LOAD_SYMBOL_OPT(cuEGLStreamProducerPresentFrame, tcuEGLStreamProducerPresentFrame, "cuEGLStreamProducerPresentFrame"); + LOAD_SYMBOL_OPT(cuEGLStreamProducerReturnFrame, tcuEGLStreamProducerReturnFrame, "cuEGLStreamProducerReturnFrame"); + +#if defined(_WIN32) || defined(__CYGWIN__) + LOAD_SYMBOL(cuD3D11GetDevice, tcuD3D11GetDevice, "cuD3D11GetDevice"); + LOAD_SYMBOL(cuD3D11GetDevices, tcuD3D11GetDevices, "cuD3D11GetDevices"); + LOAD_SYMBOL(cuGraphicsD3D11RegisterResource, tcuGraphicsD3D11RegisterResource, "cuGraphicsD3D11RegisterResource"); +#endif + + GENERIC_LOAD_FUNC_FINALE(cuda); +} +#endif + +static inline int cuvid_load_functions(CuvidFunctions **functions, void *logctx) +{ + GENERIC_LOAD_FUNC_PREAMBLE(CuvidFunctions, cuvid, NVCUVID_LIBNAME); + + LOAD_SYMBOL_OPT(cuvidGetDecoderCaps, tcuvidGetDecoderCaps, "cuvidGetDecoderCaps"); + LOAD_SYMBOL(cuvidCreateDecoder, tcuvidCreateDecoder, "cuvidCreateDecoder"); + LOAD_SYMBOL(cuvidDestroyDecoder, tcuvidDestroyDecoder, "cuvidDestroyDecoder"); + LOAD_SYMBOL_OPT(cuvidRegisterDecodeSurfaces, tcuvidRegisterDecodeSurfaces, "cuvidRegisterDecodeSurfaces"); + LOAD_SYMBOL_OPT(cuvidDecodePictureAsync, tcuvidDecodePictureAsync, "cuvidDecodePictureAsync"); + LOAD_SYMBOL(cuvidDecodePicture, tcuvidDecodePicture, "cuvidDecodePicture"); + LOAD_SYMBOL(cuvidGetDecodeStatus, tcuvidGetDecodeStatus, "cuvidGetDecodeStatus"); + LOAD_SYMBOL(cuvidReconfigureDecoder, tcuvidReconfigureDecoder, "cuvidReconfigureDecoder"); +#ifdef __CUVID_DEVPTR64 + LOAD_SYMBOL(cuvidMapVideoFrame, tcuvidMapVideoFrame, "cuvidMapVideoFrame64"); + LOAD_SYMBOL(cuvidUnmapVideoFrame, tcuvidUnmapVideoFrame, "cuvidUnmapVideoFrame64"); +#else + LOAD_SYMBOL(cuvidMapVideoFrame, tcuvidMapVideoFrame, "cuvidMapVideoFrame"); + LOAD_SYMBOL(cuvidUnmapVideoFrame, tcuvidUnmapVideoFrame, "cuvidUnmapVideoFrame"); +#endif + LOAD_SYMBOL(cuvidCtxLockCreate, tcuvidCtxLockCreate, "cuvidCtxLockCreate"); + LOAD_SYMBOL(cuvidCtxLockDestroy, tcuvidCtxLockDestroy, "cuvidCtxLockDestroy"); + LOAD_SYMBOL(cuvidCtxLock, tcuvidCtxLock, "cuvidCtxLock"); + LOAD_SYMBOL(cuvidCtxUnlock, tcuvidCtxUnlock, "cuvidCtxUnlock"); + +#if !defined(__APPLE__) + LOAD_SYMBOL(cuvidCreateVideoSource, tcuvidCreateVideoSource, "cuvidCreateVideoSource"); + LOAD_SYMBOL(cuvidCreateVideoSourceW, tcuvidCreateVideoSourceW, "cuvidCreateVideoSourceW"); + LOAD_SYMBOL(cuvidDestroyVideoSource, tcuvidDestroyVideoSource, "cuvidDestroyVideoSource"); + LOAD_SYMBOL(cuvidSetVideoSourceState, tcuvidSetVideoSourceState, "cuvidSetVideoSourceState"); + LOAD_SYMBOL(cuvidGetVideoSourceState, tcuvidGetVideoSourceState, "cuvidGetVideoSourceState"); + LOAD_SYMBOL(cuvidGetSourceVideoFormat, tcuvidGetSourceVideoFormat, "cuvidGetSourceVideoFormat"); + LOAD_SYMBOL(cuvidGetSourceAudioFormat, tcuvidGetSourceAudioFormat, "cuvidGetSourceAudioFormat"); +#endif + LOAD_SYMBOL(cuvidCreateVideoParser, tcuvidCreateVideoParser, "cuvidCreateVideoParser"); + LOAD_SYMBOL(cuvidParseVideoData, tcuvidParseVideoData, "cuvidParseVideoData"); + LOAD_SYMBOL(cuvidDestroyVideoParser, tcuvidDestroyVideoParser, "cuvidDestroyVideoParser"); + + GENERIC_LOAD_FUNC_FINALE(cuvid); +} + +static inline int nvenc_load_functions(NvencFunctions **functions, void *logctx) +{ + GENERIC_LOAD_FUNC_PREAMBLE(NvencFunctions, nvenc, NVENC_LIBNAME); + + LOAD_SYMBOL(NvEncodeAPICreateInstance, tNvEncodeAPICreateInstance, "NvEncodeAPICreateInstance"); + LOAD_SYMBOL(NvEncodeAPIGetMaxSupportedVersion, tNvEncodeAPIGetMaxSupportedVersion, "NvEncodeAPIGetMaxSupportedVersion"); + + GENERIC_LOAD_FUNC_FINALE(nvenc); +} + +#undef GENERIC_LOAD_FUNC_PREAMBLE +#undef LOAD_LIBRARY +#undef LOAD_SYMBOL +#undef GENERIC_LOAD_FUNC_FINALE +#undef GENERIC_FREE_FUNC +#undef CUDA_LIBNAME +#undef NVCUVID_LIBNAME +#undef NVENC_LIBNAME + +#endif + diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/ffnvcodec/dynlink_nvcuvid.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/ffnvcodec/dynlink_nvcuvid.h new file mode 100644 index 000000000..5064f13db --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/ffnvcodec/dynlink_nvcuvid.h @@ -0,0 +1,553 @@ +/* + * This copyright notice applies to this header file only: + * + * Copyright (c) 2010-2026 NVIDIA Corporation + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the software, and to permit persons to whom the + * software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/********************************************************************************************************************/ +//! \file nvcuvid.h +//! NVDECODE API provides video decoding interface to NVIDIA GPU devices. +//! \date 2015-2024 +//! This file contains the interface constants, structure definitions and function prototypes. +/********************************************************************************************************************/ + +#if !defined(__NVCUVID_H__) +#define __NVCUVID_H__ + +#include "dynlink_cuviddec.h" + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +#define MAX_CLOCK_TS 3 + +/***********************************************/ +//! +//! High-level helper APIs for video sources +//! +/***********************************************/ + +typedef void *CUvideosource; +typedef void *CUvideoparser; + + +/************************************************************************/ +//! \enum cudaVideoState +//! Video source state enums +//! Used in cuvidSetVideoSourceState and cuvidGetVideoSourceState APIs +/************************************************************************/ +typedef enum { + cudaVideoState_Error = -1, /**< Error state (invalid source) */ + cudaVideoState_Stopped = 0, /**< Source is stopped (or reached end-of-stream) */ + cudaVideoState_Started = 1 /**< Source is running and delivering data */ +} cudaVideoState; + +/************************************************************************/ +//! \enum cudaAudioCodec +//! Audio compression enums +//! Used in CUAUDIOFORMAT structure +/************************************************************************/ +typedef enum { + cudaAudioCodec_MPEG1=0, /**< MPEG-1 Audio */ + cudaAudioCodec_MPEG2, /**< MPEG-2 Audio */ + cudaAudioCodec_MP3, /**< MPEG-1 Layer III Audio */ + cudaAudioCodec_AC3, /**< Dolby Digital (AC3) Audio */ + cudaAudioCodec_LPCM, /**< PCM Audio */ + cudaAudioCodec_AAC, /**< AAC Audio */ +} cudaAudioCodec; + +/************************************************************************/ +//! \ingroup STRUCTS +//! \struct TIMECODESET +//! Used to store Time code set extracted from H264 and HEVC codecs +/************************************************************************/ +typedef struct _TIMECODESET +{ + unsigned int time_offset_value; + unsigned short n_frames; + unsigned char clock_timestamp_flag; + unsigned char units_field_based_flag; + unsigned char counting_type; + unsigned char full_timestamp_flag; + unsigned char discontinuity_flag; + unsigned char cnt_dropped_flag; + unsigned char seconds_value; + unsigned char minutes_value; + unsigned char hours_value; + unsigned char seconds_flag; + unsigned char minutes_flag; + unsigned char hours_flag; + unsigned char time_offset_length; + unsigned char reserved; +} TIMECODESET; + +/************************************************************************/ +//! \ingroup STRUCTS +//! \struct TIMECODE +//! Used to extract Time code in H264 and HEVC codecs +/************************************************************************/ +typedef struct _TIMECODE +{ + TIMECODESET time_code_set[MAX_CLOCK_TS]; + unsigned char num_clock_ts; +} TIMECODE; + +/**********************************************************************************/ +//! \ingroup STRUCTS +//! \struct SEIMASTERINGDISPLAYINFO +//! Used to extract mastering display color volume SEI in H264 and HEVC codecs +/**********************************************************************************/ +typedef struct _SEIMASTERINGDISPLAYINFO +{ + unsigned short display_primaries_x[3]; + unsigned short display_primaries_y[3]; + unsigned short white_point_x; + unsigned short white_point_y; + unsigned int max_display_mastering_luminance; + unsigned int min_display_mastering_luminance; +} SEIMASTERINGDISPLAYINFO; + +/**********************************************************************************/ +//! \ingroup STRUCTS +//! \struct SEICONTENTLIGHTLEVELINFO +//! Used to extract content light level info SEI in H264 and HEVC codecs +/**********************************************************************************/ +typedef struct _SEICONTENTLIGHTLEVELINFO +{ + unsigned short max_content_light_level; + unsigned short max_pic_average_light_level; + unsigned int reserved; +} SEICONTENTLIGHTLEVELINFO; + +/**********************************************************************************/ +//! \ingroup STRUCTS +//! \struct TIMECODEMPEG2 +//! Used to extract Time code in MPEG2 codec +/**********************************************************************************/ +typedef struct _TIMECODEMPEG2 +{ + unsigned char drop_frame_flag; + unsigned char time_code_hours; + unsigned char time_code_minutes; + unsigned char marker_bit; + unsigned char time_code_seconds; + unsigned char time_code_pictures; +} TIMECODEMPEG2; + +/**********************************************************************************/ +//! \ingroup STRUCTS +//! \struct SEIALTERNATIVETRANSFERCHARACTERISTICS +//! Used to extract alternative transfer characteristics SEI in H264 and HEVC codecs +/**********************************************************************************/ +typedef struct _SEIALTERNATIVETRANSFERCHARACTERISTICS +{ + unsigned char preferred_transfer_characteristics; +} SEIALTERNATIVETRANSFERCHARACTERISTICS; + +/**********************************************************************************/ +//! \ingroup STRUCTS +//! \struct CUSEIMESSAGE; +//! Used in CUVIDSEIMESSAGEINFO structure +/**********************************************************************************/ +typedef struct _CUSEIMESSAGE +{ + unsigned char sei_message_type; /**< OUT: SEI Message Type */ + unsigned char reserved[3]; + unsigned int sei_message_size; /**< OUT: SEI Message Size */ +} CUSEIMESSAGE; + +/************************************************************************************************/ +//! \ingroup STRUCTS +//! \struct CUVIDEOFORMAT +//! Video format +//! Used in cuvidGetSourceVideoFormat API +/************************************************************************************************/ +typedef struct +{ + cudaVideoCodec codec; /**< OUT: Compression format */ + /** + * OUT: frame rate = numerator / denominator (for example: 30000/1001) + */ + struct { + /**< OUT: frame rate numerator (0 = unspecified or variable frame rate) */ + unsigned int numerator; + /**< OUT: frame rate denominator (0 = unspecified or variable frame rate) */ + unsigned int denominator; + } frame_rate; + unsigned char progressive_sequence; /**< OUT: 0=interlaced, 1=progressive */ + unsigned char bit_depth_luma_minus8; /**< OUT: high bit depth luma. E.g, 2 for 10-bitdepth, 4 for 12-bitdepth */ + unsigned char bit_depth_chroma_minus8; /**< OUT: high bit depth chroma. E.g, 2 for 10-bitdepth, 4 for 12-bitdepth */ + unsigned char min_num_decode_surfaces; /**< OUT: Minimum number of decode surfaces to be allocated for correct + decoding. The client can send this value in ulNumDecodeSurfaces + (in CUVIDDECODECREATEINFO structure). + This guarantees correct functionality and optimal video memory + usage but not necessarily the best performance, which depends on + the design of the overall application. The optimal number of + decode surfaces (in terms of performance and memory utilization) + should be decided by experimentation for each application, but it + cannot go below min_num_decode_surfaces. + If this value is used for ulNumDecodeSurfaces then it must be + returned to parser during sequence callback. */ + unsigned int coded_width; /**< OUT: coded frame width in pixels */ + unsigned int coded_height; /**< OUT: coded frame height in pixels */ + /** + * area of the frame that should be displayed + * typical example: + * coded_width = 1920, coded_height = 1088 + * display_area = { 0,0,1920,1080 } + */ + struct { + int left; /**< OUT: left position of display rect */ + int top; /**< OUT: top position of display rect */ + int right; /**< OUT: right position of display rect */ + int bottom; /**< OUT: bottom position of display rect */ + } display_area; + cudaVideoChromaFormat chroma_format; /**< OUT: Chroma format */ + unsigned int bitrate; /**< OUT: video bitrate (bps, 0=unknown) */ + /** + * OUT: Display Aspect Ratio = x:y (4:3, 16:9, etc) + */ + struct { + int x; + int y; + } display_aspect_ratio; + /** + * Video Signal Description + * Refer section E.2.1 (VUI parameters semantics) of H264 spec file + */ + struct { + unsigned char video_format : 3; /**< OUT: 0-Component, 1-PAL, 2-NTSC, 3-SECAM, 4-MAC, 5-Unspecified */ + unsigned char video_full_range_flag : 1; /**< OUT: indicates the black level and luma and chroma range */ + unsigned char reserved_zero_bits : 4; /**< Reserved bits */ + unsigned char color_primaries; /**< OUT: chromaticity coordinates of source primaries */ + unsigned char transfer_characteristics; /**< OUT: opto-electronic transfer characteristic of the source picture */ + unsigned char matrix_coefficients; /**< OUT: used in deriving luma and chroma signals from RGB primaries */ + } video_signal_description; + unsigned int seqhdr_data_length; /**< OUT: Additional bytes following (CUVIDEOFORMATEX) */ +} CUVIDEOFORMAT; + +/****************************************************************/ +//! \ingroup STRUCTS +//! \struct CUVIDOPERATINGPOINTINFO +//! Operating point information of scalable bitstream +/****************************************************************/ +typedef struct +{ + cudaVideoCodec codec; + union + { + struct + { + unsigned char operating_points_cnt; + unsigned char reserved24_bits[3]; + unsigned short operating_points_idc[32]; + } av1; + unsigned char CodecReserved[1024]; + }; +} CUVIDOPERATINGPOINTINFO; + +/**********************************************************************************/ +//! \ingroup STRUCTS +//! \struct CUVIDSEIMESSAGEINFO +//! Used in cuvidParseVideoData API with PFNVIDSEIMSGCALLBACK pfnGetSEIMsg +/**********************************************************************************/ +typedef struct _CUVIDSEIMESSAGEINFO +{ + void *pSEIData; /**< OUT: SEI Message Data */ + CUSEIMESSAGE *pSEIMessage; /**< OUT: SEI Message Info */ + unsigned int sei_message_count; /**< OUT: SEI Message Count */ + unsigned int picIdx; /**< OUT: SEI Message Pic Index */ +} CUVIDSEIMESSAGEINFO; + +/****************************************************************/ +//! \ingroup STRUCTS +//! \struct CUVIDAV1SEQHDR +//! AV1 specific sequence header information +/****************************************************************/ +typedef struct _CUVIDAV1SEQHDR { + unsigned int max_width; + unsigned int max_height; + unsigned char reserved[1016]; +} CUVIDAV1SEQHDR; + +/****************************************************************/ +//! \ingroup STRUCTS +//! \struct CUVIDEOFORMATEX +//! Video format including raw sequence header information +//! Used in cuvidGetSourceVideoFormat API +/****************************************************************/ +typedef struct +{ + CUVIDEOFORMAT format; /**< OUT: CUVIDEOFORMAT structure */ + union { + CUVIDAV1SEQHDR av1; + unsigned char raw_seqhdr_data[1024]; /**< OUT: Sequence header data */ + }; +} CUVIDEOFORMATEX; + +/****************************************************************/ +//! \ingroup STRUCTS +//! \struct CUAUDIOFORMAT +//! Audio formats +//! Used in cuvidGetSourceAudioFormat API +/****************************************************************/ +typedef struct +{ + cudaAudioCodec codec; /**< OUT: Compression format */ + unsigned int channels; /**< OUT: number of audio channels */ + unsigned int samplespersec; /**< OUT: sampling frequency */ + unsigned int bitrate; /**< OUT: For uncompressed, can also be used to determine bits per sample */ + unsigned int reserved1; /**< Reserved for future use */ + unsigned int reserved2; /**< Reserved for future use */ +} CUAUDIOFORMAT; + + +/***************************************************************/ +//! \enum CUvideopacketflags +//! Data packet flags +//! Used in CUVIDSOURCEDATAPACKET structure +/***************************************************************/ +typedef enum { + CUVID_PKT_ENDOFSTREAM = 0x01, /**< Set when this is the last packet for this stream */ + CUVID_PKT_TIMESTAMP = 0x02, /**< Timestamp is valid */ + CUVID_PKT_DISCONTINUITY = 0x04, /**< Set when a discontinuity has to be signalled */ + CUVID_PKT_ENDOFPICTURE = 0x08, /**< Set when the packet contains exactly one frame or one field */ + CUVID_PKT_NOTIFY_EOS = 0x10, /**< If this flag is set along with CUVID_PKT_ENDOFSTREAM, an additional (dummy) + display callback will be invoked with null value of CUVIDPARSERDISPINFO which + should be interpreted as end of the stream. */ +} CUvideopacketflags; + +/*****************************************************************************/ +//! \ingroup STRUCTS +//! \struct CUVIDSOURCEDATAPACKET +//! Data Packet +//! Used in cuvidParseVideoData API +//! IN for cuvidParseVideoData +/*****************************************************************************/ +typedef struct _CUVIDSOURCEDATAPACKET +{ + tcu_ulong flags; /**< IN: Combination of CUVID_PKT_XXX flags */ + tcu_ulong payload_size; /**< IN: number of bytes in the payload (may be zero if EOS flag is set) */ + const unsigned char *payload; /**< IN: Pointer to packet payload data (may be NULL if EOS flag is set) */ + CUvideotimestamp timestamp; /**< IN: Presentation time stamp (10MHz clock), only valid if + CUVID_PKT_TIMESTAMP flag is set */ +} CUVIDSOURCEDATAPACKET; + +// Callback for packet delivery +typedef int (CUDAAPI *PFNVIDSOURCECALLBACK)(void *, CUVIDSOURCEDATAPACKET *); + +/**************************************************************************************************************************/ +//! \ingroup STRUCTS +//! \struct CUVIDSOURCEPARAMS +//! Describes parameters needed in cuvidCreateVideoSource API +//! NVDECODE API is intended for HW accelerated video decoding so CUvideosource doesn't have audio demuxer for all supported +//! containers. It's recommended to clients to use their own or third party demuxer if audio support is needed. +/**************************************************************************************************************************/ +typedef struct _CUVIDSOURCEPARAMS +{ + unsigned int ulClockRate; /**< IN: Time stamp units in Hz (0=default=10000000Hz) */ + unsigned int bAnnexb : 1; /**< IN: AV1 annexB stream */ + unsigned int uReserved : 31; /**< Reserved for future use - set to zero */ + unsigned int uReserved1[6]; /**< Reserved for future use - set to zero */ + void *pUserData; /**< IN: User private data passed in to the data handlers */ + PFNVIDSOURCECALLBACK pfnVideoDataHandler; /**< IN: Called to deliver video packets */ + PFNVIDSOURCECALLBACK pfnAudioDataHandler; /**< IN: Called to deliver audio packets. */ + void *pvReserved2[8]; /**< Reserved for future use - set to NULL */ +} CUVIDSOURCEPARAMS; + + +/**********************************************/ +//! \ingroup ENUMS +//! \enum CUvideosourceformat_flags +//! CUvideosourceformat_flags +//! Used in cuvidGetSourceVideoFormat API +/**********************************************/ +typedef enum { + CUVID_FMT_EXTFORMATINFO = 0x100 /**< Return extended format structure (CUVIDEOFORMATEX) */ +} CUvideosourceformat_flags; + +#if !defined(__APPLE__) +/***************************************************************************************************************************/ +//! \ingroup FUNCTS +//! \fn CUresult CUDAAPI cuvidCreateVideoSource(CUvideosource *pObj, const char *pszFileName, CUVIDSOURCEPARAMS *pParams) +//! Create CUvideosource object. CUvideosource spawns demultiplexer thread that provides two callbacks: +//! pfnVideoDataHandler() and pfnAudioDataHandler() +//! NVDECODE API is intended for HW accelerated video decoding so CUvideosource doesn't have audio demuxer for all supported +//! containers. It's recommended to clients to use their own or third party demuxer if audio support is needed. +/***************************************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidCreateVideoSource(CUvideosource *pObj, const char *pszFileName, CUVIDSOURCEPARAMS *pParams); + +/***************************************************************************************************************************/ +//! \ingroup FUNCTS +//! \fn CUresult CUDAAPI cuvidCreateVideoSourceW(CUvideosource *pObj, const wchar_t *pwszFileName, CUVIDSOURCEPARAMS *pParams) +//! Create video source +/***************************************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidCreateVideoSourceW(CUvideosource *pObj, const wchar_t *pwszFileName, CUVIDSOURCEPARAMS *pParams); + +/********************************************************************/ +//! \ingroup FUNCTS +//! \fn CUresult CUDAAPI cuvidDestroyVideoSource(CUvideosource obj) +//! Destroy video source +/********************************************************************/ +typedef CUresult CUDAAPI tcuvidDestroyVideoSource(CUvideosource obj); + +/******************************************************************************************/ +//! \ingroup FUNCTS +//! \fn CUresult CUDAAPI cuvidSetVideoSourceState(CUvideosource obj, cudaVideoState state) +//! Set video source state to: +//! cudaVideoState_Started - to signal the source to run and deliver data +//! cudaVideoState_Stopped - to stop the source from delivering the data +//! cudaVideoState_Error - invalid source +/******************************************************************************************/ +typedef CUresult CUDAAPI tcuvidSetVideoSourceState(CUvideosource obj, cudaVideoState state); + +/******************************************************************************************/ +//! \ingroup FUNCTS +//! \fn cudaVideoState CUDAAPI cuvidGetVideoSourceState(CUvideosource obj) +//! Get video source state +//! Returns: +//! cudaVideoState_Started - if Source is running and delivering data +//! cudaVideoState_Stopped - if Source is stopped or reached end-of-stream +//! cudaVideoState_Error - if Source is in error state +/******************************************************************************************/ +typedef cudaVideoState CUDAAPI tcuvidGetVideoSourceState(CUvideosource obj); + +/******************************************************************************************************************/ +//! \ingroup FUNCTS +//! \fn CUresult CUDAAPI cuvidGetSourceVideoFormat(CUvideosource obj, CUVIDEOFORMAT *pvidfmt, unsigned int flags) +//! Gets video source format in pvidfmt, flags is set to combination of CUvideosourceformat_flags as per requirement +/******************************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidGetSourceVideoFormat(CUvideosource obj, CUVIDEOFORMAT *pvidfmt, unsigned int flags); + +/**************************************************************************************************************************/ +//! \ingroup FUNCTS +//! \fn CUresult CUDAAPI cuvidGetSourceAudioFormat(CUvideosource obj, CUAUDIOFORMAT *paudfmt, unsigned int flags) +//! Get audio source format +//! NVDECODE API is intended for HW accelerated video decoding so CUvideosource doesn't have audio demuxer for all supported +//! containers. It's recommended to clients to use their own or third party demuxer if audio support is needed. +/**************************************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidGetSourceAudioFormat(CUvideosource obj, CUAUDIOFORMAT *paudfmt, unsigned int flags); + +#endif +/**********************************************************************************/ +//! \ingroup STRUCTS +//! \struct CUVIDPARSERDISPINFO +//! Used in cuvidParseVideoData API with PFNVIDDISPLAYCALLBACK pfnDisplayPicture +/**********************************************************************************/ +typedef struct _CUVIDPARSERDISPINFO +{ + int picture_index; /**< OUT: Index of the current picture */ + int progressive_frame; /**< OUT: 1 if progressive frame; 0 otherwise */ + int top_field_first; /**< OUT: 1 if top field is displayed first; 0 otherwise */ + int repeat_first_field; /**< OUT: Number of additional fields (1=ivtc, 2=frame doubling, 4=frame tripling, + -1=unpaired field) */ + CUvideotimestamp timestamp; /**< OUT: Presentation time stamp */ +} CUVIDPARSERDISPINFO; + +/***********************************************************************************************************************/ +//! Parser callbacks +//! The parser will call these synchronously from within cuvidParseVideoData(), whenever there is sequence change or a picture +//! is ready to be decoded and/or displayed. First argument in functions is "void *pUserData" member of structure CUVIDSOURCEPARAMS +//! Return values from these callbacks are interpreted as below. If the callbacks return failure, it will be propagated by +//! cuvidParseVideoData() to the application. +//! Parser picks default operating point as 0 and outputAllLayers flag as 0 if PFNVIDOPPOINTCALLBACK is not set or return value is +//! -1 or invalid operating point. +//! PFNVIDSEQUENCECALLBACK : 0: fail, 1: succeeded, > 1: override dpb size of parser (set by CUVIDPARSERPARAMS::ulMaxNumDecodeSurfaces +//! while creating parser) +//! PFNVIDDECODECALLBACK : 0: fail, >=1: succeeded +//! PFNVIDDISPLAYCALLBACK : 0: fail, >=1: succeeded +//! PFNVIDOPPOINTCALLBACK : <0: fail, >=0: succeeded (bit 0-9: OperatingPoint, bit 10-10: outputAllLayers, bit 11-30: reserved) +//! PFNVIDSEIMSGCALLBACK : 0: fail, >=1: succeeded +/***********************************************************************************************************************/ +typedef int (CUDAAPI *PFNVIDSEQUENCECALLBACK)(void *, CUVIDEOFORMAT *); +typedef int (CUDAAPI *PFNVIDDECODECALLBACK)(void *, CUVIDPICPARAMS *); +typedef int (CUDAAPI *PFNVIDDISPLAYCALLBACK)(void *, CUVIDPARSERDISPINFO *); +typedef int (CUDAAPI *PFNVIDOPPOINTCALLBACK)(void *, CUVIDOPERATINGPOINTINFO*); +typedef int (CUDAAPI *PFNVIDSEIMSGCALLBACK) (void *, CUVIDSEIMESSAGEINFO *); + +/**************************************/ +//! \ingroup STRUCTS +//! \struct CUVIDPARSERPARAMS +//! Used in cuvidCreateVideoParser API +/**************************************/ +typedef struct _CUVIDPARSERPARAMS +{ + cudaVideoCodec CodecType; /**< IN: cudaVideoCodec_XXX */ + unsigned int ulMaxNumDecodeSurfaces; /**< IN: Max # of decode surfaces (parser will cycle through these) */ + unsigned int ulClockRate; /**< IN: Timestamp units in Hz (0=default=10000000Hz) */ + unsigned int ulErrorThreshold; /**< IN: % Error threshold (0-100) for calling pfnDecodePicture (100=always + IN: call pfnDecodePicture even if picture bitstream is fully corrupted) */ + unsigned int ulMaxDisplayDelay; /**< IN: Max display queue delay (improves pipelining of decode with display) + 0=no delay (recommended values: 2..4) */ + unsigned int bAnnexb : 1; /**< IN: AV1 annexB stream */ + unsigned int bMemoryOptimize : 1; /**< IN: Utilize minimum picIdx from dpb to allow memory saving at the + decoder layer, use cuvidReconfigureDecoder() to increase the + decode surfaces if needed (perf may get impacted) */ + unsigned int uReserved : 30; /**< Reserved for future use - set to zero */ + unsigned int uReserved1[4]; /**< IN: Reserved for future use - set to 0 */ + void *pUserData; /**< IN: User data for callbacks */ + PFNVIDSEQUENCECALLBACK pfnSequenceCallback; /**< IN: Called before decoding frames and/or whenever there is a fmt change */ + PFNVIDDECODECALLBACK pfnDecodePicture; /**< IN: Called when a picture is ready to be decoded (decode order) */ + PFNVIDDISPLAYCALLBACK pfnDisplayPicture; /**< IN: Called whenever a picture is ready to be displayed (display order) */ + PFNVIDOPPOINTCALLBACK pfnGetOperatingPoint; /**< IN: Called from AV1 sequence header to get operating point of a AV1 + scalable bitstream */ + PFNVIDSEIMSGCALLBACK pfnGetSEIMsg; /**< IN: Called when all SEI messages are parsed for particular frame */ + void *pvReserved2[5]; /**< Reserved for future use - set to NULL */ + CUVIDEOFORMATEX *pExtVideoInfo; /**< IN: [Optional] sequence header data from system layer */ +} CUVIDPARSERPARAMS; + +/************************************************************************************************/ +//! \ingroup FUNCTS +//! \fn CUresult CUDAAPI cuvidCreateVideoParser(CUvideoparser *pObj, CUVIDPARSERPARAMS *pParams) +//! Create video parser object and initialize +/************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidCreateVideoParser(CUvideoparser *pObj, CUVIDPARSERPARAMS *pParams); + +/************************************************************************************************/ +//! \ingroup FUNCTS +//! \fn CUresult CUDAAPI cuvidParseVideoData(CUvideoparser obj, CUVIDSOURCEDATAPACKET *pPacket) +//! Parse the video data from source data packet in pPacket +//! Extracts parameter sets like SPS, PPS, bitstream etc. from pPacket and +//! calls back pfnDecodePicture with CUVIDPICPARAMS data for kicking of HW decoding +//! calls back pfnSequenceCallback with CUVIDEOFORMAT data for initial sequence header or when +//! the decoder encounters a video format change +//! calls back pfnDisplayPicture with CUVIDPARSERDISPINFO data to display a video frame +/************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidParseVideoData(CUvideoparser obj, CUVIDSOURCEDATAPACKET *pPacket); + +/************************************************************************************************/ +//! \ingroup FUNCTS +//! \fn CUresult CUDAAPI cuvidDestroyVideoParser(CUvideoparser obj) +//! Destroy the video parser +/************************************************************************************************/ +typedef CUresult CUDAAPI tcuvidDestroyVideoParser(CUvideoparser obj); + +/**********************************************************************************************/ + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif // __NVCUVID_H__ diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/ffnvcodec/nvEncodeAPI.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/ffnvcodec/nvEncodeAPI.h new file mode 100644 index 000000000..f059ac07a --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/ffnvcodec/nvEncodeAPI.h @@ -0,0 +1,4683 @@ +/* + * This copyright notice applies to this header file only: + * + * Copyright (c) 2010-2026 NVIDIA Corporation + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the software, and to permit persons to whom the + * software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file nvEncodeAPI.h + * NVIDIA GPUs - beginning with the Kepler generation - contain a hardware-based encoder + * (referred to as NVENC) which provides fully-accelerated hardware-based video encoding. + * NvEncodeAPI provides the interface for NVIDIA video encoder (NVENC). + * \date 2011-2024 + * This file contains the interface constants, structure definitions and function prototypes. + */ + +#ifndef _NV_ENCODEAPI_H_ +#define _NV_ENCODEAPI_H_ + +#include + +#ifdef _WIN32 +#include +#endif + +#ifdef _MSC_VER +#ifndef _STDINT +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +#endif +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup ENCODER_STRUCTURE NvEncodeAPI Data structures + * @{ + */ + +#if defined(_WIN32) || defined(__CYGWIN__) +#define NVENCAPI __stdcall +#else +#define NVENCAPI +#endif + +#ifdef _WIN32 +typedef RECT NVENC_RECT; +#else +// ========================================================================================= +#if !defined(GUID) && !defined(GUID_DEFINED) +#define GUID_DEFINED +/*! + * \struct GUID + * Abstracts the GUID structure for non-windows platforms. + */ +// ========================================================================================= +typedef struct _GUID +{ + uint32_t Data1; /**< [in]: Specifies the first 8 hexadecimal digits of the GUID. */ + uint16_t Data2; /**< [in]: Specifies the first group of 4 hexadecimal digits. */ + uint16_t Data3; /**< [in]: Specifies the second group of 4 hexadecimal digits. */ + uint8_t Data4[8]; /**< [in]: Array of 8 bytes. The first 2 bytes contain the third group of 4 hexadecimal digits. + The remaining 6 bytes contain the final 12 hexadecimal digits. */ +} GUID, *LPGUID; +#endif // GUID + +/** + * \struct _NVENC_RECT + * Defines a Rectangle. Used in ::NV_ENC_PREPROCESS_FRAME. + */ +typedef struct _NVENC_RECT +{ + uint32_t left; /**< [in]: X coordinate of the upper left corner of rectangular area to be specified. */ + uint32_t top; /**< [in]: Y coordinate of the upper left corner of the rectangular area to be specified. */ + uint32_t right; /**< [in]: X coordinate of the bottom right corner of the rectangular area to be specified. */ + uint32_t bottom; /**< [in]: Y coordinate of the bottom right corner of the rectangular area to be specified. */ +} NVENC_RECT; + +#endif // _WIN32 + +/** @} */ /* End of GUID and NVENC_RECT structure grouping*/ + +typedef void* NV_ENC_INPUT_PTR; /**< NVENCODE API input buffer */ +typedef void* NV_ENC_OUTPUT_PTR; /**< NVENCODE API output buffer*/ +typedef void* NV_ENC_REGISTERED_PTR; /**< A Resource that has been registered with NVENCODE API*/ +typedef void* NV_ENC_CUSTREAM_PTR; /**< Pointer to CUstream*/ + +#define NVENCAPI_MAJOR_VERSION 13 +#define NVENCAPI_MINOR_VERSION 1 + +#define NVENCAPI_VERSION (NVENCAPI_MAJOR_VERSION | (NVENCAPI_MINOR_VERSION << 24)) + +/** + * Macro to generate per-structure version for use with API. + */ +#define NVENCAPI_STRUCT_VERSION(ver) ((uint32_t)NVENCAPI_VERSION | ((ver)<<16) | (0x7 << 28)) + + +#define NVENC_INFINITE_GOPLENGTH 0xffffffff + +#define NV_MAX_SEQ_HDR_LEN (512) + +#ifdef __GNUC__ +#define NV_ENC_DEPRECATED __attribute__ ((deprecated("WILL BE REMOVED IN A FUTURE VIDEO CODEC SDK VERSION"))) +#elif defined(_MSC_VER) +#define NV_ENC_DEPRECATED __declspec(deprecated("WILL BE REMOVED IN A FUTURE VIDEO CODEC SDK VERSION")) +#endif + +// ========================================================================================= +// Encode Codec GUIDS supported by the NvEncodeAPI interface. +// ========================================================================================= + +// {6BC82762-4E63-4ca4-AA85-1E50F321F6BF} +static const GUID NV_ENC_CODEC_H264_GUID = +{ 0x6bc82762, 0x4e63, 0x4ca4, { 0xaa, 0x85, 0x1e, 0x50, 0xf3, 0x21, 0xf6, 0xbf } }; + +// {790CDC88-4522-4d7b-9425-BDA9975F7603} +static const GUID NV_ENC_CODEC_HEVC_GUID = +{ 0x790cdc88, 0x4522, 0x4d7b, { 0x94, 0x25, 0xbd, 0xa9, 0x97, 0x5f, 0x76, 0x3 } }; + +// {0A352289-0AA7-4759-862D-5D15CD16D254} +static const GUID NV_ENC_CODEC_AV1_GUID = +{ 0x0a352289, 0x0aa7, 0x4759, { 0x86, 0x2d, 0x5d, 0x15, 0xcd, 0x16, 0xd2, 0x54 } }; + + + +// ========================================================================================= +// * Encode Profile GUIDS supported by the NvEncodeAPI interface. +// ========================================================================================= + +// {BFD6F8E7-233C-4341-8B3E-4818523803F4} +static const GUID NV_ENC_CODEC_PROFILE_AUTOSELECT_GUID = +{ 0xbfd6f8e7, 0x233c, 0x4341, { 0x8b, 0x3e, 0x48, 0x18, 0x52, 0x38, 0x3, 0xf4 } }; + +// {0727BCAA-78C4-4c83-8C2F-EF3DFF267C6A} +static const GUID NV_ENC_H264_PROFILE_BASELINE_GUID = +{ 0x727bcaa, 0x78c4, 0x4c83, { 0x8c, 0x2f, 0xef, 0x3d, 0xff, 0x26, 0x7c, 0x6a } }; + +// {60B5C1D4-67FE-4790-94D5-C4726D7B6E6D} +static const GUID NV_ENC_H264_PROFILE_MAIN_GUID = +{ 0x60b5c1d4, 0x67fe, 0x4790, { 0x94, 0xd5, 0xc4, 0x72, 0x6d, 0x7b, 0x6e, 0x6d } }; + +// {E7CBC309-4F7A-4b89-AF2A-D537C92BE310} +static const GUID NV_ENC_H264_PROFILE_HIGH_GUID = +{ 0xe7cbc309, 0x4f7a, 0x4b89, { 0xaf, 0x2a, 0xd5, 0x37, 0xc9, 0x2b, 0xe3, 0x10 } }; + +// {8F0C337E-186C-48E9-A69D-7A8334089758} +static const GUID NV_ENC_H264_PROFILE_HIGH_10_GUID = +{ 0x8f0c337e, 0x186c, 0x48e9, { 0xa6, 0x9d, 0x7a, 0x83, 0x34, 0x08, 0x97, 0x58} }; + +// {FF3242E9-613C-4295-A1E8-2A7FE94D8133} +static const GUID NV_ENC_H264_PROFILE_HIGH_422_GUID = +{ 0xff3242e9, 0x613c, 0x4295, { 0xa1, 0xe8, 0x2a, 0x7f, 0xe9, 0x4d, 0x81, 0x33 } }; + +// {7AC663CB-A598-4960-B844-339B261A7D52} +static const GUID NV_ENC_H264_PROFILE_HIGH_444_GUID = +{ 0x7ac663cb, 0xa598, 0x4960, { 0xb8, 0x44, 0x33, 0x9b, 0x26, 0x1a, 0x7d, 0x52 } }; + +// {40847BF5-33F7-4601-9084-E8FE3C1DB8B7} +static const GUID NV_ENC_H264_PROFILE_STEREO_GUID = +{ 0x40847bf5, 0x33f7, 0x4601, { 0x90, 0x84, 0xe8, 0xfe, 0x3c, 0x1d, 0xb8, 0xb7 } }; + +// {B405AFAC-F32B-417B-89C4-9ABEED3E5978} +static const GUID NV_ENC_H264_PROFILE_PROGRESSIVE_HIGH_GUID = +{ 0xb405afac, 0xf32b, 0x417b, { 0x89, 0xc4, 0x9a, 0xbe, 0xed, 0x3e, 0x59, 0x78 } }; + +// {AEC1BD87-E85B-48f2-84C3-98BCA6285072} +static const GUID NV_ENC_H264_PROFILE_CONSTRAINED_HIGH_GUID = +{ 0xaec1bd87, 0xe85b, 0x48f2, { 0x84, 0xc3, 0x98, 0xbc, 0xa6, 0x28, 0x50, 0x72 } }; + +// {B514C39A-B55B-40fa-878F-F1253B4DFDEC} +static const GUID NV_ENC_HEVC_PROFILE_MAIN_GUID = +{ 0xb514c39a, 0xb55b, 0x40fa, { 0x87, 0x8f, 0xf1, 0x25, 0x3b, 0x4d, 0xfd, 0xec } }; + +// {fa4d2b6c-3a5b-411a-8018-0a3f5e3c9be5} +static const GUID NV_ENC_HEVC_PROFILE_MAIN10_GUID = +{ 0xfa4d2b6c, 0x3a5b, 0x411a, { 0x80, 0x18, 0x0a, 0x3f, 0x5e, 0x3c, 0x9b, 0xe5 } }; + +// For HEVC Main 422/444 8 bit and HEVC Main 422/444 10 bit profiles only +// {51ec32b5-1b4c-453c-9cbd-b616bd621341} +static const GUID NV_ENC_HEVC_PROFILE_FREXT_GUID = +{ 0x51ec32b5, 0x1b4c, 0x453c, { 0x9c, 0xbd, 0xb6, 0x16, 0xbd, 0x62, 0x13, 0x41 } }; + +// {5f2a39f5-f14e-4f95-9a9e-b76d568fcf97} +static const GUID NV_ENC_AV1_PROFILE_MAIN_GUID = +{ 0x5f2a39f5, 0xf14e, 0x4f95, { 0x9a, 0x9e, 0xb7, 0x6d, 0x56, 0x8f, 0xcf, 0x97 } }; + +// ========================================================================================= +// * Preset GUIDS supported by the NvEncodeAPI interface. +// ========================================================================================= + +// Performance degrades and quality improves as we move from P1 to P7. Presets P3 to P7 for H264 and Presets P2 to P7 for HEVC have B frames enabled by default +// for HIGH_QUALITY and LOSSLESS tuning info, and will not work with Weighted Prediction enabled. In case Weighted Prediction is required, disable B frames by +// setting frameIntervalP = 1 +// {FC0A8D3E-45F8-4CF8-80C7-298871590EBF} +static const GUID NV_ENC_PRESET_P1_GUID = +{ 0xfc0a8d3e, 0x45f8, 0x4cf8, { 0x80, 0xc7, 0x29, 0x88, 0x71, 0x59, 0xe, 0xbf } }; + +// {F581CFB8-88D6-4381-93F0-DF13F9C27DAB} +static const GUID NV_ENC_PRESET_P2_GUID = +{ 0xf581cfb8, 0x88d6, 0x4381, { 0x93, 0xf0, 0xdf, 0x13, 0xf9, 0xc2, 0x7d, 0xab } }; + +// {36850110-3A07-441F-94D5-3670631F91F6} +static const GUID NV_ENC_PRESET_P3_GUID = +{ 0x36850110, 0x3a07, 0x441f, { 0x94, 0xd5, 0x36, 0x70, 0x63, 0x1f, 0x91, 0xf6 } }; + +// {90A7B826-DF06-4862-B9D2-CD6D73A08681} +static const GUID NV_ENC_PRESET_P4_GUID = +{ 0x90a7b826, 0xdf06, 0x4862, { 0xb9, 0xd2, 0xcd, 0x6d, 0x73, 0xa0, 0x86, 0x81 } }; + +// {21C6E6B4-297A-4CBA-998F-B6CBDE72ADE3} +static const GUID NV_ENC_PRESET_P5_GUID = +{ 0x21c6e6b4, 0x297a, 0x4cba, { 0x99, 0x8f, 0xb6, 0xcb, 0xde, 0x72, 0xad, 0xe3 } }; + +// {8E75C279-6299-4AB6-8302-0B215A335CF5} +static const GUID NV_ENC_PRESET_P6_GUID = +{ 0x8e75c279, 0x6299, 0x4ab6, { 0x83, 0x2, 0xb, 0x21, 0x5a, 0x33, 0x5c, 0xf5 } }; + +// {84848C12-6F71-4C13-931B-53E283F57974} +static const GUID NV_ENC_PRESET_P7_GUID = +{ 0x84848c12, 0x6f71, 0x4c13, { 0x93, 0x1b, 0x53, 0xe2, 0x83, 0xf5, 0x79, 0x74 } }; + +/** + * \addtogroup ENCODER_STRUCTURE NvEncodeAPI Data structures + * @{ + */ + +/** + * Input frame encode modes + */ +typedef enum _NV_ENC_PARAMS_FRAME_FIELD_MODE +{ + NV_ENC_PARAMS_FRAME_FIELD_MODE_FRAME = 0x01, /**< Frame mode */ + NV_ENC_PARAMS_FRAME_FIELD_MODE_FIELD = 0x02 /**< Field mode */ +} NV_ENC_PARAMS_FRAME_FIELD_MODE; + +/** + * Rate Control Modes + */ +typedef enum _NV_ENC_PARAMS_RC_MODE +{ + NV_ENC_PARAMS_RC_CONSTQP = 0x0, /**< Constant QP mode */ + NV_ENC_PARAMS_RC_VBR = 0x1, /**< Variable bitrate mode */ + NV_ENC_PARAMS_RC_CBR = 0x2, /**< Constant bitrate mode */ +} NV_ENC_PARAMS_RC_MODE; + +/** + * Multi Pass encoding + */ +typedef enum _NV_ENC_MULTI_PASS +{ + NV_ENC_MULTI_PASS_DISABLED = 0x0, /**< Single Pass */ + NV_ENC_TWO_PASS_QUARTER_RESOLUTION = 0x1, /**< Two Pass encoding is enabled where first Pass is quarter resolution */ + NV_ENC_TWO_PASS_FULL_RESOLUTION = 0x2, /**< Two Pass encoding is enabled where first Pass is full resolution */ +} NV_ENC_MULTI_PASS; + +typedef enum _NV_ENC_STATE_RESTORE_TYPE +{ + NV_ENC_STATE_RESTORE_FULL = 0x01, /**< Restore full encoder state */ + NV_ENC_STATE_RESTORE_RATE_CONTROL = 0x02, /**< Restore only rate control state */ + NV_ENC_STATE_RESTORE_ENCODE = 0x03, /**< Restore full encoder state except for rate control state */ +} NV_ENC_STATE_RESTORE_TYPE; + +typedef enum _NV_ENC_OUTPUT_STATS_LEVEL +{ + NV_ENC_OUTPUT_STATS_NONE = 0, /** No output stats */ + NV_ENC_OUTPUT_STATS_BLOCK_LEVEL = 1, /** Output stats for every block. + Block represents a CTB for HEVC, macroblock for H.264, super block for AV1 */ + NV_ENC_OUTPUT_STATS_ROW_LEVEL = 2, /** Output stats for every row. + Row represents a CTB row for HEVC, macroblock row for H.264, super block row for AV1 */ +} NV_ENC_OUTPUT_STATS_LEVEL; + +/** + * Emphasis Levels + */ +typedef enum _NV_ENC_EMPHASIS_MAP_LEVEL +{ + NV_ENC_EMPHASIS_MAP_LEVEL_0 = 0x0, /**< Emphasis Map Level 0, for zero Delta QP value */ + NV_ENC_EMPHASIS_MAP_LEVEL_1 = 0x1, /**< Emphasis Map Level 1, for very low Delta QP value */ + NV_ENC_EMPHASIS_MAP_LEVEL_2 = 0x2, /**< Emphasis Map Level 2, for low Delta QP value */ + NV_ENC_EMPHASIS_MAP_LEVEL_3 = 0x3, /**< Emphasis Map Level 3, for medium Delta QP value */ + NV_ENC_EMPHASIS_MAP_LEVEL_4 = 0x4, /**< Emphasis Map Level 4, for high Delta QP value */ + NV_ENC_EMPHASIS_MAP_LEVEL_5 = 0x5 /**< Emphasis Map Level 5, for very high Delta QP value */ +} NV_ENC_EMPHASIS_MAP_LEVEL; + +/** + * QP MAP MODE + */ +typedef enum _NV_ENC_QP_MAP_MODE +{ + NV_ENC_QP_MAP_DISABLED = 0x0, /**< Value in NV_ENC_PIC_PARAMS::qpDeltaMap have no effect. */ + NV_ENC_QP_MAP_EMPHASIS = 0x1, /**< Value in NV_ENC_PIC_PARAMS::qpDeltaMap will be treated as Emphasis level. Currently this is only supported for H264 */ + NV_ENC_QP_MAP_DELTA = 0x2, /**< Value in NV_ENC_PIC_PARAMS::qpDeltaMap will be treated as QP delta map. */ + NV_ENC_QP_MAP = 0x3, /**< Currently This is not supported. Value in NV_ENC_PIC_PARAMS::qpDeltaMap will be treated as QP value. */ +} NV_ENC_QP_MAP_MODE; + +/** + * Input picture structure + */ +typedef enum _NV_ENC_PIC_STRUCT +{ + NV_ENC_PIC_STRUCT_FRAME = 0x01, /**< Progressive frame */ + NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM = 0x02, /**< Field encoding top field first */ + NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP = 0x03 /**< Field encoding bottom field first */ +} NV_ENC_PIC_STRUCT; + +/** + * Display picture structure + * Currently, this enum is only used for deciding the number of clock timestamp sets in Picture Timing SEI / Time Code SEI + * Otherwise, this has no impact on encoder behavior + */ +typedef enum _NV_ENC_DISPLAY_PIC_STRUCT +{ + NV_ENC_PIC_STRUCT_DISPLAY_FRAME = 0x00, /**< Progressive frame */ + NV_ENC_PIC_STRUCT_DISPLAY_FIELD_TOP_BOTTOM = 0x01, /**< Field encoding top field first */ + NV_ENC_PIC_STRUCT_DISPLAY_FIELD_BOTTOM_TOP = 0x02, /**< Field encoding bottom field first */ + NV_ENC_PIC_STRUCT_DISPLAY_FRAME_DOUBLING = 0x03, /**< Frame doubling */ + NV_ENC_PIC_STRUCT_DISPLAY_FRAME_TRIPLING = 0x04 /**< Frame tripling */ +} NV_ENC_DISPLAY_PIC_STRUCT; + +/** + * Input picture type + */ +typedef enum _NV_ENC_PIC_TYPE +{ + NV_ENC_PIC_TYPE_P = 0x0, /**< Forward predicted */ + NV_ENC_PIC_TYPE_B = 0x01, /**< Bi-directionally predicted picture */ + NV_ENC_PIC_TYPE_I = 0x02, /**< Intra predicted picture */ + NV_ENC_PIC_TYPE_IDR = 0x03, /**< IDR picture */ + NV_ENC_PIC_TYPE_BI = 0x04, /**< Bi-directionally predicted with only Intra MBs */ + NV_ENC_PIC_TYPE_SKIPPED = 0x05, /**< Picture is skipped */ + NV_ENC_PIC_TYPE_INTRA_REFRESH = 0x06, /**< First picture in intra refresh cycle */ + NV_ENC_PIC_TYPE_NONREF_P = 0x07, /**< Non reference P picture */ + NV_ENC_PIC_TYPE_SWITCH = 0x08, /**< Switch frame (AV1 only) */ + NV_ENC_PIC_TYPE_UNKNOWN = 0xFF /**< Picture type unknown */ +} NV_ENC_PIC_TYPE; + +/** + * Motion vector precisions + */ +typedef enum _NV_ENC_MV_PRECISION +{ + NV_ENC_MV_PRECISION_DEFAULT = 0x0, /**< Driver selects Quarter-Pel motion vector precision by default */ + NV_ENC_MV_PRECISION_FULL_PEL = 0x01, /**< Full-Pel motion vector precision */ + NV_ENC_MV_PRECISION_HALF_PEL = 0x02, /**< Half-Pel motion vector precision */ + NV_ENC_MV_PRECISION_QUARTER_PEL = 0x03 /**< Quarter-Pel motion vector precision */ +} NV_ENC_MV_PRECISION; + + +/** + * Input buffer formats + */ +typedef enum _NV_ENC_BUFFER_FORMAT +{ + NV_ENC_BUFFER_FORMAT_UNDEFINED = 0x00000000, /**< Undefined buffer format */ + + NV_ENC_BUFFER_FORMAT_NV12 = 0x00000001, /**< Semi-Planar YUV [Y plane followed by interleaved UV plane] */ + NV_ENC_BUFFER_FORMAT_YV12 = 0x00000010, /**< Planar YUV [Y plane followed by V and U planes] */ + NV_ENC_BUFFER_FORMAT_IYUV = 0x00000100, /**< Planar YUV [Y plane followed by U and V planes] */ + NV_ENC_BUFFER_FORMAT_YUV444 = 0x00001000, /**< Planar YUV [Y plane followed by U and V planes] */ + NV_ENC_BUFFER_FORMAT_YUV420_10BIT = 0x00010000, /**< 10 bit Semi-Planar YUV [Y plane followed by interleaved UV plane]. Each pixel of size 2 bytes. Most Significant 10 bits contain pixel data. */ + NV_ENC_BUFFER_FORMAT_YUV444_10BIT = 0x00100000, /**< 10 bit Planar YUV444 [Y plane followed by U and V planes]. Each pixel of size 2 bytes. Most Significant 10 bits contain pixel data. */ + NV_ENC_BUFFER_FORMAT_ARGB = 0x01000000, /**< 8 bit Packed A8R8G8B8. This is a word-ordered format + where a pixel is represented by a 32-bit word with B + in the lowest 8 bits, G in the next 8 bits, R in the + 8 bits after that and A in the highest 8 bits. */ + NV_ENC_BUFFER_FORMAT_ARGB10 = 0x02000000, /**< 10 bit Packed A2R10G10B10. This is a word-ordered format + where a pixel is represented by a 32-bit word with B + in the lowest 10 bits, G in the next 10 bits, R in the + 10 bits after that and A in the highest 2 bits. */ + NV_ENC_BUFFER_FORMAT_AYUV = 0x04000000, /**< 8 bit Packed A8Y8U8V8. This is a word-ordered format + where a pixel is represented by a 32-bit word with V + in the lowest 8 bits, U in the next 8 bits, Y in the + 8 bits after that and A in the highest 8 bits. */ + NV_ENC_BUFFER_FORMAT_ABGR = 0x10000000, /**< 8 bit Packed A8B8G8R8. This is a word-ordered format + where a pixel is represented by a 32-bit word with R + in the lowest 8 bits, G in the next 8 bits, B in the + 8 bits after that and A in the highest 8 bits. */ + NV_ENC_BUFFER_FORMAT_ABGR10 = 0x20000000, /**< 10 bit Packed A2B10G10R10. This is a word-ordered format + where a pixel is represented by a 32-bit word with R + in the lowest 10 bits, G in the next 10 bits, B in the + 10 bits after that and A in the highest 2 bits. */ + NV_ENC_BUFFER_FORMAT_U8 = 0x40000000, /**< Buffer format representing one-dimensional buffer. + This format should be used only when registering the + resource as output buffer, which will be used to write + the encoded bit stream or H.264 ME only mode output. */ + NV_ENC_BUFFER_FORMAT_NV16 = 0x40000001, /**< Semi-Planar YUV 422 [Y plane followed by interleaved UV plane] */ + NV_ENC_BUFFER_FORMAT_P210 = 0x40000002, /**< Semi-Planar 10-bit YUV 422 [Y plane followed by interleaved UV plane] */ +} NV_ENC_BUFFER_FORMAT; + +/** + * Encoding levels + */ +typedef enum _NV_ENC_LEVEL +{ + NV_ENC_LEVEL_AUTOSELECT = 0, + + NV_ENC_LEVEL_H264_1 = 10, + NV_ENC_LEVEL_H264_1b = 9, + NV_ENC_LEVEL_H264_11 = 11, + NV_ENC_LEVEL_H264_12 = 12, + NV_ENC_LEVEL_H264_13 = 13, + NV_ENC_LEVEL_H264_2 = 20, + NV_ENC_LEVEL_H264_21 = 21, + NV_ENC_LEVEL_H264_22 = 22, + NV_ENC_LEVEL_H264_3 = 30, + NV_ENC_LEVEL_H264_31 = 31, + NV_ENC_LEVEL_H264_32 = 32, + NV_ENC_LEVEL_H264_4 = 40, + NV_ENC_LEVEL_H264_41 = 41, + NV_ENC_LEVEL_H264_42 = 42, + NV_ENC_LEVEL_H264_5 = 50, + NV_ENC_LEVEL_H264_51 = 51, + NV_ENC_LEVEL_H264_52 = 52, + NV_ENC_LEVEL_H264_60 = 60, + NV_ENC_LEVEL_H264_61 = 61, + NV_ENC_LEVEL_H264_62 = 62, + + NV_ENC_LEVEL_HEVC_1 = 30, + NV_ENC_LEVEL_HEVC_2 = 60, + NV_ENC_LEVEL_HEVC_21 = 63, + NV_ENC_LEVEL_HEVC_3 = 90, + NV_ENC_LEVEL_HEVC_31 = 93, + NV_ENC_LEVEL_HEVC_4 = 120, + NV_ENC_LEVEL_HEVC_41 = 123, + NV_ENC_LEVEL_HEVC_5 = 150, + NV_ENC_LEVEL_HEVC_51 = 153, + NV_ENC_LEVEL_HEVC_52 = 156, + NV_ENC_LEVEL_HEVC_6 = 180, + NV_ENC_LEVEL_HEVC_61 = 183, + NV_ENC_LEVEL_HEVC_62 = 186, + + NV_ENC_TIER_HEVC_MAIN = 0, + NV_ENC_TIER_HEVC_HIGH = 1, + + NV_ENC_LEVEL_AV1_2 = 0, + NV_ENC_LEVEL_AV1_21 = 1, + NV_ENC_LEVEL_AV1_22 = 2, + NV_ENC_LEVEL_AV1_23 = 3, + NV_ENC_LEVEL_AV1_3 = 4, + NV_ENC_LEVEL_AV1_31 = 5, + NV_ENC_LEVEL_AV1_32 = 6, + NV_ENC_LEVEL_AV1_33 = 7, + NV_ENC_LEVEL_AV1_4 = 8, + NV_ENC_LEVEL_AV1_41 = 9, + NV_ENC_LEVEL_AV1_42 = 10, + NV_ENC_LEVEL_AV1_43 = 11, + NV_ENC_LEVEL_AV1_5 = 12, + NV_ENC_LEVEL_AV1_51 = 13, + NV_ENC_LEVEL_AV1_52 = 14, + NV_ENC_LEVEL_AV1_53 = 15, + NV_ENC_LEVEL_AV1_6 = 16, + NV_ENC_LEVEL_AV1_61 = 17, + NV_ENC_LEVEL_AV1_62 = 18, + NV_ENC_LEVEL_AV1_63 = 19, + NV_ENC_LEVEL_AV1_7 = 20, + NV_ENC_LEVEL_AV1_71 = 21, + NV_ENC_LEVEL_AV1_72 = 22, + NV_ENC_LEVEL_AV1_73 = 23, + NV_ENC_LEVEL_AV1_AUTOSELECT , + + NV_ENC_TIER_AV1_0 = 0, + NV_ENC_TIER_AV1_1 = 1 +} NV_ENC_LEVEL; + +/** + * Error Codes + */ +typedef enum _NVENCSTATUS +{ + /** + * This indicates that API call returned with no errors. + */ + NV_ENC_SUCCESS, + + /** + * This indicates that no encode capable devices were detected. + */ + NV_ENC_ERR_NO_ENCODE_DEVICE, + + /** + * This indicates that devices pass by the client is not supported. + */ + NV_ENC_ERR_UNSUPPORTED_DEVICE, + + /** + * This indicates that the encoder device supplied by the client is not + * valid. + */ + NV_ENC_ERR_INVALID_ENCODERDEVICE, + + /** + * This indicates that device passed to the API call is invalid. + */ + NV_ENC_ERR_INVALID_DEVICE, + + /** + * This indicates that device passed to the API call is no longer available and + * needs to be reinitialized. The clients need to destroy the current encoder + * session by freeing the allocated input output buffers and destroying the device + * and create a new encoding session. + */ + NV_ENC_ERR_DEVICE_NOT_EXIST, + + /** + * This indicates that one or more of the pointers passed to the API call + * is invalid. + */ + NV_ENC_ERR_INVALID_PTR, + + /** + * This indicates that completion event passed in ::NvEncEncodePicture() call + * is invalid. + */ + NV_ENC_ERR_INVALID_EVENT, + + /** + * This indicates that one or more of the parameter passed to the API call + * is invalid. + */ + NV_ENC_ERR_INVALID_PARAM, + + /** + * This indicates that an API call was made in wrong sequence/order. + */ + NV_ENC_ERR_INVALID_CALL, + + /** + * This indicates that the API call failed because it was unable to allocate + * enough memory to perform the requested operation. + */ + NV_ENC_ERR_OUT_OF_MEMORY, + + /** + * This indicates that the encoder has not been initialized with + * ::NvEncInitializeEncoder() or that initialization has failed. + * The client cannot allocate input or output buffers or do any encoding + * related operation before successfully initializing the encoder. + */ + NV_ENC_ERR_ENCODER_NOT_INITIALIZED, + + /** + * This indicates that an unsupported parameter was passed by the client. + */ + NV_ENC_ERR_UNSUPPORTED_PARAM, + + /** + * This indicates that the ::NvEncLockBitstream() failed to lock the output + * buffer. This happens when the client makes a non blocking lock call to + * access the output bitstream by passing NV_ENC_LOCK_BITSTREAM::doNotWait flag. + * This is not a fatal error and client should retry the same operation after + * few milliseconds. + */ + NV_ENC_ERR_LOCK_BUSY, + + /** + * This indicates that the size of the user buffer passed by the client is + * insufficient for the requested operation. + */ + NV_ENC_ERR_NOT_ENOUGH_BUFFER, + + /** + * This indicates that an invalid struct version was used by the client. + */ + NV_ENC_ERR_INVALID_VERSION, + + /** + * This indicates that ::NvEncMapInputResource() API failed to map the client + * provided input resource. + */ + NV_ENC_ERR_MAP_FAILED, + + /** + * This indicates encode driver requires more input buffers to produce an output + * bitstream. If this error is returned from ::NvEncEncodePicture() API, this + * is not a fatal error. If the client is encoding with B frames then, + * ::NvEncEncodePicture() API might be buffering the input frame for re-ordering. + * + * A client operating in synchronous mode cannot call ::NvEncLockBitstream() + * API on the output bitstream buffer if ::NvEncEncodePicture() returned the + * ::NV_ENC_ERR_NEED_MORE_INPUT error code. + * The client must continue providing input frames until encode driver returns + * ::NV_ENC_SUCCESS. After receiving ::NV_ENC_SUCCESS status the client can call + * ::NvEncLockBitstream() API on the output buffers in the same order in which + * it has called ::NvEncEncodePicture(). + */ + NV_ENC_ERR_NEED_MORE_INPUT, + + /** + * This indicates that the HW encoder is busy encoding and is unable to encode + * the input. The client should call ::NvEncEncodePicture() again after few + * milliseconds. + */ + NV_ENC_ERR_ENCODER_BUSY, + + /** + * This indicates that the completion event passed in ::NvEncEncodePicture() + * API has not been registered with encoder driver using ::NvEncRegisterAsyncEvent(). + */ + NV_ENC_ERR_EVENT_NOT_REGISTERD, + + /** + * This indicates that an unknown internal error has occurred. + */ + NV_ENC_ERR_GENERIC, + + /** + * This indicates that the client is attempting to use a feature + * that is not available for the license type for the current system. + */ + NV_ENC_ERR_INCOMPATIBLE_CLIENT_KEY, + + /** + * This indicates that the client is attempting to use a feature + * that is not implemented for the current version. + */ + NV_ENC_ERR_UNIMPLEMENTED, + + /** + * This indicates that the ::NvEncRegisterResource API failed to register the resource. + */ + NV_ENC_ERR_RESOURCE_REGISTER_FAILED, + + /** + * This indicates that the client is attempting to unregister a resource + * that has not been successfully registered. + */ + NV_ENC_ERR_RESOURCE_NOT_REGISTERED, + + /** + * This indicates that the client is attempting to unmap a resource + * that has not been successfully mapped. + */ + NV_ENC_ERR_RESOURCE_NOT_MAPPED, + + /** + * This indicates encode driver requires more output buffers to write an output + * bitstream. If this error is returned from ::NvEncRestoreEncoderState() API, this + * is not a fatal error. If the client is encoding with B frames then, + * ::NvEncRestoreEncoderState() API might be requiring the extra output buffer for accomodating overlay frame output in a separate buffer, for AV1 codec. + * In this case, client must call NvEncRestoreEncoderState() API again with NV_ENC_RESTORE_ENCODER_STATE_PARAMS::outputBitstream as input along with + * the parameters in the previous call. When operating in asynchronous mode of encoding, client must also specify NV_ENC_RESTORE_ENCODER_STATE_PARAMS::completionEvent. + */ + NV_ENC_ERR_NEED_MORE_OUTPUT, + +} NVENCSTATUS; + +/** + * Encode Picture encode flags. + */ +typedef enum _NV_ENC_PIC_FLAGS +{ + NV_ENC_PIC_FLAG_FORCEINTRA = 0x1, /**< Encode the current picture as an Intra picture */ + NV_ENC_PIC_FLAG_FORCEIDR = 0x2, /**< Encode the current picture as an IDR picture. + This flag is only valid when Picture type decision is taken by the Encoder + [_NV_ENC_INITIALIZE_PARAMS::enablePTD == 1]. */ + NV_ENC_PIC_FLAG_OUTPUT_SPSPPS = 0x4, /**< Write the sequence and picture header in encoded bitstream of the current picture */ + NV_ENC_PIC_FLAG_EOS = 0x8, /**< Indicates end of the input stream */ + NV_ENC_PIC_FLAG_DISABLE_ENC_STATE_ADVANCE = 0x10, /**< Do not advance encoder state during encode */ + NV_ENC_PIC_FLAG_OUTPUT_RECON_FRAME = 0x20, /**< Write reconstructed frame */ + NV_ENC_PIC_FLAG_PREQPDELTAMINQP = 0x40, /**< NV_ENC_RC_PARAMS::minQP values are to be applied to the pre-qpdeltamap internal RC QP values */ + NV_ENC_PIC_FLAG_PREQPDELTAMAXQP = 0x80, /**< NV_ENC_RC_PARAMS::maxQP values are to be applied to the pre-qpdeltamap internal RC QP values */ +} NV_ENC_PIC_FLAGS; + +/** + * Memory heap to allocate input and output buffers. + */ +typedef enum _NV_ENC_MEMORY_HEAP +{ + NV_ENC_MEMORY_HEAP_AUTOSELECT = 0, /**< Memory heap to be decided by the encoder driver based on the usage */ + NV_ENC_MEMORY_HEAP_VID = 1, /**< Memory heap is in local video memory */ + NV_ENC_MEMORY_HEAP_SYSMEM_CACHED = 2, /**< Memory heap is in cached system memory */ + NV_ENC_MEMORY_HEAP_SYSMEM_UNCACHED = 3 /**< Memory heap is in uncached system memory */ +} NV_ENC_MEMORY_HEAP; + +/** + * B-frame used as reference modes + */ +typedef enum _NV_ENC_BFRAME_REF_MODE +{ + NV_ENC_BFRAME_REF_MODE_DISABLED = 0x0, /**< B frame is not used for reference */ + NV_ENC_BFRAME_REF_MODE_EACH = 0x1, /**< Each B-frame will be used for reference */ + NV_ENC_BFRAME_REF_MODE_MIDDLE = 0x2, /**< For H.264 and HEVC, the (N/2)th B-frame will be used for reference where N = number of B-frames. + In case N is odd, the ((N-1)/2)th B-frame will be used for reference. + For AV1, every other B-frame will be used as an Altref2 reference, except the last B-frame + in the Altref interval. */ + NV_ENC_BFRAME_REF_MODE_HIERARCHICAL = 0x4, /**< Tree-like referencing structure with all B-frames used for reference except leaves. + This mode is supported only if: + * NV_ENC_INITIALIZE_PARAMS::enablePTD is set to 1 + * NV_ENC_CONFIG::frameIntervalP is in the form of 2^n for n in {0,...,5} + * NV_ENC_RC_PARAMS::enableLookahead is disabled or NV_ENC_RC_PARAMS::lookaheadLevel is set to NV_ENC_LOOKAHEAD_LEVEL_0 + * NV_ENC_RC_PARAMS::multiPass is disabled (NV_ENC_MULTI_PASS_DISABLED) + * NV_ENC_RC_PARAMS::disableIadapt and NV_ENC_RC_PARAMS::disableBadapt should be set + * NV_ENC_INITIALIZE_PARAMS::splitEncodeMode should be disabled, + either implicitly (NV_ENC_SPLIT_AUTO_MODE) or explicitly (NV_ENC_SPLIT_DISABLE_MODE)*/ +} NV_ENC_BFRAME_REF_MODE; + +/** + * H.264 entropy coding modes. + */ +typedef enum _NV_ENC_H264_ENTROPY_CODING_MODE +{ + NV_ENC_H264_ENTROPY_CODING_MODE_AUTOSELECT = 0x0, /**< Entropy coding mode is auto selected by the encoder driver */ + NV_ENC_H264_ENTROPY_CODING_MODE_CABAC = 0x1, /**< Entropy coding mode is CABAC */ + NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC = 0x2 /**< Entropy coding mode is CAVLC */ +} NV_ENC_H264_ENTROPY_CODING_MODE; + +/** + * H.264 specific BDirect modes + */ +typedef enum _NV_ENC_H264_BDIRECT_MODE +{ + NV_ENC_H264_BDIRECT_MODE_AUTOSELECT = 0x0, /**< BDirect mode is auto selected by the encoder driver */ + NV_ENC_H264_BDIRECT_MODE_DISABLE = 0x1, /**< Disable BDirect mode */ + NV_ENC_H264_BDIRECT_MODE_TEMPORAL = 0x2, /**< Temporal BDirect mode */ + NV_ENC_H264_BDIRECT_MODE_SPATIAL = 0x3 /**< Spatial BDirect mode */ +} NV_ENC_H264_BDIRECT_MODE; + +/** + * H.264 specific FMO usage + */ +typedef enum _NV_ENC_H264_FMO_MODE +{ + NV_ENC_H264_FMO_AUTOSELECT = 0x0, /**< FMO usage is auto selected by the encoder driver */ + NV_ENC_H264_FMO_ENABLE = 0x1, /**< Enable FMO */ + NV_ENC_H264_FMO_DISABLE = 0x2, /**< Disable FMO */ +} NV_ENC_H264_FMO_MODE; + +/** + * H.264 specific Adaptive Transform modes + */ +typedef enum _NV_ENC_H264_ADAPTIVE_TRANSFORM_MODE +{ + NV_ENC_H264_ADAPTIVE_TRANSFORM_AUTOSELECT = 0x0, /**< Adaptive Transform 8x8 mode is auto selected by the encoder driver*/ + NV_ENC_H264_ADAPTIVE_TRANSFORM_DISABLE = 0x1, /**< Adaptive Transform 8x8 mode disabled */ + NV_ENC_H264_ADAPTIVE_TRANSFORM_ENABLE = 0x2, /**< Adaptive Transform 8x8 mode should be used */ +} NV_ENC_H264_ADAPTIVE_TRANSFORM_MODE; + +/** + * Stereo frame packing modes. + */ +typedef enum _NV_ENC_STEREO_PACKING_MODE +{ + NV_ENC_STEREO_PACKING_MODE_NONE = 0x0, /**< No Stereo packing required */ + NV_ENC_STEREO_PACKING_MODE_CHECKERBOARD = 0x1, /**< Checkerboard mode for packing stereo frames */ + NV_ENC_STEREO_PACKING_MODE_COLINTERLEAVE = 0x2, /**< Column Interleave mode for packing stereo frames */ + NV_ENC_STEREO_PACKING_MODE_ROWINTERLEAVE = 0x3, /**< Row Interleave mode for packing stereo frames */ + NV_ENC_STEREO_PACKING_MODE_SIDEBYSIDE = 0x4, /**< Side-by-side mode for packing stereo frames */ + NV_ENC_STEREO_PACKING_MODE_TOPBOTTOM = 0x5, /**< Top-Bottom mode for packing stereo frames */ + NV_ENC_STEREO_PACKING_MODE_FRAMESEQ = 0x6 /**< Frame Sequential mode for packing stereo frames */ +} NV_ENC_STEREO_PACKING_MODE; + +/** + * Input Resource type + */ +typedef enum _NV_ENC_INPUT_RESOURCE_TYPE +{ + NV_ENC_INPUT_RESOURCE_TYPE_DIRECTX = 0x0, /**< input resource type is a directx9 surface*/ + NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR = 0x1, /**< input resource type is a cuda device pointer surface*/ + NV_ENC_INPUT_RESOURCE_TYPE_CUDAARRAY = 0x2, /**< input resource type is a cuda array surface. + This array must be a 2D array and the CUDA_ARRAY3D_SURFACE_LDST + flag must have been specified when creating it. */ + NV_ENC_INPUT_RESOURCE_TYPE_OPENGL_TEX = 0x3 /**< input resource type is an OpenGL texture */ +} NV_ENC_INPUT_RESOURCE_TYPE; + +/** + * Buffer usage + */ +typedef enum _NV_ENC_BUFFER_USAGE +{ + NV_ENC_INPUT_IMAGE = 0x0, /**< Registered surface will be used for input image */ + NV_ENC_OUTPUT_MOTION_VECTOR = 0x1, /**< Registered surface will be used for output of H.264 ME only mode. + This buffer usage type is not supported for HEVC ME only mode. */ + NV_ENC_OUTPUT_BITSTREAM = 0x2, /**< Registered surface will be used for output bitstream in encoding */ + NV_ENC_OUTPUT_RECON = 0x4, /**< Registered surface will be used for output reconstructed frame in encoding */ +} NV_ENC_BUFFER_USAGE; + +/** + * Encoder Device type + */ +typedef enum _NV_ENC_DEVICE_TYPE +{ + NV_ENC_DEVICE_TYPE_DIRECTX = 0x0, /**< encode device type is a directx9 device */ + NV_ENC_DEVICE_TYPE_CUDA = 0x1, /**< encode device type is a cuda device */ + NV_ENC_DEVICE_TYPE_OPENGL = 0x2 /**< encode device type is an OpenGL device. + Use of this device type is supported only on Linux */ +} NV_ENC_DEVICE_TYPE; + +/** + * Number of reference frames + */ +typedef enum _NV_ENC_NUM_REF_FRAMES +{ + NV_ENC_NUM_REF_FRAMES_AUTOSELECT = 0x0, /**< Number of reference frames is auto selected by the encoder driver */ + NV_ENC_NUM_REF_FRAMES_1 = 0x1, /**< Number of reference frames equal to 1 */ + NV_ENC_NUM_REF_FRAMES_2 = 0x2, /**< Number of reference frames equal to 2 */ + NV_ENC_NUM_REF_FRAMES_3 = 0x3, /**< Number of reference frames equal to 3 */ + NV_ENC_NUM_REF_FRAMES_4 = 0x4, /**< Number of reference frames equal to 4 */ + NV_ENC_NUM_REF_FRAMES_5 = 0x5, /**< Number of reference frames equal to 5 */ + NV_ENC_NUM_REF_FRAMES_6 = 0x6, /**< Number of reference frames equal to 6 */ + NV_ENC_NUM_REF_FRAMES_7 = 0x7 /**< Number of reference frames equal to 7 */ +} NV_ENC_NUM_REF_FRAMES; + +/** +* Enum for Temporal filtering level. +*/ +typedef enum _NV_ENC_TEMPORAL_FILTER_LEVEL +{ + NV_ENC_TEMPORAL_FILTER_LEVEL_0 = 0, + NV_ENC_TEMPORAL_FILTER_LEVEL_4 = 4, +}NV_ENC_TEMPORAL_FILTER_LEVEL; +/** + * Encoder capabilities enumeration. + */ +typedef enum _NV_ENC_CAPS +{ + /** + * Maximum number of B-Frames supported. + */ + NV_ENC_CAPS_NUM_MAX_BFRAMES, + + /** + * Rate control modes supported. + * \n The API return value is a bitmask of the values in NV_ENC_PARAMS_RC_MODE. + */ + NV_ENC_CAPS_SUPPORTED_RATECONTROL_MODES, + + /** + * Indicates HW support for field mode encoding. + * \n 0 : Interlaced mode encoding is not supported. + * \n 1 : Interlaced field mode encoding is supported. + * \n 2 : Interlaced frame encoding and field mode encoding are both supported. + */ + NV_ENC_CAPS_SUPPORT_FIELD_ENCODING, + + /** + * Indicates HW support for monochrome mode encoding. + * \n 0 : Monochrome mode not supported. + * \n 1 : Monochrome mode supported. + */ + NV_ENC_CAPS_SUPPORT_MONOCHROME, + + /** + * Indicates HW support for FMO. + * \n 0 : FMO not supported. + * \n 1 : FMO supported. + */ + NV_ENC_CAPS_SUPPORT_FMO, + + /** + * Indicates HW capability for Quarter pel motion estimation. + * \n 0 : Quarter-Pel Motion Estimation not supported. + * \n 1 : Quarter-Pel Motion Estimation supported. + */ + NV_ENC_CAPS_SUPPORT_QPELMV, + + /** + * H.264 specific. Indicates HW support for BDirect modes. + * \n 0 : BDirect mode encoding not supported. + * \n 1 : BDirect mode encoding supported. + */ + NV_ENC_CAPS_SUPPORT_BDIRECT_MODE, + + /** + * H264 specific. Indicates HW support for CABAC entropy coding mode. + * \n 0 : CABAC entropy coding not supported. + * \n 1 : CABAC entropy coding supported. + */ + NV_ENC_CAPS_SUPPORT_CABAC, + + /** + * Indicates HW support for Adaptive Transform. + * \n 0 : Adaptive Transform not supported. + * \n 1 : Adaptive Transform supported. + */ + NV_ENC_CAPS_SUPPORT_ADAPTIVE_TRANSFORM, + + /** + * Indicates HW support for Multi View Coding. + * \n 0 : Multi View Coding not supported. + * \n 1 : Multi View Coding supported. + */ + NV_ENC_CAPS_SUPPORT_STEREO_MVC, + + /** + * Indicates HW support for encoding Temporal layers. + * \n 0 : Encoding Temporal layers not supported. + * \n 1 : Encoding Temporal layers supported. + */ + NV_ENC_CAPS_NUM_MAX_TEMPORAL_LAYERS, + + /** + * Indicates HW support for Hierarchical P frames. + * \n 0 : Hierarchical P frames not supported. + * \n 1 : Hierarchical P frames supported. + */ + NV_ENC_CAPS_SUPPORT_HIERARCHICAL_PFRAMES, + + /** + * Indicates HW support for Hierarchical B frames. + * \n 0 : Hierarchical B frames not supported. + * \n 1 : Hierarchical B frames supported. + */ + NV_ENC_CAPS_SUPPORT_HIERARCHICAL_BFRAMES, + + /** + * Maximum Encoding level supported (See ::NV_ENC_LEVEL for details). + */ + NV_ENC_CAPS_LEVEL_MAX, + + /** + * Minimum Encoding level supported (See ::NV_ENC_LEVEL for details). + */ + NV_ENC_CAPS_LEVEL_MIN, + + /** + * Indicates HW support for separate colour plane encoding. + * \n 0 : Separate colour plane encoding not supported. + * \n 1 : Separate colour plane encoding supported. + */ + NV_ENC_CAPS_SEPARATE_COLOUR_PLANE, + + /** + * Maximum output width supported. + */ + NV_ENC_CAPS_WIDTH_MAX, + + /** + * Maximum output height supported. + */ + NV_ENC_CAPS_HEIGHT_MAX, + + /** + * Indicates Temporal Scalability Support. + * \n 0 : Temporal SVC encoding not supported. + * \n 1 : Temporal SVC encoding supported. + */ + NV_ENC_CAPS_SUPPORT_TEMPORAL_SVC, + + /** + * Indicates Dynamic Encode Resolution Change Support. + * Support added from NvEncodeAPI version 2.0. + * \n 0 : Dynamic Encode Resolution Change not supported. + * \n 1 : Dynamic Encode Resolution Change supported. + */ + NV_ENC_CAPS_SUPPORT_DYN_RES_CHANGE, + + /** + * Indicates Dynamic Encode Bitrate Change Support. + * Support added from NvEncodeAPI version 2.0. + * \n 0 : Dynamic Encode bitrate change not supported. + * \n 1 : Dynamic Encode bitrate change supported. + */ + NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE, + + /** + * Indicates Forcing Constant QP On The Fly Support. + * Support added from NvEncodeAPI version 2.0. + * \n 0 : Forcing constant QP on the fly not supported. + * \n 1 : Forcing constant QP on the fly supported. + */ + NV_ENC_CAPS_SUPPORT_DYN_FORCE_CONSTQP, + + /** + * Indicates Dynamic rate control mode Change Support. + * \n 0 : Dynamic rate control mode change not supported. + * \n 1 : Dynamic rate control mode change supported. + */ + NV_ENC_CAPS_SUPPORT_DYN_RCMODE_CHANGE, + + /** + * Indicates Subframe readback support for slice-based encoding. If this feature is supported, it can be enabled by setting enableSubFrameWrite = 1. + * \n 0 : Subframe readback not supported. + * \n 1 : Subframe readback supported. + */ + NV_ENC_CAPS_SUPPORT_SUBFRAME_READBACK, + + /** + * Indicates Constrained Encoding mode support. + * Support added from NvEncodeAPI version 2.0. + * \n 0 : Constrained encoding mode not supported. + * \n 1 : Constrained encoding mode supported. + * If this mode is supported client can enable this during initialization. + * Client can then force a picture to be coded as constrained picture where + * in-loop filtering is disabled across slice boundaries and prediction vectors for inter + * macroblocks in each slice will be restricted to the slice region. + */ + NV_ENC_CAPS_SUPPORT_CONSTRAINED_ENCODING, + + /** + * Indicates Intra Refresh Mode Support. + * Support added from NvEncodeAPI version 2.0. + * \n 0 : Intra Refresh Mode not supported. + * \n 1 : Intra Refresh Mode supported. + */ + NV_ENC_CAPS_SUPPORT_INTRA_REFRESH, + + /** + * Indicates Custom VBV Buffer Size support. It can be used for capping frame size. + * Support added from NvEncodeAPI version 2.0. + * \n 0 : Custom VBV buffer size specification from client, not supported. + * \n 1 : Custom VBV buffer size specification from client, supported. + */ + NV_ENC_CAPS_SUPPORT_CUSTOM_VBV_BUF_SIZE, + + /** + * Indicates Dynamic Slice Mode Support. + * Support added from NvEncodeAPI version 2.0. + * \n 0 : Dynamic Slice Mode not supported. + * \n 1 : Dynamic Slice Mode supported. + */ + NV_ENC_CAPS_SUPPORT_DYNAMIC_SLICE_MODE, + + /** + * Indicates Reference Picture Invalidation Support. + * Support added from NvEncodeAPI version 2.0. + * \n 0 : Reference Picture Invalidation not supported. + * \n 1 : Reference Picture Invalidation supported. + */ + NV_ENC_CAPS_SUPPORT_REF_PIC_INVALIDATION, + + /** + * Indicates support for Pre-Processing. + * The API return value is a bitmask of the values defined in ::NV_ENC_PREPROC_FLAGS + */ + NV_ENC_CAPS_PREPROC_SUPPORT, + + /** + * Indicates support Async mode. + * \n 0 : Async Encode mode not supported. + * \n 1 : Async Encode mode supported. + */ + NV_ENC_CAPS_ASYNC_ENCODE_SUPPORT, + + /** + * Maximum MBs per frame supported. + */ + NV_ENC_CAPS_MB_NUM_MAX, + + /** + * Maximum aggregate throughput in MBs per sec. + */ + NV_ENC_CAPS_MB_PER_SEC_MAX, + + /** + * Indicates HW support for YUV444 mode encoding. + * \n 0 : YUV444 mode encoding not supported. + * \n 1 : YUV444 mode encoding supported. + */ + NV_ENC_CAPS_SUPPORT_YUV444_ENCODE, + + /** + * Indicates HW support for lossless encoding. + * \n 0 : lossless encoding not supported. + * \n 1 : lossless encoding supported. + */ + NV_ENC_CAPS_SUPPORT_LOSSLESS_ENCODE, + + /** + * Indicates HW support for Sample Adaptive Offset. + * \n 0 : SAO not supported. + * \n 1 : SAO encoding supported. + */ + NV_ENC_CAPS_SUPPORT_SAO, + + /** + * Indicates HW support for Motion Estimation Only Mode. + * \n 0 : MEOnly Mode not supported. + * \n 1 : MEOnly Mode supported for I and P frames. + * \n 2 : MEOnly Mode supported for I, P and B frames. + */ + NV_ENC_CAPS_SUPPORT_MEONLY_MODE, + + /** + * Indicates HW support for lookahead encoding (enableLookahead=1). + * \n 0 : Lookahead not supported. + * \n 1 : Lookahead supported. + */ + NV_ENC_CAPS_SUPPORT_LOOKAHEAD, + + /** + * Indicates HW support for temporal AQ encoding (enableTemporalAQ=1). + * \n 0 : Temporal AQ not supported. + * \n 1 : Temporal AQ supported. + */ + NV_ENC_CAPS_SUPPORT_TEMPORAL_AQ, + /** + * Indicates HW support for 10 bit encoding. + * \n 0 : 10 bit encoding not supported. + * \n 1 : 10 bit encoding supported. + */ + NV_ENC_CAPS_SUPPORT_10BIT_ENCODE, + /** + * Maximum number of Long Term Reference frames supported + */ + NV_ENC_CAPS_NUM_MAX_LTR_FRAMES, + + /** + * Indicates HW support for Weighted Prediction. + * \n 0 : Weighted Prediction not supported. + * \n 1 : Weighted Prediction supported. + */ + NV_ENC_CAPS_SUPPORT_WEIGHTED_PREDICTION, + + + /** + * On managed (vGPU) platforms (Windows only), this API, in conjunction with other GRID Management APIs, can be used + * to estimate the residual capacity of the hardware encoder on the GPU as a percentage of the total available encoder capacity. + * This API can be called at any time; i.e. during the encode session or before opening the encode session. + * If the available encoder capacity is returned as zero, applications may choose to switch to software encoding + * and continue to call this API (e.g. polling once per second) until capacity becomes available. + * + * On bare metal (non-virtualized GPU) and linux platforms, this API always returns 100. + */ + NV_ENC_CAPS_DYNAMIC_QUERY_ENCODER_CAPACITY, + + /** + * Indicates B as reference support. + * \n 0 : B as reference is not supported. + * \n 1 : each B-Frame as reference is supported. + * \n 2 : only Middle B-frame as reference is supported. + * \n 4 : only Hierarchical B-frame as reference is supported. + */ + NV_ENC_CAPS_SUPPORT_BFRAME_REF_MODE, + + /** + * Indicates HW support for Emphasis Level Map based delta QP computation. + * \n 0 : Emphasis Level Map based delta QP not supported. + * \n 1 : Emphasis Level Map based delta QP is supported. + */ + NV_ENC_CAPS_SUPPORT_EMPHASIS_LEVEL_MAP, + + /** + * Minimum input width supported. + */ + NV_ENC_CAPS_WIDTH_MIN, + + /** + * Minimum input height supported. + */ + NV_ENC_CAPS_HEIGHT_MIN, + + /** + * Indicates HW support for multiple reference frames. + */ + NV_ENC_CAPS_SUPPORT_MULTIPLE_REF_FRAMES, + + /** + * Indicates HW support for HEVC with alpha encoding. + * \n 0 : HEVC with alpha encoding not supported. + * \n 1 : HEVC with alpha encoding is supported. + */ + NV_ENC_CAPS_SUPPORT_ALPHA_LAYER_ENCODING, + + /** + * Indicates number of Encoding engines present on GPU. + */ + NV_ENC_CAPS_NUM_ENCODER_ENGINES, + + /** + * Indicates single slice intra refresh support. + */ + NV_ENC_CAPS_SINGLE_SLICE_INTRA_REFRESH, + + /** + * Indicates encoding without advancing the state support. + */ + NV_ENC_CAPS_DISABLE_ENC_STATE_ADVANCE, + + /** + * Indicates reconstructed output support. + */ + NV_ENC_CAPS_OUTPUT_RECON_SURFACE, + + /** + * Indicates encoded frame output stats support for every block. Block represents a CTB for HEVC, macroblock for H.264 and super block for AV1. + */ + NV_ENC_CAPS_OUTPUT_BLOCK_STATS, + + /** + * Indicates encoded frame output stats support for every row. Row represents a CTB row for HEVC, macroblock row for H.264 and super block row for AV1. + */ + NV_ENC_CAPS_OUTPUT_ROW_STATS, + + + /** + * Indicates temporal filtering support. + */ + NV_ENC_CAPS_SUPPORT_TEMPORAL_FILTER, + + /** + * Maximum Lookahead level supported (See ::NV_ENC_LOOKAHEAD_LEVEL for details). + */ + NV_ENC_CAPS_SUPPORT_LOOKAHEAD_LEVEL, + + /** + * Indicates UnidirectionalB support. + */ + NV_ENC_CAPS_SUPPORT_UNIDIRECTIONAL_B, + + /** + * Indicates HW support for MVHEVC encoding. + * \n 0 : MVHEVC encoding not supported. + * \n 1 : MVHEVC encoding supported. + */ + NV_ENC_CAPS_SUPPORT_MVHEVC_ENCODE, + + /** + * Indicates HW support for YUV422 mode encoding. + * \n 0 : YUV422 mode encoding not supported. + * \n 1 : YUV422 mode encoding supported. + */ + NV_ENC_CAPS_SUPPORT_YUV422_ENCODE, + + /** + * Reserved - Not to be used by clients. + */ + NV_ENC_CAPS_EXPOSED_COUNT + +} NV_ENC_CAPS; + +/** + * HEVC CU SIZE + */ +typedef enum _NV_ENC_HEVC_CUSIZE +{ + NV_ENC_HEVC_CUSIZE_AUTOSELECT = 0, + NV_ENC_HEVC_CUSIZE_8x8 = 1, + NV_ENC_HEVC_CUSIZE_16x16 = 2, + NV_ENC_HEVC_CUSIZE_32x32 = 3, + NV_ENC_HEVC_CUSIZE_64x64 = 4, +} NV_ENC_HEVC_CUSIZE; + +/** +* AV1 PART SIZE +*/ +typedef enum _NV_ENC_AV1_PART_SIZE +{ + NV_ENC_AV1_PART_SIZE_AUTOSELECT = 0, + NV_ENC_AV1_PART_SIZE_4x4 = 1, + NV_ENC_AV1_PART_SIZE_8x8 = 2, + NV_ENC_AV1_PART_SIZE_16x16 = 3, + NV_ENC_AV1_PART_SIZE_32x32 = 4, + NV_ENC_AV1_PART_SIZE_64x64 = 5, +} NV_ENC_AV1_PART_SIZE; + +/** +* Enums related to fields in VUI parameters. +*/ +typedef enum _NV_ENC_VUI_VIDEO_FORMAT +{ + NV_ENC_VUI_VIDEO_FORMAT_COMPONENT = 0, + NV_ENC_VUI_VIDEO_FORMAT_PAL = 1, + NV_ENC_VUI_VIDEO_FORMAT_NTSC = 2, + NV_ENC_VUI_VIDEO_FORMAT_SECAM = 3, + NV_ENC_VUI_VIDEO_FORMAT_MAC = 4, + NV_ENC_VUI_VIDEO_FORMAT_UNSPECIFIED = 5, +} NV_ENC_VUI_VIDEO_FORMAT; + +typedef enum _NV_ENC_VUI_COLOR_PRIMARIES +{ + NV_ENC_VUI_COLOR_PRIMARIES_UNDEFINED = 0, + NV_ENC_VUI_COLOR_PRIMARIES_BT709 = 1, + NV_ENC_VUI_COLOR_PRIMARIES_UNSPECIFIED = 2, + NV_ENC_VUI_COLOR_PRIMARIES_RESERVED = 3, + NV_ENC_VUI_COLOR_PRIMARIES_BT470M = 4, + NV_ENC_VUI_COLOR_PRIMARIES_BT470BG = 5, + NV_ENC_VUI_COLOR_PRIMARIES_SMPTE170M = 6, + NV_ENC_VUI_COLOR_PRIMARIES_SMPTE240M = 7, + NV_ENC_VUI_COLOR_PRIMARIES_FILM = 8, + NV_ENC_VUI_COLOR_PRIMARIES_BT2020 = 9, + NV_ENC_VUI_COLOR_PRIMARIES_SMPTE428 = 10, + NV_ENC_VUI_COLOR_PRIMARIES_SMPTE431 = 11, + NV_ENC_VUI_COLOR_PRIMARIES_SMPTE432 = 12, + NV_ENC_VUI_COLOR_PRIMARIES_JEDEC_P22 = 22, +} NV_ENC_VUI_COLOR_PRIMARIES; + +typedef enum _NV_ENC_VUI_TRANSFER_CHARACTERISTIC +{ + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_UNDEFINED = 0, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_BT709 = 1, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_UNSPECIFIED = 2, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_RESERVED = 3, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_BT470M = 4, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_BT470BG = 5, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_SMPTE170M = 6, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_SMPTE240M = 7, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_LINEAR = 8, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_LOG = 9, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_LOG_SQRT = 10, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_IEC61966_2_4 = 11, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_BT1361_ECG = 12, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_SRGB = 13, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_BT2020_10 = 14, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_BT2020_12 = 15, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_SMPTE2084 = 16, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_SMPTE428 = 17, + NV_ENC_VUI_TRANSFER_CHARACTERISTIC_ARIB_STD_B67 = 18, +} NV_ENC_VUI_TRANSFER_CHARACTERISTIC; + +typedef enum _NV_ENC_VUI_MATRIX_COEFFS +{ + NV_ENC_VUI_MATRIX_COEFFS_RGB = 0, + NV_ENC_VUI_MATRIX_COEFFS_BT709 = 1, + NV_ENC_VUI_MATRIX_COEFFS_UNSPECIFIED = 2, + NV_ENC_VUI_MATRIX_COEFFS_RESERVED = 3, + NV_ENC_VUI_MATRIX_COEFFS_FCC = 4, + NV_ENC_VUI_MATRIX_COEFFS_BT470BG = 5, + NV_ENC_VUI_MATRIX_COEFFS_SMPTE170M = 6, + NV_ENC_VUI_MATRIX_COEFFS_SMPTE240M = 7, + NV_ENC_VUI_MATRIX_COEFFS_YCGCO = 8, + NV_ENC_VUI_MATRIX_COEFFS_BT2020_NCL = 9, + NV_ENC_VUI_MATRIX_COEFFS_BT2020_CL = 10, + NV_ENC_VUI_MATRIX_COEFFS_SMPTE2085 = 11, +} NV_ENC_VUI_MATRIX_COEFFS; + + +/** +* Enum for Lookahead level. +*/ +typedef enum _NV_ENC_LOOKAHEAD_LEVEL +{ + NV_ENC_LOOKAHEAD_LEVEL_0 = 0, + NV_ENC_LOOKAHEAD_LEVEL_1 = 1, + NV_ENC_LOOKAHEAD_LEVEL_2 = 2, + NV_ENC_LOOKAHEAD_LEVEL_3 = 3, + NV_ENC_LOOKAHEAD_LEVEL_AUTOSELECT = 15, +} NV_ENC_LOOKAHEAD_LEVEL; + +/** +* Enum for Bit Depth +*/ +typedef enum _NV_ENC_BIT_DEPTH +{ + NV_ENC_BIT_DEPTH_INVALID = 0, /**< Invalid Bit Depth */ + NV_ENC_BIT_DEPTH_8 = 8, /**< Bit Depth 8 */ + NV_ENC_BIT_DEPTH_10 = 10, /**< Bit Depth 10 */ +} NV_ENC_BIT_DEPTH; + +/** + * Input struct for querying Encoding capabilities. + */ +typedef struct _NV_ENC_CAPS_PARAM +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_CAPS_PARAM_VER */ + NV_ENC_CAPS capsToQuery; /**< [in]: Specifies the encode capability to be queried. Client should pass a member for ::NV_ENC_CAPS enum. */ + uint32_t reserved[62]; /**< [in]: Reserved and must be set to 0 */ +} NV_ENC_CAPS_PARAM; + +/** NV_ENC_CAPS_PARAM struct version. */ +#define NV_ENC_CAPS_PARAM_VER NVENCAPI_STRUCT_VERSION(1) + + +/** + * Restore encoder state parameters + */ +typedef struct _NV_ENC_RESTORE_ENCODER_STATE_PARAMS +{ + uint32_t version; /**< [in]: Struct version. */ + uint32_t bufferIdx; /**< [in]: State buffer index to which the encoder state will be restored */ + NV_ENC_STATE_RESTORE_TYPE state; /**< [in]: State type to restore */ + uint32_t reserved; /**< [in]: Reserved and must be set to 0 */ + NV_ENC_OUTPUT_PTR outputBitstream; /**< [in]: Specifies the output buffer pointer, for AV1 encode only. + Application must call NvEncRestoreEncoderState() API with _NV_ENC_RESTORE_ENCODER_STATE_PARAMS::outputBitstream and + _NV_ENC_RESTORE_ENCODER_STATE_PARAMS::completionEvent as input when an earlier call to this API returned "NV_ENC_ERR_NEED_MORE_OUTPUT", for AV1 encode. */ + void* completionEvent; /**< [in]: Specifies the completion event when asynchronous mode of encoding is enabled. Used for AV1 encode only. */ + uint32_t reserved1[64]; /**< [in]: Reserved and must be set to 0 */ + void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_RESTORE_ENCODER_STATE_PARAMS; + +/** NV_ENC_RESTORE_ENCODER_STATE_PARAMS struct version. */ +#define NV_ENC_RESTORE_ENCODER_STATE_PARAMS_VER NVENCAPI_STRUCT_VERSION(2) + +/** + * Encoded frame information parameters for every block. + */ +typedef struct _NV_ENC_OUTPUT_STATS_BLOCK +{ + uint32_t version; /**< [in]: Struct version */ + uint8_t QP; /**< [out]: QP of the block */ + uint8_t reserved[3]; /**< [in]: Reserved and must be set to 0 */ + uint32_t bitcount; /**< [out]: Bitcount of the block */ + uint32_t satdCost; /**< [out]: SATD cost of the residual error */ + uint32_t reserved1[12]; /**< [in]: Reserved and must be set to 0 */ +} NV_ENC_OUTPUT_STATS_BLOCK; + +/** NV_ENC_OUTPUT_STATS_BLOCK struct version. */ +#define NV_ENC_OUTPUT_STATS_BLOCK_VER NVENCAPI_STRUCT_VERSION(1) + +/** + * Encoded frame information parameters for every row. + */ +typedef struct _NV_ENC_OUTPUT_STATS_ROW +{ + uint32_t version; /**< [in]: Struct version */ + uint8_t QP; /**< [out]: QP of the row */ + uint8_t reserved[3]; /**< [in]: Reserved and must be set to 0 */ + uint32_t bitcount; /**< [out]: Bitcount of the row */ + uint32_t satdCost; /**< [out]: SATD cost of the residual error */ + uint32_t reserved1[12]; /**< [in]: Reserved and must be set to 0 */ +} NV_ENC_OUTPUT_STATS_ROW; + +/** NV_ENC_OUTPUT_STATS_ROW struct version. */ +#define NV_ENC_OUTPUT_STATS_ROW_VER NVENCAPI_STRUCT_VERSION(1) + +/** + * Encoder Output parameters + */ +typedef struct _NV_ENC_ENCODE_OUT_PARAMS +{ + uint32_t version; /**< [out]: Struct version. */ + uint32_t bitstreamSizeInBytes; /**< [out]: Encoded bitstream size in bytes */ + uint32_t reserved[62]; /**< [out]: Reserved and must be set to 0 */ +} NV_ENC_ENCODE_OUT_PARAMS; + +/** NV_ENC_ENCODE_OUT_PARAMS struct version. */ +#define NV_ENC_ENCODE_OUT_PARAMS_VER NVENCAPI_STRUCT_VERSION(1) + +/** + * Lookahead picture parameters + */ +typedef struct _NV_ENC_LOOKAHEAD_PIC_PARAMS +{ + uint32_t version; /**< [in]: Struct version. */ + uint32_t reserved; /**< [in]: Reserved and must be set to 0 */ + NV_ENC_INPUT_PTR inputBuffer; /**< [in]: Specifies the input buffer pointer. Client must use a pointer obtained from ::NvEncCreateInputBuffer() or ::NvEncMapInputResource() APIs.*/ + NV_ENC_PIC_TYPE pictureType; /**< [in]: Specifies input picture type. Client required to be set explicitly by the client if the client has not set NV_ENC_INITIALIZE_PARAMS::enablePTD to 1 while calling NvEncInitializeEncoder. */ + NV_ENC_BUFFER_FORMAT bufferFmt; /**< [in]: Specifies the input buffer format. */ + uint32_t encodePicFlags; /**< [in]: Specifies bit-wise OR of encode picture flags used for the corresponding EncodePicture call. See ::NV_ENC_PIC_FLAGS enum. */ + uint32_t reserved1[61]; /**< [in]: Reserved and must be set to 0 */ + void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_LOOKAHEAD_PIC_PARAMS; + +/** NV_ENC_LOOKAHEAD_PIC_PARAMS struct version. */ +#define NV_ENC_LOOKAHEAD_PIC_PARAMS_VER NVENCAPI_STRUCT_VERSION(2) + +/** + * Creation parameters for input buffer. + */ +typedef struct _NV_ENC_CREATE_INPUT_BUFFER +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_CREATE_INPUT_BUFFER_VER */ + uint32_t width; /**< [in]: Input frame width */ + uint32_t height; /**< [in]: Input frame height */ + NV_ENC_MEMORY_HEAP memoryHeap; /**< [in]: Deprecated. Do not use */ + NV_ENC_BUFFER_FORMAT bufferFmt; /**< [in]: Input buffer format */ + uint32_t reserved; /**< [in]: Reserved and must be set to 0 */ + NV_ENC_INPUT_PTR inputBuffer; /**< [out]: Pointer to input buffer */ + void* pSysMemBuffer; /**< [in]: Pointer to existing system memory buffer */ + uint32_t reserved1[58]; /**< [in]: Reserved and must be set to 0 */ + void* reserved2[63]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_CREATE_INPUT_BUFFER; + +/** NV_ENC_CREATE_INPUT_BUFFER struct version. */ +#define NV_ENC_CREATE_INPUT_BUFFER_VER NVENCAPI_STRUCT_VERSION(2) + +/** + * Creation parameters for output bitstream buffer. + */ +typedef struct _NV_ENC_CREATE_BITSTREAM_BUFFER +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_CREATE_BITSTREAM_BUFFER_VER */ + uint32_t size; /**< [in]: Deprecated. Do not use */ + NV_ENC_MEMORY_HEAP memoryHeap; /**< [in]: Deprecated. Do not use */ + uint32_t reserved; /**< [in]: Reserved and must be set to 0 */ + NV_ENC_OUTPUT_PTR bitstreamBuffer; /**< [out]: Pointer to the output bitstream buffer */ + void* bitstreamBufferPtr; /**< [out]: Reserved and should not be used */ + uint32_t reserved1[58]; /**< [in]: Reserved and should be set to 0 */ + void* reserved2[64]; /**< [in]: Reserved and should be set to NULL */ +} NV_ENC_CREATE_BITSTREAM_BUFFER; + +/** NV_ENC_CREATE_BITSTREAM_BUFFER struct version. */ +#define NV_ENC_CREATE_BITSTREAM_BUFFER_VER NVENCAPI_STRUCT_VERSION(1) + +/** + * Structs needed for ME only mode. + */ +typedef struct _NV_ENC_MVECTOR +{ + int16_t mvx; /**< the x component of MV in quarter-pel units */ + int16_t mvy; /**< the y component of MV in quarter-pel units */ +} NV_ENC_MVECTOR; + +/** + * Motion vector structure per macroblock for H264 motion estimation. + */ +typedef struct _NV_ENC_H264_MV_DATA +{ + NV_ENC_MVECTOR mv[4]; /**< up to 4 vectors for 8x8 partition */ + uint8_t mbType; /**< 0 (I), 1 (P), 2 (IPCM), 3 (B) */ + uint8_t partitionType; /**< Specifies the block partition type. 0:16x16, 1:8x8, 2:16x8, 3:8x16 */ + uint16_t reserved; /**< reserved padding for alignment */ + uint32_t mbCost; +} NV_ENC_H264_MV_DATA; + +/** + * Motion vector structure per CU for HEVC motion estimation. + */ +typedef struct _NV_ENC_HEVC_MV_DATA +{ + NV_ENC_MVECTOR mv[4]; /**< up to 4 vectors within a CU */ + uint8_t cuType; /**< 0 (I), 1(P) */ + uint8_t cuSize; /**< 0: 8x8, 1: 16x16, 2: 32x32, 3: 64x64 */ + uint8_t partitionMode; /**< The CU partition mode + 0 (2Nx2N), 1 (2NxN), 2(Nx2N), 3 (NxN), + 4 (2NxnU), 5 (2NxnD), 6(nLx2N), 7 (nRx2N) */ + uint8_t lastCUInCTB; /**< Marker to separate CUs in the current CTB from CUs in the next CTB */ +} NV_ENC_HEVC_MV_DATA; + +/** + * Creation parameters for output motion vector buffer for ME only mode. + */ +typedef struct _NV_ENC_CREATE_MV_BUFFER +{ + uint32_t version; /**< [in]: Struct version. Must be set to NV_ENC_CREATE_MV_BUFFER_VER */ + uint32_t reserved; /**< [in]: Reserved and should be set to 0 */ + NV_ENC_OUTPUT_PTR mvBuffer; /**< [out]: Pointer to the output motion vector buffer */ + uint32_t reserved1[254]; /**< [in]: Reserved and should be set to 0 */ + void* reserved2[63]; /**< [in]: Reserved and should be set to NULL */ +} NV_ENC_CREATE_MV_BUFFER; + +/** NV_ENC_CREATE_MV_BUFFER struct version*/ +#define NV_ENC_CREATE_MV_BUFFER_VER NVENCAPI_STRUCT_VERSION(2) + +/** + * QP value for frames + */ +typedef struct _NV_ENC_QP +{ + uint32_t qpInterP; /**< [in]: Specifies QP value for P-frame. Even though this field is uint32_t for legacy reasons, the client should treat this as a signed parameter(int32_t) for cases in which negative QP values are to be specified. */ + uint32_t qpInterB; /**< [in]: Specifies QP value for B-frame. Even though this field is uint32_t for legacy reasons, the client should treat this as a signed parameter(int32_t) for cases in which negative QP values are to be specified. */ + uint32_t qpIntra; /**< [in]: Specifies QP value for Intra Frame. Even though this field is uint32_t for legacy reasons, the client should treat this as a signed parameter(int32_t) for cases in which negative QP values are to be specified. */ +} NV_ENC_QP; + +#define MAX_NUM_VIEWS_MINUS_1 7 + +/** + * Rate Control Configuration Parameters + */ + typedef struct _NV_ENC_RC_PARAMS + { + uint32_t version; + NV_ENC_PARAMS_RC_MODE rateControlMode; /**< [in]: Specifies the rate control mode. Check support for various rate control modes using ::NV_ENC_CAPS_SUPPORTED_RATECONTROL_MODES caps. */ + NV_ENC_QP constQP; /**< [in]: Specifies the initial QP to be used for encoding, these values would be used for all frames if in Constant QP mode. */ + uint32_t averageBitRate; /**< [in]: Specifies the average bitrate(in bits/sec) used for encoding. */ + uint32_t maxBitRate; /**< [in]: Specifies the maximum bitrate for the encoded output. This is used for VBR and ignored for CBR mode. */ + uint32_t vbvBufferSize; /**< [in]: Specifies the VBV(HRD) buffer size. in bits. Set 0 to use the default VBV buffer size. */ + uint32_t vbvInitialDelay; /**< [in]: Specifies the VBV(HRD) initial delay in bits. Set 0 to use the default VBV initial delay .*/ + uint32_t enableMinQP :1; /**< [in]: Set this to 1 if minimum QP used for rate control. */ + uint32_t enableMaxQP :1; /**< [in]: Set this to 1 if maximum QP used for rate control. */ + uint32_t enableInitialRCQP :1; /**< [in]: Set this to 1 if user supplied initial QP is used for rate control. */ + uint32_t enableAQ :1; /**< [in]: Set this to 1 to enable adaptive quantization (Spatial). */ + uint32_t reservedBitField1 :1; /**< [in]: Reserved bitfields and must be set to 0. */ + uint32_t enableLookahead :1; /**< [in]: Set this to 1 to enable lookahead with depth (if lookahead is enabled, input frames must remain available to the encoder until encode completion) */ + uint32_t disableIadapt :1; /**< [in]: Set this to 1 to disable adaptive I-frame insertion at scene cuts (only has an effect when lookahead is enabled) */ + uint32_t disableBadapt :1; /**< [in]: Set this to 1 to disable adaptive B-frame decision (only has an effect when lookahead is enabled) */ + uint32_t enableTemporalAQ :1; /**< [in]: Set this to 1 to enable temporal AQ */ + uint32_t zeroReorderDelay :1; /**< [in]: Set this to 1 to indicate zero latency operation (no reordering delay, num_reorder_frames=0) */ + uint32_t enableNonRefP :1; /**< [in]: Set this to 1 to enable automatic insertion of non-reference P-frames (no effect if enablePTD=0) */ + uint32_t strictGOPTarget :1; /**< [in]: Set this to 1 to minimize GOP-to-GOP rate fluctuations */ + uint32_t aqStrength :4; /**< [in]: When AQ (Spatial) is enabled (i.e. NV_ENC_RC_PARAMS::enableAQ is set), this field is used to specify AQ strength. AQ strength scale is from 1 (low) - 15 (aggressive). + If not set, strength is auto selected by driver. */ + uint32_t enableExtLookahead :1; /**< [in]: Set this to 1 to enable lookahead externally. + Application must call NvEncLookahead() for NV_ENC_RC_PARAMS::lookaheadDepth number of frames, + before calling NvEncEncodePicture() for the first frame */ + uint32_t reservedBitFields :15; /**< [in]: Reserved bitfields and must be set to 0 */ + NV_ENC_QP minQP; /**< [in]: Specifies the minimum QP used for rate control. Client must set NV_ENC_CONFIG::enableMinQP to 1. */ + NV_ENC_QP maxQP; /**< [in]: Specifies the maximum QP used for rate control. Client must set NV_ENC_CONFIG::enableMaxQP to 1. */ + NV_ENC_QP initialRCQP; /**< [in]: Specifies the initial QP hint used for rate control. The parameter is just used as hint to influence the QP difference between I,P and B frames. + Client must set NV_ENC_CONFIG::enableInitialRCQP to 1. */ + uint32_t temporallayerIdxMask; /**< [in]: Specifies the temporal layers (as a bitmask) whose QPs have changed. Valid max bitmask is [2^NV_ENC_CAPS_NUM_MAX_TEMPORAL_LAYERS - 1]. + Applicable only for constant QP mode (NV_ENC_RC_PARAMS::rateControlMode = NV_ENC_PARAMS_RC_CONSTQP). */ + uint8_t temporalLayerQP[8]; /**< [in]: Specifies the temporal layer QPs used for rate control. Temporal layer index is used as the array index. + Applicable only for constant QP mode (NV_ENC_RC_PARAMS::rateControlMode = NV_ENC_PARAMS_RC_CONSTQP). */ + uint8_t targetQuality; /**< [in]: Target CQ (Constant Quality) level for VBR mode (range 0-51 for H264/HEVC, 0-63 for AV1 with 0-automatic) */ + uint8_t targetQualityLSB; /**< [in]: Fractional part of target quality (as 8.8 fixed point format) */ + uint16_t lookaheadDepth; /**< [in]: Maximum depth of lookahead with range 0-(31 - number of B frames). + lookaheadDepth is only used if enableLookahead=1.*/ + uint8_t lowDelayKeyFrameScale; /**< [in]: Specifies the ratio of I frame bits to P frame bits in case of single frame VBV and CBR rate control mode, + is set to 2 by default for low latency tuning info and 1 by default for ultra low latency tuning info */ + int8_t yDcQPIndexOffset; /**< [in]: Specifies the value of 'deltaQ_y_dc' in AV1.*/ + int8_t uDcQPIndexOffset; /**< [in]: Specifies the value of 'deltaQ_u_dc' in AV1.*/ + int8_t vDcQPIndexOffset; /**< [in]: Specifies the value of 'deltaQ_v_dc' in AV1 (for future use only - deltaQ_v_dc is currently always internally set to same value as deltaQ_u_dc). */ + NV_ENC_QP_MAP_MODE qpMapMode; /**< [in]: This flag is used to interpret values in array specified by NV_ENC_PIC_PARAMS::qpDeltaMap. + Set this to NV_ENC_QP_MAP_EMPHASIS to treat values specified by NV_ENC_PIC_PARAMS::qpDeltaMap as Emphasis Level Map. + Emphasis Level can be assigned any value specified in enum NV_ENC_EMPHASIS_MAP_LEVEL. + Emphasis Level Map is used to specify regions to be encoded at varying levels of quality. + The hardware encoder adjusts the quantization within the image as per the provided emphasis map, + by adjusting the quantization parameter (QP) assigned to each macroblock. This adjustment is commonly called "Delta QP". + The adjustment depends on the absolute QP decided by the rate control algorithm, and is applied after the rate control has decided each macroblock's QP. + Since the Delta QP overrides rate control, enabling Emphasis Level Map may violate bitrate and VBV buffer size constraints. + Emphasis Level Map is useful in situations where client has a priori knowledge of the image complexity (e.g. via use of NVFBC's Classification feature) and encoding those high-complexity areas at higher quality (lower QP) is important, even at the possible cost of violating bitrate/VBV buffer size constraints + This feature is not supported when AQ( Spatial/Temporal) is enabled. + This feature is only supported for H264 codec currently. + + Set this to NV_ENC_QP_MAP_DELTA to treat values specified by NV_ENC_PIC_PARAMS::qpDeltaMap as QP Delta. This specifies QP modifier to be applied on top of the QP chosen by rate control + + Set this to NV_ENC_QP_MAP_DISABLED to ignore NV_ENC_PIC_PARAMS::qpDeltaMap values. In this case, qpDeltaMap should be set to NULL. + + Other values are reserved for future use.*/ + NV_ENC_MULTI_PASS multiPass; /**< [in]: This flag is used to enable multi-pass encoding for a given ::NV_ENC_PARAMS_RC_MODE. This flag is not valid for H264 and HEVC MEOnly mode */ + uint32_t alphaLayerBitrateRatio; /**< [in]: Specifies the ratio in which bitrate should be split between base and alpha layer. A value 'x' for this field will split the target bitrate in a ratio of x : 1 between base and alpha layer. + The default split ratio is 15.*/ + int8_t cbQPIndexOffset; /**< [in]: Specifies the value of 'chroma_qp_index_offset' in H264 / 'pps_cb_qp_offset' in HEVC / 'deltaQ_u_ac' in AV1.*/ + int8_t crQPIndexOffset; /**< [in]: Specifies the value of 'second_chroma_qp_index_offset' in H264 / 'pps_cr_qp_offset' in HEVC / 'deltaQ_v_ac' in AV1 (for future use only - deltaQ_v_ac is currently always internally set to same value as deltaQ_u_ac). */ + uint16_t reserved2; + NV_ENC_LOOKAHEAD_LEVEL lookaheadLevel; /**< [in]: Specifies the lookahead level. Higher level may improve quality at the expense of performance. */ + uint8_t viewBitrateRatios[MAX_NUM_VIEWS_MINUS_1]; /**< [in]: Specifies the bit rate ratio for each view of MV-HEVC except the base view. + The base view bit rate ratio = 100 - (sum of bit rate ratio of all other views). */ + uint8_t reserved3; + uint32_t reserved1; + } NV_ENC_RC_PARAMS; + +/** macro for constructing the version field of ::_NV_ENC_RC_PARAMS */ +#define NV_ENC_RC_PARAMS_VER NVENCAPI_STRUCT_VERSION(1) + +#define MAX_NUM_CLOCK_TS 3 + +/** +* Clock Timestamp set parameters +* For H264, this structure is used to populate Picture Timing SEI when NV_ENC_CONFIG_H264::enableTimeCode is set to 1. +* For HEVC, this structure is used to populate Time Code SEI when NV_ENC_CONFIG_HEVC::enableTimeCodeSEI is set to 1. +* For more details, refer to Annex D of ITU-T Specification. +*/ + +typedef struct _NV_ENC_CLOCK_TIMESTAMP_SET +{ + uint32_t countingTypeLSB : 1; /**< [in] Specifies the LSB part of 'counting_type' */ + uint32_t discontinuityFlag : 1; /**< [in] Specifies the 'discontinuity_flag' */ + uint32_t cntDroppedFrames : 1; /**< [in] Specifies the 'cnt_dropped_flag' */ + uint32_t nFrames : 8; /**< [in] Specifies the value of 'n_frames' */ + uint32_t secondsValue : 6; /**< [in] Specifies the 'seconds_value' */ + uint32_t minutesValue : 6; /**< [in] Specifies the 'minutes_value' */ + uint32_t hoursValue : 5; /**< [in] Specifies the 'hours_value' */ + uint32_t countingTypeMSB : 4; /**< [in] Specifies the MSB part of 'counting_type' */ + uint32_t timeOffset; /**< [in] Specifies the 'time_offset_value' */ +} NV_ENC_CLOCK_TIMESTAMP_SET; + +typedef struct _NV_ENC_TIME_CODE +{ + NV_ENC_DISPLAY_PIC_STRUCT displayPicStruct; /**< [in] Display picStruct */ + NV_ENC_CLOCK_TIMESTAMP_SET clockTimestamp[MAX_NUM_CLOCK_TS]; /**< [in] Clock Timestamp set */ + uint32_t skipClockTimestampInsertion; /**< [in] 0 : Inserts Clock Timestamp if NV_ENC_CONFIG_H264::enableTimeCode (H264) or + NV_ENC_CONFIG_HEVC::outputTimeCodeSEI (HEVC) is specified + 1 : Skips insertion of Clock Timestamp for current frame */ +} NV_ENC_TIME_CODE; + +#define MULTIVIEW_MAX_NUM_REF_DISPLAY 32 + +/** + * G.14.2.3 3D reference displays information SEI message syntax elements + */ +typedef struct _HEVC_3D_REFERENCE_DISPLAY_INFO +{ + uint32_t refViewingDistanceFlag : 1; /**< [in] Specifies the presence of reference viewing distance.*/ + uint32_t threeDimensionalReferenceDisplaysExtensionFlag : 1; /**< [in] Should be set to 0 for this version of specs. Saved for future use.*/ + uint32_t reserved : 30; /**< [in] Reserved and must be set to 0 */ + int32_t precRefDisplayWidth; /**< [in] Specifies the exponent of the maximum allowable truncation error for refDisplayWidth[i]. Range 0-31, inclusive.*/ + int32_t precRefViewingDist; /**< [in] Specifies the exponent of the maximum allowable truncation error for refViewingDist[i]. Range 0-31, inclusive.*/ + int32_t numRefDisplaysMinus1; /**< [in] Plus 1 specifies the number of reference displays that are signalled in this SEI message. Range 0-31, inclusive.*/ + int32_t leftViewId[MULTIVIEW_MAX_NUM_REF_DISPLAY]; /**< [in] Indicates the ViewId of the left view of a stereo pair corresponding to the i-th reference display.*/ + int32_t rightViewId[MULTIVIEW_MAX_NUM_REF_DISPLAY]; /**< [in] Indicates the ViewId of the right view of a stereo-pair corresponding to the i-th reference display.*/ + int32_t exponentRefDisplayWidth[MULTIVIEW_MAX_NUM_REF_DISPLAY]; /**< [in] Specifies the exponent part of the reference display width of the i-th reference display.*/ + int32_t mantissaRefDisplayWidth[MULTIVIEW_MAX_NUM_REF_DISPLAY]; /**< [in] Specifies the mantissa part of the reference display width of the i-th reference display.*/ + int32_t exponentRefViewingDistance[MULTIVIEW_MAX_NUM_REF_DISPLAY]; /**< [in] Specifies the exponent part of the reference viewing distance of the i-th reference display.*/ + int32_t mantissaRefViewingDistance[MULTIVIEW_MAX_NUM_REF_DISPLAY]; /**< [in] Specifies the mantissa part of the reference viewing distance of the i-th reference display.*/ + int32_t numSampleShiftPlus512[MULTIVIEW_MAX_NUM_REF_DISPLAY]; /**< [in] Indicates the recommended additional horizontal shift for a stereo pair corresponding to the i-th reference baseline and the i-th reference display.*/ + uint8_t additionalShiftPresentFlag[MULTIVIEW_MAX_NUM_REF_DISPLAY]; /**< [in] Equal to 1 indicates that the information about additional horizontal shift of the left and right views for the i-th reference display is present in this SEI message.*/ + uint32_t reserved2[4]; /**< [in] Reserved and must be set to 0 */ +} HEVC_3D_REFERENCE_DISPLAY_INFO; + +/** + * Struct for storing x and y chroma points + */ +typedef struct _CHROMA_POINTS { + uint16_t x; + uint16_t y; +} CHROMA_POINTS; + +/** + * Struct for storing mastering-display information + * Refer to the AV1 spec 6.7.4 Metadata high dynamic range mastering display color volume semantics OR + * HEVC spec D.2.28 Mastering display colour volume SEI message syntax + */ +typedef struct _MASTERING_DISPLAY_INFO { + CHROMA_POINTS g; + CHROMA_POINTS b; + CHROMA_POINTS r; + CHROMA_POINTS whitePoint; + uint32_t maxLuma; + uint32_t minLuma; +} MASTERING_DISPLAY_INFO; + +/* +* Refer to Av1 spec 6.7.3 Metadata high dynamic range content light level semantics OR +* HEVC spec D.2.35 Content light level information SEI message syntax +*/ +typedef struct _CONTENT_LIGHT_LEVEL +{ + uint16_t maxContentLightLevel; + uint16_t maxPicAverageLightLevel; +} CONTENT_LIGHT_LEVEL; + + +/** + * \struct _NV_ENC_CONFIG_H264_VUI_PARAMETERS + * H264 Video Usability Info parameters + */ +typedef struct _NV_ENC_CONFIG_H264_VUI_PARAMETERS +{ + uint32_t overscanInfoPresentFlag; /**< [in]: If set to 1 , it specifies that the overscanInfo is present */ + uint32_t overscanInfo; /**< [in]: Specifies the overscan info(as defined in Annex E of the ITU-T Specification). */ + uint32_t videoSignalTypePresentFlag; /**< [in]: If set to 1, it specifies that the videoFormat, videoFullRangeFlag and colourDescriptionPresentFlag are present. */ + NV_ENC_VUI_VIDEO_FORMAT videoFormat; /**< [in]: Specifies the source video format(as defined in Annex E of the ITU-T Specification).*/ + uint32_t videoFullRangeFlag; /**< [in]: Specifies the output range of the luma and chroma samples(as defined in Annex E of the ITU-T Specification). */ + uint32_t colourDescriptionPresentFlag; /**< [in]: If set to 1, it specifies that the colourPrimaries, transferCharacteristics and colourMatrix are present. */ + NV_ENC_VUI_COLOR_PRIMARIES colourPrimaries; /**< [in]: Specifies color primaries for converting to RGB(as defined in Annex E of the ITU-T Specification) */ + NV_ENC_VUI_TRANSFER_CHARACTERISTIC transferCharacteristics; /**< [in]: Specifies the opto-electronic transfer characteristics to use (as defined in Annex E of the ITU-T Specification) */ + NV_ENC_VUI_MATRIX_COEFFS colourMatrix; /**< [in]: Specifies the matrix coefficients used in deriving the luma and chroma from the RGB primaries (as defined in Annex E of the ITU-T Specification). */ + uint32_t chromaSampleLocationFlag; /**< [in]: If set to 1 , it specifies that the chromaSampleLocationTop and chromaSampleLocationBot are present.*/ + uint32_t chromaSampleLocationTop; /**< [in]: Specifies the chroma sample location for top field(as defined in Annex E of the ITU-T Specification) */ + uint32_t chromaSampleLocationBot; /**< [in]: Specifies the chroma sample location for bottom field(as defined in Annex E of the ITU-T Specification) */ + uint32_t bitstreamRestrictionFlag; /**< [in]: If set to 1, it specifies the bitstream restriction parameters are present in the bitstream.*/ + uint32_t timingInfoPresentFlag; /**< [in]: If set to 1, it specifies that the timingInfo is present and the 'numUnitInTicks' and 'timeScale' fields are specified by the application. */ + /**< [in]: If not set, the timingInfo may still be present with timing related fields calculated internally based on the frame rate specified by the application. */ + uint32_t numUnitInTicks; /**< [in]: Specifies the number of time units of the clock(as defined in Annex E of the ITU-T Specification). */ + uint32_t timeScale; /**< [in]: Specifies the frequency of the clock(as defined in Annex E of the ITU-T Specification). */ + uint32_t reserved[12]; /**< [in]: Reserved and must be set to 0 */ +}NV_ENC_CONFIG_H264_VUI_PARAMETERS; + +typedef NV_ENC_CONFIG_H264_VUI_PARAMETERS NV_ENC_CONFIG_HEVC_VUI_PARAMETERS; + +/** + * \struct _NVENC_EXTERNAL_ME_HINT_COUNTS_PER_BLOCKTYPE + * External motion vector hint counts per block type. + * H264 and AV1 support multiple hint while HEVC supports one hint for each valid candidate. + */ +typedef struct _NVENC_EXTERNAL_ME_HINT_COUNTS_PER_BLOCKTYPE +{ + uint32_t numCandsPerBlk16x16 : 4; /**< [in]: Supported for H264, HEVC. It Specifies the number of candidates per 16x16 block. */ + uint32_t numCandsPerBlk16x8 : 4; /**< [in]: Supported for H264 only. Specifies the number of candidates per 16x8 block. */ + uint32_t numCandsPerBlk8x16 : 4; /**< [in]: Supported for H264 only. Specifies the number of candidates per 8x16 block. */ + uint32_t numCandsPerBlk8x8 : 4; /**< [in]: Supported for H264, HEVC. Specifies the number of candidates per 8x8 block. */ + uint32_t numCandsPerSb : 8; /**< [in]: Supported for AV1 only. Specifies the number of candidates per SB. */ + uint32_t reserved : 8; /**< [in]: Reserved for padding. */ + uint32_t reserved1[3]; /**< [in]: Reserved for future use. */ +} NVENC_EXTERNAL_ME_HINT_COUNTS_PER_BLOCKTYPE; + + +/** + * \struct _NVENC_EXTERNAL_ME_HINT + * External Motion Vector hint structure for H264 and HEVC. + */ +typedef struct _NVENC_EXTERNAL_ME_HINT +{ + int32_t mvx : 12; /**< [in]: Specifies the x component of integer pixel MV (relative to current MB) S12.0. */ + int32_t mvy : 10; /**< [in]: Specifies the y component of integer pixel MV (relative to current MB) S10.0 .*/ + int32_t refidx : 5; /**< [in]: Specifies the reference index (31=invalid). Currently we support only 1 reference frame per direction for external hints, so \p refidx must be 0. */ + int32_t dir : 1; /**< [in]: Specifies the direction of motion estimation . 0=L0 1=L1.*/ + int32_t partType : 2; /**< [in]: Specifies the block partition type.0=16x16 1=16x8 2=8x16 3=8x8 (blocks in partition must be consecutive).*/ + int32_t lastofPart : 1; /**< [in]: Set to 1 for the last MV of (sub) partition */ + int32_t lastOfMB : 1; /**< [in]: Set to 1 for the last MV of macroblock. */ +} NVENC_EXTERNAL_ME_HINT; + +/** + * \struct _NVENC_EXTERNAL_ME_SB_HINT + * External Motion Vector SB hint structure for AV1 + */ +typedef struct _NVENC_EXTERNAL_ME_SB_HINT +{ + int16_t refidx : 5; /**< [in]: Specifies the reference index (31=invalid) */ + int16_t direction : 1; /**< [in]: Specifies the direction of motion estimation . 0=L0 1=L1.*/ + int16_t bi : 1; /**< [in]: Specifies reference mode 0=single mv, 1=compound mv */ + int16_t partition_type : 3; /**< [in]: Specifies the partition type: 0: 2NX2N, 1:2NxN, 2:Nx2N. reserved 3bits for future modes */ + int16_t x8 : 3; /**< [in]: Specifies the current partition's top left x position in 8 pixel unit */ + int16_t last_of_cu : 1; /**< [in]: Set to 1 for the last MV current CU */ + int16_t last_of_sb : 1; /**< [in]: Set to 1 for the last MV of current SB */ + int16_t reserved0 : 1; /**< [in]: Reserved and must be set to 0 */ + int16_t mvx : 14; /**< [in]: Specifies the x component of integer pixel MV (relative to current MB) S12.2. Permissible value range: [-4092,4092]. */ + int16_t cu_size : 2; /**< [in]: Specifies the CU size: 0: 8x8, 1: 16x16, 2:32x32, 3:64x64 */ + int16_t mvy : 12; /**< [in]: Specifies the y component of integer pixel MV (relative to current MB) S10.2. Permissible value range: [-2044,2044]. */ + int16_t y8 : 3; /**< [in]: Specifies the current partition's top left y position in 8 pixel unit */ + int16_t reserved1 : 1; /**< [in]: Reserved and must be set to 0 */ +} NVENC_EXTERNAL_ME_SB_HINT; + +/** + * \struct _NV_ENC_CONFIG_H264 + * H264 encoder configuration parameters + */ +typedef struct _NV_ENC_CONFIG_H264 +{ + uint32_t enableTemporalSVC :1; /**< [in]: Set to 1 to enable SVC temporal*/ + uint32_t enableStereoMVC :1; /**< [in]: Set to 1 to enable stereo MVC*/ + uint32_t hierarchicalPFrames :1; /**< [in]: Set to 1 to enable hierarchical P Frames */ + uint32_t hierarchicalBFrames :1; /**< [in]: Set to 1 to enable hierarchical B Frames */ + uint32_t outputBufferingPeriodSEI :1; /**< [in]: Set to 1 to write SEI buffering period syntax in the bitstream */ + uint32_t outputPictureTimingSEI :1; /**< [in]: Set to 1 to write SEI picture timing syntax in the bitstream. */ + uint32_t outputAUD :1; /**< [in]: Set to 1 to write access unit delimiter syntax in bitstream */ + uint32_t disableSPSPPS :1; /**< [in]: Set to 1 to disable writing of Sequence and Picture parameter info in bitstream */ + uint32_t outputFramePackingSEI :1; /**< [in]: Set to 1 to enable writing of frame packing arrangement SEI messages to bitstream */ + uint32_t outputRecoveryPointSEI :1; /**< [in]: Set to 1 to enable writing of recovery point SEI message */ + uint32_t enableIntraRefresh :1; /**< [in]: Set to 1 to enable gradual decoder refresh or intra refresh. */ + uint32_t enableConstrainedEncoding :1; /**< [in]: Set this to 1 to enable constrainedFrame encoding where each slice in the constrained picture is independent of other slices. + Constrained encoding works only with rectangular slices. + Check support for constrained encoding using ::NV_ENC_CAPS_SUPPORT_CONSTRAINED_ENCODING caps. */ + uint32_t repeatSPSPPS :1; /**< [in]: Set to 1 to enable writing of Sequence and Picture parameter for every IDR frame */ + uint32_t enableVFR :1; /**< [in]: Setting enableVFR=1 currently only sets the fixed_frame_rate_flag=0 in the VUI but otherwise + has no impact on the encoder behavior. For more details please refer to E.1 VUI syntax of H.264 standard. Note, however, that NVENC does not support VFR encoding and rate control. */ + uint32_t enableLTR :1; /**< [in]: Set to 1 to enable LTR (Long Term Reference) frame support. LTR can be used in two modes: "LTR Trust" mode and "LTR Per Picture" mode. + LTR Trust mode: In this mode, ltrNumFrames pictures after IDR are automatically marked as LTR. This mode is enabled by setting ltrTrustMode = 1. + Use of LTR Trust mode is strongly discouraged as this mode may be deprecated in future. + LTR Per Picture mode: In this mode, client can control whether the current picture should be marked as LTR. Enable this mode by setting + ltrTrustMode = 0 and ltrMarkFrame = 1 for the picture to be marked as LTR. This is the preferred mode + for using LTR. + Note that LTRs are not supported if encoding session is configured with B-frames */ + uint32_t qpPrimeYZeroTransformBypassFlag :1; /**< [in]: To enable lossless encode set this to 1, set QP to 0 and RC_mode to NV_ENC_PARAMS_RC_CONSTQP and profile to HIGH_444_PREDICTIVE_PROFILE. + Check support for lossless encoding using ::NV_ENC_CAPS_SUPPORT_LOSSLESS_ENCODE caps. */ + uint32_t useConstrainedIntraPred :1; /**< [in]: Set 1 to enable constrained intra prediction. */ + uint32_t enableFillerDataInsertion :1; /**< [in]: Set to 1 to enable insertion of filler data in the bitstream. + This flag will take effect only when CBR rate control mode is in use and both + NV_ENC_INITIALIZE_PARAMS::frameRateNum and + NV_ENC_INITIALIZE_PARAMS::frameRateDen are set to non-zero + values. Setting this field when + NV_ENC_INITIALIZE_PARAMS::enableOutputInVidmem is also set + is currently not supported and will make ::NvEncInitializeEncoder() + return an error. */ + uint32_t disableSVCPrefixNalu :1; /**< [in]: Set to 1 to disable writing of SVC Prefix NALU preceding each slice in bitstream. + Applicable only when temporal SVC is enabled (NV_ENC_CONFIG_H264::enableTemporalSVC = 1). */ + uint32_t enableScalabilityInfoSEI :1; /**< [in]: Set to 1 to enable writing of Scalability Information SEI message preceding each IDR picture in bitstream + Applicable only when temporal SVC is enabled (NV_ENC_CONFIG_H264::enableTemporalSVC = 1). */ + uint32_t singleSliceIntraRefresh :1; /**< [in]: Set to 1 to maintain single slice in frames during intra refresh. + Check support for single slice intra refresh using ::NV_ENC_CAPS_SINGLE_SLICE_INTRA_REFRESH caps. + This flag will be ignored if the value returned for ::NV_ENC_CAPS_SINGLE_SLICE_INTRA_REFRESH caps is false. */ + uint32_t enableTimeCode :1; /**< [in]: Set to 1 to enable writing of clock timestamp sets in picture timing SEI. Note that this flag will be ignored for D3D12 interface. */ + uint32_t reservedBitFields :10; /**< [in]: Reserved bitfields and must be set to 0 */ + uint32_t level; /**< [in]: Specifies the encoding level. Client is recommended to set this to NV_ENC_LEVEL_AUTOSELECT in order to enable the NvEncodeAPI interface to select the correct level. */ + uint32_t idrPeriod; /**< [in]: Specifies the IDR interval. If not set, this is made equal to gopLength in NV_ENC_CONFIG.Low latency application client can set IDR interval to NVENC_INFINITE_GOPLENGTH so that IDR frames are not inserted automatically. */ + uint32_t separateColourPlaneFlag; /**< [in]: Set to 1 to enable 4:4:4 separate colour planes */ + uint32_t disableDeblockingFilterIDC; /**< [in]: Specifies the deblocking filter mode. Permissible value range: [0,2]. This flag corresponds + to the flag disable_deblocking_filter_idc specified in section 7.4.3 of H.264 specification, + which specifies whether the operation of the deblocking filter shall be disabled across some + block edges of the slice and specifies for which edges the filtering is disabled. See section + 7.4.3 of H.264 specification for more details.*/ + uint32_t numTemporalLayers; /**< [in]: Specifies number of temporal layers to be used for hierarchical coding / temporal SVC. Valid value range is [1,::NV_ENC_CAPS_NUM_MAX_TEMPORAL_LAYERS] */ + uint32_t spsId; /**< [in]: Specifies the SPS id of the sequence header */ + uint32_t ppsId; /**< [in]: Specifies the PPS id of the picture header */ + NV_ENC_H264_ADAPTIVE_TRANSFORM_MODE adaptiveTransformMode; /**< [in]: Specifies the AdaptiveTransform Mode. Check support for AdaptiveTransform mode using ::NV_ENC_CAPS_SUPPORT_ADAPTIVE_TRANSFORM caps. */ + NV_ENC_H264_FMO_MODE fmoMode; /**< [in]: Specifies the FMO Mode. Check support for FMO using ::NV_ENC_CAPS_SUPPORT_FMO caps. */ + NV_ENC_H264_BDIRECT_MODE bdirectMode; /**< [in]: Specifies the BDirect mode. Check support for BDirect mode using ::NV_ENC_CAPS_SUPPORT_BDIRECT_MODE caps.*/ + NV_ENC_H264_ENTROPY_CODING_MODE entropyCodingMode; /**< [in]: Specifies the entropy coding mode. Check support for CABAC mode using ::NV_ENC_CAPS_SUPPORT_CABAC caps. */ + NV_ENC_STEREO_PACKING_MODE stereoMode; /**< [in]: Specifies the stereo frame packing mode which is to be signaled in frame packing arrangement SEI */ + uint32_t intraRefreshPeriod; /**< [in]: Specifies the interval between successive intra refresh if enableIntrarefresh is set. Requires enableIntraRefresh to be set. + Will be disabled if NV_ENC_CONFIG::gopLength is not set to NVENC_INFINITE_GOPLENGTH. */ + uint32_t intraRefreshCnt; /**< [in]: Specifies the length of intra refresh in number of frames for periodic intra refresh. This value should be smaller than intraRefreshPeriod */ + uint32_t maxNumRefFrames; /**< [in]: Specifies the DPB size used for encoding. Setting it to 0 will let driver use the default DPB size. + The low latency application which wants to invalidate reference frame as an error resilience tool + is recommended to use a large DPB size so that the encoder can keep old reference frames which can be used if recent + frames are invalidated. */ + uint32_t sliceMode; /**< [in]: This parameter in conjunction with sliceModeData specifies the way in which the picture is divided into slices + sliceMode = 0 MB based slices, sliceMode = 1 Byte based slices, sliceMode = 2 MB row based slices, sliceMode = 3 numSlices in Picture. + When forceIntraRefreshWithFrameCnt is set it will have priority over sliceMode setting + When sliceMode == 0 and sliceModeData == 0 whole picture will be coded with one slice */ + uint32_t sliceModeData; /**< [in]: Specifies the parameter needed for sliceMode. For: + sliceMode = 0, sliceModeData specifies # of MBs in each slice (except last slice) + sliceMode = 1, sliceModeData specifies maximum # of bytes in each slice (except last slice) + sliceMode = 2, sliceModeData specifies # of MB rows in each slice (except last slice) + sliceMode = 3, sliceModeData specifies number of slices in the picture. Driver will divide picture into slices optimally */ + NV_ENC_CONFIG_H264_VUI_PARAMETERS h264VUIParameters; /**< [in]: Specifies the H264 video usability info parameters */ + uint32_t ltrNumFrames; /**< [in]: Specifies the number of LTR frames. This parameter has different meaning in two LTR modes. + In "LTR Trust" mode (ltrTrustMode = 1), encoder will mark the first ltrNumFrames base layer reference frames within each IDR interval as LTR. + In "LTR Per Picture" mode (ltrTrustMode = 0 and ltrMarkFrame = 1), ltrNumFrames specifies maximum number of LTR frames in DPB. */ + uint32_t ltrTrustMode; /**< [in]: Specifies the LTR operating mode. See comments near NV_ENC_CONFIG_H264::enableLTR for description of the two modes. + Set to 1 to use "LTR Trust" mode of LTR operation. Clients are discouraged to use "LTR Trust" mode as this mode may + be deprecated in future releases. + Set to 0 when using "LTR Per Picture" mode of LTR operation. */ + uint32_t chromaFormatIDC; /**< [in]: Specifies the chroma format. Should be set to 1 for yuv420 input, 3 for yuv444 input. + Check support for YUV444 encoding using ::NV_ENC_CAPS_SUPPORT_YUV444_ENCODE caps.*/ + uint32_t maxTemporalLayers; /**< [in]: Specifies the max temporal layer used for temporal SVC / hierarchical coding. + Default value of this field is NV_ENC_CAPS::NV_ENC_CAPS_NUM_MAX_TEMPORAL_LAYERS. Note that the value NV_ENC_CONFIG_H264::maxNumRefFrames should + be greater than or equal to (NV_ENC_CONFIG_H264::maxTemporalLayers - 2) * 2, for NV_ENC_CONFIG_H264::maxTemporalLayers >= 2.*/ + NV_ENC_BFRAME_REF_MODE useBFramesAsRef; /**< [in]: Specifies the B-Frame as reference mode. Check support for useBFramesAsRef mode using ::NV_ENC_CAPS_SUPPORT_BFRAME_REF_MODE caps.*/ + NV_ENC_NUM_REF_FRAMES numRefL0; /**< [in]: Specifies max number of reference frames in reference picture list L0, that can be used by hardware for prediction of a frame. + Check support for numRefL0 using ::NV_ENC_CAPS_SUPPORT_MULTIPLE_REF_FRAMES caps. */ + NV_ENC_NUM_REF_FRAMES numRefL1; /**< [in]: Specifies max number of reference frames in reference picture list L1, that can be used by hardware for prediction of a frame. + Check support for numRefL1 using ::NV_ENC_CAPS_SUPPORT_MULTIPLE_REF_FRAMES caps. */ + NV_ENC_BIT_DEPTH outputBitDepth; /**< [in]: Specifies pixel bit depth of encoded video. Should be set to NV_ENC_BIT_DEPTH_8 for 8 bit, NV_ENC_BIT_DEPTH_10 for 10 bit. */ + NV_ENC_BIT_DEPTH inputBitDepth; /**< [in]: Specifies pixel bit depth of video input. Should be set to NV_ENC_BIT_DEPTH_8 for 8 bit input, NV_ENC_BIT_DEPTH_10 for 10 bit input. */ + NV_ENC_TEMPORAL_FILTER_LEVEL tfLevel; /**< [in]: Specifies the strength of temporal filtering. Check support for temporal filter using ::NV_ENC_CAPS_SUPPORT_TEMPORAL_FILTER caps. + Temporal filter feature is supported only if frameIntervalP >= 5. + If ZeroReorderDelay or enableStereoMVC is enabled, the temporal filter feature is not supported. + Temporal filter is recommended for natural contents. */ + uint32_t reserved1[264]; /**< [in]: Reserved and must be set to 0 */ + void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_CONFIG_H264; + +/** + * \struct _NV_ENC_CONFIG_HEVC + * HEVC encoder configuration parameters to be set during initialization. + */ +typedef struct _NV_ENC_CONFIG_HEVC +{ + uint32_t level; /**< [in]: Specifies the level of the encoded bitstream.*/ + uint32_t tier; /**< [in]: Specifies the level tier of the encoded bitstream.*/ + NV_ENC_HEVC_CUSIZE minCUSize; /**< [in]: Specifies the minimum size of luma coding unit.*/ + NV_ENC_HEVC_CUSIZE maxCUSize; /**< [in]: Specifies the maximum size of luma coding unit. Currently NVENC SDK only supports maxCUSize equal to NV_ENC_HEVC_CUSIZE_32x32.*/ + uint32_t useConstrainedIntraPred :1; /**< [in]: Set 1 to enable constrained intra prediction. */ + uint32_t disableDeblockAcrossSliceBoundary :1; /**< [in]: Set 1 to disable in loop filtering across slice boundary.*/ + uint32_t outputBufferingPeriodSEI :1; /**< [in]: Set 1 to write SEI buffering period syntax in the bitstream */ + uint32_t outputPictureTimingSEI :1; /**< [in]: Set 1 to write SEI picture timing syntax in the bitstream */ + uint32_t outputAUD :1; /**< [in]: Set 1 to write Access Unit Delimiter syntax. */ + uint32_t enableLTR :1; /**< [in]: Set to 1 to enable LTR (Long Term Reference) frame support. LTR can be used in two modes: "LTR Trust" mode and "LTR Per Picture" mode. + LTR Trust mode: In this mode, ltrNumFrames pictures after IDR are automatically marked as LTR. This mode is enabled by setting ltrTrustMode = 1. + Use of LTR Trust mode is strongly discouraged as this mode may be deprecated in future releases. + LTR Per Picture mode: In this mode, client can control whether the current picture should be marked as LTR. Enable this mode by setting + ltrTrustMode = 0 and ltrMarkFrame = 1 for the picture to be marked as LTR. This is the preferred mode + for using LTR. + Note that LTRs are not supported if encoding session is configured with B-frames */ + uint32_t disableSPSPPS :1; /**< [in]: Set 1 to disable VPS, SPS and PPS signaling in the bitstream. */ + uint32_t repeatSPSPPS :1; /**< [in]: Set 1 to output VPS,SPS and PPS for every IDR frame.*/ + uint32_t enableIntraRefresh :1; /**< [in]: Set 1 to enable gradual decoder refresh or intra refresh. */ + uint32_t chromaFormatIDC :2; /**< [in]: Specifies the chroma format. Should be set to 1 for yuv420 input, 3 for yuv444 input.*/ + uint32_t reserved3 :3; /**< [in]: Reserved and must be set to 0.*/ + uint32_t enableFillerDataInsertion :1; /**< [in]: Set to 1 to enable insertion of filler data in the bitstream. + This flag will take effect only when CBR rate control mode is in use and both + NV_ENC_INITIALIZE_PARAMS::frameRateNum and + NV_ENC_INITIALIZE_PARAMS::frameRateDen are set to non-zero + values. Setting this field when + NV_ENC_INITIALIZE_PARAMS::enableOutputInVidmem is also set + is currently not supported and will make ::NvEncInitializeEncoder() + return an error. */ + uint32_t enableConstrainedEncoding :1; /**< [in]: Set this to 1 to enable constrainedFrame encoding where each slice in the constrained picture is independent of other slices. + Constrained encoding works only with rectangular slices. + Check support for constrained encoding using ::NV_ENC_CAPS_SUPPORT_CONSTRAINED_ENCODING caps. */ + uint32_t enableAlphaLayerEncoding :1; /**< [in]: Set this to 1 to enable HEVC encode with alpha layer. */ + uint32_t singleSliceIntraRefresh :1; /**< [in]: Set this to 1 to maintain single slice frames during intra refresh. + Check support for single slice intra refresh using ::NV_ENC_CAPS_SINGLE_SLICE_INTRA_REFRESH caps. + This flag will be ignored if the value returned for ::NV_ENC_CAPS_SINGLE_SLICE_INTRA_REFRESH caps is false. */ + uint32_t outputRecoveryPointSEI :1; /**< [in]: Set to 1 to enable writing of recovery point SEI message */ + uint32_t outputTimeCodeSEI :1; /**< [in]: Set 1 to write SEI time code syntax in the bitstream. Note that this flag will be ignored for D3D12 interface.*/ + uint32_t enableTemporalSVC :1; /**< [in]: Set to 1 to enable SVC temporal */ + uint32_t enableMVHEVC :1; /**< [in]: Set to 1 to enable stereo MVHEVC. This feature currently supports only 2 views. + This feature is disabled for LTR, Alpha Layer Encoding, UniDirectionalB, + PyramidalME, Lookahead, Temporal Filter, Split encoding, 2 pass encoding and for NV_ENC_TUNING_INFO other than + NV_ENC_TUNING_INFO_HIGH_QUALITY. */ + uint32_t outputHevc3DReferenceDisplayInfo :1; /**< [in]: Set to 1 to write 3D reference displays information SEI message for MVHEVC */ + uint32_t outputMaxCll :1; /**< [in]: Set to 1 to write Content Light Level information SEI message for HEVC */ + uint32_t outputMasteringDisplay :1; /**< [in]: Set to 1 to write Mastering displays information SEI message for HEVC */ + uint32_t reserved0 :1; /**< [in]: Reserved bitfields.*/ + uint32_t enableRefPicListModification :1; /**< [in]: Enable ref pic list modification flag in PPS. */ + uint32_t reserved :5; /**< [in]: Reserved bitfields.*/ + uint32_t idrPeriod; /**< [in]: Specifies the IDR interval. If not set, this is made equal to gopLength in NV_ENC_CONFIG. Low latency application client can set IDR interval to NVENC_INFINITE_GOPLENGTH so that IDR frames are not inserted automatically. */ + uint32_t intraRefreshPeriod; /**< [in]: Specifies the interval between successive intra refresh if enableIntrarefresh is set. Requires enableIntraRefresh to be set. + Will be disabled if NV_ENC_CONFIG::gopLength is not set to NVENC_INFINITE_GOPLENGTH. */ + uint32_t intraRefreshCnt; /**< [in]: Specifies the length of intra refresh in number of frames for periodic intra refresh. This value should be smaller than intraRefreshPeriod */ + uint32_t maxNumRefFramesInDPB; /**< [in]: Specifies the maximum number of reference frames in the DPB.*/ + uint32_t ltrNumFrames; /**< [in]: This parameter has different meaning in two LTR modes. + In "LTR Trust" mode (ltrTrustMode = 1), encoder will mark the first ltrNumFrames base layer reference frames within each IDR interval as LTR. + In "LTR Per Picture" mode (ltrTrustMode = 0 and ltrMarkFrame = 1), ltrNumFrames specifies maximum number of LTR frames in DPB. + These ltrNumFrames acts as a guidance to the encoder and are not necessarily honored. To achieve a right balance between the encoding + quality and keeping LTR frames in the DPB queue, the encoder can internally limit the number of LTR frames. + The number of LTR frames actually used depends upon the encoding preset being used; Faster encoding presets will use fewer LTR frames.*/ + uint32_t vpsId; /**< [in]: Specifies the VPS id of the video parameter set */ + uint32_t spsId; /**< [in]: Specifies the SPS id of the sequence header */ + uint32_t ppsId; /**< [in]: Specifies the PPS id of the picture header */ + uint32_t sliceMode; /**< [in]: This parameter in conjunction with sliceModeData specifies the way in which the picture is divided into slices + sliceMode = 0 CTU based slices, sliceMode = 1 Byte based slices, sliceMode = 2 CTU row based slices, sliceMode = 3, numSlices in Picture + When sliceMode == 0 and sliceModeData == 0 whole picture will be coded with one slice */ + uint32_t sliceModeData; /**< [in]: Specifies the parameter needed for sliceMode. For: + sliceMode = 0, sliceModeData specifies # of CTUs in each slice (except last slice) + sliceMode = 1, sliceModeData specifies maximum # of bytes in each slice (except last slice) + sliceMode = 2, sliceModeData specifies # of CTU rows in each slice (except last slice) + sliceMode = 3, sliceModeData specifies number of slices in the picture. Driver will divide picture into slices optimally */ + uint32_t maxTemporalLayersMinus1; /**< [in]: Specifies the max temporal layer used for hierarchical coding. */ + NV_ENC_CONFIG_HEVC_VUI_PARAMETERS hevcVUIParameters; /**< [in]: Specifies the HEVC video usability info parameters */ + uint32_t ltrTrustMode; /**< [in]: Specifies the LTR operating mode. See comments near NV_ENC_CONFIG_HEVC::enableLTR for description of the two modes. + Set to 1 to use "LTR Trust" mode of LTR operation. Clients are discouraged to use "LTR Trust" mode as this mode may + be deprecated in future releases. + Set to 0 when using "LTR Per Picture" mode of LTR operation. */ + NV_ENC_BFRAME_REF_MODE useBFramesAsRef; /**< [in]: Specifies the B-Frame as reference mode. Check support for useBFramesAsRef mode using ::NV_ENC_CAPS_SUPPORT_BFRAME_REF_MODE caps.*/ + NV_ENC_NUM_REF_FRAMES numRefL0; /**< [in]: Specifies max number of reference frames in reference picture list L0, that can be used by hardware for prediction of a frame. + Check support for numRefL0 using ::NV_ENC_CAPS_SUPPORT_MULTIPLE_REF_FRAMES caps. */ + NV_ENC_NUM_REF_FRAMES numRefL1; /**< [in]: Specifies max number of reference frames in reference picture list L1, that can be used by hardware for prediction of a frame. + Check support for numRefL1 using ::NV_ENC_CAPS_SUPPORT_MULTIPLE_REF_FRAMES caps. */ + NV_ENC_TEMPORAL_FILTER_LEVEL tfLevel; /**< [in]: Specifies the strength of the temporal filtering. Check support for temporal filtering using ::NV_ENC_CAPS_SUPPORT_TEMPORAL_FILTER caps. + Temporal filter feature is supported only if frameIntervalP >= 5. + Temporal filter feature is not supported with ZeroReorderDelay/enableStereoMVC/AlphaLayerEncoding. + Temporal filter is recommended for natural contents. */ + uint32_t disableDeblockingFilterIDC; /**< [in]: Specifies the deblocking filter mode. Permissible value range: [0,2]. This flag corresponds + to the flag pps_deblocking_filter_disabled_flag specified in section 7.4.3.3 of H.265 specification, + which specifies whether the operation of the deblocking filter shall be disabled across some + block edges of the slice and specifies for which edges the filtering is disabled. See section + 7.4.3.3 of H.265 specification for more details.*/ + NV_ENC_BIT_DEPTH outputBitDepth; /**< [in]: Specifies pixel bit depth of encoded video. Should be set to NV_ENC_BIT_DEPTH_8 for 8 bit, NV_ENC_BIT_DEPTH_10 for 10 bit. + SW will do the bitdepth conversion internally from inputBitDepth -> outputBitDepth if bit depths differ + Support for 8 bit input to 10 bit encode conversion only*/ + NV_ENC_BIT_DEPTH inputBitDepth; /**< [in]: Specifies pixel bit depth of video input. Should be set to NV_ENC_BIT_DEPTH_8 for 8 bit input, NV_ENC_BIT_DEPTH_10 for 10 bit input.*/ + uint32_t numTemporalLayers; /**< [in]: Specifies the number of temporal layers to be used for hierarchical coding.*/ + uint32_t numViews; /**< [in]: Specifies number of views for MVHEVC */ + uint32_t reserved1[208]; /**< [in]: Reserved and must be set to 0.*/ + void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_CONFIG_HEVC; + +#define NV_MAX_TILE_COLS_AV1 64 +#define NV_MAX_TILE_ROWS_AV1 64 + +/** + * \struct _NV_ENC_FILM_GRAIN_PARAMS_AV1 + * AV1 Film Grain Parameters structure + */ + +typedef struct _NV_ENC_FILM_GRAIN_PARAMS_AV1 +{ + uint32_t applyGrain :1; /**< [in]: Set to 1 to specify film grain should be added to frame */ + uint32_t chromaScalingFromLuma :1; /**< [in]: Set to 1 to specify the chroma scaling is inferred from luma scaling */ + uint32_t overlapFlag :1; /**< [in]: Set to 1 to indicate that overlap between film grain blocks should be applied*/ + uint32_t clipToRestrictedRange :1; /**< [in]: Set to 1 to clip values to restricted (studio) range after adding film grain */ + uint32_t grainScalingMinus8 :2; /**< [in]: Represents the shift - 8 applied to the values of the chroma component */ + uint32_t arCoeffLag :2; /**< [in]: Specifies the number of auto-regressive coefficients for luma and chroma */ + uint32_t numYPoints :4; /**< [in]: Specifies the number of points for the piecewise linear scaling function of the luma component */ + uint32_t numCbPoints :4; /**< [in]: Specifies the number of points for the piecewise linear scaling function of the cb component */ + uint32_t numCrPoints :4; /**< [in]: Specifies the number of points for the piecewise linear scaling function of the cr component */ + uint32_t arCoeffShiftMinus6 :2; /**< [in]: specifies the range of the auto-regressive coefficients */ + uint32_t grainScaleShift :2; /**< [in]: Specifies how much the Gaussian random numbers should be scaled down during the grain synthesis process */ + uint32_t reserved1 :8; /**< [in]: Reserved bits field - should be set to 0 */ + uint8_t pointYValue[14]; /**< [in]: pointYValue[i]: x coordinate for i-th point of luma piecewise linear scaling function. Values on a scale of 0...255 */ + uint8_t pointYScaling[14]; /**< [in]: pointYScaling[i]: i-th point output value of luma piecewise linear scaling function */ + uint8_t pointCbValue[10]; /**< [in]: pointCbValue[i]: x coordinate for i-th point of cb piecewise linear scaling function. Values on a scale of 0...255 */ + uint8_t pointCbScaling[10]; /**< [in]: pointCbScaling[i]: i-th point output value of cb piecewise linear scaling function */ + uint8_t pointCrValue[10]; /**< [in]: pointCrValue[i]: x coordinate for i-th point of cr piecewise linear scaling function. Values on a scale of 0...255 */ + uint8_t pointCrScaling[10]; /**< [in]: pointCrScaling[i]: i-th point output value of cr piecewise linear scaling function */ + uint8_t arCoeffsYPlus128[24]; /**< [in]: Specifies auto-regressive coefficients used for the Y plane */ + uint8_t arCoeffsCbPlus128[25]; /**< [in]: Specifies auto-regressive coefficients used for the U plane */ + uint8_t arCoeffsCrPlus128[25]; /**< [in]: Specifies auto-regressive coefficients used for the V plane */ + uint8_t reserved2[2]; /**< [in]: Reserved bytes - should be set to 0 */ + uint8_t cbMult; /**< [in]: Represents a multiplier for the cb component used in derivation of the input index to the cb component scaling function */ + uint8_t cbLumaMult; /**< [in]: represents a multiplier for the average luma component used in derivation of the input index to the cb component scaling function. */ + uint16_t cbOffset; /**< [in]: Represents an offset used in derivation of the input index to the cb component scaling function */ + uint8_t crMult; /**< [in]: Represents a multiplier for the cr component used in derivation of the input index to the cr component scaling function */ + uint8_t crLumaMult; /**< [in]: represents a multiplier for the average luma component used in derivation of the input index to the cr component scaling function. */ + uint16_t crOffset; /**< [in]: Represents an offset used in derivation of the input index to the cr component scaling function */ +} NV_ENC_FILM_GRAIN_PARAMS_AV1; + +/** +* \struct _NV_ENC_CONFIG_AV1 +* AV1 encoder configuration parameters to be set during initialization. +*/ +typedef struct _NV_ENC_CONFIG_AV1 +{ + uint32_t level; /**< [in]: Specifies the level of the encoded bitstream.*/ + uint32_t tier; /**< [in]: Specifies the level tier of the encoded bitstream.*/ + NV_ENC_AV1_PART_SIZE minPartSize; /**< [in]: Specifies the minimum size of luma coding block partition.*/ + NV_ENC_AV1_PART_SIZE maxPartSize; /**< [in]: Specifies the maximum size of luma coding block partition.*/ + uint32_t outputAnnexBFormat : 1; /**< [in]: Set 1 to use Annex B format for bitstream output.*/ + uint32_t enableTimingInfo : 1; /**< [in]: Set 1 to write Timing Info into sequence/frame headers */ + uint32_t enableDecoderModelInfo : 1; /**< [in]: Set 1 to write Decoder Model Info into sequence/frame headers */ + uint32_t enableFrameIdNumbers : 1; /**< [in]: Set 1 to write Frame id numbers in bitstream */ + uint32_t disableSeqHdr : 1; /**< [in]: Set 1 to disable Sequence Header signaling in the bitstream. */ + uint32_t repeatSeqHdr : 1; /**< [in]: Set 1 to output Sequence Header for every Key frame.*/ + uint32_t enableIntraRefresh : 1; /**< [in]: Set 1 to enable gradual decoder refresh or intra refresh. */ + uint32_t chromaFormatIDC : 2; /**< [in]: Specifies the chroma format. Should be set to 1 for yuv420 input (yuv444 input currently not supported).*/ + uint32_t enableBitstreamPadding : 1; /**< [in]: Set 1 to enable bitstream padding. */ + uint32_t enableCustomTileConfig : 1; /**< [in]: Set 1 to enable custom tile configuration: numTileColumns and numTileRows must have non zero values and tileWidths and tileHeights must point to a valid address */ + uint32_t enableFilmGrainParams : 1; /**< [in]: Set 1 to enable custom film grain parameters: filmGrainParams must point to a valid address */ + uint32_t enableLTR : 1; /**< [in]: Set to 1 to enable LTR (Long Term Reference) frame support. LTR can be used in "LTR Per Picture" mode. + In this mode, client can control whether the current picture should be marked as LTR. + use ltrMarkFrame = 1 for the picture to be marked as LTR. + Note that LTRs are not supported if encoding session is configured with B-frames */ + uint32_t enableTemporalSVC : 1; /**< [in]: Set to 1 to enable SVC temporal */ + uint32_t outputMaxCll : 1; /**< [in]: Set to 1 to write Content Light Level metadata for Av1 */ + uint32_t outputMasteringDisplay : 1; /**< [in]: Set to 1 to write Mastering displays metadata for Av1 */ + uint32_t reserved4 : 2; /**< [in]: Reserved and must be set to 0.*/ + uint32_t reserved : 14; /**< [in]: Reserved bitfields.*/ + uint32_t idrPeriod; /**< [in]: Specifies the IDR/Key frame interval. If not set, this is made equal to gopLength in NV_ENC_CONFIG.Low latency application client can set IDR interval to NVENC_INFINITE_GOPLENGTH so that IDR frames are not inserted automatically. */ + uint32_t intraRefreshPeriod; /**< [in]: Specifies the interval between successive intra refresh if enableIntrarefresh is set. Requires enableIntraRefresh to be set. + Will be disabled if NV_ENC_CONFIG::gopLength is not set to NVENC_INFINITE_GOPLENGTH. */ + uint32_t intraRefreshCnt; /**< [in]: Specifies the length of intra refresh in number of frames for periodic intra refresh. This value should be smaller than intraRefreshPeriod */ + uint32_t maxNumRefFramesInDPB; /**< [in]: Specifies the maximum number of reference frames in the DPB.*/ + uint32_t numTileColumns; /**< [in]: This parameter in conjunction with the flag enableCustomTileConfig and the array tileWidths[] specifies the way in which the picture is divided into tile columns. + When enableCustomTileConfig == 0, the picture will be uniformly divided into numTileColumns tile columns. If numTileColumns is not a power of 2, + it will be rounded down to the next power of 2 value. If numTileColumns == 0, the picture will be coded with the smallest number of vertical tiles as allowed by standard. + When enableCustomTileConfig == 1, numTileColumns must be > 0 and <= NV_MAX_TILE_COLS_AV1 and tileWidths must point to a valid array of numTileColumns entries. + Entry i specifies the width in 64x64 CTU unit of tile column i. The sum of all the entries should be equal to the picture width in 64x64 CTU units. */ + uint32_t numTileRows; /**< [in]: This parameter in conjunction with the flag enableCustomTileConfig and the array tileHeights[] specifies the way in which the picture is divided into tiles rows + When enableCustomTileConfig == 0, the picture will be uniformly divided into numTileRows tile rows. If numTileRows is not a power of 2, + it will be rounded down to the next power of 2 value. If numTileRows == 0, the picture will be coded with the smallest number of horizontal tiles as allowed by standard. + When enableCustomTileConfig == 1, numTileRows must be > 0 and <= NV_MAX_TILE_ROWS_AV1 and tileHeights must point to a valid array of numTileRows entries. + Entry i specifies the height in 64x64 CTU unit of tile row i. The sum of all the entries should be equal to the picture height in 64x64 CTU units. */ + uint32_t reserved2; /**< [in]: Reserved and must be set to 0.*/ + uint32_t *tileWidths; /**< [in]: If enableCustomTileConfig == 1, tileWidths[i] specifies the width of tile column i in 64x64 CTU unit, with 0 <= i <= numTileColumns -1. */ + uint32_t *tileHeights; /**< [in]: If enableCustomTileConfig == 1, tileHeights[i] specifies the height of tile row i in 64x64 CTU unit, with 0 <= i <= numTileRows -1. */ + uint32_t maxTemporalLayersMinus1; /**< [in]: Specifies the max temporal layer used for hierarchical coding. Cannot be reconfigured and must be specified during encoder creation if temporal layer is considered. */ + NV_ENC_VUI_COLOR_PRIMARIES colorPrimaries; /**< [in]: as defined in section of ISO/IEC 23091-4/ITU-T H.273 */ + NV_ENC_VUI_TRANSFER_CHARACTERISTIC transferCharacteristics; /**< [in]: as defined in section of ISO/IEC 23091-4/ITU-T H.273 */ + NV_ENC_VUI_MATRIX_COEFFS matrixCoefficients; /**< [in]: as defined in section of ISO/IEC 23091-4/ITU-T H.273 */ + uint32_t colorRange; /**< [in]: 0: studio swing representation - 1: full swing representation */ + uint32_t chromaSamplePosition; /**< [in]: 0: unknown + 1: Horizontally collocated with luma (0,0) sample, between two vertical samples + 2: Co-located with luma (0,0) sample */ + NV_ENC_BFRAME_REF_MODE useBFramesAsRef; /**< [in]: Specifies the B-Frame as reference mode. Check support for useBFramesAsRef mode using ::NV_ENC_CAPS_SUPPORT_BFRAME_REF_MODE caps.*/ + NV_ENC_FILM_GRAIN_PARAMS_AV1 *filmGrainParams; /**< [in]: If enableFilmGrainParams == 1, filmGrainParams must point to a valid NV_ENC_FILM_GRAIN_PARAMS_AV1 structure */ + NV_ENC_NUM_REF_FRAMES numFwdRefs; /**< [in]: Specifies max number of forward reference frame used for prediction of a frame. It must be in range 1-4 (Last, Last2, last3 and Golden). It's a suggestive value not necessarily be honored always. */ + NV_ENC_NUM_REF_FRAMES numBwdRefs; /**< [in]: Specifies max number of L1 list reference frame used for prediction of a frame. It must be in range 1-3 (Backward, Altref2, Altref). It's a suggestive value not necessarily be honored always. */ + NV_ENC_BIT_DEPTH outputBitDepth; /**< [in]: Specifies pixel bit depth of encoded video. Should be set to NV_ENC_BIT_DEPTH_8 for 8 bit, NV_ENC_BIT_DEPTH_10 for 10 bit. + HW will do the bitdepth conversion internally from inputBitDepth -> outputBitDepth if bit depths differ + Support for 8 bit input to 10 bit encode conversion only */ + NV_ENC_BIT_DEPTH inputBitDepth; /**< [in]: Specifies pixel bit depth of video input. Should be set to NV_ENC_BIT_DEPTH_8 for 8 bit input, NV_ENC_BIT_DEPTH_10 for 10 bit input. */ + uint32_t ltrNumFrames; /**< [in]: In "LTR Per Picture" mode (ltrMarkFrame = 1), ltrNumFrames specifies maximum number of LTR frames in DPB. + These ltrNumFrames acts as a guidance to the encoder and are not necessarily honored. To achieve a right balance between the encoding + quality and keeping LTR frames in the DPB queue, the encoder can internally limit the number of LTR frames. + The number of LTR frames actually used depends upon the encoding preset being used; Faster encoding presets will use fewer LTR frames.*/ + uint32_t numTemporalLayers; /**< [in]: Specifies the number of temporal layers to be used for hierarchical coding.*/ + NV_ENC_TEMPORAL_FILTER_LEVEL tfLevel; /**< [in]: Specifies the strength of temporal filtering. Check support for temporal filter using ::NV_ENC_CAPS_SUPPORT_TEMPORAL_FILTER caps. + Temporal filter feature is supported only if frameIntervalP >= 5. + If ZeroReorderDelay or enableStereoMVC is enabled, the temporal filter feature is not supported. + Temporal filter is recommended for natural contents. */ + uint32_t reserved1[230]; /**< [in]: Reserved and must be set to 0.*/ + void* reserved3[62]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_CONFIG_AV1; + +/** + * \struct _NV_ENC_CONFIG_H264_MEONLY + * H264 encoder configuration parameters for ME only Mode + * + */ +typedef struct _NV_ENC_CONFIG_H264_MEONLY +{ + uint32_t disablePartition16x16 :1; /**< [in]: Disable Motion Estimation on 16x16 blocks*/ + uint32_t disablePartition8x16 :1; /**< [in]: Disable Motion Estimation on 8x16 blocks*/ + uint32_t disablePartition16x8 :1; /**< [in]: Disable Motion Estimation on 16x8 blocks*/ + uint32_t disablePartition8x8 :1; /**< [in]: Disable Motion Estimation on 8x8 blocks*/ + uint32_t disableIntraSearch :1; /**< [in]: Disable Intra search during Motion Estimation*/ + uint32_t bStereoEnable :1; /**< [in]: Enable Stereo Mode for Motion Estimation where each view is independently executed*/ + uint32_t reserved :26; /**< [in]: Reserved and must be set to 0 */ + uint32_t reserved1 [255]; /**< [in]: Reserved and must be set to 0 */ + void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_CONFIG_H264_MEONLY; + + +/** + * \struct _NV_ENC_CONFIG_HEVC_MEONLY + * HEVC encoder configuration parameters for ME only Mode + * + */ +typedef struct _NV_ENC_CONFIG_HEVC_MEONLY +{ + uint32_t reserved [256]; /**< [in]: Reserved and must be set to 0 */ + void* reserved1[64]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_CONFIG_HEVC_MEONLY; + +/** + * \struct _NV_ENC_CODEC_CONFIG + * Codec-specific encoder configuration parameters to be set during initialization. + */ +typedef union _NV_ENC_CODEC_CONFIG +{ + NV_ENC_CONFIG_H264 h264Config; /**< [in]: Specifies the H.264-specific encoder configuration. */ + NV_ENC_CONFIG_HEVC hevcConfig; /**< [in]: Specifies the HEVC-specific encoder configuration. */ + NV_ENC_CONFIG_AV1 av1Config; /**< [in]: Specifies the AV1-specific encoder configuration. */ + NV_ENC_CONFIG_H264_MEONLY h264MeOnlyConfig; /**< [in]: Specifies the H.264-specific ME only encoder configuration. */ + NV_ENC_CONFIG_HEVC_MEONLY hevcMeOnlyConfig; /**< [in]: Specifies the HEVC-specific ME only encoder configuration. */ + uint32_t reserved[320]; /**< [in]: Reserved and must be set to 0 */ +} NV_ENC_CODEC_CONFIG; + + +/** + * \struct _NV_ENC_CONFIG + * Encoder configuration parameters to be set during initialization. + */ +typedef struct _NV_ENC_CONFIG +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_CONFIG_VER. */ + GUID profileGUID; /**< [in]: Specifies the codec profile GUID. If client specifies \p NV_ENC_CODEC_PROFILE_AUTOSELECT_GUID the NvEncodeAPI interface will select the appropriate codec profile. */ + uint32_t gopLength; /**< [in]: Specifies the number of pictures in one GOP. Low latency application client can set goplength to NVENC_INFINITE_GOPLENGTH so that keyframes are not inserted automatically. */ + int32_t frameIntervalP; /**< [in]: Specifies the GOP pattern as follows: \p frameIntervalP = 0: I, 1: IPP, 2: IBP, 3: IBBP If goplength is set to NVENC_INFINITE_GOPLENGTH \p frameIntervalP should be set to 1. */ + uint32_t monoChromeEncoding; /**< [in]: Set this to 1 to enable monochrome encoding for this session. */ + NV_ENC_PARAMS_FRAME_FIELD_MODE frameFieldMode; /**< [in]: Specifies the frame/field mode. + Check support for field encoding using ::NV_ENC_CAPS_SUPPORT_FIELD_ENCODING caps. + Using a frameFieldMode other than NV_ENC_PARAMS_FRAME_FIELD_MODE_FRAME for RGB input is not supported. */ + NV_ENC_MV_PRECISION mvPrecision; /**< [in]: Specifies the desired motion vector prediction precision. */ + NV_ENC_RC_PARAMS rcParams; /**< [in]: Specifies the rate control parameters for the current encoding session. */ + NV_ENC_CODEC_CONFIG encodeCodecConfig; /**< [in]: Specifies the codec specific config parameters through this union. */ + uint32_t reserved [278]; /**< [in]: Reserved and must be set to 0 */ + void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_CONFIG; + +/** macro for constructing the version field of ::_NV_ENC_CONFIG */ +#define NV_ENC_CONFIG_VER (NVENCAPI_STRUCT_VERSION(9) | ( 1u<<31 )) + +/** + * Tuning information of NVENC encoding (TuningInfo is not applicable to H264 and HEVC MEOnly mode). + */ +typedef enum NV_ENC_TUNING_INFO +{ + NV_ENC_TUNING_INFO_UNDEFINED = 0, /**< Undefined tuningInfo. Invalid value for encoding. */ + NV_ENC_TUNING_INFO_HIGH_QUALITY = 1, /**< Tune presets for latency tolerant encoding.*/ + NV_ENC_TUNING_INFO_LOW_LATENCY = 2, /**< Tune presets for low latency streaming.*/ + NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY = 3, /**< Tune presets for ultra low latency streaming.*/ + NV_ENC_TUNING_INFO_LOSSLESS = 4, /**< Tune presets for lossless encoding.*/ + NV_ENC_TUNING_INFO_ULTRA_HIGH_QUALITY = 5, /**< Tune presets for latency tolerant encoding for higher quality. Only supported for HEVC and AV1 on Turing+ architectures */ + NV_ENC_TUNING_INFO_COUNT /**< Count number of tuningInfos. Invalid value. */ +}NV_ENC_TUNING_INFO; + +/** + * Split Encoding Modes (Split Encoding is not applicable to H264). + */ +typedef enum _NV_ENC_SPLIT_ENCODE_MODE +{ + NV_ENC_SPLIT_AUTO_MODE = 0, /**< Default value, implicit mode. Split frame will not always be enabled, even if NVENC number > 1. It will be decided by the driver based on preset, tuning information and video resolution. */ + NV_ENC_SPLIT_AUTO_FORCED_MODE = 1, /**< Split frame forced mode enabled with number of strips automatically selected by driver to best fit configuration. If NVENC number > 1, split frame will be forced. */ + NV_ENC_SPLIT_TWO_FORCED_MODE = 2, /**< Forced 2-strip split frame encoding (if NVENC number > 1, 1-strip encode otherwise) */ + NV_ENC_SPLIT_THREE_FORCED_MODE = 3, /**< Forced 3-strip split frame encoding (if NVENC number > 2, NVENC number of strips otherwise) */ + NV_ENC_SPLIT_FOUR_FORCED_MODE = 4, /**< Forced 4-strip split frame encoding (if NVENC number > 3, NVENC number of strips otherwise) */ + NV_ENC_SPLIT_DISABLE_MODE = 15, /**< Both split frame auto mode and forced mode are disabled */ +} NV_ENC_SPLIT_ENCODE_MODE; + +/** + * \struct _NV_ENC_INITIALIZE_PARAMS + * Encode Session Initialization parameters. + */ +typedef struct _NV_ENC_INITIALIZE_PARAMS +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_INITIALIZE_PARAMS_VER. */ + GUID encodeGUID; /**< [in]: Specifies the Encode GUID for which the encoder is being created. ::NvEncInitializeEncoder() API will fail if this is not set, or set to unsupported value. */ + GUID presetGUID; /**< [in]: Specifies the preset for encoding. If the preset GUID is set then , the preset configuration will be applied before any other parameter. */ + uint32_t encodeWidth; /**< [in]: Specifies the encode width. If not set ::NvEncInitializeEncoder() API will fail. */ + uint32_t encodeHeight; /**< [in]: Specifies the encode height. If not set ::NvEncInitializeEncoder() API will fail. */ + uint32_t darWidth; /**< [in]: Specifies the display aspect ratio width (H264/HEVC) or the render width (AV1). */ + uint32_t darHeight; /**< [in]: Specifies the display aspect ratio height (H264/HEVC) or the render height (AV1). */ + uint32_t frameRateNum; /**< [in]: Specifies the numerator for frame rate used for encoding in frames per second ( Frame rate = frameRateNum / frameRateDen ). */ + uint32_t frameRateDen; /**< [in]: Specifies the denominator for frame rate used for encoding in frames per second ( Frame rate = frameRateNum / frameRateDen ). */ + uint32_t enableEncodeAsync; /**< [in]: Set this to 1 to enable asynchronous mode and is expected to use events to get picture completion notification. */ + uint32_t enablePTD; /**< [in]: Set this to 1 to enable the Picture Type Decision is be taken by the NvEncodeAPI interface. */ + uint32_t reportSliceOffsets :1; /**< [in]: Set this to 1 to enable reporting slice offsets in ::_NV_ENC_LOCK_BITSTREAM. NV_ENC_INITIALIZE_PARAMS::enableEncodeAsync must be set to 0 to use this feature. Client must set this to 0 if NV_ENC_CONFIG_H264::sliceMode is 1 on Kepler GPUs */ + uint32_t enableSubFrameWrite :1; /**< [in]: Set this to 1 to write out available bitstream to memory at subframe intervals. + If enableSubFrameWrite = 1, then the hardware encoder returns data as soon as a slice (H264/HEVC) or tile (AV1) has completed encoding. + This results in better encoding latency, but the downside is that the application has to keep polling via a call to nvEncLockBitstream API continuously to see if any encoded slice/tile data is available. + Use this mode if you feel that the marginal reduction in latency from sub-frame encoding is worth the increase in complexity due to CPU-based polling. */ + uint32_t enableExternalMEHints :1; /**< [in]: Set to 1 to enable external ME hints for the current frame. For NV_ENC_INITIALIZE_PARAMS::enablePTD=1 with B frames, programming L1 hints is optional for B frames since Client doesn't know internal GOP structure. + NV_ENC_PIC_PARAMS::meHintRefPicDist should preferably be set with enablePTD=1. */ + uint32_t enableMEOnlyMode :1; /**< [in]: Set to 1 to enable ME Only Mode .*/ + uint32_t enableWeightedPrediction :1; /**< [in]: Set this to 1 to enable weighted prediction. Not supported if encode session is configured for B-Frames (i.e. NV_ENC_CONFIG::frameIntervalP > 1 or preset >=P3 when tuningInfo = ::NV_ENC_TUNING_INFO_HIGH_QUALITY or + tuningInfo = ::NV_ENC_TUNING_INFO_LOSSLESS. This is because preset >=p3 internally enables B frames when tuningInfo = ::NV_ENC_TUNING_INFO_HIGH_QUALITY or ::NV_ENC_TUNING_INFO_LOSSLESS). */ + uint32_t splitEncodeMode :4; /**< [in]: Split Encoding mode in NVENC (Split Encoding is not applicable to H264). + Not supported if any of the following features: weighted prediction, alpha layer encoding, + subframe mode, output into video memory buffer, picture timing/buffering period SEI message + insertion with DX12 interface are enabled in case of HEVC. + For AV1, split encoding is not supported when output into video memory buffer is enabled. + For valid values see ::NV_ENC_SPLIT_ENCODE_MODE enum.*/ + uint32_t enableOutputInVidmem :1; /**< [in]: Set this to 1 to enable output of NVENC in video memory buffer created by application. This feature is not supported for HEVC ME only mode. */ + uint32_t enableReconFrameOutput :1; /**< [in]: Set this to 1 to enable reconstructed frame output. */ + uint32_t enableOutputStats :1; /**< [in]: Set this to 1 to enable encoded frame output stats. Client must allocate buffer of size equal to number of blocks multiplied by the size of + NV_ENC_OUTPUT_STATS_BLOCK struct in system memory and assign to NV_ENC_LOCK_BITSTREAM::encodedOutputStatsPtr to receive the encoded frame output stats.*/ + uint32_t enableUniDirectionalB :1; /**< [in]: Set this to 1 to enable uni directional B-frame(both reference will be from past). It will give better compression + efficiency for LowLatency/UltraLowLatency use case. Value of parameter is ignored when regular B frames are used. */ + uint32_t reservedBitFields :19; /**< [in]: Reserved bitfields and must be set to 0 */ + uint32_t privDataSize; /**< [in]: Reserved private data buffer size and must be set to 0 */ + uint32_t reserved; /**< [in]: Reserved and must be set to 0 */ + void* privData; /**< [in]: Reserved private data buffer and must be set to NULL */ + NV_ENC_CONFIG* encodeConfig; /**< [in]: Specifies the advanced codec specific structure. If client has sent a valid codec config structure, it will override parameters set by the NV_ENC_INITIALIZE_PARAMS::presetGUID parameter. If set to NULL the NvEncodeAPI interface will use the NV_ENC_INITIALIZE_PARAMS::presetGUID to set the codec specific parameters. + Client can also optionally query the NvEncodeAPI interface to get codec specific parameters for a presetGUID using ::NvEncGetEncodePresetConfigEx() API. It can then modify (if required) some of the codec config parameters and send down a custom config structure as part of ::_NV_ENC_INITIALIZE_PARAMS. + Even in this case client is recommended to pass the same preset guid it has used in ::NvEncGetEncodePresetConfigEx() API to query the config structure; as NV_ENC_INITIALIZE_PARAMS::presetGUID. This will not override the custom config structure but will be used to determine other Encoder HW specific parameters not exposed in the API. */ + uint32_t maxEncodeWidth; /**< [in]: Maximum encode width to be used for current Encode session. + Client should allocate output buffers according to this dimension for dynamic resolution change. If set to 0, Encoder will not allow dynamic resolution change. */ + uint32_t maxEncodeHeight; /**< [in]: Maximum encode height to be allowed for current Encode session. + Client should allocate output buffers according to this dimension for dynamic resolution change. If set to 0, Encode will not allow dynamic resolution change. */ + NVENC_EXTERNAL_ME_HINT_COUNTS_PER_BLOCKTYPE maxMEHintCountsPerBlock[2]; /**< [in]: If Client wants to pass external motion vectors in NV_ENC_PIC_PARAMS::meExternalHints buffer it must specify the maximum number of hint candidates per block per direction for the encode session. + The NV_ENC_INITIALIZE_PARAMS::maxMEHintCountsPerBlock[0] is for L0 predictors and NV_ENC_INITIALIZE_PARAMS::maxMEHintCountsPerBlock[1] is for L1 predictors. + This client must also set NV_ENC_INITIALIZE_PARAMS::enableExternalMEHints to 1. */ + NV_ENC_TUNING_INFO tuningInfo; /**< [in]: Tuning Info of NVENC encoding(TuningInfo is not applicable to H264 and HEVC meonly mode). */ + NV_ENC_BUFFER_FORMAT bufferFormat; /**< [in]: Input buffer format. Used only when DX12 interface type is used */ + uint32_t numStateBuffers; /**< [in]: Number of state buffers to allocate to save encoder state. Set this to value greater than zero to enable encoding without advancing the encoder state. */ + NV_ENC_OUTPUT_STATS_LEVEL outputStatsLevel; /**< [in]: Specifies the level for encoded frame output stats, when NV_ENC_INITIALIZE_PARAMS::enableOutputStats is set to 1. + Client should allocate buffer of size equal to number of blocks multiplied by the size of NV_ENC_OUTPUT_STATS_BLOCK struct + if NV_ENC_INITIALIZE_PARAMS::outputStatsLevel is set to NV_ENC_OUTPUT_STATS_BLOCK or number of rows multiplied by the size of + NV_ENC_OUTPUT_STATS_ROW struct if NV_ENC_INITIALIZE_PARAMS::outputStatsLevel is set to NV_ENC_OUTPUT_STATS_ROW + in system memory and assign to NV_ENC_LOCK_BITSTREAM::encodedOutputStatsPtr to receive the encoded frame output stats. */ + uint32_t reserved1[284]; /**< [in]: Reserved and must be set to 0 */ + void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_INITIALIZE_PARAMS; + +/** macro for constructing the version field of ::_NV_ENC_INITIALIZE_PARAMS */ +#define NV_ENC_INITIALIZE_PARAMS_VER (NVENCAPI_STRUCT_VERSION(7) | ( 1u<<31 )) + + +/** + * \struct _NV_ENC_RECONFIGURE_PARAMS + * Encode Session Reconfigured parameters. + */ +typedef struct _NV_ENC_RECONFIGURE_PARAMS +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_RECONFIGURE_PARAMS_VER. */ + uint32_t reserved; /**< [in]: Reserved and must be set to 0 */ + NV_ENC_INITIALIZE_PARAMS reInitEncodeParams; /**< [in]: Encoder session re-initialization parameters. + If reInitEncodeParams.encodeConfig is NULL and + reInitEncodeParams.presetGUID is the same as the preset + GUID specified on the call to NvEncInitializeEncoder(), + EncodeAPI will continue to use the existing encode + configuration. + If reInitEncodeParams.encodeConfig is NULL and + reInitEncodeParams.presetGUID is different from the preset + GUID specified on the call to NvEncInitializeEncoder(), + EncodeAPI will try to use the default configuration for + the preset specified by reInitEncodeParams.presetGUID. + In this case, reconfiguration may fail if the new + configuration is incompatible with the existing + configuration (e.g. the new configuration results in + a change in the GOP structure). */ + uint32_t resetEncoder :1; /**< [in]: This resets the rate control states and other internal encoder states. This should be used only with an IDR frame. + If NV_ENC_INITIALIZE_PARAMS::enablePTD is set to 1, encoder will force the frame type to IDR */ + uint32_t forceIDR :1; /**< [in]: Encode the current picture as an IDR picture. This flag is only valid when Picture type decision is taken by the Encoder + [_NV_ENC_INITIALIZE_PARAMS::enablePTD == 1]. */ + uint32_t reserved1 :30; + uint32_t reserved2; /**< [in]: Reserved and must be set to 0 */ + +}NV_ENC_RECONFIGURE_PARAMS; + +/** macro for constructing the version field of ::_NV_ENC_RECONFIGURE_PARAMS */ +#define NV_ENC_RECONFIGURE_PARAMS_VER (NVENCAPI_STRUCT_VERSION(2) | ( 1u<<31 )) + +/** + * \struct _NV_ENC_PRESET_CONFIG + * Encoder preset config + */ +typedef struct _NV_ENC_PRESET_CONFIG +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_PRESET_CONFIG_VER. */ + uint32_t reserved; /**< [in]: Reserved and must be set to 0 */ + NV_ENC_CONFIG presetCfg; /**< [out]: preset config returned by the Nvidia Video Encoder interface. */ + uint32_t reserved1[256]; /**< [in]: Reserved and must be set to 0 */ + void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ +}NV_ENC_PRESET_CONFIG; + +/** macro for constructing the version field of ::_NV_ENC_PRESET_CONFIG */ +#define NV_ENC_PRESET_CONFIG_VER (NVENCAPI_STRUCT_VERSION(5) | ( 1u<<31 )) + + +/** + * \struct _NV_ENC_PIC_PARAMS_MVC + * MVC-specific parameters to be sent on a per-frame basis. + */ +typedef struct _NV_ENC_PIC_PARAMS_MVC +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_PIC_PARAMS_MVC_VER. */ + uint32_t viewID; /**< [in]: Specifies the view ID associated with the current input view. */ + uint32_t temporalID; /**< [in]: Specifies the temporal ID associated with the current input view. */ + uint32_t priorityID; /**< [in]: Specifies the priority ID associated with the current input view. Reserved and ignored by the NvEncodeAPI interface. */ + uint32_t reserved1[12]; /**< [in]: Reserved and must be set to 0. */ + void* reserved2[8]; /**< [in]: Reserved and must be set to NULL. */ +}NV_ENC_PIC_PARAMS_MVC; + +/** macro for constructing the version field of ::_NV_ENC_PIC_PARAMS_MVC */ +#define NV_ENC_PIC_PARAMS_MVC_VER NVENCAPI_STRUCT_VERSION(1) + + +/** + * \union _NV_ENC_PIC_PARAMS_H264_EXT + * H264 extension picture parameters + */ +typedef union _NV_ENC_PIC_PARAMS_H264_EXT +{ + NV_ENC_PIC_PARAMS_MVC mvcPicParams; /**< [in]: Specifies the MVC picture parameters. */ + uint32_t reserved1[32]; /**< [in]: Reserved and must be set to 0. */ +}NV_ENC_PIC_PARAMS_H264_EXT; + +/** + * \struct _NV_ENC_SEI_PAYLOAD + * User SEI message + */ +typedef struct _NV_ENC_SEI_PAYLOAD +{ + uint32_t payloadSize; /**< [in] SEI payload size in bytes. SEI payload must be byte aligned, as described in Annex D */ + uint32_t payloadType; /**< [in] SEI payload types and syntax can be found in Annex D of the H.264 Specification. */ + uint8_t *payload; /**< [in] pointer to user data */ +} NV_ENC_SEI_PAYLOAD; + +#define NV_ENC_H264_SEI_PAYLOAD NV_ENC_SEI_PAYLOAD + +/** + * \struct _NV_ENC_PIC_PARAMS_H264 + * H264 specific enc pic params. sent on a per frame basis. + */ +typedef struct _NV_ENC_PIC_PARAMS_H264 +{ + uint32_t displayPOCSyntax; /**< [in]: Specifies the display POC syntax This is required to be set if client is handling the picture type decision. */ + uint32_t reserved3; /**< [in]: Reserved and must be set to 0 */ + uint32_t refPicFlag; /**< [in]: Set to 1 for a reference picture. This is ignored if NV_ENC_INITIALIZE_PARAMS::enablePTD is set to 1. */ + uint32_t colourPlaneId; /**< [in]: Specifies the colour plane ID associated with the current input. */ + uint32_t forceIntraRefreshWithFrameCnt; /**< [in]: Forces an intra refresh with duration equal to intraRefreshFrameCnt. + When outputRecoveryPointSEI is set this is value is used for recovery_frame_cnt in recovery point SEI message + forceIntraRefreshWithFrameCnt cannot be used if B frames are used in the GOP structure specified */ + uint32_t constrainedFrame :1; /**< [in]: Set to 1 if client wants to encode this frame with each slice completely independent of other slices in the frame. + NV_ENC_INITIALIZE_PARAMS::enableConstrainedEncoding should be set to 1 */ + uint32_t sliceModeDataUpdate :1; /**< [in]: Set to 1 if client wants to change the sliceModeData field to specify new sliceSize Parameter + When forceIntraRefreshWithFrameCnt is set it will have priority over sliceMode setting */ + uint32_t ltrMarkFrame :1; /**< [in]: Set to 1 if client wants to mark this frame as LTR */ + uint32_t ltrUseFrames :1; /**< [in]: Set to 1 if client allows encoding this frame using the LTR frames specified in ltrFrameBitmap */ + uint32_t reservedBitFields :28; /**< [in]: Reserved bit fields and must be set to 0 */ + uint8_t* sliceTypeData; /**< [in]: Deprecated. */ + uint32_t sliceTypeArrayCnt; /**< [in]: Deprecated. */ + uint32_t seiPayloadArrayCnt; /**< [in]: Specifies the number of elements allocated in seiPayloadArray array. */ + NV_ENC_SEI_PAYLOAD* seiPayloadArray; /**< [in]: Array of SEI payloads which will be inserted for this frame. */ + uint32_t sliceMode; /**< [in]: This parameter in conjunction with sliceModeData specifies the way in which the picture is divided into slices + sliceMode = 0 MB based slices, sliceMode = 1 Byte based slices, sliceMode = 2 MB row based slices, sliceMode = 3, numSlices in Picture + When forceIntraRefreshWithFrameCnt is set it will have priority over sliceMode setting + When sliceMode == 0 and sliceModeData == 0 whole picture will be coded with one slice */ + uint32_t sliceModeData; /**< [in]: Specifies the parameter needed for sliceMode. For: + sliceMode = 0, sliceModeData specifies # of MBs in each slice (except last slice) + sliceMode = 1, sliceModeData specifies maximum # of bytes in each slice (except last slice) + sliceMode = 2, sliceModeData specifies # of MB rows in each slice (except last slice) + sliceMode = 3, sliceModeData specifies number of slices in the picture. Driver will divide picture into slices optimally */ + uint32_t ltrMarkFrameIdx; /**< [in]: Specifies the long term reference frame index to use for marking this frame as LTR.*/ + uint32_t ltrUseFrameBitmap; /**< [in]: Specifies the associated bitmap of LTR frame indices to use when encoding this frame. */ + uint32_t ltrUsageMode; /**< [in]: Not supported. Reserved for future use and must be set to 0. */ + uint32_t forceIntraSliceCount; /**< [in]: Specifies the number of slices to be forced to Intra in the current picture. + This option along with forceIntraSliceIdx[] array needs to be used with sliceMode = 3 only */ + uint32_t *forceIntraSliceIdx; /**< [in]: Slice indices to be forced to intra in the current picture. Each slice index should be <= num_slices_in_picture -1. Index starts from 0 for first slice. + The number of entries in this array should be equal to forceIntraSliceCount */ + NV_ENC_PIC_PARAMS_H264_EXT h264ExtPicParams; /**< [in]: Specifies the H264 extension config parameters using this config. */ + NV_ENC_TIME_CODE timeCode; /**< [in]: Specifies the clock timestamp sets used in picture timing SEI. Applicable only when NV_ENC_CONFIG_H264::enableTimeCode is set to 1. */ + uint32_t reserved [202]; /**< [in]: Reserved and must be set to 0. */ + void* reserved2[61]; /**< [in]: Reserved and must be set to NULL. */ +} NV_ENC_PIC_PARAMS_H264; + +/** + * \struct _NV_ENC_PIC_PARAMS_HEVC + * HEVC specific enc pic params. sent on a per frame basis. + */ +typedef struct _NV_ENC_PIC_PARAMS_HEVC +{ + uint32_t displayPOCSyntax; /**< [in]: Specifies the display POC syntax This is required to be set if client is handling the picture type decision. */ + uint32_t refPicFlag; /**< [in]: Set to 1 for a reference picture. This is ignored if NV_ENC_INITIALIZE_PARAMS::enablePTD is set to 1. */ + uint32_t temporalId; /**< [in]: Specifies the temporal id of the picture */ + uint32_t forceIntraRefreshWithFrameCnt; /**< [in]: Forces an intra refresh with duration equal to intraRefreshFrameCnt. + When outputRecoveryPointSEI is set this is value is used for recovery_frame_cnt in recovery point SEI message + forceIntraRefreshWithFrameCnt cannot be used if B frames are used in the GOP structure specified */ + uint32_t constrainedFrame :1; /**< [in]: Set to 1 if client wants to encode this frame with each slice completely independent of other slices in the frame. + NV_ENC_INITIALIZE_PARAMS::enableConstrainedEncoding should be set to 1 */ + uint32_t sliceModeDataUpdate :1; /**< [in]: Set to 1 if client wants to change the sliceModeData field to specify new sliceSize Parameter + When forceIntraRefreshWithFrameCnt is set it will have priority over sliceMode setting */ + uint32_t ltrMarkFrame :1; /**< [in]: Set to 1 if client wants to mark this frame as LTR */ + uint32_t ltrUseFrames :1; /**< [in]: Set to 1 if client allows encoding this frame using the LTR frames specified in ltrFrameBitmap */ + uint32_t temporalConfigUpdate :1; /**< [in]: Set to 1 if client wants to change the number of temporal layers in temporal SVC encoding */ + uint32_t reservedBitFields :27; /**< [in]: Reserved bit fields and must be set to 0 */ + uint32_t reserved1; /**< [in]: Reserved and must be set to 0. */ + uint8_t* sliceTypeData; /**< [in]: Deprecated. */ + uint32_t sliceTypeArrayCnt; /**< [in]: Deprecated. */ + uint32_t sliceMode; /**< [in]: This parameter in conjunction with sliceModeData specifies the way in which the picture is divided into slices + sliceMode = 0 CTU based slices, sliceMode = 1 Byte based slices, sliceMode = 2 CTU row based slices, sliceMode = 3, numSlices in Picture + When forceIntraRefreshWithFrameCnt is set it will have priority over sliceMode setting + When sliceMode == 0 and sliceModeData == 0 whole picture will be coded with one slice */ + uint32_t sliceModeData; /**< [in]: Specifies the parameter needed for sliceMode. For: + sliceMode = 0, sliceModeData specifies # of CTUs in each slice (except last slice) + sliceMode = 1, sliceModeData specifies maximum # of bytes in each slice (except last slice) + sliceMode = 2, sliceModeData specifies # of CTU rows in each slice (except last slice) + sliceMode = 3, sliceModeData specifies number of slices in the picture. Driver will divide picture into slices optimally */ + uint32_t ltrMarkFrameIdx; /**< [in]: Specifies the long term reference frame index to use for marking this frame as LTR.*/ + uint32_t ltrUseFrameBitmap; /**< [in]: Specifies the associated bitmap of LTR frame indices to use when encoding this frame. */ + uint32_t ltrUsageMode; /**< [in]: Not supported. Reserved for future use and must be set to 0. */ + uint32_t seiPayloadArrayCnt; /**< [in]: Specifies the number of elements allocated in seiPayloadArray array. */ + uint32_t reserved; /**< [in]: Reserved and must be set to 0. */ + NV_ENC_SEI_PAYLOAD* seiPayloadArray; /**< [in]: Array of SEI payloads which will be inserted for this frame. */ + NV_ENC_TIME_CODE timeCode; /**< [in]: Specifies the clock timestamp sets used in time code SEI. Applicable only when NV_ENC_CONFIG_HEVC::enableTimeCodeSEI is set to 1. */ + uint32_t numTemporalLayers; /**< [in]: Specifies the number of temporal layers to be used for hierarchical coding. The set only takes place when temporalConfigUpdate == 1.*/ + uint32_t viewId; /**< [in]: Specifies the view id of the picture */ + HEVC_3D_REFERENCE_DISPLAY_INFO *p3DReferenceDisplayInfo; /**< [in]: Specifies the 3D reference displays information SEI message. + Applicable only when NV_ENC_CONFIG_HEVC::outputHevc3DReferenceDisplayInfo is set to 1. */ + CONTENT_LIGHT_LEVEL *pMaxCll; /**< [in]: Specifies the Content light level information SEI syntax*/ + MASTERING_DISPLAY_INFO *pMasteringDisplay; /**< [in]: Specifies the Mastering display colour volume SEI syntax*/ + uint32_t reserved2[234]; /**< [in]: Reserved and must be set to 0. */ + void* reserved3[58]; /**< [in]: Reserved and must be set to NULL. */ +} NV_ENC_PIC_PARAMS_HEVC; + +#define NV_ENC_AV1_OBU_PAYLOAD NV_ENC_SEI_PAYLOAD + +/** +* \struct _NV_ENC_PIC_PARAMS_AV1 +* AV1 specific enc pic params. sent on a per frame basis. +*/ +typedef struct _NV_ENC_PIC_PARAMS_AV1 +{ + uint32_t displayPOCSyntax; /**< [in]: Specifies the display POC syntax This is required to be set if client is handling the picture type decision. */ + uint32_t refPicFlag; /**< [in]: Set to 1 for a reference picture. This is ignored if NV_ENC_INITIALIZE_PARAMS::enablePTD is set to 1. */ + uint32_t temporalId; /**< [in]: Specifies the temporal id of the picture */ + uint32_t forceIntraRefreshWithFrameCnt; /**< [in]: Forces an intra refresh with duration equal to intraRefreshFrameCnt. + forceIntraRefreshWithFrameCnt cannot be used if B frames are used in the GOP structure specified */ + uint32_t goldenFrameFlag : 1; /**< [in]: Encode frame as Golden Frame. This is ignored if NV_ENC_INITIALIZE_PARAMS::enablePTD is set to 1. */ + uint32_t arfFrameFlag : 1; /**< [in]: Encode frame as Alternate Reference Frame. This is ignored if NV_ENC_INITIALIZE_PARAMS::enablePTD is set to 1. */ + uint32_t arf2FrameFlag : 1; /**< [in]: Encode frame as Alternate Reference 2 Frame. This is ignored if NV_ENC_INITIALIZE_PARAMS::enablePTD is set to 1. */ + uint32_t bwdFrameFlag : 1; /**< [in]: Encode frame as Backward Reference Frame. This is ignored if NV_ENC_INITIALIZE_PARAMS::enablePTD is set to 1. */ + uint32_t overlayFrameFlag : 1; /**< [in]: Encode frame as overlay frame. A previously encoded frame with the same displayPOCSyntax value should be present in reference frame buffer. + This is ignored if NV_ENC_INITIALIZE_PARAMS::enablePTD is set to 1. */ + uint32_t showExistingFrameFlag : 1; /**< [in]: When overlayFrameFlag is set to 1, this flag controls the value of the show_existing_frame syntax element associated with the overlay frame. + This flag is added to the interface as a placeholder. Its value is ignored for now and always assumed to be set to 1. + This is ignored if NV_ENC_INITIALIZE_PARAMS::enablePTD is set to 1. */ + uint32_t errorResilientModeFlag : 1; /**< [in]: encode frame independently from previously encoded frames */ + + uint32_t tileConfigUpdate : 1; /**< [in]: Set to 1 if client wants to overwrite the default tile configuration with the tile parameters specified below + When forceIntraRefreshWithFrameCnt is set it will have priority over tileConfigUpdate setting */ + uint32_t enableCustomTileConfig : 1; /**< [in]: Set 1 to enable custom tile configuration: numTileColumns and numTileRows must have non zero values and tileWidths and tileHeights must point to a valid address */ + uint32_t filmGrainParamsUpdate : 1; /**< [in]: Set to 1 if client wants to update previous film grain parameters: filmGrainParams must point to a valid address and encoder must have been configured with film grain enabled */ + uint32_t ltrMarkFrame : 1; /**< [in]: Set to 1 if client wants to mark this frame as LTR */ + uint32_t ltrUseFrames : 1; /**< [in]: Set to 1 if client allows encoding this frame using the LTR frames specified in ltrFrameBitmap */ + uint32_t temporalConfigUpdate : 1; /**< [in]: Set to 1 if client wants to change the number of temporal layers in temporal SVC encoding */ + uint32_t reservedBitFields : 19; /**< [in]: Reserved bitfields and must be set to 0 */ + uint32_t numTileColumns; /**< [in]: This parameter in conjunction with the flag enableCustomTileConfig and the array tileWidths[] specifies the way in which the picture is divided into tile columns. + When enableCustomTileConfig == 0, the picture will be uniformly divided into numTileColumns tile columns. If numTileColumns is not a power of 2, + it will be rounded down to the next power of 2 value. If numTileColumns == 0, the picture will be coded with the smallest number of vertical tiles as allowed by standard. + When enableCustomTileConfig == 1, numTileColumns must be > 0 and <= NV_MAX_TILE_COLS_AV1 and tileWidths must point to a valid array of numTileColumns entries. + Entry i specifies the width in 64x64 CTU unit of tile column i. The sum of all the entries should be equal to the picture width in 64x64 CTU units. */ + uint32_t numTileRows; /**< [in]: This parameter in conjunction with the flag enableCustomTileConfig and the array tileHeights[] specifies the way in which the picture is divided into tiles rows + When enableCustomTileConfig == 0, the picture will be uniformly divided into numTileRows tile rows. If numTileRows is not a power of 2, + it will be rounded down to the next power of 2 value. If numTileRows == 0, the picture will be coded with the smallest number of horizontal tiles as allowed by standard. + When enableCustomTileConfig == 1, numTileRows must be > 0 and <= NV_MAX_TILE_ROWS_AV1 and tileHeights must point to a valid array of numTileRows entries. + Entry i specifies the height in 64x64 CTU unit of tile row i. The sum of all the entries should be equal to the picture height in 64x64 CTU units. */ + uint32_t reserved; /**< [in]: Reserved and must be set to 0. */ + uint32_t *tileWidths; /**< [in]: If enableCustomTileConfig == 1, tileWidths[i] specifies the width of tile column i in 64x64 CTU unit, with 0 <= i <= numTileColumns -1. */ + uint32_t *tileHeights; /**< [in]: If enableCustomTileConfig == 1, tileHeights[i] specifies the height of tile row i in 64x64 CTU unit, with 0 <= i <= numTileRows -1. */ + uint32_t obuPayloadArrayCnt; /**< [in]: Specifies the number of elements allocated in obuPayloadArray array. */ + uint32_t reserved1; /**< [in]: Reserved and must be set to 0. */ + NV_ENC_AV1_OBU_PAYLOAD* obuPayloadArray; /**< [in]: Array of OBU payloads which will be inserted for this frame. */ + NV_ENC_FILM_GRAIN_PARAMS_AV1 *filmGrainParams; /**< [in]: If filmGrainParamsUpdate == 1, filmGrainParams must point to a valid NV_ENC_FILM_GRAIN_PARAMS_AV1 structure */ + uint32_t ltrMarkFrameIdx; /**< [in]: Specifies the long term reference frame index to use for marking this frame as LTR.*/ + uint32_t ltrUseFrameBitmap; /**< [in]: Specifies the associated bitmap of LTR frame indices to use when encoding this frame. */ + uint32_t numTemporalLayers; /**< [in]: Specifies the number of temporal layers to be used for hierarchical coding. The set only takes place when temporalConfigUpdate == 1.*/ + uint32_t reserved4; /**< [in]: Reserved and must be set to 0. */ + CONTENT_LIGHT_LEVEL *pMaxCll; /**< [in]: Specifies the Content light level metadata syntax*/ + MASTERING_DISPLAY_INFO *pMasteringDisplay; /**< [in]: Specifies the Mastering display colour volume metadata syntax*/ + uint32_t reserved2[242]; /**< [in]: Reserved and must be set to 0. */ + void* reserved3[59]; /**< [in]: Reserved and must be set to NULL. */ +} NV_ENC_PIC_PARAMS_AV1; + +/** + * Codec specific per-picture encoding parameters. + */ +typedef union _NV_ENC_CODEC_PIC_PARAMS +{ + NV_ENC_PIC_PARAMS_H264 h264PicParams; /**< [in]: H264 encode picture params. */ + NV_ENC_PIC_PARAMS_HEVC hevcPicParams; /**< [in]: HEVC encode picture params. */ + NV_ENC_PIC_PARAMS_AV1 av1PicParams; /**< [in]: AV1 encode picture params. */ + uint32_t reserved[256]; /**< [in]: Reserved and must be set to 0. */ +} NV_ENC_CODEC_PIC_PARAMS; + + +/** + * \struct _NV_ENC_PIC_PARAMS + * Encoding parameters that need to be sent on a per frame basis. + */ +typedef struct _NV_ENC_PIC_PARAMS +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_PIC_PARAMS_VER. */ + uint32_t inputWidth; /**< [in]: Specifies the input frame width */ + uint32_t inputHeight; /**< [in]: Specifies the input frame height */ + uint32_t inputPitch; /**< [in]: Specifies the input buffer pitch. If pitch value is not known, set this to inputWidth. */ + uint32_t encodePicFlags; /**< [in]: Specifies bit-wise OR of encode picture flags. See ::NV_ENC_PIC_FLAGS enum. */ + uint32_t frameIdx; /**< [in]: Specifies the frame index associated with the input frame. It is necessary to pass this as monotonically increasing starting 0 when lookaheadLevel, UHQ Tuning Info + or encoding same frames multiple times without advancing encoder state feature are enabled */ + uint64_t inputTimeStamp; /**< [in]: Specifies opaque data which is associated with the encoded frame, but not actually encoded in the output bitstream. + This opaque data can be used later to uniquely refer to the corresponding encoded frame. For example, it can be used + for identifying the frame to be invalidated in the reference picture buffer, if lost at the client. */ + uint64_t inputDuration; /**< [in]: Specifies duration of the input picture */ + NV_ENC_INPUT_PTR inputBuffer; /**< [in]: Specifies the input buffer pointer. Client must use a pointer obtained from ::NvEncCreateInputBuffer() or ::NvEncMapInputResource() APIs.*/ + NV_ENC_OUTPUT_PTR outputBitstream; /**< [in]: Specifies the output buffer pointer. + If NV_ENC_INITIALIZE_PARAMS::enableOutputInVidmem is set to 0, specifies the pointer to output buffer. Client should use a pointer obtained from ::NvEncCreateBitstreamBuffer() API. + If NV_ENC_INITIALIZE_PARAMS::enableOutputInVidmem is set to 1, client should allocate buffer in video memory for NV_ENC_ENCODE_OUT_PARAMS struct and encoded bitstream data. Client + should use a pointer obtained from ::NvEncMapInputResource() API, when mapping this output buffer and assign it to NV_ENC_PIC_PARAMS::outputBitstream. + First 256 bytes of this buffer should be interpreted as NV_ENC_ENCODE_OUT_PARAMS struct followed by encoded bitstream data. Recommended size for output buffer is sum of size of + NV_ENC_ENCODE_OUT_PARAMS struct and twice the input frame size for lower resolution eg. CIF and 1.5 times the input frame size for higher resolutions. If encoded bitstream size is + greater than the allocated buffer size for encoded bitstream, then the output buffer will have encoded bitstream data equal to buffer size. All CUDA operations on this buffer must use + the default stream. */ + void* completionEvent; /**< [in]: Specifies an event to be signaled on completion of encoding of this Frame [only if operating in Asynchronous mode]. Each output buffer should be associated with a distinct event pointer. */ + NV_ENC_BUFFER_FORMAT bufferFmt; /**< [in]: Specifies the input buffer format. */ + NV_ENC_PIC_STRUCT pictureStruct; /**< [in]: Specifies structure of the input picture. */ + NV_ENC_PIC_TYPE pictureType; /**< [in]: Specifies input picture type. Client required to be set explicitly by the client if the client has not set NV_ENC_INITIALIZE_PARAMS::enablePTD to 1 while calling NvEncInitializeEncoder. */ + NV_ENC_CODEC_PIC_PARAMS codecPicParams; /**< [in]: Specifies the codec specific per-picture encoding parameters. */ + NVENC_EXTERNAL_ME_HINT_COUNTS_PER_BLOCKTYPE meHintCountsPerBlock[2]; /**< [in]: For H264 and Hevc, specifies the number of hint candidates per block per direction for the current frame. meHintCountsPerBlock[0] is for L0 predictors and meHintCountsPerBlock[1] is for L1 predictors. + The candidate count in NV_ENC_PIC_PARAMS::meHintCountsPerBlock[lx] must never exceed NV_ENC_INITIALIZE_PARAMS::maxMEHintCountsPerBlock[lx] provided during encoder initialization. */ + NVENC_EXTERNAL_ME_HINT *meExternalHints; /**< [in]: For H264 and Hevc, Specifies the pointer to ME external hints for the current frame. The size of ME hint buffer should be equal to number of macroblocks * the total number of candidates per macroblock. + The total number of candidates per MB per direction = 1*meHintCountsPerBlock[Lx].numCandsPerBlk16x16 + 2*meHintCountsPerBlock[Lx].numCandsPerBlk16x8 + 2*meHintCountsPerBlock[Lx].numCandsPerBlk8x16 + + 4*meHintCountsPerBlock[Lx].numCandsPerBlk8x8. For frames using bidirectional ME , the total number of candidates for single macroblock is sum of total number of candidates per MB for each direction (L0 and L1) */ + uint32_t reserved2[7]; /**< [in]: Reserved and must be set to 0 */ + void* reserved5[2]; /**< [in]: Reserved and must be set to NULL */ + int8_t *qpDeltaMap; /**< [in]: Specifies the pointer to signed byte array containing value per MB for H264, per CTB for HEVC and per SB for AV1 in raster scan order for the current picture, which will be interpreted depending on NV_ENC_RC_PARAMS::qpMapMode. + If NV_ENC_RC_PARAMS::qpMapMode is NV_ENC_QP_MAP_DELTA, qpDeltaMap specifies QP modifier per MB for H264, per CTB for HEVC and per SB for AV1. This QP modifier will be applied on top of the QP chosen by rate control. + If NV_ENC_RC_PARAMS::qpMapMode is NV_ENC_QP_MAP_EMPHASIS, qpDeltaMap specifies Emphasis Level Map per MB for H264. This level value along with QP chosen by rate control is used to + compute the QP modifier, which in turn is applied on top of QP chosen by rate control. + If NV_ENC_RC_PARAMS::qpMapMode is NV_ENC_QP_MAP_DISABLED, value in qpDeltaMap will be ignored.*/ + uint32_t qpDeltaMapSize; /**< [in]: Specifies the size in bytes of qpDeltaMap surface allocated by client and pointed to by NV_ENC_PIC_PARAMS::qpDeltaMap. Surface (array) should be picWidthInMbs * picHeightInMbs for H264, picWidthInCtbs * picHeightInCtbs for HEVC and + picWidthInSbs * picHeightInSbs for AV1 */ + uint32_t reservedBitFields; /**< [in]: Reserved bitfields and must be set to 0 */ + uint16_t meHintRefPicDist[2]; /**< [in]: Specifies temporal distance for reference picture (NVENC_EXTERNAL_ME_HINT::refidx = 0) used during external ME with NV_ENC_INITIALIZE_PARAMS::enablePTD = 1 . meHintRefPicDist[0] is for L0 hints and meHintRefPicDist[1] is for L1 hints. + If not set, will internally infer distance of 1. Ignored for NV_ENC_INITIALIZE_PARAMS::enablePTD = 0 */ + int32_t diffPicNumHint; /**< [in]: Difference between the current picture number and the picture number of the most likely reference picture (0 = unknown or unspecified) */ + NV_ENC_INPUT_PTR alphaBuffer; /**< [in]: Specifies the input alpha buffer pointer. Client must use a pointer obtained from ::NvEncCreateInputBuffer() or ::NvEncMapInputResource() APIs. + Applicable only when encoding hevc with alpha layer is enabled. */ + NVENC_EXTERNAL_ME_SB_HINT *meExternalSbHints; /**< [in]: For AV1,Specifies the pointer to ME external SB hints for the current frame. The size of ME hint buffer should be equal to meSbHintsCount. */ + uint32_t meSbHintsCount; /**< [in]: For AV1, specifies the total number of external ME SB hint candidates for the frame + NV_ENC_PIC_PARAMS::meSbHintsCount must never exceed the total number of SBs in frame * the max number of candidates per SB provided during encoder initialization. + The max number of candidates per SB is maxMeHintCountsPerBlock[0].numCandsPerSb + maxMeHintCountsPerBlock[1].numCandsPerSb */ + uint32_t stateBufferIdx; /**< [in]: Specifies the buffer index in which the encoder state will be saved for current frame encode. It must be in the + range 0 to NV_ENC_INITIALIZE_PARAMS::numStateBuffers - 1. */ + NV_ENC_OUTPUT_PTR outputReconBuffer; /**< [in]: Specifies the reconstructed frame buffer pointer to output reconstructed frame, if enabled by setting NV_ENC_INITIALIZE_PARAMS::enableReconFrameOutput. + Client must allocate buffers for writing the reconstructed frames and register them with the Nvidia Video Encoder Interface with NV_ENC_REGISTER_RESOURCE::bufferUsage + set to NV_ENC_OUTPUT_RECON. + Client must use the pointer obtained from ::NvEncMapInputResource() API and assign it to NV_ENC_PIC_PARAMS::outputReconBuffer. + Reconstructed output will be in NV_ENC_BUFFER_FORMAT_NV12 format when chromaFormatIDC is set to 1. + chromaFormatIDC = 3 is not supported. */ + uint32_t reserved3[284]; /**< [in]: Reserved and must be set to 0 */ + void* reserved6[57]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_PIC_PARAMS; + +/** Macro for constructing the version field of ::_NV_ENC_PIC_PARAMS */ +#define NV_ENC_PIC_PARAMS_VER (NVENCAPI_STRUCT_VERSION(7) | ( 1u<<31 )) + + +/** + * \struct _NV_ENC_MEONLY_PARAMS + * MEOnly parameters that need to be sent on a per motion estimation basis. + * NV_ENC_MEONLY_PARAMS::meExternalHints is supported for H264 only. + */ +typedef struct _NV_ENC_MEONLY_PARAMS +{ + uint32_t version; /**< [in]: Struct version. Must be set to NV_ENC_MEONLY_PARAMS_VER.*/ + uint32_t inputWidth; /**< [in]: Specifies the input frame width */ + uint32_t inputHeight; /**< [in]: Specifies the input frame height */ + uint32_t reserved; /**< [in]: Reserved and must be set to 0 */ + NV_ENC_INPUT_PTR inputBuffer; /**< [in]: Specifies the input buffer pointer. Client must use a pointer obtained from NvEncCreateInputBuffer() or NvEncMapInputResource() APIs. */ + NV_ENC_INPUT_PTR referenceFrame; /**< [in]: Specifies the reference frame pointer */ + NV_ENC_OUTPUT_PTR mvBuffer; /**< [in]: Specifies the output buffer pointer. + If NV_ENC_INITIALIZE_PARAMS::enableOutputInVidmem is set to 0, specifies the pointer to motion vector data buffer allocated by NvEncCreateMVBuffer. + Client must lock mvBuffer using ::NvEncLockBitstream() API to get the motion vector data. + If NV_ENC_INITIALIZE_PARAMS::enableOutputInVidmem is set to 1, client should allocate buffer in video memory for storing the motion vector data. The size of this buffer must + be equal to total number of macroblocks multiplied by size of NV_ENC_H264_MV_DATA struct. Client should use a pointer obtained from ::NvEncMapInputResource() API, when mapping this + output buffer and assign it to NV_ENC_MEONLY_PARAMS::mvBuffer. All CUDA operations on this buffer must use the default stream. */ + uint32_t reserved2; /**< [in]: Reserved and must be set to 0 */ + NV_ENC_BUFFER_FORMAT bufferFmt; /**< [in]: Specifies the input buffer format. */ + void* completionEvent; /**< [in]: Specifies an event to be signaled on completion of motion estimation + of this Frame [only if operating in Asynchronous mode]. + Each output buffer should be associated with a distinct event pointer. */ + uint32_t viewID; /**< [in]: Specifies left or right viewID if NV_ENC_CONFIG_H264_MEONLY::bStereoEnable is set. + viewID can be 0,1 if bStereoEnable is set, 0 otherwise. */ + NVENC_EXTERNAL_ME_HINT_COUNTS_PER_BLOCKTYPE + meHintCountsPerBlock[2]; /**< [in]: Specifies the number of hint candidates per block for the current frame. meHintCountsPerBlock[0] is for L0 predictors. + The candidate count in NV_ENC_PIC_PARAMS::meHintCountsPerBlock[lx] must never exceed NV_ENC_INITIALIZE_PARAMS::maxMEHintCountsPerBlock[lx] provided during encoder initialization. */ + NVENC_EXTERNAL_ME_HINT *meExternalHints; /**< [in]: Specifies the pointer to ME external hints for the current frame. The size of ME hint buffer should be equal to number of macroblocks * the total number of candidates per macroblock. + The total number of candidates per MB per direction = 1*meHintCountsPerBlock[Lx].numCandsPerBlk16x16 + 2*meHintCountsPerBlock[Lx].numCandsPerBlk16x8 + 2*meHintCountsPerBlock[Lx].numCandsPerBlk8x16 + + 4*meHintCountsPerBlock[Lx].numCandsPerBlk8x8. For frames using bidirectional ME , the total number of candidates for single macroblock is sum of total number of candidates per MB for each direction (L0 and L1) */ + uint32_t reserved1[241]; /**< [in]: Reserved and must be set to 0 */ + void* reserved3[59]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_MEONLY_PARAMS; + +/** NV_ENC_MEONLY_PARAMS struct version*/ +#define NV_ENC_MEONLY_PARAMS_VER NVENCAPI_STRUCT_VERSION(4) + + +/** + * \struct _NV_ENC_LOCK_BITSTREAM + * Bitstream buffer lock parameters. + */ +typedef struct _NV_ENC_LOCK_BITSTREAM +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_LOCK_BITSTREAM_VER. */ + uint32_t doNotWait :1; /**< [in]: If this flag is set, the NvEncodeAPI interface will return buffer pointer even if operation is not completed. If not set, the call will block until operation completes. */ + uint32_t ltrFrame :1; /**< [out]: Flag indicating this frame is marked as LTR frame */ + uint32_t getRCStats :1; /**< [in]: If this flag is set then lockBitstream call will add additional intra-inter MB count and average MVX, MVY */ + uint32_t reservedBitFields :29; /**< [in]: Reserved bit fields and must be set to 0 */ + void* outputBitstream; /**< [in]: Pointer to the bitstream buffer being locked. */ + uint32_t* sliceOffsets; /**< [in, out]: Array which receives the slice (H264/HEVC) or tile (AV1) offsets. This is not supported if NV_ENC_CONFIG_H264::sliceMode is 1 on Kepler GPUs. Array size must be equal to size of frame in MBs. */ + uint32_t frameIdx; /**< [out]: Frame no. for which the bitstream is being retrieved. */ + uint32_t hwEncodeStatus; /**< [out]: The NvEncodeAPI interface status for the locked picture. */ + uint32_t numSlices; /**< [out]: Number of slices (H264/HEVC) or tiles (AV1) in the encoded picture. Will be reported only if NV_ENC_INITIALIZE_PARAMS::reportSliceOffsets set to 1. */ + uint32_t bitstreamSizeInBytes; /**< [out]: Actual number of bytes generated and copied to the memory pointed by bitstreamBufferPtr. + When HEVC alpha layer encoding is enabled, this field reports the total encoded size in bytes i.e it is the encoded size of the base plus the alpha layer. + For AV1 when enablePTD is set, this field reports the total encoded size in bytes of all the encoded frames packed into the current output surface i.e. show frame plus all preceding no-show frames */ + uint64_t outputTimeStamp; /**< [out]: Presentation timestamp associated with the encoded output. */ + uint64_t outputDuration; /**< [out]: Presentation duration associated with the encoded output. */ + void* bitstreamBufferPtr; /**< [out]: Pointer to the generated output bitstream. + For MEOnly mode _NV_ENC_LOCK_BITSTREAM::bitstreamBufferPtr should be typecast to + NV_ENC_H264_MV_DATA/NV_ENC_HEVC_MV_DATA pointer respectively for H264/HEVC */ + NV_ENC_PIC_TYPE pictureType; /**< [out]: Picture type of the encoded picture. */ + NV_ENC_PIC_STRUCT pictureStruct; /**< [out]: Structure of the generated output picture. */ + uint32_t frameAvgQP; /**< [out]: Average QP of the frame. */ + uint32_t frameSatd; /**< [out]: Total SATD cost for whole frame. */ + uint32_t ltrFrameIdx; /**< [out]: Frame index associated with this LTR frame. */ + uint32_t ltrFrameBitmap; /**< [out]: Bitmap of LTR frames indices which were used for encoding this frame. Value of 0 if no LTR frames were used. */ + uint32_t temporalId; /**< [out]: TemporalId value of the frame when using temporalSVC encoding */ + uint32_t intraMBCount; /**< [out]: For H264, Number of Intra MBs in the encoded frame. For HEVC, Number of Intra CTBs in the encoded frame. For AV1, Number of Intra SBs in the encoded show frame. Supported only if _NV_ENC_LOCK_BITSTREAM::getRCStats set to 1. */ + uint32_t interMBCount; /**< [out]: For H264, Number of Inter MBs in the encoded frame, includes skip MBs. For HEVC, Number of Inter CTBs in the encoded frame. For AV1, Number of Inter SBs in the encoded show frame. Supported only if _NV_ENC_LOCK_BITSTREAM::getRCStats set to 1. */ + int32_t averageMVX; /**< [out]: Average Motion Vector in X direction for the encoded frame. Supported only if _NV_ENC_LOCK_BITSTREAM::getRCStats set to 1. */ + int32_t averageMVY; /**< [out]: Average Motion Vector in y direction for the encoded frame. Supported only if _NV_ENC_LOCK_BITSTREAM::getRCStats set to 1. */ + uint32_t alphaLayerSizeInBytes; /**< [out]: Number of bytes generated for the alpha layer in the encoded output. Applicable only when HEVC with alpha encoding is enabled. */ + uint32_t outputStatsPtrSize; /**< [in]: Size of the buffer pointed by NV_ENC_LOCK_BITSTREAM::outputStatsPtr. */ + uint32_t reserved; /**< [in]: Reserved and must be set to 0 */ + void* outputStatsPtr; /**< [in, out]: Buffer which receives the encoded frame output stats, if NV_ENC_INITIALIZE_PARAMS::enableOutputStats is set to 1. */ + uint32_t frameIdxDisplay; /**< [out]: Frame index in display order */ + uint32_t reserved1[219]; /**< [in]: Reserved and must be set to 0 */ + void* reserved2[63]; /**< [in]: Reserved and must be set to NULL */ + uint32_t reservedInternal[8]; /**< [in]: Reserved and must be set to 0 */ +} NV_ENC_LOCK_BITSTREAM; + +#define NV_ENC_LOCK_BITSTREAM_VER (NVENCAPI_STRUCT_VERSION(2) | ( 1u<<31 )) + +/** + * \struct _NV_ENC_LOCK_INPUT_BUFFER + * Uncompressed Input Buffer lock parameters. + */ +typedef struct _NV_ENC_LOCK_INPUT_BUFFER +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_LOCK_INPUT_BUFFER_VER. */ + uint32_t doNotWait :1; /**< [in]: Set to 1 to make ::NvEncLockInputBuffer() a unblocking call. If the encoding is not completed, driver will return ::NV_ENC_ERR_ENCODER_BUSY error code. */ + uint32_t reservedBitFields :31; /**< [in]: Reserved bitfields and must be set to 0 */ + NV_ENC_INPUT_PTR inputBuffer; /**< [in]: Pointer to the input buffer to be locked, client should pass the pointer obtained from ::NvEncCreateInputBuffer() or ::NvEncMapInputResource API. */ + void* bufferDataPtr; /**< [out]: Pointed to the locked input buffer data. Client can only access input buffer using the \p bufferDataPtr. */ + uint32_t pitch; /**< [out]: Pitch of the locked input buffer. */ + uint32_t reserved1[251]; /**< [in]: Reserved and must be set to 0 */ + void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_LOCK_INPUT_BUFFER; + +/** Macro for constructing the version field of ::_NV_ENC_LOCK_INPUT_BUFFER */ +#define NV_ENC_LOCK_INPUT_BUFFER_VER NVENCAPI_STRUCT_VERSION(1) + + +/** + * \struct _NV_ENC_MAP_INPUT_RESOURCE + * Map an input resource to a Nvidia Encoder Input Buffer + */ +typedef struct _NV_ENC_MAP_INPUT_RESOURCE +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_MAP_INPUT_RESOURCE_VER. */ + uint32_t subResourceIndex; /**< [in]: Deprecated. Do not use. */ + void* inputResource; /**< [in]: Deprecated. Do not use. */ + NV_ENC_REGISTERED_PTR registeredResource; /**< [in]: The Registered resource handle obtained by calling NvEncRegisterInputResource. */ + NV_ENC_INPUT_PTR mappedResource; /**< [out]: Mapped pointer corresponding to the registeredResource. This pointer must be used in NV_ENC_PIC_PARAMS::inputBuffer parameter in ::NvEncEncodePicture() API. */ + NV_ENC_BUFFER_FORMAT mappedBufferFmt; /**< [out]: Buffer format of the outputResource. This buffer format must be used in NV_ENC_PIC_PARAMS::bufferFmt if client using the above mapped resource pointer. */ + uint32_t reserved1[251]; /**< [in]: Reserved and must be set to 0. */ + void* reserved2[63]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_MAP_INPUT_RESOURCE; + +/** Macro for constructing the version field of ::_NV_ENC_MAP_INPUT_RESOURCE */ +#define NV_ENC_MAP_INPUT_RESOURCE_VER NVENCAPI_STRUCT_VERSION(4) + +/** + * \struct _NV_ENC_INPUT_RESOURCE_OPENGL_TEX + * NV_ENC_REGISTER_RESOURCE::resourceToRegister must be a pointer to a variable of this type, + * when NV_ENC_REGISTER_RESOURCE::resourceType is NV_ENC_INPUT_RESOURCE_TYPE_OPENGL_TEX + */ +typedef struct _NV_ENC_INPUT_RESOURCE_OPENGL_TEX +{ + uint32_t texture; /**< [in]: The name of the texture to be used. */ + uint32_t target; /**< [in]: Accepted values are GL_TEXTURE_RECTANGLE and GL_TEXTURE_2D. */ +} NV_ENC_INPUT_RESOURCE_OPENGL_TEX; + +/** \struct NV_ENC_FENCE_POINT_D3D12 +* Fence and fence value for synchronization. +*/ +typedef struct _NV_ENC_FENCE_POINT_D3D12 +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_FENCE_POINT_D3D12_VER. */ + uint32_t reserved; /**< [in]: Reserved and must be set to 0. */ + void* pFence; /**< [in]: Pointer to ID3D12Fence. This fence object is used for synchronization. */ + uint64_t waitValue; /**< [in]: Fence value to reach or exceed before the GPU operation. */ + uint64_t signalValue; /**< [in]: Fence value to set the fence to, after the GPU operation. */ + uint32_t bWait:1; /**< [in]: Wait on 'waitValue' if bWait is set to 1, before starting GPU operation. */ + uint32_t bSignal:1; /**< [in]: Signal on 'signalValue' if bSignal is set to 1, after GPU operation is complete. */ + uint32_t reservedBitField:30; /**< [in]: Reserved and must be set to 0. */ + uint32_t reserved1[7]; /**< [in]: Reserved and must be set to 0. */ +} NV_ENC_FENCE_POINT_D3D12; + +#define NV_ENC_FENCE_POINT_D3D12_VER NVENCAPI_STRUCT_VERSION(1) + +/** + * \struct _NV_ENC_INPUT_RESOURCE_D3D12 + * NV_ENC_PIC_PARAMS::inputBuffer and NV_ENC_PIC_PARAMS::alphaBuffer must be a pointer to a struct of this type, + * when D3D12 interface is used + */ +typedef struct _NV_ENC_INPUT_RESOURCE_D3D12 +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_INPUT_RESOURCE_D3D12_VER. */ + uint32_t reserved; /**< [in]: Reserved and must be set to 0. */ + NV_ENC_INPUT_PTR pInputBuffer; /**< [in]: Specifies the input surface pointer. Client must use a pointer obtained from NvEncMapInputResource() in NV_ENC_MAP_INPUT_RESOURCE::mappedResource + when mapping the input surface. */ + NV_ENC_FENCE_POINT_D3D12 inputFencePoint; /**< [in]: Specifies the fence and corresponding fence values to do GPU wait and signal. */ + uint32_t reserved1[16]; /**< [in]: Reserved and must be set to 0. */ + void* reserved2[16]; /**< [in]: Reserved and must be set to NULL. */ +} NV_ENC_INPUT_RESOURCE_D3D12; + +#define NV_ENC_INPUT_RESOURCE_D3D12_VER NVENCAPI_STRUCT_VERSION(1) + +/** + * \struct _NV_ENC_OUTPUT_RESOURCE_D3D12 + * NV_ENC_PIC_PARAMS::outputBitstream and NV_ENC_LOCK_BITSTREAM::outputBitstream must be a pointer to a struct of this type, + * when D3D12 interface is used + */ +typedef struct _NV_ENC_OUTPUT_RESOURCE_D3D12 +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_OUTPUT_RESOURCE_D3D12_VER. */ + uint32_t reserved; /**< [in]: Reserved and must be set to 0. */ + NV_ENC_INPUT_PTR pOutputBuffer; /**< [in]: Specifies the output buffer pointer. Client must use a pointer obtained from NvEncMapInputResource() in NV_ENC_MAP_INPUT_RESOURCE::mappedResource + when mapping output bitstream buffer */ + NV_ENC_FENCE_POINT_D3D12 outputFencePoint; /**< [in]: Specifies the fence and corresponding fence values to do GPU wait and signal.*/ + uint32_t reserved1[16]; /**< [in]: Reserved and must be set to 0. */ + void* reserved2[16]; /**< [in]: Reserved and must be set to NULL. */ +} NV_ENC_OUTPUT_RESOURCE_D3D12; + +#define NV_ENC_OUTPUT_RESOURCE_D3D12_VER NVENCAPI_STRUCT_VERSION(1) + +/** + * \struct _NV_ENC_REGISTER_RESOURCE + * Register a resource for future use with the Nvidia Video Encoder Interface. + */ +typedef struct _NV_ENC_REGISTER_RESOURCE +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_REGISTER_RESOURCE_VER. */ + NV_ENC_INPUT_RESOURCE_TYPE resourceType; /**< [in]: Specifies the type of resource to be registered. + Supported values are + ::NV_ENC_INPUT_RESOURCE_TYPE_DIRECTX, + ::NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR, + ::NV_ENC_INPUT_RESOURCE_TYPE_OPENGL_TEX */ + uint32_t width; /**< [in]: Input frame width. */ + uint32_t height; /**< [in]: Input frame height. */ + uint32_t pitch; /**< [in]: Input buffer pitch. + For ::NV_ENC_INPUT_RESOURCE_TYPE_DIRECTX resources, set this to 0. + For ::NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR resources, set this to + the pitch as obtained from cuMemAllocPitch(), or to the width in + bytes (if this resource was created by using cuMemAlloc()). This + value must be a multiple of 4. + For ::NV_ENC_INPUT_RESOURCE_TYPE_CUDAARRAY resources, set this to the + width of the allocation in bytes (i.e. + CUDA_ARRAY3D_DESCRIPTOR::Width * CUDA_ARRAY3D_DESCRIPTOR::NumChannels). + For ::NV_ENC_INPUT_RESOURCE_TYPE_OPENGL_TEX resources, set this to the + texture width multiplied by the number of components in the texture + format. */ + uint32_t subResourceIndex; /**< [in]: Subresource Index of the DirectX resource to be registered. Should be set to 0 for other interfaces. */ + void* resourceToRegister; /**< [in]: Handle to the resource that is being registered. */ + NV_ENC_REGISTERED_PTR registeredResource; /**< [out]: Registered resource handle. This should be used in future interactions with the Nvidia Video Encoder Interface. */ + NV_ENC_BUFFER_FORMAT bufferFormat; /**< [in]: Buffer format of resource to be registered. */ + NV_ENC_BUFFER_USAGE bufferUsage; /**< [in]: Usage of resource to be registered. */ + NV_ENC_FENCE_POINT_D3D12* pInputFencePoint; /**< [in]: Specifies the input fence and corresponding fence values to do GPU wait and signal. + To be used only when NV_ENC_REGISTER_RESOURCE::resourceToRegister represents D3D12 surface and + NV_ENC_BUFFER_USAGE::bufferUsage is NV_ENC_INPUT_IMAGE. + The fence NV_ENC_FENCE_POINT_D3D12::pFence and NV_ENC_FENCE_POINT_D3D12::waitValue will be used to do GPU wait + before starting GPU operation, if NV_ENC_FENCE_POINT_D3D12::bWait is set. + The fence NV_ENC_FENCE_POINT_D3D12::pFence and NV_ENC_FENCE_POINT_D3D12::signalValue will be used to do GPU signal + when GPU operation finishes, if NV_ENC_FENCE_POINT_D3D12::bSignal is set. */ + uint32_t chromaOffset[2]; /**< [out]: Chroma offset for the reconstructed output buffer when NV_ENC_BUFFER_USAGE::bufferUsage is set + to NV_ENC_OUTPUT_RECON and D3D11 interface is used. + When chroma components are interleaved, 'chromaOffset[0]' will contain chroma offset. + chromaOffset[1] is reserved for future use. */ + uint32_t chromaOffsetIn[2]; /**< [in]: Chroma offset for input buffer when NV_ENC_BUFFER_USAGE::bufferUsage is set to NV_ENC_INPUT_IMAGE + and NVCUVID interface is used. This is required only when luma and chroma allocations are not continuous, + and the planes are padded. */ + uint32_t reserved1[244]; /**< [in]: Reserved and must be set to 0. */ + void* reserved2[61]; /**< [in]: Reserved and must be set to NULL. */ +} NV_ENC_REGISTER_RESOURCE; + +/** Macro for constructing the version field of ::_NV_ENC_REGISTER_RESOURCE */ +#define NV_ENC_REGISTER_RESOURCE_VER NVENCAPI_STRUCT_VERSION(5) + +/** + * \struct _NV_ENC_STAT + * Encode Stats structure. + */ +typedef struct _NV_ENC_STAT +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_STAT_VER. */ + uint32_t reserved; /**< [in]: Reserved and must be set to 0 */ + NV_ENC_OUTPUT_PTR outputBitStream; /**< [in]: Specifies the pointer to output bitstream. */ + uint32_t bitStreamSize; /**< [out]: Size of generated bitstream in bytes. */ + uint32_t picType; /**< [out]: Picture type of encoded picture. See ::NV_ENC_PIC_TYPE. */ + uint32_t lastValidByteOffset; /**< [out]: Offset of last valid bytes of completed bitstream */ + uint32_t sliceOffsets[16]; /**< [out]: Offsets of each slice */ + uint32_t picIdx; /**< [out]: Picture number */ + uint32_t frameAvgQP; /**< [out]: Average QP of the frame. */ + uint32_t ltrFrame :1; /**< [out]: Flag indicating this frame is marked as LTR frame */ + uint32_t reservedBitFields :31; /**< [in]: Reserved bit fields and must be set to 0 */ + uint32_t ltrFrameIdx; /**< [out]: Frame index associated with this LTR frame. */ + uint32_t intraMBCount; /**< [out]: For H264, Number of Intra MBs in the encoded frame. For HEVC, Number of Intra CTBs in the encoded frame. */ + uint32_t interMBCount; /**< [out]: For H264, Number of Inter MBs in the encoded frame, includes skip MBs. For HEVC, Number of Inter CTBs in the encoded frame. */ + int32_t averageMVX; /**< [out]: Average Motion Vector in X direction for the encoded frame. */ + int32_t averageMVY; /**< [out]: Average Motion Vector in y direction for the encoded frame. */ + uint32_t reserved1[227]; /**< [in]: Reserved and must be set to 0 */ + void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_STAT; + +/** Macro for constructing the version field of ::_NV_ENC_STAT */ +#define NV_ENC_STAT_VER NVENCAPI_STRUCT_VERSION(2) + + +/** + * \struct _NV_ENC_SEQUENCE_PARAM_PAYLOAD + * Sequence and picture parameters payload. + */ +typedef struct _NV_ENC_SEQUENCE_PARAM_PAYLOAD +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_SEQUENCE_PARAM_PAYLOAD_VER. */ + uint32_t inBufferSize; /**< [in]: Specifies the size of the spsppsBuffer provided by the client */ + uint32_t spsId; /**< [in]: Specifies the SPS id to be used in sequence header. Default value is 0. */ + uint32_t ppsId; /**< [in]: Specifies the PPS id to be used in picture header. Default value is 0. */ + void* spsppsBuffer; /**< [in]: Specifies bitstream header pointer of size NV_ENC_SEQUENCE_PARAM_PAYLOAD::inBufferSize. + It is the client's responsibility to manage this memory. */ + uint32_t* outSPSPPSPayloadSize; /**< [out]: Size of the sequence and picture header in bytes. */ + uint32_t reserved [250]; /**< [in]: Reserved and must be set to 0 */ + void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_SEQUENCE_PARAM_PAYLOAD; + +/** Macro for constructing the version field of ::_NV_ENC_SEQUENCE_PARAM_PAYLOAD */ +#define NV_ENC_SEQUENCE_PARAM_PAYLOAD_VER NVENCAPI_STRUCT_VERSION(1) + + +/** + * Event registration/unregistration parameters. + */ +typedef struct _NV_ENC_EVENT_PARAMS +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_EVENT_PARAMS_VER. */ + uint32_t reserved; /**< [in]: Reserved and must be set to 0 */ + void* completionEvent; /**< [in]: Handle to event to be registered/unregistered with the NvEncodeAPI interface. */ + uint32_t reserved1[254]; /**< [in]: Reserved and must be set to 0 */ + void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_EVENT_PARAMS; + +/** Macro for constructing the version field of ::_NV_ENC_EVENT_PARAMS */ +#define NV_ENC_EVENT_PARAMS_VER NVENCAPI_STRUCT_VERSION(2) + +/** + * Encoder Session Creation parameters + */ +typedef struct _NV_ENC_OPEN_ENCODE_SESSIONEX_PARAMS +{ + uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER. */ + NV_ENC_DEVICE_TYPE deviceType; /**< [in]: Specifies the device Type */ + void* device; /**< [in]: Pointer to client device. */ + void* reserved; /**< [in]: Reserved and must be set to 0. */ + uint32_t apiVersion; /**< [in]: API version. Should be set to NVENCAPI_VERSION. */ + uint32_t reserved1[253]; /**< [in]: Reserved and must be set to 0 */ + void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS; +/** Macro for constructing the version field of ::_NV_ENC_OPEN_ENCODE_SESSIONEX_PARAMS */ +#define NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER NVENCAPI_STRUCT_VERSION(1) + +/** @} */ /* END ENCODER_STRUCTURE */ + + +/** + * \addtogroup ENCODE_FUNC NvEncodeAPI Functions + * @{ + */ + +// NvEncOpenEncodeSession +/** + * \brief Opens an encoding session. + * + * Deprecated. + * + * \return + * ::NV_ENC_ERR_INVALID_CALL\n + * + */ +NVENCSTATUS NVENCAPI NvEncOpenEncodeSession (void* device, uint32_t deviceType, void** encoder); + +// NvEncGetEncodeGuidCount +/** + * \brief Retrieves the number of supported encode GUIDs. + * + * The function returns the number of codec GUIDs supported by the NvEncodeAPI + * interface. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [out] encodeGUIDCount + * Number of supported encode GUIDs. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncGetEncodeGUIDCount (void* encoder, uint32_t* encodeGUIDCount); + + +// NvEncGetEncodeGUIDs +/** + * \brief Retrieves an array of supported encoder codec GUIDs. + * + * The function returns an array of codec GUIDs supported by the NvEncodeAPI interface. + * The client must allocate an array where the NvEncodeAPI interface can + * fill the supported GUIDs and pass the pointer in \p *GUIDs parameter. + * The size of the array can be determined by using ::NvEncGetEncodeGUIDCount() API. + * The Nvidia Encoding interface returns the number of codec GUIDs it has actually + * filled in the GUID array in the \p GUIDCount parameter. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] guidArraySize + * Number of GUIDs to retrieved. Should be set to the number retrieved using + * ::NvEncGetEncodeGUIDCount. + * \param [out] GUIDs + * Array of supported Encode GUIDs. + * \param [out] GUIDCount + * Number of supported Encode GUIDs. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncGetEncodeGUIDs (void* encoder, GUID* GUIDs, uint32_t guidArraySize, uint32_t* GUIDCount); + + +// NvEncGetEncodeProfileGuidCount +/** + * \brief Retrieves the number of supported profile GUIDs. + * + * The function returns the number of profile GUIDs supported for a given codec. + * The client must first enumerate the codec GUIDs supported by the NvEncodeAPI + * interface. After determining the codec GUID, it can query the NvEncodeAPI + * interface to determine the number of profile GUIDs supported for a particular + * codec GUID. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] encodeGUID + * The codec GUID for which the profile GUIDs are being enumerated. + * \param [out] encodeProfileGUIDCount + * Number of encode profiles supported for the given encodeGUID. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncGetEncodeProfileGUIDCount (void* encoder, GUID encodeGUID, uint32_t* encodeProfileGUIDCount); + + +// NvEncGetEncodeProfileGUIDs +/** + * \brief Retrieves an array of supported encode profile GUIDs. + * + * The function returns an array of supported profile GUIDs for a particular + * codec GUID. The client must allocate an array where the NvEncodeAPI interface + * can populate the profile GUIDs. The client can determine the array size using + * ::NvEncGetEncodeProfileGUIDCount() API. The client must also validiate that the + * NvEncodeAPI interface supports the GUID the client wants to pass as \p encodeGUID + * parameter. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] encodeGUID + * The encode GUID whose profile GUIDs are being enumerated. + * \param [in] guidArraySize + * Number of GUIDs to be retrieved. Should be set to the number retrieved using + * ::NvEncGetEncodeProfileGUIDCount. + * \param [out] profileGUIDs + * Array of supported Encode Profile GUIDs + * \param [out] GUIDCount + * Number of valid encode profile GUIDs in \p profileGUIDs array. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncGetEncodeProfileGUIDs (void* encoder, GUID encodeGUID, GUID* profileGUIDs, uint32_t guidArraySize, uint32_t* GUIDCount); + +// NvEncGetInputFormatCount +/** + * \brief Retrieve the number of supported Input formats. + * + * The function returns the number of supported input formats. The client must + * query the NvEncodeAPI interface to determine the supported input formats + * before creating the input surfaces. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] encodeGUID + * Encode GUID, corresponding to which the number of supported input formats + * is to be retrieved. + * \param [out] inputFmtCount + * Number of input formats supported for specified Encode GUID. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_GENERIC \n + */ +NVENCSTATUS NVENCAPI NvEncGetInputFormatCount (void* encoder, GUID encodeGUID, uint32_t* inputFmtCount); + + +// NvEncGetInputFormats +/** + * \brief Retrieves an array of supported Input formats + * + * Returns an array of supported input formats The client must use the input + * format to create input surface using ::NvEncCreateInputBuffer() API. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] encodeGUID + * Encode GUID, corresponding to which the number of supported input formats + * is to be retrieved. + *\param [in] inputFmtArraySize + * Size input format count array passed in \p inputFmts. + *\param [out] inputFmts + * Array of input formats supported for this Encode GUID. + *\param [out] inputFmtCount + * The number of valid input format types returned by the NvEncodeAPI + * interface in \p inputFmts array. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncGetInputFormats (void* encoder, GUID encodeGUID, NV_ENC_BUFFER_FORMAT* inputFmts, uint32_t inputFmtArraySize, uint32_t* inputFmtCount); + + +// NvEncGetEncodeCaps +/** + * \brief Retrieves the capability value for a specified encoder attribute. + * + * The function returns the capability value for a given encoder attribute. The + * client must validate the encodeGUID using ::NvEncGetEncodeGUIDs() API before + * calling this function. The encoder attribute being queried are enumerated in + * ::NV_ENC_CAPS_PARAM enum. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] encodeGUID + * Encode GUID, corresponding to which the capability attribute is to be retrieved. + * \param [in] capsParam + * Used to specify attribute being queried. Refer ::NV_ENC_CAPS_PARAM for more + * details. + * \param [out] capsVal + * The value corresponding to the capability attribute being queried. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_GENERIC \n + */ +NVENCSTATUS NVENCAPI NvEncGetEncodeCaps (void* encoder, GUID encodeGUID, NV_ENC_CAPS_PARAM* capsParam, int* capsVal); + + +// NvEncGetEncodePresetCount +/** + * \brief Retrieves the number of supported preset GUIDs. + * + * The function returns the number of preset GUIDs available for a given codec. + * The client must validate the codec GUID using ::NvEncGetEncodeGUIDs() API + * before calling this function. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] encodeGUID + * Encode GUID, corresponding to which the number of supported presets is to + * be retrieved. + * \param [out] encodePresetGUIDCount + * Receives the number of supported preset GUIDs. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncGetEncodePresetCount (void* encoder, GUID encodeGUID, uint32_t* encodePresetGUIDCount); + + +// NvEncGetEncodePresetGUIDs +/** + * \brief Receives an array of supported encoder preset GUIDs. + * + * The function returns an array of encode preset GUIDs available for a given codec. + * The client can directly use one of the preset GUIDs based upon the use case + * or target device. The preset GUID chosen can be directly used in + * NV_ENC_INITIALIZE_PARAMS::presetGUID parameter to ::NvEncInitializeEncoder() API. + * Alternately client can also use the preset GUID to retrieve the encoding config + * parameters being used by NvEncodeAPI interface for that given preset, using + * ::NvEncGetEncodePresetConfig() API. It can then modify preset config parameters + * as per its use case and send it to NvEncodeAPI interface as part of + * NV_ENC_INITIALIZE_PARAMS::encodeConfig parameter for NvEncInitializeEncoder() + * API. + * + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] encodeGUID + * Encode GUID, corresponding to which the list of supported presets is to be + * retrieved. + * \param [in] guidArraySize + * Size of array of preset GUIDs passed in \p preset GUIDs + * \param [out] presetGUIDs + * Array of supported Encode preset GUIDs from the NvEncodeAPI interface + * to client. + * \param [out] encodePresetGUIDCount + * Receives the number of preset GUIDs returned by the NvEncodeAPI + * interface. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncGetEncodePresetGUIDs (void* encoder, GUID encodeGUID, GUID* presetGUIDs, uint32_t guidArraySize, uint32_t* encodePresetGUIDCount); + + +// NvEncGetEncodePresetConfig +/** + * \brief Returns a preset config structure supported for given preset GUID. + * + * NOTE : This function is not supported starting from driver version 590 (will return NV_ENC_ERR_UNSUPPORTED_PARAM) + * + * The function returns a preset config structure for a given preset GUID. + * NvEncGetEncodePresetConfig() API is not applicable to AV1. + * Before using this function the client must enumerate the preset GUIDs available for + * a given codec. The preset config structure can be modified by the client depending + * upon its use case and can be then used to initialize the encoder using + * ::NvEncInitializeEncoder() API. The client can use this function only if it + * wants to modify the NvEncodeAPI preset configuration, otherwise it can + * directly use the preset GUID. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] encodeGUID + * Encode GUID, corresponding to which the list of supported presets is to be + * retrieved. + * \param [in] presetGUID + * Preset GUID, corresponding to which the Encoding configurations is to be + * retrieved. + * \param [out] presetConfig + * The requested Preset Encoder Attribute set. Refer ::_NV_ENC_CONFIG for +* more details. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncGetEncodePresetConfig (void* encoder, GUID encodeGUID, GUID presetGUID, NV_ENC_PRESET_CONFIG* presetConfig); + +// NvEncGetEncodePresetConfigEx +/** + * \brief Returns a preset config structure supported for given preset GUID. + * + * The function returns a preset config structure for a given preset GUID and tuning info. + * NvEncGetEncodePresetConfigEx() API is not applicable to H264 and HEVC meonly mode. + * Before using this function the client must enumerate the preset GUIDs available for + * a given codec. The preset config structure can be modified by the client depending + * upon its use case and can be then used to initialize the encoder using + * ::NvEncInitializeEncoder() API. The client can use this function only if it + * wants to modify the NvEncodeAPI preset configuration, otherwise it can + * directly use the preset GUID. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] encodeGUID + * Encode GUID, corresponding to which the list of supported presets is to be + * retrieved. + * \param [in] presetGUID + * Preset GUID, corresponding to which the Encoding configurations is to be + * retrieved. + * \param [in] tuningInfo + * tuning info, corresponding to which the Encoding configurations is to be + * retrieved. + * \param [out] presetConfig + * The requested Preset Encoder Attribute set. Refer ::_NV_ENC_CONFIG for + * more details. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncGetEncodePresetConfigEx (void* encoder, GUID encodeGUID, GUID presetGUID, NV_ENC_TUNING_INFO tuningInfo, NV_ENC_PRESET_CONFIG* presetConfig); + +// NvEncInitializeEncoder +/** + * \brief Initialize the encoder. + * + * This API must be used to initialize the encoder. The initialization parameter + * is passed using \p *createEncodeParams The client must send the following + * fields of the _NV_ENC_INITIALIZE_PARAMS structure with a valid value. + * - NV_ENC_INITIALIZE_PARAMS::encodeGUID + * - NV_ENC_INITIALIZE_PARAMS::encodeWidth + * - NV_ENC_INITIALIZE_PARAMS::encodeHeight + * + * The client can pass a preset GUID directly to the NvEncodeAPI interface using + * NV_ENC_INITIALIZE_PARAMS::presetGUID field. If the client doesn't pass + * NV_ENC_INITIALIZE_PARAMS::encodeConfig structure, the codec specific parameters + * will be selected based on the preset GUID. The preset GUID must have been + * validated by the client using ::NvEncGetEncodePresetGUIDs() API. + * If the client passes a custom ::_NV_ENC_CONFIG structure through + * NV_ENC_INITIALIZE_PARAMS::encodeConfig , it will override the codec specific parameters + * based on the preset GUID. It is recommended that even if the client passes a custom config, + * it should also send a preset GUID. In this case, the preset GUID passed by the client + * will not override any of the custom config parameters programmed by the client, + * it is only used as a hint by the NvEncodeAPI interface to determine certain encoder parameters + * which are not exposed to the client. + * + * There are two modes of operation for the encoder namely: + * - Asynchronous mode + * - Synchronous mode + * + * The client can select asynchronous or synchronous mode by setting the \p + * enableEncodeAsync field in ::_NV_ENC_INITIALIZE_PARAMS to 1 or 0 respectively. + *\par Asynchronous mode of operation: + * The Asynchronous mode can be enabled by setting NV_ENC_INITIALIZE_PARAMS::enableEncodeAsync to 1. + * The client operating in asynchronous mode must allocate completion event object + * for each output buffer and pass the completion event object in the + * ::NvEncEncodePicture() API. The client can create another thread and wait on + * the event object to be signaled by NvEncodeAPI interface on completion of the + * encoding process for the output frame. This should unblock the main thread from + * submitting work to the encoder. When the event is signaled the client can call + * NvEncodeAPI interfaces to copy the bitstream data using ::NvEncLockBitstream() + * API. This is the preferred mode of operation. + * + * NOTE: Asynchronous mode is not supported on Linux. + * + *\par Synchronous mode of operation: + * The client can select synchronous mode by setting NV_ENC_INITIALIZE_PARAMS::enableEncodeAsync to 0. + * The client working in synchronous mode can work in a single threaded or multi + * threaded mode. The client need not allocate any event objects. The client can + * only lock the bitstream data after NvEncodeAPI interface has returned + * ::NV_ENC_SUCCESS from encode picture. The NvEncodeAPI interface can return + * ::NV_ENC_ERR_NEED_MORE_INPUT error code from ::NvEncEncodePicture() API. The + * client must not lock the output buffer in such case but should send the next + * frame for encoding. The client must keep on calling ::NvEncEncodePicture() API + * until it returns ::NV_ENC_SUCCESS. \n + * The client must always lock the bitstream data in order in which it has submitted. + * This is true for both asynchronous and synchronous mode. + * + *\par Picture type decision: + * If the client is taking the picture type decision and it must disable the picture + * type decision module in NvEncodeAPI by setting NV_ENC_INITIALIZE_PARAMS::enablePTD + * to 0. In this case the client is required to send the picture in encoding + * order to NvEncodeAPI by doing the re-ordering for B frames. \n + * If the client doesn't want to take the picture type decision it can enable + * picture type decision module in the NvEncodeAPI interface by setting + * NV_ENC_INITIALIZE_PARAMS::enablePTD to 1 and send the input pictures in display + * order. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] createEncodeParams + * Refer ::_NV_ENC_INITIALIZE_PARAMS for details. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncInitializeEncoder (void* encoder, NV_ENC_INITIALIZE_PARAMS* createEncodeParams); + + +// NvEncCreateInputBuffer +/** + * \brief Allocates Input buffer. + * + * This function is used to allocate an input buffer. The client must enumerate + * the input buffer format before allocating the input buffer resources. The + * NV_ENC_INPUT_PTR returned by the NvEncodeAPI interface in the + * NV_ENC_CREATE_INPUT_BUFFER::inputBuffer field can be directly used in + * ::NvEncEncodePicture() API. The number of input buffers to be allocated by the + * client must be at least 4 more than the number of B frames being used for encoding. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in,out] createInputBufferParams + * Pointer to the ::NV_ENC_CREATE_INPUT_BUFFER structure. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncCreateInputBuffer (void* encoder, NV_ENC_CREATE_INPUT_BUFFER* createInputBufferParams); + + +// NvEncDestroyInputBuffer +/** + * \brief Release an input buffers. + * + * This function is used to free an input buffer. If the client has allocated + * any input buffer using ::NvEncCreateInputBuffer() API, it must free those + * input buffers by calling this function. The client must release the input + * buffers before destroying the encoder using ::NvEncDestroyEncoder() API. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] inputBuffer + * Pointer to the input buffer to be released. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncDestroyInputBuffer (void* encoder, NV_ENC_INPUT_PTR inputBuffer); + +// NvEncSetIOCudaStreams +/** + * \brief Set input and output CUDA stream for specified encoder attribute. + * + * Encoding may involve CUDA pre-processing on the input and post-processing on encoded output. + * This function is used to set input and output CUDA streams to pipeline the CUDA pre-processing + * and post-processing tasks. Clients should call this function before the call to + * NvEncUnlockInputBuffer(). If this function is not called, the default CUDA stream is used for + * input and output processing. After a successful call to this function, the streams specified + * in that call will replace the previously-used streams. + * This API is supported for NVCUVID interface only. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] inputStream + * Pointer to CUstream which is used to process ::NV_ENC_PIC_PARAMS::inputFrame for encode. + * In case of ME-only mode, inputStream is used to process ::NV_ENC_MEONLY_PARAMS::inputBuffer and + * ::NV_ENC_MEONLY_PARAMS::referenceFrame + * \param [in] outputStream + * Pointer to CUstream which is used to process ::NV_ENC_PIC_PARAMS::outputBuffer for encode. + * In case of ME-only mode, outputStream is used to process ::NV_ENC_MEONLY_PARAMS::mvBuffer + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_GENERIC \n + */ +NVENCSTATUS NVENCAPI NvEncSetIOCudaStreams (void* encoder, NV_ENC_CUSTREAM_PTR inputStream, NV_ENC_CUSTREAM_PTR outputStream); + + +// NvEncCreateBitstreamBuffer +/** + * \brief Allocates an output bitstream buffer + * + * This function is used to allocate an output bitstream buffer and returns a + * NV_ENC_OUTPUT_PTR to bitstream buffer to the client in the + * NV_ENC_CREATE_BITSTREAM_BUFFER::bitstreamBuffer field. + * The client can only call this function after the encoder session has been + * initialized using ::NvEncInitializeEncoder() API. The minimum number of output + * buffers allocated by the client must be at least 4 more than the number of B + * B frames being used for encoding. The client can only access the output + * bitstream data by locking the \p bitstreamBuffer using the ::NvEncLockBitstream() + * function. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in,out] createBitstreamBufferParams + * Pointer ::NV_ENC_CREATE_BITSTREAM_BUFFER for details. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncCreateBitstreamBuffer (void* encoder, NV_ENC_CREATE_BITSTREAM_BUFFER* createBitstreamBufferParams); + + +// NvEncDestroyBitstreamBuffer +/** + * \brief Release a bitstream buffer. + * + * This function is used to release the output bitstream buffer allocated using + * the ::NvEncCreateBitstreamBuffer() function. The client must release the output + * bitstreamBuffer using this function before destroying the encoder session. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] bitstreamBuffer + * Pointer to the bitstream buffer being released. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncDestroyBitstreamBuffer (void* encoder, NV_ENC_OUTPUT_PTR bitstreamBuffer); + +// NvEncEncodePicture +/** + * \brief Submit an input picture for encoding. + * + * This function is used to submit an input picture buffer for encoding. The + * encoding parameters are passed using \p *encodePicParams which is a pointer + * to the ::_NV_ENC_PIC_PARAMS structure. + * + * If the client has set NV_ENC_INITIALIZE_PARAMS::enablePTD to 0, then it must + * send a valid value for the following fields. + * - NV_ENC_PIC_PARAMS::pictureType + * - NV_ENC_PIC_PARAMS_H264::displayPOCSyntax (H264 only) + * - NV_ENC_PIC_PARAMS_H264::frameNumSyntax(H264 only) + * - NV_ENC_PIC_PARAMS_H264::refPicFlag(H264 only) + * + *\par MVC Encoding: + * For MVC encoding the client must call encode picture API for each view separately + * and must pass valid view id in NV_ENC_PIC_PARAMS_MVC::viewID field. Currently + * NvEncodeAPI only support stereo MVC so client must send viewID as 0 for base + * view and view ID as 1 for dependent view. + * + *\par Asynchronous Encoding + * If the client has enabled asynchronous mode of encoding by setting + * NV_ENC_INITIALIZE_PARAMS::enableEncodeAsync to 1 in the ::NvEncInitializeEncoder() + * API ,then the client must send a valid NV_ENC_PIC_PARAMS::completionEvent. + * Incase of asynchronous mode of operation, client can queue the ::NvEncEncodePicture() + * API commands from the main thread and then queue output buffers to be processed + * to a secondary worker thread. Before the locking the output buffers in the + * secondary thread , the client must wait on NV_ENC_PIC_PARAMS::completionEvent + * it has queued in ::NvEncEncodePicture() API call. The client must always process + * completion event and the output buffer in the same order in which they have been + * submitted for encoding. The NvEncodeAPI interface is responsible for any + * re-ordering required for B frames and will always ensure that encoded bitstream + * data is written in the same order in which output buffer is submitted. + * The NvEncodeAPI interface may return ::NV_ENC_ERR_NEED_MORE_INPUT error code for + * some ::NvEncEncodePicture() API calls but the client must not treat it as a fatal error. + * The NvEncodeAPI interface might not be able to submit an input picture buffer for encoding + * immediately due to re-ordering for B frames. + *\code + The below example shows how asynchronous encoding in case of 1 B frames + ------------------------------------------------------------------------ + Suppose the client allocated 4 input buffers(I1,I2..), 4 output buffers(O1,O2..) + and 4 completion events(E1, E2, ...). The NvEncodeAPI interface will need to + keep a copy of the input buffers for re-ordering and it allocates following + internal buffers (NvI1, NvI2...). These internal buffers are managed by NvEncodeAPI + and the client is not responsible for the allocating or freeing the memory of + the internal buffers. + + a) The client main thread will queue the following encode frame calls. + Note the picture type is unknown to the client, the decision is being taken by + NvEncodeAPI interface. The client should pass ::_NV_ENC_PIC_PARAMS parameter + consisting of allocated input buffer, output buffer and output events in successive + ::NvEncEncodePicture() API calls along with other required encode picture params. + For example: + 1st EncodePicture parameters - (I1, O1, E1) + 2nd EncodePicture parameters - (I2, O2, E2) + 3rd EncodePicture parameters - (I3, O3, E3) + + b) NvEncodeAPI SW will receive the following encode Commands from the client. + The left side shows input from client in the form (Input buffer, Output Buffer, + Output Event). The right hand side shows a possible picture type decision take by + the NvEncodeAPI interface. + (I1, O1, E1) ---P1 Frame + (I2, O2, E2) ---B2 Frame + (I3, O3, E3) ---P3 Frame + + c) NvEncodeAPI interface will make a copy of the input buffers to its internal + buffers for re-ordering. These copies are done as part of nvEncEncodePicture + function call from the client and NvEncodeAPI interface is responsible for + synchronization of copy operation with the actual encoding operation. + I1 --> NvI1 + I2 --> NvI2 + I3 --> NvI3 + + d) The NvEncodeAPI encodes I1 as P frame and submits I1 to encoder HW and returns ::NV_ENC_SUCCESS. + The NvEncodeAPI tries to encode I2 as B frame and fails with ::NV_ENC_ERR_NEED_MORE_INPUT error code. + The error is not fatal and it notifies client that I2 is not submitted to encoder immediately. + The NvEncodeAPI encodes I3 as P frame and submits I3 for encoding which will be used as backward + reference frame for I2. The NvEncodeAPI then submits I2 for encoding and returns ::NV_ENC_SUCESS. + Both the submission are part of the same ::NvEncEncodePicture() function call. + + e) After returning from ::NvEncEncodePicture() call , the client must queue the output + bitstream processing work to the secondary thread. The output bitstream processing + for asynchronous mode consist of first waiting on completion event(E1, E2..) + and then locking the output bitstream buffer(O1, O2..) for reading the encoded + data. The work queued to the secondary thread by the client is in the following order + (I1, O1, E1) + (I2, O2, E2) + (I3, O3, E3) + Note they are in the same order in which client calls ::NvEncEncodePicture() API + in \p step a). + + f) NvEncodeAPI interface will do the re-ordering such that Encoder HW will receive + the following encode commands: + (NvI1, O1, E1) ---P1 Frame + (NvI3, O2, E2) ---P3 Frame + (NvI2, O3, E3) ---B2 frame + + g) After the encoding operations are completed, the events will be signaled + by NvEncodeAPI interface in the following order : + (O1, E1) ---P1 Frame ,output bitstream copied to O1 and event E1 signaled. + (O2, E2) ---P3 Frame ,output bitstream copied to O2 and event E2 signaled. + (O3, E3) ---B2 Frame ,output bitstream copied to O3 and event E3 signaled. + + h) The client must lock the bitstream data using ::NvEncLockBitstream() API in + the order O1,O2,O3 to read the encoded data, after waiting for the events + to be signaled in the same order i.e E1, E2 and E3.The output processing is + done in the secondary thread in the following order: + Waits on E1, copies encoded bitstream from O1 + Waits on E2, copies encoded bitstream from O2 + Waits on E3, copies encoded bitstream from O3 + + -Note the client will receive the events signaling and output buffer in the + same order in which they have submitted for encoding. + -Note the LockBitstream will have picture type field which will notify the + output picture type to the clients. + -Note the input, output buffer and the output completion event are free to be + reused once NvEncodeAPI interfaced has signaled the event and the client has + copied the data from the output buffer. + + * \endcode + * + *\par Synchronous Encoding + * The client can enable synchronous mode of encoding by setting + * NV_ENC_INITIALIZE_PARAMS::enableEncodeAsync to 0 in ::NvEncInitializeEncoder() API. + * The NvEncodeAPI interface may return ::NV_ENC_ERR_NEED_MORE_INPUT error code for + * some ::NvEncEncodePicture() API calls when NV_ENC_INITIALIZE_PARAMS::enablePTD + * is set to 1, but the client must not treat it as a fatal error. The NvEncodeAPI + * interface might not be able to submit an input picture buffer for encoding + * immediately due to re-ordering for B frames. The NvEncodeAPI interface cannot + * submit the input picture which is decided to be encoded as B frame as it waits + * for backward reference from temporally subsequent frames. This input picture + * is buffered internally and waits for more input picture to arrive. The client + * must not call ::NvEncLockBitstream() API on the output buffers whose + * ::NvEncEncodePicture() API returns ::NV_ENC_ERR_NEED_MORE_INPUT. The client must + * wait for the NvEncodeAPI interface to return ::NV_ENC_SUCCESS before locking the + * output bitstreams to read the encoded bitstream data. The following example + * explains the scenario with synchronous encoding with 2 B frames. + *\code + The below example shows how synchronous encoding works in case of 1 B frames + ----------------------------------------------------------------------------- + Suppose the client allocated 4 input buffers(I1,I2..), 4 output buffers(O1,O2..) + and 4 completion events(E1, E2, ...). The NvEncodeAPI interface will need to + keep a copy of the input buffers for re-ordering and it allocates following + internal buffers (NvI1, NvI2...). These internal buffers are managed by NvEncodeAPI + and the client is not responsible for the allocating or freeing the memory of + the internal buffers. + + The client calls ::NvEncEncodePicture() API with input buffer I1 and output buffer O1. + The NvEncodeAPI decides to encode I1 as P frame and submits it to encoder + HW and returns ::NV_ENC_SUCCESS. + The client can now read the encoded data by locking the output O1 by calling + NvEncLockBitstream API. + + The client calls ::NvEncEncodePicture() API with input buffer I2 and output buffer O2. + The NvEncodeAPI decides to encode I2 as B frame and buffers I2 by copying it + to internal buffer and returns ::NV_ENC_ERR_NEED_MORE_INPUT. + The error is not fatal and it notifies client that it cannot read the encoded + data by locking the output O2 by calling ::NvEncLockBitstream() API without submitting + more work to the NvEncodeAPI interface. + + The client calls ::NvEncEncodePicture() with input buffer I3 and output buffer O3. + The NvEncodeAPI decides to encode I3 as P frame and it first submits I3 for + encoding which will be used as backward reference frame for I2. + The NvEncodeAPI then submits I2 for encoding and returns ::NV_ENC_SUCESS. Both + the submission are part of the same ::NvEncEncodePicture() function call. + The client can now read the encoded data for both the frames by locking the output + O2 followed by O3 ,by calling ::NvEncLockBitstream() API. + + The client must always lock the output in the same order in which it has submitted + to receive the encoded bitstream in correct encoding order. + + * \endcode + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in,out] encodePicParams + * Pointer to the ::_NV_ENC_PIC_PARAMS structure. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_ENCODER_BUSY \n + * ::NV_ENC_ERR_NEED_MORE_INPUT \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncEncodePicture (void* encoder, NV_ENC_PIC_PARAMS* encodePicParams); + + +// NvEncLockBitstream +/** + * \brief Lock output bitstream buffer + * + * This function is used to lock the bitstream buffer to read the encoded data. + * The client can only access the encoded data by calling this function. + * The pointer to client accessible encoded data is returned in the + * NV_ENC_LOCK_BITSTREAM::bitstreamBufferPtr field. The size of the encoded data + * in the output buffer is returned in the NV_ENC_LOCK_BITSTREAM::bitstreamSizeInBytes + * The NvEncodeAPI interface also returns the output picture type and picture structure + * of the encoded frame in NV_ENC_LOCK_BITSTREAM::pictureType and + * NV_ENC_LOCK_BITSTREAM::pictureStruct fields respectively. If the client has + * set NV_ENC_LOCK_BITSTREAM::doNotWait to 1, the function might return + * ::NV_ENC_ERR_LOCK_BUSY if client is operating in synchronous mode. This is not + * a fatal failure if NV_ENC_LOCK_BITSTREAM::doNotWait is set to 1. In the above case the client can + * retry the function after few milliseconds. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in,out] lockBitstreamBufferParams + * Pointer to the ::_NV_ENC_LOCK_BITSTREAM structure. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_LOCK_BUSY \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncLockBitstream (void* encoder, NV_ENC_LOCK_BITSTREAM* lockBitstreamBufferParams); + + +// NvEncUnlockBitstream +/** + * \brief Unlock the output bitstream buffer + * + * This function is used to unlock the output bitstream buffer after the client + * has read the encoded data from output buffer. The client must call this function + * to unlock the output buffer which it has previously locked using ::NvEncLockBitstream() + * function. Using a locked bitstream buffer in ::NvEncEncodePicture() API will cause + * the function to fail. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in,out] bitstreamBuffer + * bitstream buffer pointer being unlocked + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncUnlockBitstream (void* encoder, NV_ENC_OUTPUT_PTR bitstreamBuffer); + +// NvEncRestoreEncoderState +/** + * \brief Restore state of encoder + * + * This function is used to restore the state of encoder with state saved internally in + * state buffer corresponding to index equal to 'NV_ENC_RESTORE_ENCODER_STATE_PARAMS::bufferIdx'. + * Client can specify the state type to be updated by specifying appropriate value in + * 'NV_ENC_RESTORE_ENCODER_STATE_PARAMS::state'. The client must call this + * function after all previous encodes have finished. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] restoreState + * Pointer to the ::_NV_ENC_RESTORE_ENCODER_STATE_PARAMS structure + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncRestoreEncoderState (void* encoder, NV_ENC_RESTORE_ENCODER_STATE_PARAMS* restoreState); + +// NvLockInputBuffer +/** + * \brief Locks an input buffer + * + * This function is used to lock the input buffer to load the uncompressed YUV + * pixel data into input buffer memory. The client must pass the NV_ENC_INPUT_PTR + * it had previously allocated using ::NvEncCreateInputBuffer()in the + * NV_ENC_LOCK_INPUT_BUFFER::inputBuffer field. + * The NvEncodeAPI interface returns pointer to client accessible input buffer + * memory in NV_ENC_LOCK_INPUT_BUFFER::bufferDataPtr field. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in,out] lockInputBufferParams + * Pointer to the ::_NV_ENC_LOCK_INPUT_BUFFER structure + * + * \return + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_LOCK_BUSY \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncLockInputBuffer (void* encoder, NV_ENC_LOCK_INPUT_BUFFER* lockInputBufferParams); + + +// NvUnlockInputBuffer +/** + * \brief Unlocks the input buffer + * + * This function is used to unlock the input buffer memory previously locked for + * uploading YUV pixel data. The input buffer must be unlocked before being used + * again for encoding, otherwise NvEncodeAPI will fail the ::NvEncEncodePicture() + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] inputBuffer + * Pointer to the input buffer that is being unlocked. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_GENERIC \n + * + * + */ +NVENCSTATUS NVENCAPI NvEncUnlockInputBuffer (void* encoder, NV_ENC_INPUT_PTR inputBuffer); + + +// NvEncGetEncodeStats +/** + * \brief Get encoding statistics. + * + * This function is used to retrieve the encoding statistics. + * This API is not supported when encode device type is CUDA. + * Note that this API will be removed in future Video Codec SDK release. + * Clients should use NvEncLockBitstream() API to retrieve the encoding statistics. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in,out] encodeStats + * Pointer to the ::_NV_ENC_STAT structure. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncGetEncodeStats (void* encoder, NV_ENC_STAT* encodeStats); + + +// NvEncGetSequenceParams +/** + * \brief Get encoded sequence and picture header. + * + * This function can be used to retrieve the sequence and picture header out of + * band. The client must call this function only after the encoder has been + * initialized using ::NvEncInitializeEncoder() function. The client must + * allocate the memory where the NvEncodeAPI interface can copy the bitstream + * header and pass the pointer to the memory in NV_ENC_SEQUENCE_PARAM_PAYLOAD::spsppsBuffer. + * The size of buffer is passed in the field NV_ENC_SEQUENCE_PARAM_PAYLOAD::inBufferSize. + * The NvEncodeAPI interface will copy the bitstream header payload and returns + * the actual size of the bitstream header in the field + * NV_ENC_SEQUENCE_PARAM_PAYLOAD::outSPSPPSPayloadSize. + * The client must call ::NvEncGetSequenceParams() function from the same thread which is + * being used to call ::NvEncEncodePicture() function. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in,out] sequenceParamPayload + * Pointer to the ::_NV_ENC_SEQUENCE_PARAM_PAYLOAD structure. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncGetSequenceParams (void* encoder, NV_ENC_SEQUENCE_PARAM_PAYLOAD* sequenceParamPayload); + +// NvEncGetSequenceParamEx +/** + * \brief Get sequence and picture header. + * + * This function can be used to retrieve the sequence and picture header out of band, even when + * encoder has not been initialized using ::NvEncInitializeEncoder() function. + * The client must allocate the memory where the NvEncodeAPI interface can copy the bitstream + * header and pass the pointer to the memory in NV_ENC_SEQUENCE_PARAM_PAYLOAD::spsppsBuffer. + * The size of buffer is passed in the field NV_ENC_SEQUENCE_PARAM_PAYLOAD::inBufferSize. + * If encoder has not been initialized using ::NvEncInitializeEncoder() function, client must + * send NV_ENC_INITIALIZE_PARAMS as input. The NV_ENC_INITIALIZE_PARAMS passed must be same as the + * one which will be used for initializing encoder using ::NvEncInitializeEncoder() function later. + * If encoder is already initialized using ::NvEncInitializeEncoder() function, the provided + * NV_ENC_INITIALIZE_PARAMS structure is ignored. The NvEncodeAPI interface will copy the bitstream + * header payload and returns the actual size of the bitstream header in the field + * NV_ENC_SEQUENCE_PARAM_PAYLOAD::outSPSPPSPayloadSize. The client must call ::NvEncGetSequenceParamsEx() + * function from the same thread which is being used to call ::NvEncEncodePicture() function. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] encInitParams + * Pointer to the _NV_ENC_INITIALIZE_PARAMS structure. + * \param [in,out] sequenceParamPayload + * Pointer to the ::_NV_ENC_SEQUENCE_PARAM_PAYLOAD structure. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncGetSequenceParamEx (void* encoder, NV_ENC_INITIALIZE_PARAMS* encInitParams, NV_ENC_SEQUENCE_PARAM_PAYLOAD* sequenceParamPayload); + +// NvEncRegisterAsyncEvent +/** + * \brief Register event for notification to encoding completion. + * + * This function is used to register the completion event with NvEncodeAPI + * interface. The event is required when the client has configured the encoder to + * work in asynchronous mode. In this mode the client needs to send a completion + * event with every output buffer. The NvEncodeAPI interface will signal the + * completion of the encoding process using this event. Only after the event is + * signaled the client can get the encoded data using ::NvEncLockBitstream() function. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] eventParams + * Pointer to the ::_NV_ENC_EVENT_PARAMS structure. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncRegisterAsyncEvent (void* encoder, NV_ENC_EVENT_PARAMS* eventParams); + + +// NvEncUnregisterAsyncEvent +/** + * \brief Unregister completion event. + * + * This function is used to unregister completion event which has been previously + * registered using ::NvEncRegisterAsyncEvent() function. The client must unregister + * all events before destroying the encoder using ::NvEncDestroyEncoder() function. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] eventParams + * Pointer to the ::_NV_ENC_EVENT_PARAMS structure. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncUnregisterAsyncEvent (void* encoder, NV_ENC_EVENT_PARAMS* eventParams); + + +// NvEncMapInputResource +/** + * \brief Map an externally created input resource pointer for encoding. + * + * Maps an externally allocated input resource [using and returns a NV_ENC_INPUT_PTR + * which can be used for encoding in the ::NvEncEncodePicture() function. The + * mapped resource is returned in the field NV_ENC_MAP_INPUT_RESOURCE::outputResourcePtr. + * The NvEncodeAPI interface also returns the buffer format of the mapped resource + * in the field NV_ENC_MAP_INPUT_RESOURCE::outbufferFmt. + * This function provides synchronization guarantee that any graphics work submitted + * on the input buffer is completed before the buffer is used for encoding. This is + * also true for compute (i.e. CUDA) work, provided that the previous workload using + * the input resource was submitted to the default stream. + * The client should not access any input buffer while they are mapped by the encoder. + * For D3D12 interface type, this function does not provide synchronization guarantee. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in,out] mapInputResParams + * Pointer to the ::_NV_ENC_MAP_INPUT_RESOURCE structure. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_RESOURCE_NOT_REGISTERED \n + * ::NV_ENC_ERR_MAP_FAILED \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncMapInputResource (void* encoder, NV_ENC_MAP_INPUT_RESOURCE* mapInputResParams); + + +// NvEncUnmapInputResource +/** + * \brief UnMaps a NV_ENC_INPUT_PTR which was mapped for encoding + * + * + * UnMaps an input buffer which was previously mapped using ::NvEncMapInputResource() + * API. The mapping created using ::NvEncMapInputResource() should be invalidated + * using this API before the external resource is destroyed by the client. The client + * must unmap the buffer after ::NvEncLockBitstream() API returns successfully for encode + * work submitted using the mapped input buffer. + * + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] mappedInputBuffer + * Pointer to the NV_ENC_INPUT_PTR + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_RESOURCE_NOT_REGISTERED \n + * ::NV_ENC_ERR_RESOURCE_NOT_MAPPED \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncUnmapInputResource (void* encoder, NV_ENC_INPUT_PTR mappedInputBuffer); + +// NvEncDestroyEncoder +/** + * \brief Destroy Encoding Session + * + * Destroys the encoder session previously created using ::NvEncOpenEncodeSession() + * function. The client must flush the encoder before freeing any resources. In order + * to flush the encoder the client must pass a NULL encode picture packet and either + * wait for the ::NvEncEncodePicture() function to return in synchronous mode or wait + * for the flush event to be signaled by the encoder in asynchronous mode. + * The client must free all the input and output resources created using the + * NvEncodeAPI interface before destroying the encoder. If the client is operating + * in asynchronous mode, it must also unregister the completion events previously + * registered. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncDestroyEncoder (void* encoder); + +// NvEncInvalidateRefFrames +/** + * \brief Invalidate reference frames + * + * Invalidates reference frame based on the time stamp provided by the client. + * The encoder marks any reference frames or any frames which have been reconstructed + * using the corrupt frame as invalid for motion estimation and uses older reference + * frames for motion estimation. The encoder forces the current frame to be encoded + * as an intra frame if no reference frames are left after invalidation process. + * This is useful for low latency application for error resiliency. The client + * is recommended to set NV_ENC_CONFIG_H264::maxNumRefFrames to a large value so + * that encoder can keep a backup of older reference frames in the DPB and can use them + * for motion estimation when the newer reference frames have been invalidated. + * This API can be called multiple times. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] invalidRefFrameTimeStamp + * Timestamp of the invalid reference frames which needs to be invalidated. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncInvalidateRefFrames(void* encoder, uint64_t invalidRefFrameTimeStamp); + +// NvEncOpenEncodeSessionEx +/** + * \brief Opens an encoding session. + * + * Opens an encoding session and returns a pointer to the encoder interface in + * the \p **encoder parameter. The client should start encoding process by calling + * this API first. + * The client must pass a pointer to IDirect3DDevice9 device or CUDA context in the \p *device parameter. + * For the OpenGL interface, \p device must be NULL. An OpenGL context must be current when + * calling all NvEncodeAPI functions. + * If the creation of encoder session fails, the client must call ::NvEncDestroyEncoder API + * before exiting. + * + * \param [in] openSessionExParams + * Pointer to a ::NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS structure. + * \param [out] encoder + * Encode Session pointer to the NvEncodeAPI interface. + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_NO_ENCODE_DEVICE \n + * ::NV_ENC_ERR_UNSUPPORTED_DEVICE \n + * ::NV_ENC_ERR_INVALID_DEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncOpenEncodeSessionEx (NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS *openSessionExParams, void** encoder); + +// NvEncRegisterResource +/** + * \brief Registers a resource with the Nvidia Video Encoder Interface. + * + * Registers a resource with the Nvidia Video Encoder Interface for book keeping. + * The client is expected to pass the registered resource handle as well, while calling ::NvEncMapInputResource API. + * + * \param [in] encoder + * Pointer to the NVEncodeAPI interface. + * + * \param [in] registerResParams + * Pointer to a ::_NV_ENC_REGISTER_RESOURCE structure + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_RESOURCE_REGISTER_FAILED \n + * ::NV_ENC_ERR_GENERIC \n + * ::NV_ENC_ERR_UNIMPLEMENTED \n + * + */ +NVENCSTATUS NVENCAPI NvEncRegisterResource (void* encoder, NV_ENC_REGISTER_RESOURCE* registerResParams); + +// NvEncUnregisterResource +/** + * \brief Unregisters a resource previously registered with the Nvidia Video Encoder Interface. + * + * Unregisters a resource previously registered with the Nvidia Video Encoder Interface. + * The client is expected to unregister any resource that it has registered with the + * Nvidia Video Encoder Interface before destroying the resource. + * + * \param [in] encoder + * Pointer to the NVEncodeAPI interface. + * + * \param [in] registeredResource + * The registered resource pointer that was returned in ::NvEncRegisterResource. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_RESOURCE_NOT_REGISTERED \n + * ::NV_ENC_ERR_GENERIC \n + * ::NV_ENC_ERR_UNIMPLEMENTED \n + * + */ +NVENCSTATUS NVENCAPI NvEncUnregisterResource (void* encoder, NV_ENC_REGISTERED_PTR registeredResource); + +// NvEncReconfigureEncoder +/** + * \brief Reconfigure an existing encoding session. + * + * Reconfigure an existing encoding session. + * The client should call this API to change/reconfigure the parameter passed during + * NvEncInitializeEncoder API call. + * Currently Reconfiguration of following are not supported. + * Change in GOP structure. + * Change in sync-Async mode. + * Change in MaxWidth & MaxHeight. + * Change in PTD mode. + * + * Resolution change is possible only if maxEncodeWidth & maxEncodeHeight of NV_ENC_INITIALIZE_PARAMS + * is set while creating encoder session. + * + * \param [in] encoder + * Pointer to the NVEncodeAPI interface. + * + * \param [in] reInitEncodeParams + * Pointer to a ::NV_ENC_RECONFIGURE_PARAMS structure. + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_NO_ENCODE_DEVICE \n + * ::NV_ENC_ERR_UNSUPPORTED_DEVICE \n + * ::NV_ENC_ERR_INVALID_DEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_GENERIC \n + * + */ +NVENCSTATUS NVENCAPI NvEncReconfigureEncoder (void *encoder, NV_ENC_RECONFIGURE_PARAMS* reInitEncodeParams); + + + +// NvEncCreateMVBuffer +/** + * \brief Allocates output MV buffer for ME only mode. + * + * This function is used to allocate an output MV buffer. The size of the mvBuffer is + * dependent on the frame height and width of the last ::NvEncCreateInputBuffer() call. + * The NV_ENC_OUTPUT_PTR returned by the NvEncodeAPI interface in the + * ::NV_ENC_CREATE_MV_BUFFER::mvBuffer field should be used in + * ::NvEncRunMotionEstimationOnly() API. + * Client must lock ::NV_ENC_CREATE_MV_BUFFER::mvBuffer using ::NvEncLockBitstream() API to get the motion vector data. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in,out] createMVBufferParams + * Pointer to the ::NV_ENC_CREATE_MV_BUFFER structure. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_GENERIC \n + */ +NVENCSTATUS NVENCAPI NvEncCreateMVBuffer (void* encoder, NV_ENC_CREATE_MV_BUFFER* createMVBufferParams); + + +// NvEncDestroyMVBuffer +/** + * \brief Release an output MV buffer for ME only mode. + * + * This function is used to release the output MV buffer allocated using + * the ::NvEncCreateMVBuffer() function. The client must release the output + * mvBuffer using this function before destroying the encoder session. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] mvBuffer + * Pointer to the mvBuffer being released. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_GENERIC \n + */ +NVENCSTATUS NVENCAPI NvEncDestroyMVBuffer (void* encoder, NV_ENC_OUTPUT_PTR mvBuffer); + + +// NvEncRunMotionEstimationOnly +/** + * \brief Submit an input picture and reference frame for motion estimation in ME only mode. + * + * This function is used to submit the input frame and reference frame for motion + * estimation. The ME parameters are passed using *meOnlyParams which is a pointer + * to ::_NV_ENC_MEONLY_PARAMS structure. + * Client must lock ::NV_ENC_CREATE_MV_BUFFER::mvBuffer using ::NvEncLockBitstream() API to get the motion vector data. + * to get motion vector data. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] meOnlyParams + * Pointer to the ::_NV_ENC_MEONLY_PARAMS structure. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_INVALID_VERSION \n + * ::NV_ENC_ERR_NEED_MORE_INPUT \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_GENERIC \n + */ +NVENCSTATUS NVENCAPI NvEncRunMotionEstimationOnly (void* encoder, NV_ENC_MEONLY_PARAMS* meOnlyParams); + +// NvEncodeAPIGetMaxSupportedVersion +/** + * \brief Get the largest NvEncodeAPI version supported by the driver. + * + * This function can be used by clients to determine if the driver supports + * the NvEncodeAPI header the application was compiled with. + * + * \param [out] version + * Pointer to the requested value. The 4 least significant bits in the returned + * indicate the minor version and the rest of the bits indicate the major + * version of the largest supported version. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_ERR_INVALID_PTR \n + */ +NVENCSTATUS NVENCAPI NvEncodeAPIGetMaxSupportedVersion (uint32_t* version); + + +// NvEncGetLastErrorString +/** + * \brief Get the description of the last error reported by the API. + * + * This function returns a null-terminated string that can be used by clients to better understand the reason + * for failure of a previous API call. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * + * \return + * Pointer to buffer containing the details of the last error encountered by the API. + */ +const char * NVENCAPI NvEncGetLastErrorString (void* encoder); + +// NvEncLookaheadPicture +/** + * \brief Submit an input picture for lookahead. + * + * This function can be used by clients to submit input frame for lookahead. Client could call this function + * NV_ENC_INITIALIZE_PARAMS::lookaheadDepth plus one number of frames, before calling NvEncEncodePicture() for the first frame. + * + * \param [in] encoder + * Pointer to the NvEncodeAPI interface. + * \param [in] lookaheadParams + * Pointer to the ::_NV_ENC_LOOKAHEAD_PIC_PARAMS structure. + * + * \return + * ::NV_ENC_SUCCESS \n + * ::NV_ENC_NEED_MORE_INPUT \n + * ::NV_ENC_ERR_INVALID_PTR \n + * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n + * ::NV_ENC_ERR_GENERIC \n + * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n + * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n + * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n + * ::NV_ENC_ERR_OUT_OF_MEMORY \n + * ::NV_ENC_ERR_INVALID_PARAM \n + * ::NV_ENC_ERR_INVALID_VERSION \n + */ +NVENCSTATUS NVENCAPI NvEncLookaheadPicture (void* encoder, NV_ENC_LOOKAHEAD_PIC_PARAMS *lookaheadParamas); + +/// \cond API PFN +/* + * Defines API function pointers + */ +typedef NVENCSTATUS (NVENCAPI* PNVENCOPENENCODESESSION) (void* device, uint32_t deviceType, void** encoder); +typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODEGUIDCOUNT) (void* encoder, uint32_t* encodeGUIDCount); +typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODEGUIDS) (void* encoder, GUID* GUIDs, uint32_t guidArraySize, uint32_t* GUIDCount); +typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODEPROFILEGUIDCOUNT) (void* encoder, GUID encodeGUID, uint32_t* encodeProfileGUIDCount); +typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODEPROFILEGUIDS) (void* encoder, GUID encodeGUID, GUID* profileGUIDs, uint32_t guidArraySize, uint32_t* GUIDCount); +typedef NVENCSTATUS (NVENCAPI* PNVENCGETINPUTFORMATCOUNT) (void* encoder, GUID encodeGUID, uint32_t* inputFmtCount); +typedef NVENCSTATUS (NVENCAPI* PNVENCGETINPUTFORMATS) (void* encoder, GUID encodeGUID, NV_ENC_BUFFER_FORMAT* inputFmts, uint32_t inputFmtArraySize, uint32_t* inputFmtCount); +typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODECAPS) (void* encoder, GUID encodeGUID, NV_ENC_CAPS_PARAM* capsParam, int* capsVal); +typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODEPRESETCOUNT) (void* encoder, GUID encodeGUID, uint32_t* encodePresetGUIDCount); +typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODEPRESETGUIDS) (void* encoder, GUID encodeGUID, GUID* presetGUIDs, uint32_t guidArraySize, uint32_t* encodePresetGUIDCount); +typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODEPRESETCONFIG) (void* encoder, GUID encodeGUID, GUID presetGUID, NV_ENC_PRESET_CONFIG* presetConfig); +typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODEPRESETCONFIGEX) (void* encoder, GUID encodeGUID, GUID presetGUID, NV_ENC_TUNING_INFO tuningInfo, NV_ENC_PRESET_CONFIG* presetConfig); +typedef NVENCSTATUS (NVENCAPI* PNVENCINITIALIZEENCODER) (void* encoder, NV_ENC_INITIALIZE_PARAMS* createEncodeParams); +typedef NVENCSTATUS (NVENCAPI* PNVENCCREATEINPUTBUFFER) (void* encoder, NV_ENC_CREATE_INPUT_BUFFER* createInputBufferParams); +typedef NVENCSTATUS (NVENCAPI* PNVENCDESTROYINPUTBUFFER) (void* encoder, NV_ENC_INPUT_PTR inputBuffer); +typedef NVENCSTATUS (NVENCAPI* PNVENCCREATEBITSTREAMBUFFER) (void* encoder, NV_ENC_CREATE_BITSTREAM_BUFFER* createBitstreamBufferParams); +typedef NVENCSTATUS (NVENCAPI* PNVENCDESTROYBITSTREAMBUFFER) (void* encoder, NV_ENC_OUTPUT_PTR bitstreamBuffer); +typedef NVENCSTATUS (NVENCAPI* PNVENCENCODEPICTURE) (void* encoder, NV_ENC_PIC_PARAMS* encodePicParams); +typedef NVENCSTATUS (NVENCAPI* PNVENCLOCKBITSTREAM) (void* encoder, NV_ENC_LOCK_BITSTREAM* lockBitstreamBufferParams); +typedef NVENCSTATUS (NVENCAPI* PNVENCUNLOCKBITSTREAM) (void* encoder, NV_ENC_OUTPUT_PTR bitstreamBuffer); +typedef NVENCSTATUS (NVENCAPI* PNVENCLOCKINPUTBUFFER) (void* encoder, NV_ENC_LOCK_INPUT_BUFFER* lockInputBufferParams); +typedef NVENCSTATUS (NVENCAPI* PNVENCUNLOCKINPUTBUFFER) (void* encoder, NV_ENC_INPUT_PTR inputBuffer); +typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODESTATS) (void* encoder, NV_ENC_STAT* encodeStats); +typedef NVENCSTATUS (NVENCAPI* PNVENCGETSEQUENCEPARAMS) (void* encoder, NV_ENC_SEQUENCE_PARAM_PAYLOAD* sequenceParamPayload); +typedef NVENCSTATUS (NVENCAPI* PNVENCREGISTERASYNCEVENT) (void* encoder, NV_ENC_EVENT_PARAMS* eventParams); +typedef NVENCSTATUS (NVENCAPI* PNVENCUNREGISTERASYNCEVENT) (void* encoder, NV_ENC_EVENT_PARAMS* eventParams); +typedef NVENCSTATUS (NVENCAPI* PNVENCMAPINPUTRESOURCE) (void* encoder, NV_ENC_MAP_INPUT_RESOURCE* mapInputResParams); +typedef NVENCSTATUS (NVENCAPI* PNVENCUNMAPINPUTRESOURCE) (void* encoder, NV_ENC_INPUT_PTR mappedInputBuffer); +typedef NVENCSTATUS (NVENCAPI* PNVENCDESTROYENCODER) (void* encoder); +typedef NVENCSTATUS (NVENCAPI* PNVENCINVALIDATEREFFRAMES) (void* encoder, uint64_t invalidRefFrameTimeStamp); +typedef NVENCSTATUS (NVENCAPI* PNVENCOPENENCODESESSIONEX) (NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS *openSessionExParams, void** encoder); +typedef NVENCSTATUS (NVENCAPI* PNVENCREGISTERRESOURCE) (void* encoder, NV_ENC_REGISTER_RESOURCE* registerResParams); +typedef NVENCSTATUS (NVENCAPI* PNVENCUNREGISTERRESOURCE) (void* encoder, NV_ENC_REGISTERED_PTR registeredRes); +typedef NVENCSTATUS (NVENCAPI* PNVENCRECONFIGUREENCODER) (void* encoder, NV_ENC_RECONFIGURE_PARAMS* reInitEncodeParams); + +typedef NVENCSTATUS (NVENCAPI* PNVENCCREATEMVBUFFER) (void* encoder, NV_ENC_CREATE_MV_BUFFER* createMVBufferParams); +typedef NVENCSTATUS (NVENCAPI* PNVENCDESTROYMVBUFFER) (void* encoder, NV_ENC_OUTPUT_PTR mvBuffer); +typedef NVENCSTATUS (NVENCAPI* PNVENCRUNMOTIONESTIMATIONONLY) (void* encoder, NV_ENC_MEONLY_PARAMS* meOnlyParams); +typedef const char * (NVENCAPI* PNVENCGETLASTERROR) (void* encoder); +typedef NVENCSTATUS (NVENCAPI* PNVENCSETIOCUDASTREAMS) (void* encoder, NV_ENC_CUSTREAM_PTR inputStream, NV_ENC_CUSTREAM_PTR outputStream); +typedef NVENCSTATUS (NVENCAPI* PNVENCGETSEQUENCEPARAMEX) (void* encoder, NV_ENC_INITIALIZE_PARAMS* encInitParams, NV_ENC_SEQUENCE_PARAM_PAYLOAD* sequenceParamPayload); +typedef NVENCSTATUS (NVENCAPI* PNVENCRESTOREENCODERSTATE) (void* encoder, NV_ENC_RESTORE_ENCODER_STATE_PARAMS* restoreState); +typedef NVENCSTATUS (NVENCAPI* PNVENCLOOKAHEADPICTURE) (void* encoder, NV_ENC_LOOKAHEAD_PIC_PARAMS* lookaheadParams); + + +/// \endcond + + +/** @} */ /* END ENCODE_FUNC */ + +/** + * \ingroup ENCODER_STRUCTURE + * NV_ENCODE_API_FUNCTION_LIST + */ +typedef struct _NV_ENCODE_API_FUNCTION_LIST +{ + uint32_t version; /**< [in]: Client should pass NV_ENCODE_API_FUNCTION_LIST_VER. */ + uint32_t reserved; /**< [in]: Reserved and should be set to 0. */ + PNVENCOPENENCODESESSION nvEncOpenEncodeSession; /**< [out]: Client should access ::NvEncOpenEncodeSession() API through this pointer. */ + PNVENCGETENCODEGUIDCOUNT nvEncGetEncodeGUIDCount; /**< [out]: Client should access ::NvEncGetEncodeGUIDCount() API through this pointer. */ + PNVENCGETENCODEPROFILEGUIDCOUNT nvEncGetEncodeProfileGUIDCount; /**< [out]: Client should access ::NvEncGetEncodeProfileGUIDCount() API through this pointer.*/ + PNVENCGETENCODEPROFILEGUIDS nvEncGetEncodeProfileGUIDs; /**< [out]: Client should access ::NvEncGetEncodeProfileGUIDs() API through this pointer. */ + PNVENCGETENCODEGUIDS nvEncGetEncodeGUIDs; /**< [out]: Client should access ::NvEncGetEncodeGUIDs() API through this pointer. */ + PNVENCGETINPUTFORMATCOUNT nvEncGetInputFormatCount; /**< [out]: Client should access ::NvEncGetInputFormatCount() API through this pointer. */ + PNVENCGETINPUTFORMATS nvEncGetInputFormats; /**< [out]: Client should access ::NvEncGetInputFormats() API through this pointer. */ + PNVENCGETENCODECAPS nvEncGetEncodeCaps; /**< [out]: Client should access ::NvEncGetEncodeCaps() API through this pointer. */ + PNVENCGETENCODEPRESETCOUNT nvEncGetEncodePresetCount; /**< [out]: Client should access ::NvEncGetEncodePresetCount() API through this pointer. */ + PNVENCGETENCODEPRESETGUIDS nvEncGetEncodePresetGUIDs; /**< [out]: Client should access ::NvEncGetEncodePresetGUIDs() API through this pointer. */ + PNVENCGETENCODEPRESETCONFIG nvEncGetEncodePresetConfig; /**< [out]: Client should access ::NvEncGetEncodePresetConfig() API through this pointer. */ + PNVENCINITIALIZEENCODER nvEncInitializeEncoder; /**< [out]: Client should access ::NvEncInitializeEncoder() API through this pointer. */ + PNVENCCREATEINPUTBUFFER nvEncCreateInputBuffer; /**< [out]: Client should access ::NvEncCreateInputBuffer() API through this pointer. */ + PNVENCDESTROYINPUTBUFFER nvEncDestroyInputBuffer; /**< [out]: Client should access ::NvEncDestroyInputBuffer() API through this pointer. */ + PNVENCCREATEBITSTREAMBUFFER nvEncCreateBitstreamBuffer; /**< [out]: Client should access ::NvEncCreateBitstreamBuffer() API through this pointer. */ + PNVENCDESTROYBITSTREAMBUFFER nvEncDestroyBitstreamBuffer; /**< [out]: Client should access ::NvEncDestroyBitstreamBuffer() API through this pointer. */ + PNVENCENCODEPICTURE nvEncEncodePicture; /**< [out]: Client should access ::NvEncEncodePicture() API through this pointer. */ + PNVENCLOCKBITSTREAM nvEncLockBitstream; /**< [out]: Client should access ::NvEncLockBitstream() API through this pointer. */ + PNVENCUNLOCKBITSTREAM nvEncUnlockBitstream; /**< [out]: Client should access ::NvEncUnlockBitstream() API through this pointer. */ + PNVENCLOCKINPUTBUFFER nvEncLockInputBuffer; /**< [out]: Client should access ::NvEncLockInputBuffer() API through this pointer. */ + PNVENCUNLOCKINPUTBUFFER nvEncUnlockInputBuffer; /**< [out]: Client should access ::NvEncUnlockInputBuffer() API through this pointer. */ + PNVENCGETENCODESTATS nvEncGetEncodeStats; /**< [out]: Client should access ::NvEncGetEncodeStats() API through this pointer. */ + PNVENCGETSEQUENCEPARAMS nvEncGetSequenceParams; /**< [out]: Client should access ::NvEncGetSequenceParams() API through this pointer. */ + PNVENCREGISTERASYNCEVENT nvEncRegisterAsyncEvent; /**< [out]: Client should access ::NvEncRegisterAsyncEvent() API through this pointer. */ + PNVENCUNREGISTERASYNCEVENT nvEncUnregisterAsyncEvent; /**< [out]: Client should access ::NvEncUnregisterAsyncEvent() API through this pointer. */ + PNVENCMAPINPUTRESOURCE nvEncMapInputResource; /**< [out]: Client should access ::NvEncMapInputResource() API through this pointer. */ + PNVENCUNMAPINPUTRESOURCE nvEncUnmapInputResource; /**< [out]: Client should access ::NvEncUnmapInputResource() API through this pointer. */ + PNVENCDESTROYENCODER nvEncDestroyEncoder; /**< [out]: Client should access ::NvEncDestroyEncoder() API through this pointer. */ + PNVENCINVALIDATEREFFRAMES nvEncInvalidateRefFrames; /**< [out]: Client should access ::NvEncInvalidateRefFrames() API through this pointer. */ + PNVENCOPENENCODESESSIONEX nvEncOpenEncodeSessionEx; /**< [out]: Client should access ::NvEncOpenEncodeSession() API through this pointer. */ + PNVENCREGISTERRESOURCE nvEncRegisterResource; /**< [out]: Client should access ::NvEncRegisterResource() API through this pointer. */ + PNVENCUNREGISTERRESOURCE nvEncUnregisterResource; /**< [out]: Client should access ::NvEncUnregisterResource() API through this pointer. */ + PNVENCRECONFIGUREENCODER nvEncReconfigureEncoder; /**< [out]: Client should access ::NvEncReconfigureEncoder() API through this pointer. */ + void* reserved1; + PNVENCCREATEMVBUFFER nvEncCreateMVBuffer; /**< [out]: Client should access ::NvEncCreateMVBuffer API through this pointer. */ + PNVENCDESTROYMVBUFFER nvEncDestroyMVBuffer; /**< [out]: Client should access ::NvEncDestroyMVBuffer API through this pointer. */ + PNVENCRUNMOTIONESTIMATIONONLY nvEncRunMotionEstimationOnly; /**< [out]: Client should access ::NvEncRunMotionEstimationOnly API through this pointer. */ + PNVENCGETLASTERROR nvEncGetLastErrorString; /**< [out]: Client should access ::nvEncGetLastErrorString API through this pointer. */ + PNVENCSETIOCUDASTREAMS nvEncSetIOCudaStreams; /**< [out]: Client should access ::nvEncSetIOCudaStreams API through this pointer. */ + PNVENCGETENCODEPRESETCONFIGEX nvEncGetEncodePresetConfigEx; /**< [out]: Client should access ::NvEncGetEncodePresetConfigEx() API through this pointer. */ + PNVENCGETSEQUENCEPARAMEX nvEncGetSequenceParamEx; /**< [out]: Client should access ::NvEncGetSequenceParamEx() API through this pointer. */ + PNVENCRESTOREENCODERSTATE nvEncRestoreEncoderState; /**< [out]: Client should access ::NvEncRestoreEncoderState() API through this pointer. */ + PNVENCLOOKAHEADPICTURE nvEncLookaheadPicture; /**< [out]: Client should access ::NvEncLookaheadPicture() API through this pointer. */ + void* reserved2[275]; /**< [in]: Reserved and must be set to NULL */ +} NV_ENCODE_API_FUNCTION_LIST; + +/** Macro for constructing the version field of ::_NV_ENCODEAPI_FUNCTION_LIST. */ +#define NV_ENCODE_API_FUNCTION_LIST_VER NVENCAPI_STRUCT_VERSION(2) + +// NvEncodeAPICreateInstance +/** + * \ingroup ENCODE_FUNC + * Entry Point to the NvEncodeAPI interface. + * + * Creates an instance of the NvEncodeAPI interface, and populates the + * pFunctionList with function pointers to the API routines implemented by the + * NvEncodeAPI interface. + * + * \param [out] functionList + * + * \return + * ::NV_ENC_SUCCESS + * ::NV_ENC_ERR_INVALID_PTR + */ +NVENCSTATUS NVENCAPI NvEncodeAPICreateInstance(NV_ENCODE_API_FUNCTION_LIST *functionList); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_av1std.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_av1std.h new file mode 100644 index 000000000..5347b3639 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_av1std.h @@ -0,0 +1,394 @@ +#ifndef VULKAN_VIDEO_CODEC_AV1STD_H_ +#define VULKAN_VIDEO_CODEC_AV1STD_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_av1std is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_av1std 1 +#include "vulkan_video_codecs_common.h" +#define STD_VIDEO_AV1_NUM_REF_FRAMES 8U +#define STD_VIDEO_AV1_REFS_PER_FRAME 7U +#define STD_VIDEO_AV1_TOTAL_REFS_PER_FRAME 8U +#define STD_VIDEO_AV1_MAX_TILE_COLS 64U +#define STD_VIDEO_AV1_MAX_TILE_ROWS 64U +#define STD_VIDEO_AV1_MAX_SEGMENTS 8U +#define STD_VIDEO_AV1_SEG_LVL_MAX 8U +#define STD_VIDEO_AV1_PRIMARY_REF_NONE 7U +#define STD_VIDEO_AV1_SELECT_INTEGER_MV 2U +#define STD_VIDEO_AV1_SELECT_SCREEN_CONTENT_TOOLS 2U +#define STD_VIDEO_AV1_SKIP_MODE_FRAMES 2U +#define STD_VIDEO_AV1_MAX_LOOP_FILTER_STRENGTHS 4U +#define STD_VIDEO_AV1_LOOP_FILTER_ADJUSTMENTS 2U +#define STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS 8U +#define STD_VIDEO_AV1_MAX_NUM_PLANES 3U +#define STD_VIDEO_AV1_GLOBAL_MOTION_PARAMS 6U +#define STD_VIDEO_AV1_MAX_NUM_Y_POINTS 14U +#define STD_VIDEO_AV1_MAX_NUM_CB_POINTS 10U +#define STD_VIDEO_AV1_MAX_NUM_CR_POINTS 10U +#define STD_VIDEO_AV1_MAX_NUM_POS_LUMA 24U +#define STD_VIDEO_AV1_MAX_NUM_POS_CHROMA 25U + +typedef enum StdVideoAV1Profile { + STD_VIDEO_AV1_PROFILE_MAIN = 0, + STD_VIDEO_AV1_PROFILE_HIGH = 1, + STD_VIDEO_AV1_PROFILE_PROFESSIONAL = 2, + STD_VIDEO_AV1_PROFILE_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_PROFILE_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1Profile; + +typedef enum StdVideoAV1Level { + STD_VIDEO_AV1_LEVEL_2_0 = 0, + STD_VIDEO_AV1_LEVEL_2_1 = 1, + STD_VIDEO_AV1_LEVEL_2_2 = 2, + STD_VIDEO_AV1_LEVEL_2_3 = 3, + STD_VIDEO_AV1_LEVEL_3_0 = 4, + STD_VIDEO_AV1_LEVEL_3_1 = 5, + STD_VIDEO_AV1_LEVEL_3_2 = 6, + STD_VIDEO_AV1_LEVEL_3_3 = 7, + STD_VIDEO_AV1_LEVEL_4_0 = 8, + STD_VIDEO_AV1_LEVEL_4_1 = 9, + STD_VIDEO_AV1_LEVEL_4_2 = 10, + STD_VIDEO_AV1_LEVEL_4_3 = 11, + STD_VIDEO_AV1_LEVEL_5_0 = 12, + STD_VIDEO_AV1_LEVEL_5_1 = 13, + STD_VIDEO_AV1_LEVEL_5_2 = 14, + STD_VIDEO_AV1_LEVEL_5_3 = 15, + STD_VIDEO_AV1_LEVEL_6_0 = 16, + STD_VIDEO_AV1_LEVEL_6_1 = 17, + STD_VIDEO_AV1_LEVEL_6_2 = 18, + STD_VIDEO_AV1_LEVEL_6_3 = 19, + STD_VIDEO_AV1_LEVEL_7_0 = 20, + STD_VIDEO_AV1_LEVEL_7_1 = 21, + STD_VIDEO_AV1_LEVEL_7_2 = 22, + STD_VIDEO_AV1_LEVEL_7_3 = 23, + STD_VIDEO_AV1_LEVEL_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_LEVEL_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1Level; + +typedef enum StdVideoAV1FrameType { + STD_VIDEO_AV1_FRAME_TYPE_KEY = 0, + STD_VIDEO_AV1_FRAME_TYPE_INTER = 1, + STD_VIDEO_AV1_FRAME_TYPE_INTRA_ONLY = 2, + STD_VIDEO_AV1_FRAME_TYPE_SWITCH = 3, + STD_VIDEO_AV1_FRAME_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_FRAME_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1FrameType; + +typedef enum StdVideoAV1ReferenceName { + STD_VIDEO_AV1_REFERENCE_NAME_INTRA_FRAME = 0, + STD_VIDEO_AV1_REFERENCE_NAME_LAST_FRAME = 1, + STD_VIDEO_AV1_REFERENCE_NAME_LAST2_FRAME = 2, + STD_VIDEO_AV1_REFERENCE_NAME_LAST3_FRAME = 3, + STD_VIDEO_AV1_REFERENCE_NAME_GOLDEN_FRAME = 4, + STD_VIDEO_AV1_REFERENCE_NAME_BWDREF_FRAME = 5, + STD_VIDEO_AV1_REFERENCE_NAME_ALTREF2_FRAME = 6, + STD_VIDEO_AV1_REFERENCE_NAME_ALTREF_FRAME = 7, + STD_VIDEO_AV1_REFERENCE_NAME_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_REFERENCE_NAME_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1ReferenceName; + +typedef enum StdVideoAV1InterpolationFilter { + STD_VIDEO_AV1_INTERPOLATION_FILTER_EIGHTTAP = 0, + STD_VIDEO_AV1_INTERPOLATION_FILTER_EIGHTTAP_SMOOTH = 1, + STD_VIDEO_AV1_INTERPOLATION_FILTER_EIGHTTAP_SHARP = 2, + STD_VIDEO_AV1_INTERPOLATION_FILTER_BILINEAR = 3, + STD_VIDEO_AV1_INTERPOLATION_FILTER_SWITCHABLE = 4, + STD_VIDEO_AV1_INTERPOLATION_FILTER_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_INTERPOLATION_FILTER_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1InterpolationFilter; + +typedef enum StdVideoAV1TxMode { + STD_VIDEO_AV1_TX_MODE_ONLY_4X4 = 0, + STD_VIDEO_AV1_TX_MODE_LARGEST = 1, + STD_VIDEO_AV1_TX_MODE_SELECT = 2, + STD_VIDEO_AV1_TX_MODE_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_TX_MODE_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1TxMode; + +typedef enum StdVideoAV1FrameRestorationType { + STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_NONE = 0, + STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_WIENER = 1, + STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_SGRPROJ = 2, + STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_SWITCHABLE = 3, + STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1FrameRestorationType; + +typedef enum StdVideoAV1ColorPrimaries { + STD_VIDEO_AV1_COLOR_PRIMARIES_BT_709 = 1, + STD_VIDEO_AV1_COLOR_PRIMARIES_UNSPECIFIED = 2, + STD_VIDEO_AV1_COLOR_PRIMARIES_BT_470_M = 4, + STD_VIDEO_AV1_COLOR_PRIMARIES_BT_470_B_G = 5, + STD_VIDEO_AV1_COLOR_PRIMARIES_BT_601 = 6, + STD_VIDEO_AV1_COLOR_PRIMARIES_SMPTE_240 = 7, + STD_VIDEO_AV1_COLOR_PRIMARIES_GENERIC_FILM = 8, + STD_VIDEO_AV1_COLOR_PRIMARIES_BT_2020 = 9, + STD_VIDEO_AV1_COLOR_PRIMARIES_XYZ = 10, + STD_VIDEO_AV1_COLOR_PRIMARIES_SMPTE_431 = 11, + STD_VIDEO_AV1_COLOR_PRIMARIES_SMPTE_432 = 12, + STD_VIDEO_AV1_COLOR_PRIMARIES_EBU_3213 = 22, + STD_VIDEO_AV1_COLOR_PRIMARIES_INVALID = 0x7FFFFFFF, + // STD_VIDEO_AV1_COLOR_PRIMARIES_BT_UNSPECIFIED is a legacy alias + STD_VIDEO_AV1_COLOR_PRIMARIES_BT_UNSPECIFIED = STD_VIDEO_AV1_COLOR_PRIMARIES_UNSPECIFIED, + STD_VIDEO_AV1_COLOR_PRIMARIES_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1ColorPrimaries; + +typedef enum StdVideoAV1TransferCharacteristics { + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_RESERVED_0 = 0, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_709 = 1, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_UNSPECIFIED = 2, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_RESERVED_3 = 3, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_470_M = 4, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_470_B_G = 5, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_601 = 6, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_SMPTE_240 = 7, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_LINEAR = 8, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_LOG_100 = 9, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_LOG_100_SQRT10 = 10, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_IEC_61966 = 11, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_1361 = 12, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_SRGB = 13, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_2020_10_BIT = 14, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_2020_12_BIT = 15, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_SMPTE_2084 = 16, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_SMPTE_428 = 17, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_HLG = 18, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1TransferCharacteristics; + +typedef enum StdVideoAV1MatrixCoefficients { + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_IDENTITY = 0, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_709 = 1, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_UNSPECIFIED = 2, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_RESERVED_3 = 3, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_FCC = 4, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_470_B_G = 5, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_601 = 6, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_SMPTE_240 = 7, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_SMPTE_YCGCO = 8, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_2020_NCL = 9, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_2020_CL = 10, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_SMPTE_2085 = 11, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_CHROMAT_NCL = 12, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_CHROMAT_CL = 13, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_ICTCP = 14, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_MATRIX_COEFFICIENTS_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1MatrixCoefficients; + +typedef enum StdVideoAV1ChromaSamplePosition { + STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_UNKNOWN = 0, + STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_VERTICAL = 1, + STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_COLOCATED = 2, + STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_RESERVED = 3, + STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_INVALID = 0x7FFFFFFF, + STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_MAX_ENUM = 0x7FFFFFFF +} StdVideoAV1ChromaSamplePosition; +typedef struct StdVideoAV1ColorConfigFlags { + uint32_t mono_chrome : 1; + uint32_t color_range : 1; + uint32_t separate_uv_delta_q : 1; + uint32_t color_description_present_flag : 1; + uint32_t reserved : 28; +} StdVideoAV1ColorConfigFlags; + +typedef struct StdVideoAV1ColorConfig { + StdVideoAV1ColorConfigFlags flags; + uint8_t BitDepth; + uint8_t subsampling_x; + uint8_t subsampling_y; + uint8_t reserved1; + StdVideoAV1ColorPrimaries color_primaries; + StdVideoAV1TransferCharacteristics transfer_characteristics; + StdVideoAV1MatrixCoefficients matrix_coefficients; + StdVideoAV1ChromaSamplePosition chroma_sample_position; +} StdVideoAV1ColorConfig; + +typedef struct StdVideoAV1TimingInfoFlags { + uint32_t equal_picture_interval : 1; + uint32_t reserved : 31; +} StdVideoAV1TimingInfoFlags; + +typedef struct StdVideoAV1TimingInfo { + StdVideoAV1TimingInfoFlags flags; + uint32_t num_units_in_display_tick; + uint32_t time_scale; + uint32_t num_ticks_per_picture_minus_1; +} StdVideoAV1TimingInfo; + +typedef struct StdVideoAV1LoopFilterFlags { + uint32_t loop_filter_delta_enabled : 1; + uint32_t loop_filter_delta_update : 1; + uint32_t reserved : 30; +} StdVideoAV1LoopFilterFlags; + +typedef struct StdVideoAV1LoopFilter { + StdVideoAV1LoopFilterFlags flags; + uint8_t loop_filter_level[STD_VIDEO_AV1_MAX_LOOP_FILTER_STRENGTHS]; + uint8_t loop_filter_sharpness; + uint8_t update_ref_delta; + int8_t loop_filter_ref_deltas[STD_VIDEO_AV1_TOTAL_REFS_PER_FRAME]; + uint8_t update_mode_delta; + int8_t loop_filter_mode_deltas[STD_VIDEO_AV1_LOOP_FILTER_ADJUSTMENTS]; +} StdVideoAV1LoopFilter; + +typedef struct StdVideoAV1QuantizationFlags { + uint32_t using_qmatrix : 1; + uint32_t diff_uv_delta : 1; + uint32_t reserved : 30; +} StdVideoAV1QuantizationFlags; + +typedef struct StdVideoAV1Quantization { + StdVideoAV1QuantizationFlags flags; + uint8_t base_q_idx; + int8_t DeltaQYDc; + int8_t DeltaQUDc; + int8_t DeltaQUAc; + int8_t DeltaQVDc; + int8_t DeltaQVAc; + uint8_t qm_y; + uint8_t qm_u; + uint8_t qm_v; +} StdVideoAV1Quantization; + +typedef struct StdVideoAV1Segmentation { + uint8_t FeatureEnabled[STD_VIDEO_AV1_MAX_SEGMENTS]; + int16_t FeatureData[STD_VIDEO_AV1_MAX_SEGMENTS][STD_VIDEO_AV1_SEG_LVL_MAX]; +} StdVideoAV1Segmentation; + +typedef struct StdVideoAV1TileInfoFlags { + uint32_t uniform_tile_spacing_flag : 1; + uint32_t reserved : 31; +} StdVideoAV1TileInfoFlags; + +typedef struct StdVideoAV1TileInfo { + StdVideoAV1TileInfoFlags flags; + uint8_t TileCols; + uint8_t TileRows; + uint16_t context_update_tile_id; + uint8_t tile_size_bytes_minus_1; + uint8_t reserved1[7]; + const uint16_t* pMiColStarts; + const uint16_t* pMiRowStarts; + const uint16_t* pWidthInSbsMinus1; + const uint16_t* pHeightInSbsMinus1; +} StdVideoAV1TileInfo; + +typedef struct StdVideoAV1CDEF { + uint8_t cdef_damping_minus_3; + uint8_t cdef_bits; + uint8_t cdef_y_pri_strength[STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS]; + uint8_t cdef_y_sec_strength[STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS]; + uint8_t cdef_uv_pri_strength[STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS]; + uint8_t cdef_uv_sec_strength[STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS]; +} StdVideoAV1CDEF; + +typedef struct StdVideoAV1LoopRestoration { + StdVideoAV1FrameRestorationType FrameRestorationType[STD_VIDEO_AV1_MAX_NUM_PLANES]; + uint16_t LoopRestorationSize[STD_VIDEO_AV1_MAX_NUM_PLANES]; +} StdVideoAV1LoopRestoration; + +typedef struct StdVideoAV1GlobalMotion { + uint8_t GmType[STD_VIDEO_AV1_NUM_REF_FRAMES]; + int32_t gm_params[STD_VIDEO_AV1_NUM_REF_FRAMES][STD_VIDEO_AV1_GLOBAL_MOTION_PARAMS]; +} StdVideoAV1GlobalMotion; + +typedef struct StdVideoAV1FilmGrainFlags { + uint32_t chroma_scaling_from_luma : 1; + uint32_t overlap_flag : 1; + uint32_t clip_to_restricted_range : 1; + uint32_t update_grain : 1; + uint32_t reserved : 28; +} StdVideoAV1FilmGrainFlags; + +typedef struct StdVideoAV1FilmGrain { + StdVideoAV1FilmGrainFlags flags; + uint8_t grain_scaling_minus_8; + uint8_t ar_coeff_lag; + uint8_t ar_coeff_shift_minus_6; + uint8_t grain_scale_shift; + uint16_t grain_seed; + uint8_t film_grain_params_ref_idx; + uint8_t num_y_points; + uint8_t point_y_value[STD_VIDEO_AV1_MAX_NUM_Y_POINTS]; + uint8_t point_y_scaling[STD_VIDEO_AV1_MAX_NUM_Y_POINTS]; + uint8_t num_cb_points; + uint8_t point_cb_value[STD_VIDEO_AV1_MAX_NUM_CB_POINTS]; + uint8_t point_cb_scaling[STD_VIDEO_AV1_MAX_NUM_CB_POINTS]; + uint8_t num_cr_points; + uint8_t point_cr_value[STD_VIDEO_AV1_MAX_NUM_CR_POINTS]; + uint8_t point_cr_scaling[STD_VIDEO_AV1_MAX_NUM_CR_POINTS]; + int8_t ar_coeffs_y_plus_128[STD_VIDEO_AV1_MAX_NUM_POS_LUMA]; + int8_t ar_coeffs_cb_plus_128[STD_VIDEO_AV1_MAX_NUM_POS_CHROMA]; + int8_t ar_coeffs_cr_plus_128[STD_VIDEO_AV1_MAX_NUM_POS_CHROMA]; + uint8_t cb_mult; + uint8_t cb_luma_mult; + uint16_t cb_offset; + uint8_t cr_mult; + uint8_t cr_luma_mult; + uint16_t cr_offset; +} StdVideoAV1FilmGrain; + +typedef struct StdVideoAV1SequenceHeaderFlags { + uint32_t still_picture : 1; + uint32_t reduced_still_picture_header : 1; + uint32_t use_128x128_superblock : 1; + uint32_t enable_filter_intra : 1; + uint32_t enable_intra_edge_filter : 1; + uint32_t enable_interintra_compound : 1; + uint32_t enable_masked_compound : 1; + uint32_t enable_warped_motion : 1; + uint32_t enable_dual_filter : 1; + uint32_t enable_order_hint : 1; + uint32_t enable_jnt_comp : 1; + uint32_t enable_ref_frame_mvs : 1; + uint32_t frame_id_numbers_present_flag : 1; + uint32_t enable_superres : 1; + uint32_t enable_cdef : 1; + uint32_t enable_restoration : 1; + uint32_t film_grain_params_present : 1; + uint32_t timing_info_present_flag : 1; + uint32_t initial_display_delay_present_flag : 1; + uint32_t reserved : 13; +} StdVideoAV1SequenceHeaderFlags; + +typedef struct StdVideoAV1SequenceHeader { + StdVideoAV1SequenceHeaderFlags flags; + StdVideoAV1Profile seq_profile; + uint8_t frame_width_bits_minus_1; + uint8_t frame_height_bits_minus_1; + uint16_t max_frame_width_minus_1; + uint16_t max_frame_height_minus_1; + uint8_t delta_frame_id_length_minus_2; + uint8_t additional_frame_id_length_minus_1; + uint8_t order_hint_bits_minus_1; + uint8_t seq_force_integer_mv; + uint8_t seq_force_screen_content_tools; + uint8_t reserved1[5]; + const StdVideoAV1ColorConfig* pColorConfig; + const StdVideoAV1TimingInfo* pTimingInfo; +} StdVideoAV1SequenceHeader; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_av1std_decode.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_av1std_decode.h new file mode 100644 index 000000000..e262e961a --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_av1std_decode.h @@ -0,0 +1,109 @@ +#ifndef VULKAN_VIDEO_CODEC_AV1STD_DECODE_H_ +#define VULKAN_VIDEO_CODEC_AV1STD_DECODE_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_av1std_decode is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_av1std_decode 1 +#include "vulkan_video_codec_av1std.h" + +#define VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) + +#define VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_API_VERSION_1_0_0 +#define VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_av1_decode" +typedef struct StdVideoDecodeAV1PictureInfoFlags { + uint32_t error_resilient_mode : 1; + uint32_t disable_cdf_update : 1; + uint32_t use_superres : 1; + uint32_t render_and_frame_size_different : 1; + uint32_t allow_screen_content_tools : 1; + uint32_t is_filter_switchable : 1; + uint32_t force_integer_mv : 1; + uint32_t frame_size_override_flag : 1; + uint32_t buffer_removal_time_present_flag : 1; + uint32_t allow_intrabc : 1; + uint32_t frame_refs_short_signaling : 1; + uint32_t allow_high_precision_mv : 1; + uint32_t is_motion_mode_switchable : 1; + uint32_t use_ref_frame_mvs : 1; + uint32_t disable_frame_end_update_cdf : 1; + uint32_t allow_warped_motion : 1; + uint32_t reduced_tx_set : 1; + uint32_t reference_select : 1; + uint32_t skip_mode_present : 1; + uint32_t delta_q_present : 1; + uint32_t delta_lf_present : 1; + uint32_t delta_lf_multi : 1; + uint32_t segmentation_enabled : 1; + uint32_t segmentation_update_map : 1; + uint32_t segmentation_temporal_update : 1; + uint32_t segmentation_update_data : 1; + uint32_t UsesLr : 1; + uint32_t usesChromaLr : 1; + uint32_t apply_grain : 1; + uint32_t reserved : 3; +} StdVideoDecodeAV1PictureInfoFlags; + +typedef struct StdVideoDecodeAV1PictureInfo { + StdVideoDecodeAV1PictureInfoFlags flags; + StdVideoAV1FrameType frame_type; + uint32_t current_frame_id; + uint8_t OrderHint; + uint8_t primary_ref_frame; + uint8_t refresh_frame_flags; + uint8_t reserved1; + StdVideoAV1InterpolationFilter interpolation_filter; + StdVideoAV1TxMode TxMode; + uint8_t delta_q_res; + uint8_t delta_lf_res; + uint8_t SkipModeFrame[STD_VIDEO_AV1_SKIP_MODE_FRAMES]; + uint8_t coded_denom; + uint8_t reserved2[3]; + uint8_t OrderHints[STD_VIDEO_AV1_NUM_REF_FRAMES]; + uint32_t expectedFrameId[STD_VIDEO_AV1_NUM_REF_FRAMES]; + const StdVideoAV1TileInfo* pTileInfo; + const StdVideoAV1Quantization* pQuantization; + const StdVideoAV1Segmentation* pSegmentation; + const StdVideoAV1LoopFilter* pLoopFilter; + const StdVideoAV1CDEF* pCDEF; + const StdVideoAV1LoopRestoration* pLoopRestoration; + const StdVideoAV1GlobalMotion* pGlobalMotion; + const StdVideoAV1FilmGrain* pFilmGrain; +} StdVideoDecodeAV1PictureInfo; + +typedef struct StdVideoDecodeAV1ReferenceInfoFlags { + uint32_t disable_frame_end_update_cdf : 1; + uint32_t segmentation_enabled : 1; + uint32_t reserved : 30; +} StdVideoDecodeAV1ReferenceInfoFlags; + +typedef struct StdVideoDecodeAV1ReferenceInfo { + StdVideoDecodeAV1ReferenceInfoFlags flags; + uint8_t frame_type; + uint8_t RefFrameSignBias; + uint8_t OrderHint; + uint8_t SavedOrderHints[STD_VIDEO_AV1_NUM_REF_FRAMES]; +} StdVideoDecodeAV1ReferenceInfo; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_av1std_encode.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_av1std_encode.h new file mode 100644 index 000000000..8afb2537f --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_av1std_encode.h @@ -0,0 +1,143 @@ +#ifndef VULKAN_VIDEO_CODEC_AV1STD_ENCODE_H_ +#define VULKAN_VIDEO_CODEC_AV1STD_ENCODE_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_av1std_encode is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_av1std_encode 1 +#include "vulkan_video_codec_av1std.h" + +#define VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) + +#define VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_API_VERSION_1_0_0 +#define VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_av1_encode" +typedef struct StdVideoEncodeAV1DecoderModelInfo { + uint8_t buffer_delay_length_minus_1; + uint8_t buffer_removal_time_length_minus_1; + uint8_t frame_presentation_time_length_minus_1; + uint8_t reserved1; + uint32_t num_units_in_decoding_tick; +} StdVideoEncodeAV1DecoderModelInfo; + +typedef struct StdVideoEncodeAV1ExtensionHeader { + uint8_t temporal_id; + uint8_t spatial_id; +} StdVideoEncodeAV1ExtensionHeader; + +typedef struct StdVideoEncodeAV1OperatingPointInfoFlags { + uint32_t decoder_model_present_for_this_op : 1; + uint32_t low_delay_mode_flag : 1; + uint32_t initial_display_delay_present_for_this_op : 1; + uint32_t reserved : 29; +} StdVideoEncodeAV1OperatingPointInfoFlags; + +typedef struct StdVideoEncodeAV1OperatingPointInfo { + StdVideoEncodeAV1OperatingPointInfoFlags flags; + uint16_t operating_point_idc; + uint8_t seq_level_idx; + uint8_t seq_tier; + uint32_t decoder_buffer_delay; + uint32_t encoder_buffer_delay; + uint8_t initial_display_delay_minus_1; +} StdVideoEncodeAV1OperatingPointInfo; + +typedef struct StdVideoEncodeAV1PictureInfoFlags { + uint32_t error_resilient_mode : 1; + uint32_t disable_cdf_update : 1; + uint32_t use_superres : 1; + uint32_t render_and_frame_size_different : 1; + uint32_t allow_screen_content_tools : 1; + uint32_t is_filter_switchable : 1; + uint32_t force_integer_mv : 1; + uint32_t frame_size_override_flag : 1; + uint32_t buffer_removal_time_present_flag : 1; + uint32_t allow_intrabc : 1; + uint32_t frame_refs_short_signaling : 1; + uint32_t allow_high_precision_mv : 1; + uint32_t is_motion_mode_switchable : 1; + uint32_t use_ref_frame_mvs : 1; + uint32_t disable_frame_end_update_cdf : 1; + uint32_t allow_warped_motion : 1; + uint32_t reduced_tx_set : 1; + uint32_t skip_mode_present : 1; + uint32_t delta_q_present : 1; + uint32_t delta_lf_present : 1; + uint32_t delta_lf_multi : 1; + uint32_t segmentation_enabled : 1; + uint32_t segmentation_update_map : 1; + uint32_t segmentation_temporal_update : 1; + uint32_t segmentation_update_data : 1; + uint32_t UsesLr : 1; + uint32_t usesChromaLr : 1; + uint32_t show_frame : 1; + uint32_t showable_frame : 1; + uint32_t reserved : 3; +} StdVideoEncodeAV1PictureInfoFlags; + +typedef struct StdVideoEncodeAV1PictureInfo { + StdVideoEncodeAV1PictureInfoFlags flags; + StdVideoAV1FrameType frame_type; + uint32_t frame_presentation_time; + uint32_t current_frame_id; + uint8_t order_hint; + uint8_t primary_ref_frame; + uint8_t refresh_frame_flags; + uint8_t coded_denom; + uint16_t render_width_minus_1; + uint16_t render_height_minus_1; + StdVideoAV1InterpolationFilter interpolation_filter; + StdVideoAV1TxMode TxMode; + uint8_t delta_q_res; + uint8_t delta_lf_res; + uint8_t ref_order_hint[STD_VIDEO_AV1_NUM_REF_FRAMES]; + int8_t ref_frame_idx[STD_VIDEO_AV1_REFS_PER_FRAME]; + uint8_t reserved1[3]; + uint32_t delta_frame_id_minus_1[STD_VIDEO_AV1_REFS_PER_FRAME]; + const StdVideoAV1TileInfo* pTileInfo; + const StdVideoAV1Quantization* pQuantization; + const StdVideoAV1Segmentation* pSegmentation; + const StdVideoAV1LoopFilter* pLoopFilter; + const StdVideoAV1CDEF* pCDEF; + const StdVideoAV1LoopRestoration* pLoopRestoration; + const StdVideoAV1GlobalMotion* pGlobalMotion; + const StdVideoEncodeAV1ExtensionHeader* pExtensionHeader; + const uint32_t* pBufferRemovalTimes; +} StdVideoEncodeAV1PictureInfo; + +typedef struct StdVideoEncodeAV1ReferenceInfoFlags { + uint32_t disable_frame_end_update_cdf : 1; + uint32_t segmentation_enabled : 1; + uint32_t reserved : 30; +} StdVideoEncodeAV1ReferenceInfoFlags; + +typedef struct StdVideoEncodeAV1ReferenceInfo { + StdVideoEncodeAV1ReferenceInfoFlags flags; + uint32_t RefFrameId; + StdVideoAV1FrameType frame_type; + uint8_t OrderHint; + uint8_t reserved1[3]; + const StdVideoEncodeAV1ExtensionHeader* pExtensionHeader; +} StdVideoEncodeAV1ReferenceInfo; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h264std.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h264std.h new file mode 100644 index 000000000..2ae893243 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h264std.h @@ -0,0 +1,314 @@ +#ifndef VULKAN_VIDEO_CODEC_H264STD_H_ +#define VULKAN_VIDEO_CODEC_H264STD_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_h264std is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_h264std 1 +#include "vulkan_video_codecs_common.h" +#define STD_VIDEO_H264_CPB_CNT_LIST_SIZE 32U +#define STD_VIDEO_H264_SCALING_LIST_4X4_NUM_LISTS 6U +#define STD_VIDEO_H264_SCALING_LIST_4X4_NUM_ELEMENTS 16U +#define STD_VIDEO_H264_SCALING_LIST_8X8_NUM_LISTS 6U +#define STD_VIDEO_H264_SCALING_LIST_8X8_NUM_ELEMENTS 64U +#define STD_VIDEO_H264_MAX_NUM_LIST_REF 32U +#define STD_VIDEO_H264_MAX_CHROMA_PLANES 2U +#define STD_VIDEO_H264_NO_REFERENCE_PICTURE 0xFFU + +typedef enum StdVideoH264ChromaFormatIdc { + STD_VIDEO_H264_CHROMA_FORMAT_IDC_MONOCHROME = 0, + STD_VIDEO_H264_CHROMA_FORMAT_IDC_420 = 1, + STD_VIDEO_H264_CHROMA_FORMAT_IDC_422 = 2, + STD_VIDEO_H264_CHROMA_FORMAT_IDC_444 = 3, + STD_VIDEO_H264_CHROMA_FORMAT_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_CHROMA_FORMAT_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264ChromaFormatIdc; + +typedef enum StdVideoH264ProfileIdc { + STD_VIDEO_H264_PROFILE_IDC_BASELINE = 66, + STD_VIDEO_H264_PROFILE_IDC_MAIN = 77, + STD_VIDEO_H264_PROFILE_IDC_HIGH = 100, + STD_VIDEO_H264_PROFILE_IDC_HIGH_10 = 110, + STD_VIDEO_H264_PROFILE_IDC_HIGH_422 = 122, + STD_VIDEO_H264_PROFILE_IDC_HIGH_444_PREDICTIVE = 244, + STD_VIDEO_H264_PROFILE_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_PROFILE_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264ProfileIdc; + +typedef enum StdVideoH264LevelIdc { + STD_VIDEO_H264_LEVEL_IDC_1_0 = 0, + STD_VIDEO_H264_LEVEL_IDC_1_1 = 1, + STD_VIDEO_H264_LEVEL_IDC_1_2 = 2, + STD_VIDEO_H264_LEVEL_IDC_1_3 = 3, + STD_VIDEO_H264_LEVEL_IDC_2_0 = 4, + STD_VIDEO_H264_LEVEL_IDC_2_1 = 5, + STD_VIDEO_H264_LEVEL_IDC_2_2 = 6, + STD_VIDEO_H264_LEVEL_IDC_3_0 = 7, + STD_VIDEO_H264_LEVEL_IDC_3_1 = 8, + STD_VIDEO_H264_LEVEL_IDC_3_2 = 9, + STD_VIDEO_H264_LEVEL_IDC_4_0 = 10, + STD_VIDEO_H264_LEVEL_IDC_4_1 = 11, + STD_VIDEO_H264_LEVEL_IDC_4_2 = 12, + STD_VIDEO_H264_LEVEL_IDC_5_0 = 13, + STD_VIDEO_H264_LEVEL_IDC_5_1 = 14, + STD_VIDEO_H264_LEVEL_IDC_5_2 = 15, + STD_VIDEO_H264_LEVEL_IDC_6_0 = 16, + STD_VIDEO_H264_LEVEL_IDC_6_1 = 17, + STD_VIDEO_H264_LEVEL_IDC_6_2 = 18, + STD_VIDEO_H264_LEVEL_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_LEVEL_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264LevelIdc; + +typedef enum StdVideoH264PocType { + STD_VIDEO_H264_POC_TYPE_0 = 0, + STD_VIDEO_H264_POC_TYPE_1 = 1, + STD_VIDEO_H264_POC_TYPE_2 = 2, + STD_VIDEO_H264_POC_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_POC_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264PocType; + +typedef enum StdVideoH264AspectRatioIdc { + STD_VIDEO_H264_ASPECT_RATIO_IDC_UNSPECIFIED = 0, + STD_VIDEO_H264_ASPECT_RATIO_IDC_SQUARE = 1, + STD_VIDEO_H264_ASPECT_RATIO_IDC_12_11 = 2, + STD_VIDEO_H264_ASPECT_RATIO_IDC_10_11 = 3, + STD_VIDEO_H264_ASPECT_RATIO_IDC_16_11 = 4, + STD_VIDEO_H264_ASPECT_RATIO_IDC_40_33 = 5, + STD_VIDEO_H264_ASPECT_RATIO_IDC_24_11 = 6, + STD_VIDEO_H264_ASPECT_RATIO_IDC_20_11 = 7, + STD_VIDEO_H264_ASPECT_RATIO_IDC_32_11 = 8, + STD_VIDEO_H264_ASPECT_RATIO_IDC_80_33 = 9, + STD_VIDEO_H264_ASPECT_RATIO_IDC_18_11 = 10, + STD_VIDEO_H264_ASPECT_RATIO_IDC_15_11 = 11, + STD_VIDEO_H264_ASPECT_RATIO_IDC_64_33 = 12, + STD_VIDEO_H264_ASPECT_RATIO_IDC_160_99 = 13, + STD_VIDEO_H264_ASPECT_RATIO_IDC_4_3 = 14, + STD_VIDEO_H264_ASPECT_RATIO_IDC_3_2 = 15, + STD_VIDEO_H264_ASPECT_RATIO_IDC_2_1 = 16, + STD_VIDEO_H264_ASPECT_RATIO_IDC_EXTENDED_SAR = 255, + STD_VIDEO_H264_ASPECT_RATIO_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_ASPECT_RATIO_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264AspectRatioIdc; + +typedef enum StdVideoH264WeightedBipredIdc { + STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_DEFAULT = 0, + STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_EXPLICIT = 1, + STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_IMPLICIT = 2, + STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264WeightedBipredIdc; + +typedef enum StdVideoH264ModificationOfPicNumsIdc { + STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_SHORT_TERM_SUBTRACT = 0, + STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_SHORT_TERM_ADD = 1, + STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_LONG_TERM = 2, + STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_END = 3, + STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264ModificationOfPicNumsIdc; + +typedef enum StdVideoH264MemMgmtControlOp { + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_END = 0, + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_UNMARK_SHORT_TERM = 1, + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_UNMARK_LONG_TERM = 2, + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MARK_LONG_TERM = 3, + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_SET_MAX_LONG_TERM_INDEX = 4, + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_UNMARK_ALL = 5, + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MARK_CURRENT_AS_LONG_TERM = 6, + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264MemMgmtControlOp; + +typedef enum StdVideoH264CabacInitIdc { + STD_VIDEO_H264_CABAC_INIT_IDC_0 = 0, + STD_VIDEO_H264_CABAC_INIT_IDC_1 = 1, + STD_VIDEO_H264_CABAC_INIT_IDC_2 = 2, + STD_VIDEO_H264_CABAC_INIT_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_CABAC_INIT_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264CabacInitIdc; + +typedef enum StdVideoH264DisableDeblockingFilterIdc { + STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_DISABLED = 0, + STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_ENABLED = 1, + STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_PARTIAL = 2, + STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264DisableDeblockingFilterIdc; + +typedef enum StdVideoH264SliceType { + STD_VIDEO_H264_SLICE_TYPE_P = 0, + STD_VIDEO_H264_SLICE_TYPE_B = 1, + STD_VIDEO_H264_SLICE_TYPE_I = 2, + STD_VIDEO_H264_SLICE_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_SLICE_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264SliceType; + +typedef enum StdVideoH264PictureType { + STD_VIDEO_H264_PICTURE_TYPE_P = 0, + STD_VIDEO_H264_PICTURE_TYPE_B = 1, + STD_VIDEO_H264_PICTURE_TYPE_I = 2, + STD_VIDEO_H264_PICTURE_TYPE_IDR = 5, + STD_VIDEO_H264_PICTURE_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_PICTURE_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264PictureType; + +typedef enum StdVideoH264NonVclNaluType { + STD_VIDEO_H264_NON_VCL_NALU_TYPE_SPS = 0, + STD_VIDEO_H264_NON_VCL_NALU_TYPE_PPS = 1, + STD_VIDEO_H264_NON_VCL_NALU_TYPE_AUD = 2, + STD_VIDEO_H264_NON_VCL_NALU_TYPE_PREFIX = 3, + STD_VIDEO_H264_NON_VCL_NALU_TYPE_END_OF_SEQUENCE = 4, + STD_VIDEO_H264_NON_VCL_NALU_TYPE_END_OF_STREAM = 5, + STD_VIDEO_H264_NON_VCL_NALU_TYPE_PRECODED = 6, + STD_VIDEO_H264_NON_VCL_NALU_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_H264_NON_VCL_NALU_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoH264NonVclNaluType; +typedef struct StdVideoH264SpsVuiFlags { + uint32_t aspect_ratio_info_present_flag : 1; + uint32_t overscan_info_present_flag : 1; + uint32_t overscan_appropriate_flag : 1; + uint32_t video_signal_type_present_flag : 1; + uint32_t video_full_range_flag : 1; + uint32_t color_description_present_flag : 1; + uint32_t chroma_loc_info_present_flag : 1; + uint32_t timing_info_present_flag : 1; + uint32_t fixed_frame_rate_flag : 1; + uint32_t bitstream_restriction_flag : 1; + uint32_t nal_hrd_parameters_present_flag : 1; + uint32_t vcl_hrd_parameters_present_flag : 1; +} StdVideoH264SpsVuiFlags; + +typedef struct StdVideoH264HrdParameters { + uint8_t cpb_cnt_minus1; + uint8_t bit_rate_scale; + uint8_t cpb_size_scale; + uint8_t reserved1; + uint32_t bit_rate_value_minus1[STD_VIDEO_H264_CPB_CNT_LIST_SIZE]; + uint32_t cpb_size_value_minus1[STD_VIDEO_H264_CPB_CNT_LIST_SIZE]; + uint8_t cbr_flag[STD_VIDEO_H264_CPB_CNT_LIST_SIZE]; + uint32_t initial_cpb_removal_delay_length_minus1; + uint32_t cpb_removal_delay_length_minus1; + uint32_t dpb_output_delay_length_minus1; + uint32_t time_offset_length; +} StdVideoH264HrdParameters; + +typedef struct StdVideoH264SequenceParameterSetVui { + StdVideoH264SpsVuiFlags flags; + StdVideoH264AspectRatioIdc aspect_ratio_idc; + uint16_t sar_width; + uint16_t sar_height; + uint8_t video_format; + uint8_t colour_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + uint32_t num_units_in_tick; + uint32_t time_scale; + uint8_t max_num_reorder_frames; + uint8_t max_dec_frame_buffering; + uint8_t chroma_sample_loc_type_top_field; + uint8_t chroma_sample_loc_type_bottom_field; + uint32_t reserved1; + const StdVideoH264HrdParameters* pHrdParameters; +} StdVideoH264SequenceParameterSetVui; + +typedef struct StdVideoH264SpsFlags { + uint32_t constraint_set0_flag : 1; + uint32_t constraint_set1_flag : 1; + uint32_t constraint_set2_flag : 1; + uint32_t constraint_set3_flag : 1; + uint32_t constraint_set4_flag : 1; + uint32_t constraint_set5_flag : 1; + uint32_t direct_8x8_inference_flag : 1; + uint32_t mb_adaptive_frame_field_flag : 1; + uint32_t frame_mbs_only_flag : 1; + uint32_t delta_pic_order_always_zero_flag : 1; + uint32_t separate_colour_plane_flag : 1; + uint32_t gaps_in_frame_num_value_allowed_flag : 1; + uint32_t qpprime_y_zero_transform_bypass_flag : 1; + uint32_t frame_cropping_flag : 1; + uint32_t seq_scaling_matrix_present_flag : 1; + uint32_t vui_parameters_present_flag : 1; +} StdVideoH264SpsFlags; + +typedef struct StdVideoH264ScalingLists { + uint16_t scaling_list_present_mask; + uint16_t use_default_scaling_matrix_mask; + uint8_t ScalingList4x4[STD_VIDEO_H264_SCALING_LIST_4X4_NUM_LISTS][STD_VIDEO_H264_SCALING_LIST_4X4_NUM_ELEMENTS]; + uint8_t ScalingList8x8[STD_VIDEO_H264_SCALING_LIST_8X8_NUM_LISTS][STD_VIDEO_H264_SCALING_LIST_8X8_NUM_ELEMENTS]; +} StdVideoH264ScalingLists; + +typedef struct StdVideoH264SequenceParameterSet { + StdVideoH264SpsFlags flags; + StdVideoH264ProfileIdc profile_idc; + StdVideoH264LevelIdc level_idc; + StdVideoH264ChromaFormatIdc chroma_format_idc; + uint8_t seq_parameter_set_id; + uint8_t bit_depth_luma_minus8; + uint8_t bit_depth_chroma_minus8; + uint8_t log2_max_frame_num_minus4; + StdVideoH264PocType pic_order_cnt_type; + int32_t offset_for_non_ref_pic; + int32_t offset_for_top_to_bottom_field; + uint8_t log2_max_pic_order_cnt_lsb_minus4; + uint8_t num_ref_frames_in_pic_order_cnt_cycle; + uint8_t max_num_ref_frames; + uint8_t reserved1; + uint32_t pic_width_in_mbs_minus1; + uint32_t pic_height_in_map_units_minus1; + uint32_t frame_crop_left_offset; + uint32_t frame_crop_right_offset; + uint32_t frame_crop_top_offset; + uint32_t frame_crop_bottom_offset; + uint32_t reserved2; + const int32_t* pOffsetForRefFrame; + const StdVideoH264ScalingLists* pScalingLists; + const StdVideoH264SequenceParameterSetVui* pSequenceParameterSetVui; +} StdVideoH264SequenceParameterSet; + +typedef struct StdVideoH264PpsFlags { + uint32_t transform_8x8_mode_flag : 1; + uint32_t redundant_pic_cnt_present_flag : 1; + uint32_t constrained_intra_pred_flag : 1; + uint32_t deblocking_filter_control_present_flag : 1; + uint32_t weighted_pred_flag : 1; + uint32_t bottom_field_pic_order_in_frame_present_flag : 1; + uint32_t entropy_coding_mode_flag : 1; + uint32_t pic_scaling_matrix_present_flag : 1; +} StdVideoH264PpsFlags; + +typedef struct StdVideoH264PictureParameterSet { + StdVideoH264PpsFlags flags; + uint8_t seq_parameter_set_id; + uint8_t pic_parameter_set_id; + uint8_t num_ref_idx_l0_default_active_minus1; + uint8_t num_ref_idx_l1_default_active_minus1; + StdVideoH264WeightedBipredIdc weighted_bipred_idc; + int8_t pic_init_qp_minus26; + int8_t pic_init_qs_minus26; + int8_t chroma_qp_index_offset; + int8_t second_chroma_qp_index_offset; + const StdVideoH264ScalingLists* pScalingLists; +} StdVideoH264PictureParameterSet; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h264std_decode.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h264std_decode.h new file mode 100644 index 000000000..fa1140586 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h264std_decode.h @@ -0,0 +1,77 @@ +#ifndef VULKAN_VIDEO_CODEC_H264STD_DECODE_H_ +#define VULKAN_VIDEO_CODEC_H264STD_DECODE_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_h264std_decode is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_h264std_decode 1 +#include "vulkan_video_codec_h264std.h" + +#define VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) + +#define VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_API_VERSION_1_0_0 +#define VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h264_decode" +#define STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_LIST_SIZE 2U + +typedef enum StdVideoDecodeH264FieldOrderCount { + STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_TOP = 0, + STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_BOTTOM = 1, + STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_INVALID = 0x7FFFFFFF, + STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_MAX_ENUM = 0x7FFFFFFF +} StdVideoDecodeH264FieldOrderCount; +typedef struct StdVideoDecodeH264PictureInfoFlags { + uint32_t field_pic_flag : 1; + uint32_t is_intra : 1; + uint32_t IdrPicFlag : 1; + uint32_t bottom_field_flag : 1; + uint32_t is_reference : 1; + uint32_t complementary_field_pair : 1; +} StdVideoDecodeH264PictureInfoFlags; + +typedef struct StdVideoDecodeH264PictureInfo { + StdVideoDecodeH264PictureInfoFlags flags; + uint8_t seq_parameter_set_id; + uint8_t pic_parameter_set_id; + uint8_t reserved1; + uint8_t reserved2; + uint16_t frame_num; + uint16_t idr_pic_id; + int32_t PicOrderCnt[STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_LIST_SIZE]; +} StdVideoDecodeH264PictureInfo; + +typedef struct StdVideoDecodeH264ReferenceInfoFlags { + uint32_t top_field_flag : 1; + uint32_t bottom_field_flag : 1; + uint32_t used_for_long_term_reference : 1; + uint32_t is_non_existing : 1; +} StdVideoDecodeH264ReferenceInfoFlags; + +typedef struct StdVideoDecodeH264ReferenceInfo { + StdVideoDecodeH264ReferenceInfoFlags flags; + uint16_t FrameNum; + uint16_t reserved; + int32_t PicOrderCnt[STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_LIST_SIZE]; +} StdVideoDecodeH264ReferenceInfo; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h264std_encode.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h264std_encode.h new file mode 100644 index 000000000..aba6fbf3a --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h264std_encode.h @@ -0,0 +1,147 @@ +#ifndef VULKAN_VIDEO_CODEC_H264STD_ENCODE_H_ +#define VULKAN_VIDEO_CODEC_H264STD_ENCODE_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_h264std_encode is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_h264std_encode 1 +#include "vulkan_video_codec_h264std.h" + +#define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) + +#define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_API_VERSION_1_0_0 +#define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h264_encode" +typedef struct StdVideoEncodeH264WeightTableFlags { + uint32_t luma_weight_l0_flag; + uint32_t chroma_weight_l0_flag; + uint32_t luma_weight_l1_flag; + uint32_t chroma_weight_l1_flag; +} StdVideoEncodeH264WeightTableFlags; + +typedef struct StdVideoEncodeH264WeightTable { + StdVideoEncodeH264WeightTableFlags flags; + uint8_t luma_log2_weight_denom; + uint8_t chroma_log2_weight_denom; + int8_t luma_weight_l0[STD_VIDEO_H264_MAX_NUM_LIST_REF]; + int8_t luma_offset_l0[STD_VIDEO_H264_MAX_NUM_LIST_REF]; + int8_t chroma_weight_l0[STD_VIDEO_H264_MAX_NUM_LIST_REF][STD_VIDEO_H264_MAX_CHROMA_PLANES]; + int8_t chroma_offset_l0[STD_VIDEO_H264_MAX_NUM_LIST_REF][STD_VIDEO_H264_MAX_CHROMA_PLANES]; + int8_t luma_weight_l1[STD_VIDEO_H264_MAX_NUM_LIST_REF]; + int8_t luma_offset_l1[STD_VIDEO_H264_MAX_NUM_LIST_REF]; + int8_t chroma_weight_l1[STD_VIDEO_H264_MAX_NUM_LIST_REF][STD_VIDEO_H264_MAX_CHROMA_PLANES]; + int8_t chroma_offset_l1[STD_VIDEO_H264_MAX_NUM_LIST_REF][STD_VIDEO_H264_MAX_CHROMA_PLANES]; +} StdVideoEncodeH264WeightTable; + +typedef struct StdVideoEncodeH264SliceHeaderFlags { + uint32_t direct_spatial_mv_pred_flag : 1; + uint32_t num_ref_idx_active_override_flag : 1; + uint32_t reserved : 30; +} StdVideoEncodeH264SliceHeaderFlags; + +typedef struct StdVideoEncodeH264PictureInfoFlags { + uint32_t IdrPicFlag : 1; + uint32_t is_reference : 1; + uint32_t no_output_of_prior_pics_flag : 1; + uint32_t long_term_reference_flag : 1; + uint32_t adaptive_ref_pic_marking_mode_flag : 1; + uint32_t reserved : 27; +} StdVideoEncodeH264PictureInfoFlags; + +typedef struct StdVideoEncodeH264ReferenceInfoFlags { + uint32_t used_for_long_term_reference : 1; + uint32_t reserved : 31; +} StdVideoEncodeH264ReferenceInfoFlags; + +typedef struct StdVideoEncodeH264ReferenceListsInfoFlags { + uint32_t ref_pic_list_modification_flag_l0 : 1; + uint32_t ref_pic_list_modification_flag_l1 : 1; + uint32_t reserved : 30; +} StdVideoEncodeH264ReferenceListsInfoFlags; + +typedef struct StdVideoEncodeH264RefListModEntry { + StdVideoH264ModificationOfPicNumsIdc modification_of_pic_nums_idc; + uint16_t abs_diff_pic_num_minus1; + uint16_t long_term_pic_num; +} StdVideoEncodeH264RefListModEntry; + +typedef struct StdVideoEncodeH264RefPicMarkingEntry { + StdVideoH264MemMgmtControlOp memory_management_control_operation; + uint16_t difference_of_pic_nums_minus1; + uint16_t long_term_pic_num; + uint16_t long_term_frame_idx; + uint16_t max_long_term_frame_idx_plus1; +} StdVideoEncodeH264RefPicMarkingEntry; + +typedef struct StdVideoEncodeH264ReferenceListsInfo { + StdVideoEncodeH264ReferenceListsInfoFlags flags; + uint8_t num_ref_idx_l0_active_minus1; + uint8_t num_ref_idx_l1_active_minus1; + uint8_t RefPicList0[STD_VIDEO_H264_MAX_NUM_LIST_REF]; + uint8_t RefPicList1[STD_VIDEO_H264_MAX_NUM_LIST_REF]; + uint8_t refList0ModOpCount; + uint8_t refList1ModOpCount; + uint8_t refPicMarkingOpCount; + uint8_t reserved1[7]; + const StdVideoEncodeH264RefListModEntry* pRefList0ModOperations; + const StdVideoEncodeH264RefListModEntry* pRefList1ModOperations; + const StdVideoEncodeH264RefPicMarkingEntry* pRefPicMarkingOperations; +} StdVideoEncodeH264ReferenceListsInfo; + +typedef struct StdVideoEncodeH264PictureInfo { + StdVideoEncodeH264PictureInfoFlags flags; + uint8_t seq_parameter_set_id; + uint8_t pic_parameter_set_id; + uint16_t idr_pic_id; + StdVideoH264PictureType primary_pic_type; + uint32_t frame_num; + int32_t PicOrderCnt; + uint8_t temporal_id; + uint8_t reserved1[3]; + const StdVideoEncodeH264ReferenceListsInfo* pRefLists; +} StdVideoEncodeH264PictureInfo; + +typedef struct StdVideoEncodeH264ReferenceInfo { + StdVideoEncodeH264ReferenceInfoFlags flags; + StdVideoH264PictureType primary_pic_type; + uint32_t FrameNum; + int32_t PicOrderCnt; + uint16_t long_term_pic_num; + uint16_t long_term_frame_idx; + uint8_t temporal_id; +} StdVideoEncodeH264ReferenceInfo; + +typedef struct StdVideoEncodeH264SliceHeader { + StdVideoEncodeH264SliceHeaderFlags flags; + uint32_t first_mb_in_slice; + StdVideoH264SliceType slice_type; + int8_t slice_alpha_c0_offset_div2; + int8_t slice_beta_offset_div2; + int8_t slice_qp_delta; + uint8_t reserved1; + StdVideoH264CabacInitIdc cabac_init_idc; + StdVideoH264DisableDeblockingFilterIdc disable_deblocking_filter_idc; + const StdVideoEncodeH264WeightTable* pWeightTable; +} StdVideoEncodeH264SliceHeader; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h265std.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h265std.h new file mode 100644 index 000000000..cf0cbefc0 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h265std.h @@ -0,0 +1,446 @@ +#ifndef VULKAN_VIDEO_CODEC_H265STD_H_ +#define VULKAN_VIDEO_CODEC_H265STD_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_h265std is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_h265std 1 +#include "vulkan_video_codecs_common.h" +#define STD_VIDEO_H265_CPB_CNT_LIST_SIZE 32U +#define STD_VIDEO_H265_SUBLAYERS_LIST_SIZE 7U +#define STD_VIDEO_H265_SCALING_LIST_4X4_NUM_LISTS 6U +#define STD_VIDEO_H265_SCALING_LIST_4X4_NUM_ELEMENTS 16U +#define STD_VIDEO_H265_SCALING_LIST_8X8_NUM_LISTS 6U +#define STD_VIDEO_H265_SCALING_LIST_8X8_NUM_ELEMENTS 64U +#define STD_VIDEO_H265_SCALING_LIST_16X16_NUM_LISTS 6U +#define STD_VIDEO_H265_SCALING_LIST_16X16_NUM_ELEMENTS 64U +#define STD_VIDEO_H265_SCALING_LIST_32X32_NUM_LISTS 2U +#define STD_VIDEO_H265_SCALING_LIST_32X32_NUM_ELEMENTS 64U +#define STD_VIDEO_H265_CHROMA_QP_OFFSET_LIST_SIZE 6U +#define STD_VIDEO_H265_CHROMA_QP_OFFSET_TILE_COLS_LIST_SIZE 19U +#define STD_VIDEO_H265_CHROMA_QP_OFFSET_TILE_ROWS_LIST_SIZE 21U +#define STD_VIDEO_H265_PREDICTOR_PALETTE_COMPONENTS_LIST_SIZE 3U +#define STD_VIDEO_H265_PREDICTOR_PALETTE_COMP_ENTRIES_LIST_SIZE 128U +#define STD_VIDEO_H265_MAX_NUM_LIST_REF 15U +#define STD_VIDEO_H265_MAX_CHROMA_PLANES 2U +#define STD_VIDEO_H265_MAX_SHORT_TERM_REF_PIC_SETS 64U +#define STD_VIDEO_H265_MAX_DPB_SIZE 16U +#define STD_VIDEO_H265_MAX_LONG_TERM_REF_PICS_SPS 32U +#define STD_VIDEO_H265_MAX_LONG_TERM_PICS 16U +#define STD_VIDEO_H265_MAX_DELTA_POC 48U +#define STD_VIDEO_H265_NO_REFERENCE_PICTURE 0xFFU + +typedef enum StdVideoH265ChromaFormatIdc { + STD_VIDEO_H265_CHROMA_FORMAT_IDC_MONOCHROME = 0, + STD_VIDEO_H265_CHROMA_FORMAT_IDC_420 = 1, + STD_VIDEO_H265_CHROMA_FORMAT_IDC_422 = 2, + STD_VIDEO_H265_CHROMA_FORMAT_IDC_444 = 3, + STD_VIDEO_H265_CHROMA_FORMAT_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H265_CHROMA_FORMAT_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH265ChromaFormatIdc; + +typedef enum StdVideoH265ProfileIdc { + STD_VIDEO_H265_PROFILE_IDC_MAIN = 1, + STD_VIDEO_H265_PROFILE_IDC_MAIN_10 = 2, + STD_VIDEO_H265_PROFILE_IDC_MAIN_STILL_PICTURE = 3, + STD_VIDEO_H265_PROFILE_IDC_FORMAT_RANGE_EXTENSIONS = 4, + STD_VIDEO_H265_PROFILE_IDC_SCC_EXTENSIONS = 9, + STD_VIDEO_H265_PROFILE_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H265_PROFILE_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH265ProfileIdc; + +typedef enum StdVideoH265LevelIdc { + STD_VIDEO_H265_LEVEL_IDC_1_0 = 0, + STD_VIDEO_H265_LEVEL_IDC_2_0 = 1, + STD_VIDEO_H265_LEVEL_IDC_2_1 = 2, + STD_VIDEO_H265_LEVEL_IDC_3_0 = 3, + STD_VIDEO_H265_LEVEL_IDC_3_1 = 4, + STD_VIDEO_H265_LEVEL_IDC_4_0 = 5, + STD_VIDEO_H265_LEVEL_IDC_4_1 = 6, + STD_VIDEO_H265_LEVEL_IDC_5_0 = 7, + STD_VIDEO_H265_LEVEL_IDC_5_1 = 8, + STD_VIDEO_H265_LEVEL_IDC_5_2 = 9, + STD_VIDEO_H265_LEVEL_IDC_6_0 = 10, + STD_VIDEO_H265_LEVEL_IDC_6_1 = 11, + STD_VIDEO_H265_LEVEL_IDC_6_2 = 12, + STD_VIDEO_H265_LEVEL_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H265_LEVEL_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH265LevelIdc; + +typedef enum StdVideoH265SliceType { + STD_VIDEO_H265_SLICE_TYPE_B = 0, + STD_VIDEO_H265_SLICE_TYPE_P = 1, + STD_VIDEO_H265_SLICE_TYPE_I = 2, + STD_VIDEO_H265_SLICE_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_H265_SLICE_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoH265SliceType; + +typedef enum StdVideoH265PictureType { + STD_VIDEO_H265_PICTURE_TYPE_P = 0, + STD_VIDEO_H265_PICTURE_TYPE_B = 1, + STD_VIDEO_H265_PICTURE_TYPE_I = 2, + STD_VIDEO_H265_PICTURE_TYPE_IDR = 3, + STD_VIDEO_H265_PICTURE_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_H265_PICTURE_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoH265PictureType; + +typedef enum StdVideoH265AspectRatioIdc { + STD_VIDEO_H265_ASPECT_RATIO_IDC_UNSPECIFIED = 0, + STD_VIDEO_H265_ASPECT_RATIO_IDC_SQUARE = 1, + STD_VIDEO_H265_ASPECT_RATIO_IDC_12_11 = 2, + STD_VIDEO_H265_ASPECT_RATIO_IDC_10_11 = 3, + STD_VIDEO_H265_ASPECT_RATIO_IDC_16_11 = 4, + STD_VIDEO_H265_ASPECT_RATIO_IDC_40_33 = 5, + STD_VIDEO_H265_ASPECT_RATIO_IDC_24_11 = 6, + STD_VIDEO_H265_ASPECT_RATIO_IDC_20_11 = 7, + STD_VIDEO_H265_ASPECT_RATIO_IDC_32_11 = 8, + STD_VIDEO_H265_ASPECT_RATIO_IDC_80_33 = 9, + STD_VIDEO_H265_ASPECT_RATIO_IDC_18_11 = 10, + STD_VIDEO_H265_ASPECT_RATIO_IDC_15_11 = 11, + STD_VIDEO_H265_ASPECT_RATIO_IDC_64_33 = 12, + STD_VIDEO_H265_ASPECT_RATIO_IDC_160_99 = 13, + STD_VIDEO_H265_ASPECT_RATIO_IDC_4_3 = 14, + STD_VIDEO_H265_ASPECT_RATIO_IDC_3_2 = 15, + STD_VIDEO_H265_ASPECT_RATIO_IDC_2_1 = 16, + STD_VIDEO_H265_ASPECT_RATIO_IDC_EXTENDED_SAR = 255, + STD_VIDEO_H265_ASPECT_RATIO_IDC_INVALID = 0x7FFFFFFF, + STD_VIDEO_H265_ASPECT_RATIO_IDC_MAX_ENUM = 0x7FFFFFFF +} StdVideoH265AspectRatioIdc; +typedef struct StdVideoH265DecPicBufMgr { + uint32_t max_latency_increase_plus1[STD_VIDEO_H265_SUBLAYERS_LIST_SIZE]; + uint8_t max_dec_pic_buffering_minus1[STD_VIDEO_H265_SUBLAYERS_LIST_SIZE]; + uint8_t max_num_reorder_pics[STD_VIDEO_H265_SUBLAYERS_LIST_SIZE]; +} StdVideoH265DecPicBufMgr; + +typedef struct StdVideoH265SubLayerHrdParameters { + uint32_t bit_rate_value_minus1[STD_VIDEO_H265_CPB_CNT_LIST_SIZE]; + uint32_t cpb_size_value_minus1[STD_VIDEO_H265_CPB_CNT_LIST_SIZE]; + uint32_t cpb_size_du_value_minus1[STD_VIDEO_H265_CPB_CNT_LIST_SIZE]; + uint32_t bit_rate_du_value_minus1[STD_VIDEO_H265_CPB_CNT_LIST_SIZE]; + uint32_t cbr_flag; +} StdVideoH265SubLayerHrdParameters; + +typedef struct StdVideoH265HrdFlags { + uint32_t nal_hrd_parameters_present_flag : 1; + uint32_t vcl_hrd_parameters_present_flag : 1; + uint32_t sub_pic_hrd_params_present_flag : 1; + uint32_t sub_pic_cpb_params_in_pic_timing_sei_flag : 1; + uint32_t fixed_pic_rate_general_flag : 8; + uint32_t fixed_pic_rate_within_cvs_flag : 8; + uint32_t low_delay_hrd_flag : 8; +} StdVideoH265HrdFlags; + +typedef struct StdVideoH265HrdParameters { + StdVideoH265HrdFlags flags; + uint8_t tick_divisor_minus2; + uint8_t du_cpb_removal_delay_increment_length_minus1; + uint8_t dpb_output_delay_du_length_minus1; + uint8_t bit_rate_scale; + uint8_t cpb_size_scale; + uint8_t cpb_size_du_scale; + uint8_t initial_cpb_removal_delay_length_minus1; + uint8_t au_cpb_removal_delay_length_minus1; + uint8_t dpb_output_delay_length_minus1; + uint8_t cpb_cnt_minus1[STD_VIDEO_H265_SUBLAYERS_LIST_SIZE]; + uint16_t elemental_duration_in_tc_minus1[STD_VIDEO_H265_SUBLAYERS_LIST_SIZE]; + uint16_t reserved[3]; + const StdVideoH265SubLayerHrdParameters* pSubLayerHrdParametersNal; + const StdVideoH265SubLayerHrdParameters* pSubLayerHrdParametersVcl; +} StdVideoH265HrdParameters; + +typedef struct StdVideoH265VpsFlags { + uint32_t vps_temporal_id_nesting_flag : 1; + uint32_t vps_sub_layer_ordering_info_present_flag : 1; + uint32_t vps_timing_info_present_flag : 1; + uint32_t vps_poc_proportional_to_timing_flag : 1; +} StdVideoH265VpsFlags; + +typedef struct StdVideoH265ProfileTierLevelFlags { + uint32_t general_tier_flag : 1; + uint32_t general_progressive_source_flag : 1; + uint32_t general_interlaced_source_flag : 1; + uint32_t general_non_packed_constraint_flag : 1; + uint32_t general_frame_only_constraint_flag : 1; +} StdVideoH265ProfileTierLevelFlags; + +typedef struct StdVideoH265ProfileTierLevel { + StdVideoH265ProfileTierLevelFlags flags; + StdVideoH265ProfileIdc general_profile_idc; + StdVideoH265LevelIdc general_level_idc; +} StdVideoH265ProfileTierLevel; + +typedef struct StdVideoH265VideoParameterSet { + StdVideoH265VpsFlags flags; + uint8_t vps_video_parameter_set_id; + uint8_t vps_max_sub_layers_minus1; + uint8_t reserved1; + uint8_t reserved2; + uint32_t vps_num_units_in_tick; + uint32_t vps_time_scale; + uint32_t vps_num_ticks_poc_diff_one_minus1; + uint32_t reserved3; + const StdVideoH265DecPicBufMgr* pDecPicBufMgr; + const StdVideoH265HrdParameters* pHrdParameters; + const StdVideoH265ProfileTierLevel* pProfileTierLevel; +} StdVideoH265VideoParameterSet; + +typedef struct StdVideoH265ScalingLists { + uint8_t ScalingList4x4[STD_VIDEO_H265_SCALING_LIST_4X4_NUM_LISTS][STD_VIDEO_H265_SCALING_LIST_4X4_NUM_ELEMENTS]; + uint8_t ScalingList8x8[STD_VIDEO_H265_SCALING_LIST_8X8_NUM_LISTS][STD_VIDEO_H265_SCALING_LIST_8X8_NUM_ELEMENTS]; + uint8_t ScalingList16x16[STD_VIDEO_H265_SCALING_LIST_16X16_NUM_LISTS][STD_VIDEO_H265_SCALING_LIST_16X16_NUM_ELEMENTS]; + uint8_t ScalingList32x32[STD_VIDEO_H265_SCALING_LIST_32X32_NUM_LISTS][STD_VIDEO_H265_SCALING_LIST_32X32_NUM_ELEMENTS]; + uint8_t ScalingListDCCoef16x16[STD_VIDEO_H265_SCALING_LIST_16X16_NUM_LISTS]; + uint8_t ScalingListDCCoef32x32[STD_VIDEO_H265_SCALING_LIST_32X32_NUM_LISTS]; +} StdVideoH265ScalingLists; + +typedef struct StdVideoH265SpsVuiFlags { + uint32_t aspect_ratio_info_present_flag : 1; + uint32_t overscan_info_present_flag : 1; + uint32_t overscan_appropriate_flag : 1; + uint32_t video_signal_type_present_flag : 1; + uint32_t video_full_range_flag : 1; + uint32_t colour_description_present_flag : 1; + uint32_t chroma_loc_info_present_flag : 1; + uint32_t neutral_chroma_indication_flag : 1; + uint32_t field_seq_flag : 1; + uint32_t frame_field_info_present_flag : 1; + uint32_t default_display_window_flag : 1; + uint32_t vui_timing_info_present_flag : 1; + uint32_t vui_poc_proportional_to_timing_flag : 1; + uint32_t vui_hrd_parameters_present_flag : 1; + uint32_t bitstream_restriction_flag : 1; + uint32_t tiles_fixed_structure_flag : 1; + uint32_t motion_vectors_over_pic_boundaries_flag : 1; + uint32_t restricted_ref_pic_lists_flag : 1; +} StdVideoH265SpsVuiFlags; + +typedef struct StdVideoH265SequenceParameterSetVui { + StdVideoH265SpsVuiFlags flags; + StdVideoH265AspectRatioIdc aspect_ratio_idc; + uint16_t sar_width; + uint16_t sar_height; + uint8_t video_format; + uint8_t colour_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coeffs; + uint8_t chroma_sample_loc_type_top_field; + uint8_t chroma_sample_loc_type_bottom_field; + uint8_t reserved1; + uint8_t reserved2; + uint16_t def_disp_win_left_offset; + uint16_t def_disp_win_right_offset; + uint16_t def_disp_win_top_offset; + uint16_t def_disp_win_bottom_offset; + uint32_t vui_num_units_in_tick; + uint32_t vui_time_scale; + uint32_t vui_num_ticks_poc_diff_one_minus1; + uint16_t min_spatial_segmentation_idc; + uint16_t reserved3; + uint8_t max_bytes_per_pic_denom; + uint8_t max_bits_per_min_cu_denom; + uint8_t log2_max_mv_length_horizontal; + uint8_t log2_max_mv_length_vertical; + const StdVideoH265HrdParameters* pHrdParameters; +} StdVideoH265SequenceParameterSetVui; + +typedef struct StdVideoH265PredictorPaletteEntries { + uint16_t PredictorPaletteEntries[STD_VIDEO_H265_PREDICTOR_PALETTE_COMPONENTS_LIST_SIZE][STD_VIDEO_H265_PREDICTOR_PALETTE_COMP_ENTRIES_LIST_SIZE]; +} StdVideoH265PredictorPaletteEntries; + +typedef struct StdVideoH265SpsFlags { + uint32_t sps_temporal_id_nesting_flag : 1; + uint32_t separate_colour_plane_flag : 1; + uint32_t conformance_window_flag : 1; + uint32_t sps_sub_layer_ordering_info_present_flag : 1; + uint32_t scaling_list_enabled_flag : 1; + uint32_t sps_scaling_list_data_present_flag : 1; + uint32_t amp_enabled_flag : 1; + uint32_t sample_adaptive_offset_enabled_flag : 1; + uint32_t pcm_enabled_flag : 1; + uint32_t pcm_loop_filter_disabled_flag : 1; + uint32_t long_term_ref_pics_present_flag : 1; + uint32_t sps_temporal_mvp_enabled_flag : 1; + uint32_t strong_intra_smoothing_enabled_flag : 1; + uint32_t vui_parameters_present_flag : 1; + uint32_t sps_extension_present_flag : 1; + uint32_t sps_range_extension_flag : 1; + uint32_t transform_skip_rotation_enabled_flag : 1; + uint32_t transform_skip_context_enabled_flag : 1; + uint32_t implicit_rdpcm_enabled_flag : 1; + uint32_t explicit_rdpcm_enabled_flag : 1; + uint32_t extended_precision_processing_flag : 1; + uint32_t intra_smoothing_disabled_flag : 1; + uint32_t high_precision_offsets_enabled_flag : 1; + uint32_t persistent_rice_adaptation_enabled_flag : 1; + uint32_t cabac_bypass_alignment_enabled_flag : 1; + uint32_t sps_scc_extension_flag : 1; + uint32_t sps_curr_pic_ref_enabled_flag : 1; + uint32_t palette_mode_enabled_flag : 1; + uint32_t sps_palette_predictor_initializers_present_flag : 1; + uint32_t intra_boundary_filtering_disabled_flag : 1; +} StdVideoH265SpsFlags; + +typedef struct StdVideoH265ShortTermRefPicSetFlags { + uint32_t inter_ref_pic_set_prediction_flag : 1; + uint32_t delta_rps_sign : 1; +} StdVideoH265ShortTermRefPicSetFlags; + +typedef struct StdVideoH265ShortTermRefPicSet { + StdVideoH265ShortTermRefPicSetFlags flags; + uint32_t delta_idx_minus1; + uint16_t use_delta_flag; + uint16_t abs_delta_rps_minus1; + uint16_t used_by_curr_pic_flag; + uint16_t used_by_curr_pic_s0_flag; + uint16_t used_by_curr_pic_s1_flag; + uint16_t reserved1; + uint8_t reserved2; + uint8_t reserved3; + uint8_t num_negative_pics; + uint8_t num_positive_pics; + uint16_t delta_poc_s0_minus1[STD_VIDEO_H265_MAX_DPB_SIZE]; + uint16_t delta_poc_s1_minus1[STD_VIDEO_H265_MAX_DPB_SIZE]; +} StdVideoH265ShortTermRefPicSet; + +typedef struct StdVideoH265LongTermRefPicsSps { + uint32_t used_by_curr_pic_lt_sps_flag; + uint32_t lt_ref_pic_poc_lsb_sps[STD_VIDEO_H265_MAX_LONG_TERM_REF_PICS_SPS]; +} StdVideoH265LongTermRefPicsSps; + +typedef struct StdVideoH265SequenceParameterSet { + StdVideoH265SpsFlags flags; + StdVideoH265ChromaFormatIdc chroma_format_idc; + uint32_t pic_width_in_luma_samples; + uint32_t pic_height_in_luma_samples; + uint8_t sps_video_parameter_set_id; + uint8_t sps_max_sub_layers_minus1; + uint8_t sps_seq_parameter_set_id; + uint8_t bit_depth_luma_minus8; + uint8_t bit_depth_chroma_minus8; + uint8_t log2_max_pic_order_cnt_lsb_minus4; + uint8_t log2_min_luma_coding_block_size_minus3; + uint8_t log2_diff_max_min_luma_coding_block_size; + uint8_t log2_min_luma_transform_block_size_minus2; + uint8_t log2_diff_max_min_luma_transform_block_size; + uint8_t max_transform_hierarchy_depth_inter; + uint8_t max_transform_hierarchy_depth_intra; + uint8_t num_short_term_ref_pic_sets; + uint8_t num_long_term_ref_pics_sps; + uint8_t pcm_sample_bit_depth_luma_minus1; + uint8_t pcm_sample_bit_depth_chroma_minus1; + uint8_t log2_min_pcm_luma_coding_block_size_minus3; + uint8_t log2_diff_max_min_pcm_luma_coding_block_size; + uint8_t reserved1; + uint8_t reserved2; + uint8_t palette_max_size; + uint8_t delta_palette_max_predictor_size; + uint8_t motion_vector_resolution_control_idc; + uint8_t sps_num_palette_predictor_initializers_minus1; + uint32_t conf_win_left_offset; + uint32_t conf_win_right_offset; + uint32_t conf_win_top_offset; + uint32_t conf_win_bottom_offset; + const StdVideoH265ProfileTierLevel* pProfileTierLevel; + const StdVideoH265DecPicBufMgr* pDecPicBufMgr; + const StdVideoH265ScalingLists* pScalingLists; + const StdVideoH265ShortTermRefPicSet* pShortTermRefPicSet; + const StdVideoH265LongTermRefPicsSps* pLongTermRefPicsSps; + const StdVideoH265SequenceParameterSetVui* pSequenceParameterSetVui; + const StdVideoH265PredictorPaletteEntries* pPredictorPaletteEntries; +} StdVideoH265SequenceParameterSet; + +typedef struct StdVideoH265PpsFlags { + uint32_t dependent_slice_segments_enabled_flag : 1; + uint32_t output_flag_present_flag : 1; + uint32_t sign_data_hiding_enabled_flag : 1; + uint32_t cabac_init_present_flag : 1; + uint32_t constrained_intra_pred_flag : 1; + uint32_t transform_skip_enabled_flag : 1; + uint32_t cu_qp_delta_enabled_flag : 1; + uint32_t pps_slice_chroma_qp_offsets_present_flag : 1; + uint32_t weighted_pred_flag : 1; + uint32_t weighted_bipred_flag : 1; + uint32_t transquant_bypass_enabled_flag : 1; + uint32_t tiles_enabled_flag : 1; + uint32_t entropy_coding_sync_enabled_flag : 1; + uint32_t uniform_spacing_flag : 1; + uint32_t loop_filter_across_tiles_enabled_flag : 1; + uint32_t pps_loop_filter_across_slices_enabled_flag : 1; + uint32_t deblocking_filter_control_present_flag : 1; + uint32_t deblocking_filter_override_enabled_flag : 1; + uint32_t pps_deblocking_filter_disabled_flag : 1; + uint32_t pps_scaling_list_data_present_flag : 1; + uint32_t lists_modification_present_flag : 1; + uint32_t slice_segment_header_extension_present_flag : 1; + uint32_t pps_extension_present_flag : 1; + uint32_t cross_component_prediction_enabled_flag : 1; + uint32_t chroma_qp_offset_list_enabled_flag : 1; + uint32_t pps_curr_pic_ref_enabled_flag : 1; + uint32_t residual_adaptive_colour_transform_enabled_flag : 1; + uint32_t pps_slice_act_qp_offsets_present_flag : 1; + uint32_t pps_palette_predictor_initializers_present_flag : 1; + uint32_t monochrome_palette_flag : 1; + uint32_t pps_range_extension_flag : 1; +} StdVideoH265PpsFlags; + +typedef struct StdVideoH265PictureParameterSet { + StdVideoH265PpsFlags flags; + uint8_t pps_pic_parameter_set_id; + uint8_t pps_seq_parameter_set_id; + uint8_t sps_video_parameter_set_id; + uint8_t num_extra_slice_header_bits; + uint8_t num_ref_idx_l0_default_active_minus1; + uint8_t num_ref_idx_l1_default_active_minus1; + int8_t init_qp_minus26; + uint8_t diff_cu_qp_delta_depth; + int8_t pps_cb_qp_offset; + int8_t pps_cr_qp_offset; + int8_t pps_beta_offset_div2; + int8_t pps_tc_offset_div2; + uint8_t log2_parallel_merge_level_minus2; + uint8_t log2_max_transform_skip_block_size_minus2; + uint8_t diff_cu_chroma_qp_offset_depth; + uint8_t chroma_qp_offset_list_len_minus1; + int8_t cb_qp_offset_list[STD_VIDEO_H265_CHROMA_QP_OFFSET_LIST_SIZE]; + int8_t cr_qp_offset_list[STD_VIDEO_H265_CHROMA_QP_OFFSET_LIST_SIZE]; + uint8_t log2_sao_offset_scale_luma; + uint8_t log2_sao_offset_scale_chroma; + int8_t pps_act_y_qp_offset_plus5; + int8_t pps_act_cb_qp_offset_plus5; + int8_t pps_act_cr_qp_offset_plus3; + uint8_t pps_num_palette_predictor_initializers; + uint8_t luma_bit_depth_entry_minus8; + uint8_t chroma_bit_depth_entry_minus8; + uint8_t num_tile_columns_minus1; + uint8_t num_tile_rows_minus1; + uint8_t reserved1; + uint8_t reserved2; + uint16_t column_width_minus1[STD_VIDEO_H265_CHROMA_QP_OFFSET_TILE_COLS_LIST_SIZE]; + uint16_t row_height_minus1[STD_VIDEO_H265_CHROMA_QP_OFFSET_TILE_ROWS_LIST_SIZE]; + uint32_t reserved3; + const StdVideoH265ScalingLists* pScalingLists; + const StdVideoH265PredictorPaletteEntries* pPredictorPaletteEntries; +} StdVideoH265PictureParameterSet; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h265std_decode.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h265std_decode.h new file mode 100644 index 000000000..7cfe54f28 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h265std_decode.h @@ -0,0 +1,67 @@ +#ifndef VULKAN_VIDEO_CODEC_H265STD_DECODE_H_ +#define VULKAN_VIDEO_CODEC_H265STD_DECODE_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_h265std_decode is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_h265std_decode 1 +#include "vulkan_video_codec_h265std.h" + +#define VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) + +#define VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_API_VERSION_1_0_0 +#define VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h265_decode" +#define STD_VIDEO_DECODE_H265_REF_PIC_SET_LIST_SIZE 8U +typedef struct StdVideoDecodeH265PictureInfoFlags { + uint32_t IrapPicFlag : 1; + uint32_t IdrPicFlag : 1; + uint32_t IsReference : 1; + uint32_t short_term_ref_pic_set_sps_flag : 1; +} StdVideoDecodeH265PictureInfoFlags; + +typedef struct StdVideoDecodeH265PictureInfo { + StdVideoDecodeH265PictureInfoFlags flags; + uint8_t sps_video_parameter_set_id; + uint8_t pps_seq_parameter_set_id; + uint8_t pps_pic_parameter_set_id; + uint8_t NumDeltaPocsOfRefRpsIdx; + int32_t PicOrderCntVal; + uint16_t NumBitsForSTRefPicSetInSlice; + uint16_t reserved; + uint8_t RefPicSetStCurrBefore[STD_VIDEO_DECODE_H265_REF_PIC_SET_LIST_SIZE]; + uint8_t RefPicSetStCurrAfter[STD_VIDEO_DECODE_H265_REF_PIC_SET_LIST_SIZE]; + uint8_t RefPicSetLtCurr[STD_VIDEO_DECODE_H265_REF_PIC_SET_LIST_SIZE]; +} StdVideoDecodeH265PictureInfo; + +typedef struct StdVideoDecodeH265ReferenceInfoFlags { + uint32_t used_for_long_term_reference : 1; + uint32_t unused_for_reference : 1; +} StdVideoDecodeH265ReferenceInfoFlags; + +typedef struct StdVideoDecodeH265ReferenceInfo { + StdVideoDecodeH265ReferenceInfoFlags flags; + int32_t PicOrderCntVal; +} StdVideoDecodeH265ReferenceInfo; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h265std_encode.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h265std_encode.h new file mode 100644 index 000000000..fd8ee03b6 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_h265std_encode.h @@ -0,0 +1,157 @@ +#ifndef VULKAN_VIDEO_CODEC_H265STD_ENCODE_H_ +#define VULKAN_VIDEO_CODEC_H265STD_ENCODE_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_h265std_encode is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_h265std_encode 1 +#include "vulkan_video_codec_h265std.h" + +#define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) + +#define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_API_VERSION_1_0_0 +#define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h265_encode" +typedef struct StdVideoEncodeH265WeightTableFlags { + uint16_t luma_weight_l0_flag; + uint16_t chroma_weight_l0_flag; + uint16_t luma_weight_l1_flag; + uint16_t chroma_weight_l1_flag; +} StdVideoEncodeH265WeightTableFlags; + +typedef struct StdVideoEncodeH265WeightTable { + StdVideoEncodeH265WeightTableFlags flags; + uint8_t luma_log2_weight_denom; + int8_t delta_chroma_log2_weight_denom; + int8_t delta_luma_weight_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF]; + int8_t luma_offset_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF]; + int8_t delta_chroma_weight_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF][STD_VIDEO_H265_MAX_CHROMA_PLANES]; + int8_t delta_chroma_offset_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF][STD_VIDEO_H265_MAX_CHROMA_PLANES]; + int8_t delta_luma_weight_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF]; + int8_t luma_offset_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF]; + int8_t delta_chroma_weight_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF][STD_VIDEO_H265_MAX_CHROMA_PLANES]; + int8_t delta_chroma_offset_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF][STD_VIDEO_H265_MAX_CHROMA_PLANES]; +} StdVideoEncodeH265WeightTable; + +typedef struct StdVideoEncodeH265SliceSegmentHeaderFlags { + uint32_t first_slice_segment_in_pic_flag : 1; + uint32_t dependent_slice_segment_flag : 1; + uint32_t slice_sao_luma_flag : 1; + uint32_t slice_sao_chroma_flag : 1; + uint32_t num_ref_idx_active_override_flag : 1; + uint32_t mvd_l1_zero_flag : 1; + uint32_t cabac_init_flag : 1; + uint32_t cu_chroma_qp_offset_enabled_flag : 1; + uint32_t deblocking_filter_override_flag : 1; + uint32_t slice_deblocking_filter_disabled_flag : 1; + uint32_t collocated_from_l0_flag : 1; + uint32_t slice_loop_filter_across_slices_enabled_flag : 1; + uint32_t reserved : 20; +} StdVideoEncodeH265SliceSegmentHeaderFlags; + +typedef struct StdVideoEncodeH265SliceSegmentHeader { + StdVideoEncodeH265SliceSegmentHeaderFlags flags; + StdVideoH265SliceType slice_type; + uint32_t slice_segment_address; + uint8_t collocated_ref_idx; + uint8_t MaxNumMergeCand; + int8_t slice_cb_qp_offset; + int8_t slice_cr_qp_offset; + int8_t slice_beta_offset_div2; + int8_t slice_tc_offset_div2; + int8_t slice_act_y_qp_offset; + int8_t slice_act_cb_qp_offset; + int8_t slice_act_cr_qp_offset; + int8_t slice_qp_delta; + uint16_t reserved1; + const StdVideoEncodeH265WeightTable* pWeightTable; +} StdVideoEncodeH265SliceSegmentHeader; + +typedef struct StdVideoEncodeH265ReferenceListsInfoFlags { + uint32_t ref_pic_list_modification_flag_l0 : 1; + uint32_t ref_pic_list_modification_flag_l1 : 1; + uint32_t reserved : 30; +} StdVideoEncodeH265ReferenceListsInfoFlags; + +typedef struct StdVideoEncodeH265ReferenceListsInfo { + StdVideoEncodeH265ReferenceListsInfoFlags flags; + uint8_t num_ref_idx_l0_active_minus1; + uint8_t num_ref_idx_l1_active_minus1; + uint8_t RefPicList0[STD_VIDEO_H265_MAX_NUM_LIST_REF]; + uint8_t RefPicList1[STD_VIDEO_H265_MAX_NUM_LIST_REF]; + uint8_t list_entry_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF]; + uint8_t list_entry_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF]; +} StdVideoEncodeH265ReferenceListsInfo; + +typedef struct StdVideoEncodeH265PictureInfoFlags { + uint32_t is_reference : 1; + uint32_t IrapPicFlag : 1; + uint32_t used_for_long_term_reference : 1; + uint32_t discardable_flag : 1; + uint32_t cross_layer_bla_flag : 1; + uint32_t pic_output_flag : 1; + uint32_t no_output_of_prior_pics_flag : 1; + uint32_t short_term_ref_pic_set_sps_flag : 1; + uint32_t slice_temporal_mvp_enabled_flag : 1; + uint32_t reserved : 23; +} StdVideoEncodeH265PictureInfoFlags; + +typedef struct StdVideoEncodeH265LongTermRefPics { + uint8_t num_long_term_sps; + uint8_t num_long_term_pics; + uint8_t lt_idx_sps[STD_VIDEO_H265_MAX_LONG_TERM_REF_PICS_SPS]; + uint8_t poc_lsb_lt[STD_VIDEO_H265_MAX_LONG_TERM_PICS]; + uint16_t used_by_curr_pic_lt_flag; + uint8_t delta_poc_msb_present_flag[STD_VIDEO_H265_MAX_DELTA_POC]; + uint8_t delta_poc_msb_cycle_lt[STD_VIDEO_H265_MAX_DELTA_POC]; +} StdVideoEncodeH265LongTermRefPics; + +typedef struct StdVideoEncodeH265PictureInfo { + StdVideoEncodeH265PictureInfoFlags flags; + StdVideoH265PictureType pic_type; + uint8_t sps_video_parameter_set_id; + uint8_t pps_seq_parameter_set_id; + uint8_t pps_pic_parameter_set_id; + uint8_t short_term_ref_pic_set_idx; + int32_t PicOrderCntVal; + uint8_t TemporalId; + uint8_t reserved1[7]; + const StdVideoEncodeH265ReferenceListsInfo* pRefLists; + const StdVideoH265ShortTermRefPicSet* pShortTermRefPicSet; + const StdVideoEncodeH265LongTermRefPics* pLongTermRefPics; +} StdVideoEncodeH265PictureInfo; + +typedef struct StdVideoEncodeH265ReferenceInfoFlags { + uint32_t used_for_long_term_reference : 1; + uint32_t unused_for_reference : 1; + uint32_t reserved : 30; +} StdVideoEncodeH265ReferenceInfoFlags; + +typedef struct StdVideoEncodeH265ReferenceInfo { + StdVideoEncodeH265ReferenceInfoFlags flags; + StdVideoH265PictureType pic_type; + int32_t PicOrderCntVal; + uint8_t TemporalId; +} StdVideoEncodeH265ReferenceInfo; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_vp9std.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_vp9std.h new file mode 100644 index 000000000..312a78574 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_vp9std.h @@ -0,0 +1,151 @@ +#ifndef VULKAN_VIDEO_CODEC_VP9STD_H_ +#define VULKAN_VIDEO_CODEC_VP9STD_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_vp9std is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_vp9std 1 +#include "vulkan_video_codecs_common.h" +#define STD_VIDEO_VP9_NUM_REF_FRAMES 8U +#define STD_VIDEO_VP9_REFS_PER_FRAME 3U +#define STD_VIDEO_VP9_MAX_REF_FRAMES 4U +#define STD_VIDEO_VP9_LOOP_FILTER_ADJUSTMENTS 2U +#define STD_VIDEO_VP9_MAX_SEGMENTS 8U +#define STD_VIDEO_VP9_SEG_LVL_MAX 4U +#define STD_VIDEO_VP9_MAX_SEGMENTATION_TREE_PROBS 7U +#define STD_VIDEO_VP9_MAX_SEGMENTATION_PRED_PROB 3U + +typedef enum StdVideoVP9Profile { + STD_VIDEO_VP9_PROFILE_0 = 0, + STD_VIDEO_VP9_PROFILE_1 = 1, + STD_VIDEO_VP9_PROFILE_2 = 2, + STD_VIDEO_VP9_PROFILE_3 = 3, + STD_VIDEO_VP9_PROFILE_INVALID = 0x7FFFFFFF, + STD_VIDEO_VP9_PROFILE_MAX_ENUM = 0x7FFFFFFF +} StdVideoVP9Profile; + +typedef enum StdVideoVP9Level { + STD_VIDEO_VP9_LEVEL_1_0 = 0, + STD_VIDEO_VP9_LEVEL_1_1 = 1, + STD_VIDEO_VP9_LEVEL_2_0 = 2, + STD_VIDEO_VP9_LEVEL_2_1 = 3, + STD_VIDEO_VP9_LEVEL_3_0 = 4, + STD_VIDEO_VP9_LEVEL_3_1 = 5, + STD_VIDEO_VP9_LEVEL_4_0 = 6, + STD_VIDEO_VP9_LEVEL_4_1 = 7, + STD_VIDEO_VP9_LEVEL_5_0 = 8, + STD_VIDEO_VP9_LEVEL_5_1 = 9, + STD_VIDEO_VP9_LEVEL_5_2 = 10, + STD_VIDEO_VP9_LEVEL_6_0 = 11, + STD_VIDEO_VP9_LEVEL_6_1 = 12, + STD_VIDEO_VP9_LEVEL_6_2 = 13, + STD_VIDEO_VP9_LEVEL_INVALID = 0x7FFFFFFF, + STD_VIDEO_VP9_LEVEL_MAX_ENUM = 0x7FFFFFFF +} StdVideoVP9Level; + +typedef enum StdVideoVP9FrameType { + STD_VIDEO_VP9_FRAME_TYPE_KEY = 0, + STD_VIDEO_VP9_FRAME_TYPE_NON_KEY = 1, + STD_VIDEO_VP9_FRAME_TYPE_INVALID = 0x7FFFFFFF, + STD_VIDEO_VP9_FRAME_TYPE_MAX_ENUM = 0x7FFFFFFF +} StdVideoVP9FrameType; + +typedef enum StdVideoVP9ReferenceName { + STD_VIDEO_VP9_REFERENCE_NAME_INTRA_FRAME = 0, + STD_VIDEO_VP9_REFERENCE_NAME_LAST_FRAME = 1, + STD_VIDEO_VP9_REFERENCE_NAME_GOLDEN_FRAME = 2, + STD_VIDEO_VP9_REFERENCE_NAME_ALTREF_FRAME = 3, + STD_VIDEO_VP9_REFERENCE_NAME_INVALID = 0x7FFFFFFF, + STD_VIDEO_VP9_REFERENCE_NAME_MAX_ENUM = 0x7FFFFFFF +} StdVideoVP9ReferenceName; + +typedef enum StdVideoVP9InterpolationFilter { + STD_VIDEO_VP9_INTERPOLATION_FILTER_EIGHTTAP = 0, + STD_VIDEO_VP9_INTERPOLATION_FILTER_EIGHTTAP_SMOOTH = 1, + STD_VIDEO_VP9_INTERPOLATION_FILTER_EIGHTTAP_SHARP = 2, + STD_VIDEO_VP9_INTERPOLATION_FILTER_BILINEAR = 3, + STD_VIDEO_VP9_INTERPOLATION_FILTER_SWITCHABLE = 4, + STD_VIDEO_VP9_INTERPOLATION_FILTER_INVALID = 0x7FFFFFFF, + STD_VIDEO_VP9_INTERPOLATION_FILTER_MAX_ENUM = 0x7FFFFFFF +} StdVideoVP9InterpolationFilter; + +typedef enum StdVideoVP9ColorSpace { + STD_VIDEO_VP9_COLOR_SPACE_UNKNOWN = 0, + STD_VIDEO_VP9_COLOR_SPACE_BT_601 = 1, + STD_VIDEO_VP9_COLOR_SPACE_BT_709 = 2, + STD_VIDEO_VP9_COLOR_SPACE_SMPTE_170 = 3, + STD_VIDEO_VP9_COLOR_SPACE_SMPTE_240 = 4, + STD_VIDEO_VP9_COLOR_SPACE_BT_2020 = 5, + STD_VIDEO_VP9_COLOR_SPACE_RESERVED = 6, + STD_VIDEO_VP9_COLOR_SPACE_RGB = 7, + STD_VIDEO_VP9_COLOR_SPACE_INVALID = 0x7FFFFFFF, + STD_VIDEO_VP9_COLOR_SPACE_MAX_ENUM = 0x7FFFFFFF +} StdVideoVP9ColorSpace; +typedef struct StdVideoVP9ColorConfigFlags { + uint32_t color_range : 1; + uint32_t reserved : 31; +} StdVideoVP9ColorConfigFlags; + +typedef struct StdVideoVP9ColorConfig { + StdVideoVP9ColorConfigFlags flags; + uint8_t BitDepth; + uint8_t subsampling_x; + uint8_t subsampling_y; + uint8_t reserved1; + StdVideoVP9ColorSpace color_space; +} StdVideoVP9ColorConfig; + +typedef struct StdVideoVP9LoopFilterFlags { + uint32_t loop_filter_delta_enabled : 1; + uint32_t loop_filter_delta_update : 1; + uint32_t reserved : 30; +} StdVideoVP9LoopFilterFlags; + +typedef struct StdVideoVP9LoopFilter { + StdVideoVP9LoopFilterFlags flags; + uint8_t loop_filter_level; + uint8_t loop_filter_sharpness; + uint8_t update_ref_delta; + int8_t loop_filter_ref_deltas[STD_VIDEO_VP9_MAX_REF_FRAMES]; + uint8_t update_mode_delta; + int8_t loop_filter_mode_deltas[STD_VIDEO_VP9_LOOP_FILTER_ADJUSTMENTS]; +} StdVideoVP9LoopFilter; + +typedef struct StdVideoVP9SegmentationFlags { + uint32_t segmentation_update_map : 1; + uint32_t segmentation_temporal_update : 1; + uint32_t segmentation_update_data : 1; + uint32_t segmentation_abs_or_delta_update : 1; + uint32_t reserved : 28; +} StdVideoVP9SegmentationFlags; + +typedef struct StdVideoVP9Segmentation { + StdVideoVP9SegmentationFlags flags; + uint8_t segmentation_tree_probs[STD_VIDEO_VP9_MAX_SEGMENTATION_TREE_PROBS]; + uint8_t segmentation_pred_prob[STD_VIDEO_VP9_MAX_SEGMENTATION_PRED_PROB]; + uint8_t FeatureEnabled[STD_VIDEO_VP9_MAX_SEGMENTS]; + int16_t FeatureData[STD_VIDEO_VP9_MAX_SEGMENTS][STD_VIDEO_VP9_SEG_LVL_MAX]; +} StdVideoVP9Segmentation; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_vp9std_decode.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_vp9std_decode.h new file mode 100644 index 000000000..2a7ecdc97 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codec_vp9std_decode.h @@ -0,0 +1,68 @@ +#ifndef VULKAN_VIDEO_CODEC_VP9STD_DECODE_H_ +#define VULKAN_VIDEO_CODEC_VP9STD_DECODE_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codec_vp9std_decode is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codec_vp9std_decode 1 +#include "vulkan_video_codec_vp9std.h" + +#define VK_STD_VULKAN_VIDEO_CODEC_VP9_DECODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) + +#define VK_STD_VULKAN_VIDEO_CODEC_VP9_DECODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_VP9_DECODE_API_VERSION_1_0_0 +#define VK_STD_VULKAN_VIDEO_CODEC_VP9_DECODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_vp9_decode" +typedef struct StdVideoDecodeVP9PictureInfoFlags { + uint32_t error_resilient_mode : 1; + uint32_t intra_only : 1; + uint32_t allow_high_precision_mv : 1; + uint32_t refresh_frame_context : 1; + uint32_t frame_parallel_decoding_mode : 1; + uint32_t segmentation_enabled : 1; + uint32_t show_frame : 1; + uint32_t UsePrevFrameMvs : 1; + uint32_t reserved : 24; +} StdVideoDecodeVP9PictureInfoFlags; + +typedef struct StdVideoDecodeVP9PictureInfo { + StdVideoDecodeVP9PictureInfoFlags flags; + StdVideoVP9Profile profile; + StdVideoVP9FrameType frame_type; + uint8_t frame_context_idx; + uint8_t reset_frame_context; + uint8_t refresh_frame_flags; + uint8_t ref_frame_sign_bias_mask; + StdVideoVP9InterpolationFilter interpolation_filter; + uint8_t base_q_idx; + int8_t delta_q_y_dc; + int8_t delta_q_uv_dc; + int8_t delta_q_uv_ac; + uint8_t tile_cols_log2; + uint8_t tile_rows_log2; + uint16_t reserved1[3]; + const StdVideoVP9ColorConfig* pColorConfig; + const StdVideoVP9LoopFilter* pLoopFilter; + const StdVideoVP9Segmentation* pSegmentation; +} StdVideoDecodeVP9PictureInfo; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codecs_common.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codecs_common.h new file mode 100644 index 000000000..faedbef46 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vk_video/vulkan_video_codecs_common.h @@ -0,0 +1,36 @@ +#ifndef VULKAN_VIDEO_CODECS_COMMON_H_ +#define VULKAN_VIDEO_CODECS_COMMON_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// vulkan_video_codecs_common is a preprocessor guard. Do not pass it to API calls. +#define vulkan_video_codecs_common 1 +#if !defined(VK_NO_STDINT_H) + #include +#endif + +#define VK_MAKE_VIDEO_STD_VERSION(major, minor, patch) \ + ((((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch))) + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vk_icd.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vk_icd.h new file mode 100644 index 000000000..38b137ce2 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vk_icd.h @@ -0,0 +1,244 @@ +/* + * Copyright 2015-2023 The Khronos Group Inc. + * Copyright 2015-2023 Valve Corporation + * Copyright 2015-2023 LunarG, Inc. + * SPDX-License-Identifier: Apache-2.0 OR MIT + */ +#pragma once + +#include "vulkan.h" +#include + +// Loader-ICD version negotiation API. Versions add the following features: +// Version 0 - Initial. Doesn't support vk_icdGetInstanceProcAddr +// or vk_icdNegotiateLoaderICDInterfaceVersion. +// Version 1 - Add support for vk_icdGetInstanceProcAddr. +// Version 2 - Add Loader/ICD Interface version negotiation +// via vk_icdNegotiateLoaderICDInterfaceVersion. +// Version 3 - Add ICD creation/destruction of KHR_surface objects. +// Version 4 - Add unknown physical device extension querying via +// vk_icdGetPhysicalDeviceProcAddr. +// Version 5 - Tells ICDs that the loader is now paying attention to the +// application version of Vulkan passed into the ApplicationInfo +// structure during vkCreateInstance. This will tell the ICD +// that if the loader is older, it should automatically fail a +// call for any API version > 1.0. Otherwise, the loader will +// manually determine if it can support the expected version. +// Version 6 - Add support for vk_icdEnumerateAdapterPhysicalDevices. +// Version 7 - If an ICD supports any of the following functions, they must be +// queryable with vk_icdGetInstanceProcAddr: +// vk_icdNegotiateLoaderICDInterfaceVersion +// vk_icdGetPhysicalDeviceProcAddr +// vk_icdEnumerateAdapterPhysicalDevices (Windows only) +// In addition, these functions no longer need to be exported directly. +// This version allows drivers provided through the extension +// VK_LUNARG_direct_driver_loading be able to support the entire +// Driver-Loader interface. + +#define CURRENT_LOADER_ICD_INTERFACE_VERSION 7 +#define MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION 0 +#define MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION 4 + +// Old typedefs that don't follow a proper naming convention but are preserved for compatibility +typedef VkResult(VKAPI_PTR *PFN_vkNegotiateLoaderICDInterfaceVersion)(uint32_t *pVersion); +// This is defined in vk_layer.h which will be found by the loader, but if an ICD is building against this +// file directly, it won't be found. +#ifndef IS_DEFINED_PFN_GetPhysicalDeviceProcAddr +typedef PFN_vkVoidFunction(VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char *pName); +#define IS_DEFINED_PFN_GetPhysicalDeviceProcAddr +#endif + +// Typedefs for loader/ICD interface +typedef VkResult (VKAPI_PTR *PFN_vk_icdNegotiateLoaderICDInterfaceVersion)(uint32_t* pVersion); +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vk_icdGetInstanceProcAddr)(VkInstance instance, const char* pName); +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vk_icdGetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName); +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef VkResult (VKAPI_PTR *PFN_vk_icdEnumerateAdapterPhysicalDevices)(VkInstance instance, LUID adapterLUID, + uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); +#endif + +// Prototypes for loader/ICD interface +#if !defined(VK_NO_PROTOTYPES) +#ifdef __cplusplus +extern "C" { +#endif + VKAPI_ATTR VkResult VKAPI_CALL vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pVersion); + VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetInstanceProcAddr(VkInstance instance, const char* pName); + VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetPhysicalDeviceProcAddr(VkInstance instance, const char* pName); +#if defined(VK_USE_PLATFORM_WIN32_KHR) + VKAPI_ATTR VkResult VKAPI_CALL vk_icdEnumerateAdapterPhysicalDevices(VkInstance instance, LUID adapterLUID, + uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); +#endif +#ifdef __cplusplus +} +#endif +#endif + +/* + * The ICD must reserve space for a pointer for the loader's dispatch + * table, at the start of . + * The ICD must initialize this variable using the SET_LOADER_MAGIC_VALUE macro. + */ + +#define ICD_LOADER_MAGIC 0x01CDC0DE + +typedef union { + uintptr_t loaderMagic; + void *loaderData; +} VK_LOADER_DATA; + +static inline void set_loader_magic_value(void *pNewObject) { + VK_LOADER_DATA *loader_info = (VK_LOADER_DATA *)pNewObject; + loader_info->loaderMagic = ICD_LOADER_MAGIC; +} + +static inline bool valid_loader_magic_value(void *pNewObject) { + const VK_LOADER_DATA *loader_info = (VK_LOADER_DATA *)pNewObject; + return (loader_info->loaderMagic & 0xffffffff) == ICD_LOADER_MAGIC; +} + +/* + * Windows and Linux ICDs will treat VkSurfaceKHR as a pointer to a struct that + * contains the platform-specific connection and surface information. + */ +typedef enum { + VK_ICD_WSI_PLATFORM_MIR, + VK_ICD_WSI_PLATFORM_WAYLAND, + VK_ICD_WSI_PLATFORM_WIN32, + VK_ICD_WSI_PLATFORM_XCB, + VK_ICD_WSI_PLATFORM_XLIB, + VK_ICD_WSI_PLATFORM_ANDROID, + VK_ICD_WSI_PLATFORM_MACOS, + VK_ICD_WSI_PLATFORM_IOS, + VK_ICD_WSI_PLATFORM_DISPLAY, + VK_ICD_WSI_PLATFORM_HEADLESS, + VK_ICD_WSI_PLATFORM_METAL, + VK_ICD_WSI_PLATFORM_DIRECTFB, + VK_ICD_WSI_PLATFORM_VI, + VK_ICD_WSI_PLATFORM_GGP, + VK_ICD_WSI_PLATFORM_SCREEN, + VK_ICD_WSI_PLATFORM_FUCHSIA, +} VkIcdWsiPlatform; + +typedef struct { + VkIcdWsiPlatform platform; +} VkIcdSurfaceBase; + +#ifdef VK_USE_PLATFORM_MIR_KHR +typedef struct { + VkIcdSurfaceBase base; + MirConnection *connection; + MirSurface *mirSurface; +} VkIcdSurfaceMir; +#endif // VK_USE_PLATFORM_MIR_KHR + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR +typedef struct { + VkIcdSurfaceBase base; + struct wl_display *display; + struct wl_surface *surface; +} VkIcdSurfaceWayland; +#endif // VK_USE_PLATFORM_WAYLAND_KHR + +#ifdef VK_USE_PLATFORM_WIN32_KHR +typedef struct { + VkIcdSurfaceBase base; + HINSTANCE hinstance; + HWND hwnd; +} VkIcdSurfaceWin32; +#endif // VK_USE_PLATFORM_WIN32_KHR + +#ifdef VK_USE_PLATFORM_XCB_KHR +typedef struct { + VkIcdSurfaceBase base; + xcb_connection_t *connection; + xcb_window_t window; +} VkIcdSurfaceXcb; +#endif // VK_USE_PLATFORM_XCB_KHR + +#ifdef VK_USE_PLATFORM_XLIB_KHR +typedef struct { + VkIcdSurfaceBase base; + Display *dpy; + Window window; +} VkIcdSurfaceXlib; +#endif // VK_USE_PLATFORM_XLIB_KHR + +#ifdef VK_USE_PLATFORM_DIRECTFB_EXT +typedef struct { + VkIcdSurfaceBase base; + IDirectFB *dfb; + IDirectFBSurface *surface; +} VkIcdSurfaceDirectFB; +#endif // VK_USE_PLATFORM_DIRECTFB_EXT + +#ifdef VK_USE_PLATFORM_ANDROID_KHR +typedef struct { + VkIcdSurfaceBase base; + struct ANativeWindow *window; +} VkIcdSurfaceAndroid; +#endif // VK_USE_PLATFORM_ANDROID_KHR + +#ifdef VK_USE_PLATFORM_MACOS_MVK +typedef struct { + VkIcdSurfaceBase base; + const void *pView; +} VkIcdSurfaceMacOS; +#endif // VK_USE_PLATFORM_MACOS_MVK + +#ifdef VK_USE_PLATFORM_IOS_MVK +typedef struct { + VkIcdSurfaceBase base; + const void *pView; +} VkIcdSurfaceIOS; +#endif // VK_USE_PLATFORM_IOS_MVK + +#ifdef VK_USE_PLATFORM_GGP +typedef struct { + VkIcdSurfaceBase base; + GgpStreamDescriptor streamDescriptor; +} VkIcdSurfaceGgp; +#endif // VK_USE_PLATFORM_GGP + +typedef struct { + VkIcdSurfaceBase base; + VkDisplayModeKHR displayMode; + uint32_t planeIndex; + uint32_t planeStackIndex; + VkSurfaceTransformFlagBitsKHR transform; + float globalAlpha; + VkDisplayPlaneAlphaFlagBitsKHR alphaMode; + VkExtent2D imageExtent; +} VkIcdSurfaceDisplay; + +typedef struct { + VkIcdSurfaceBase base; +} VkIcdSurfaceHeadless; + +#ifdef VK_USE_PLATFORM_METAL_EXT +typedef struct { + VkIcdSurfaceBase base; + const CAMetalLayer *pLayer; +} VkIcdSurfaceMetal; +#endif // VK_USE_PLATFORM_METAL_EXT + +#ifdef VK_USE_PLATFORM_VI_NN +typedef struct { + VkIcdSurfaceBase base; + void *window; +} VkIcdSurfaceVi; +#endif // VK_USE_PLATFORM_VI_NN + +#ifdef VK_USE_PLATFORM_SCREEN_QNX +typedef struct { + VkIcdSurfaceBase base; + struct _screen_context *context; + struct _screen_window *window; +} VkIcdSurfaceScreen; +#endif // VK_USE_PLATFORM_SCREEN_QNX + +#ifdef VK_USE_PLATFORM_FUCHSIA +typedef struct { + VkIcdSurfaceBase base; +} VkIcdSurfaceImagePipe; +#endif // VK_USE_PLATFORM_FUCHSIA diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vk_layer.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vk_layer.h new file mode 100644 index 000000000..0e9a27b12 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vk_layer.h @@ -0,0 +1,191 @@ +/* + * Copyright 2015-2023 The Khronos Group Inc. + * Copyright 2015-2023 Valve Corporation + * Copyright 2015-2023 LunarG, Inc. + * SPDX-License-Identifier: Apache-2.0 OR MIT + */ +#pragma once + +/* Need to define dispatch table + * Core struct can then have ptr to dispatch table at the top + * Along with object ptrs for current and next OBJ + */ + +#include "vulkan_core.h" + +#define MAX_NUM_UNKNOWN_EXTS 250 + + // Loader-Layer version negotiation API. Versions add the following features: + // Versions 0/1 - Initial. Doesn't support vk_layerGetPhysicalDeviceProcAddr + // or vk_icdNegotiateLoaderLayerInterfaceVersion. + // Version 2 - Add support for vk_layerGetPhysicalDeviceProcAddr and + // vk_icdNegotiateLoaderLayerInterfaceVersion. +#define CURRENT_LOADER_LAYER_INTERFACE_VERSION 2 +#define MIN_SUPPORTED_LOADER_LAYER_INTERFACE_VERSION 1 + +#define VK_CURRENT_CHAIN_VERSION 1 + +// Typedef for use in the interfaces below +#ifndef IS_DEFINED_PFN_GetPhysicalDeviceProcAddr +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName); +#define IS_DEFINED_PFN_GetPhysicalDeviceProcAddr +#endif + +// Version negotiation values +typedef enum VkNegotiateLayerStructType { + LAYER_NEGOTIATE_UNINTIALIZED = 0, + LAYER_NEGOTIATE_INTERFACE_STRUCT = 1, +} VkNegotiateLayerStructType; + +// Version negotiation structures +typedef struct VkNegotiateLayerInterface { + VkNegotiateLayerStructType sType; + void *pNext; + uint32_t loaderLayerInterfaceVersion; + PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr; + PFN_vkGetDeviceProcAddr pfnGetDeviceProcAddr; + PFN_GetPhysicalDeviceProcAddr pfnGetPhysicalDeviceProcAddr; +} VkNegotiateLayerInterface; + +// Version negotiation functions +typedef VkResult (VKAPI_PTR *PFN_vkNegotiateLoaderLayerInterfaceVersion)(VkNegotiateLayerInterface *pVersionStruct); + +// Function prototype for unknown physical device extension command +typedef VkResult(VKAPI_PTR *PFN_PhysDevExt)(VkPhysicalDevice phys_device); + +// ------------------------------------------------------------------------------------------------ +// CreateInstance and CreateDevice support structures + +/* Sub type of structure for instance and device loader ext of CreateInfo. + * When sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO + * or sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO + * then VkLayerFunction indicates struct type pointed to by pNext + */ +typedef enum VkLayerFunction_ { + VK_LAYER_LINK_INFO = 0, + VK_LOADER_DATA_CALLBACK = 1, + VK_LOADER_LAYER_CREATE_DEVICE_CALLBACK = 2, + VK_LOADER_FEATURES = 3, +} VkLayerFunction; + +typedef struct VkLayerInstanceLink_ { + struct VkLayerInstanceLink_ *pNext; + PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr; + PFN_GetPhysicalDeviceProcAddr pfnNextGetPhysicalDeviceProcAddr; +} VkLayerInstanceLink; + +/* + * When creating the device chain the loader needs to pass + * down information about it's device structure needed at + * the end of the chain. Passing the data via the + * VkLayerDeviceInfo avoids issues with finding the + * exact instance being used. + */ +typedef struct VkLayerDeviceInfo_ { + void *device_info; + PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr; +} VkLayerDeviceInfo; + +typedef VkResult (VKAPI_PTR *PFN_vkSetInstanceLoaderData)(VkInstance instance, + void *object); +typedef VkResult (VKAPI_PTR *PFN_vkSetDeviceLoaderData)(VkDevice device, + void *object); +typedef VkResult (VKAPI_PTR *PFN_vkLayerCreateDevice)(VkInstance instance, VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, PFN_vkGetInstanceProcAddr layerGIPA, PFN_vkGetDeviceProcAddr *nextGDPA); +typedef void (VKAPI_PTR *PFN_vkLayerDestroyDevice)(VkDevice physicalDevice, const VkAllocationCallbacks *pAllocator, PFN_vkDestroyDevice destroyFunction); + +typedef enum VkLoaderFeastureFlagBits { + VK_LOADER_FEATURE_PHYSICAL_DEVICE_SORTING = 0x00000001, +} VkLoaderFlagBits; +typedef VkFlags VkLoaderFeatureFlags; + +typedef struct { + VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO + const void *pNext; + VkLayerFunction function; + union { + VkLayerInstanceLink *pLayerInfo; + PFN_vkSetInstanceLoaderData pfnSetInstanceLoaderData; + struct { + PFN_vkLayerCreateDevice pfnLayerCreateDevice; + PFN_vkLayerDestroyDevice pfnLayerDestroyDevice; + } layerDevice; + VkLoaderFeatureFlags loaderFeatures; + } u; +} VkLayerInstanceCreateInfo; + +typedef struct VkLayerDeviceLink_ { + struct VkLayerDeviceLink_ *pNext; + PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr; + PFN_vkGetDeviceProcAddr pfnNextGetDeviceProcAddr; +} VkLayerDeviceLink; + +typedef struct { + VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO + const void *pNext; + VkLayerFunction function; + union { + VkLayerDeviceLink *pLayerInfo; + PFN_vkSetDeviceLoaderData pfnSetDeviceLoaderData; + } u; +} VkLayerDeviceCreateInfo; + +#ifdef __cplusplus +extern "C" { +#endif + +VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct); + +typedef enum VkChainType { + VK_CHAIN_TYPE_UNKNOWN = 0, + VK_CHAIN_TYPE_ENUMERATE_INSTANCE_EXTENSION_PROPERTIES = 1, + VK_CHAIN_TYPE_ENUMERATE_INSTANCE_LAYER_PROPERTIES = 2, + VK_CHAIN_TYPE_ENUMERATE_INSTANCE_VERSION = 3, +} VkChainType; + +typedef struct VkChainHeader { + VkChainType type; + uint32_t version; + uint32_t size; +} VkChainHeader; + +typedef struct VkEnumerateInstanceExtensionPropertiesChain { + VkChainHeader header; + VkResult(VKAPI_PTR *pfnNextLayer)(const struct VkEnumerateInstanceExtensionPropertiesChain *, const char *, uint32_t *, + VkExtensionProperties *); + const struct VkEnumerateInstanceExtensionPropertiesChain *pNextLink; + +#if defined(__cplusplus) + inline VkResult CallDown(const char *pLayerName, uint32_t *pPropertyCount, VkExtensionProperties *pProperties) const { + return pfnNextLayer(pNextLink, pLayerName, pPropertyCount, pProperties); + } +#endif +} VkEnumerateInstanceExtensionPropertiesChain; + +typedef struct VkEnumerateInstanceLayerPropertiesChain { + VkChainHeader header; + VkResult(VKAPI_PTR *pfnNextLayer)(const struct VkEnumerateInstanceLayerPropertiesChain *, uint32_t *, VkLayerProperties *); + const struct VkEnumerateInstanceLayerPropertiesChain *pNextLink; + +#if defined(__cplusplus) + inline VkResult CallDown(uint32_t *pPropertyCount, VkLayerProperties *pProperties) const { + return pfnNextLayer(pNextLink, pPropertyCount, pProperties); + } +#endif +} VkEnumerateInstanceLayerPropertiesChain; + +typedef struct VkEnumerateInstanceVersionChain { + VkChainHeader header; + VkResult(VKAPI_PTR *pfnNextLayer)(const struct VkEnumerateInstanceVersionChain *, uint32_t *); + const struct VkEnumerateInstanceVersionChain *pNextLink; + +#if defined(__cplusplus) + inline VkResult CallDown(uint32_t *pApiVersion) const { + return pfnNextLayer(pNextLink, pApiVersion); + } +#endif +} VkEnumerateInstanceVersionChain; + +#ifdef __cplusplus +} +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vk_platform.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vk_platform.h new file mode 100644 index 000000000..bbe60245d --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vk_platform.h @@ -0,0 +1,83 @@ +// +// File: vk_platform.h +// +/* +** Copyright 2014-2026 The Khronos Group Inc. +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + + +#ifndef VK_PLATFORM_H_ +#define VK_PLATFORM_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/* +*************************************************************************************************** +* Platform-specific directives and type declarations +*************************************************************************************************** +*/ + +/* Platform-specific calling convention macros. + * + * Platforms should define these so that Vulkan clients call Vulkan commands + * with the same calling conventions that the Vulkan implementation expects. + * + * VKAPI_ATTR - Placed before the return type in function declarations. + * Useful for C++11 and GCC/Clang-style function attribute syntax. + * VKAPI_CALL - Placed after the return type in function declarations. + * Useful for MSVC-style calling convention syntax. + * VKAPI_PTR - Placed between the '(' and '*' in function pointer types. + * + * Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void); + * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); + */ +#if defined(_WIN32) + // On Windows, Vulkan commands use the stdcall convention + #define VKAPI_ATTR + #define VKAPI_CALL __stdcall + #define VKAPI_PTR VKAPI_CALL +#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 + #error "Vulkan is not supported for the 'armeabi' NDK ABI" +#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) + // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" + // calling convention, i.e. float parameters are passed in registers. This + // is true even if the rest of the application passes floats on the stack, + // as it does by default when compiling for the armeabi-v7a NDK ABI. + #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) + #define VKAPI_CALL + #define VKAPI_PTR VKAPI_ATTR +#else + // On other platforms, use the default calling convention + #define VKAPI_ATTR + #define VKAPI_CALL + #define VKAPI_PTR +#endif + +#if !defined(VK_NO_STDDEF_H) + #include +#endif // !defined(VK_NO_STDDEF_H) + +#if !defined(VK_NO_STDINT_H) + #if defined(_MSC_VER) && (_MSC_VER < 1600) + typedef signed __int8 int8_t; + typedef unsigned __int8 uint8_t; + typedef signed __int16 int16_t; + typedef unsigned __int16 uint16_t; + typedef signed __int32 int32_t; + typedef unsigned __int32 uint32_t; + typedef signed __int64 int64_t; + typedef unsigned __int64 uint64_t; + #else + #include + #endif +#endif // !defined(VK_NO_STDINT_H) + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan.h new file mode 100644 index 000000000..934d9b1ec --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan.h @@ -0,0 +1,102 @@ +#ifndef VULKAN_H_ +#define VULKAN_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +#include "vk_platform.h" +#include "vulkan_core.h" + +#ifdef VK_USE_PLATFORM_ANDROID_KHR +#include "vulkan_android.h" +#endif + +#ifdef VK_USE_PLATFORM_FUCHSIA +#include +#include "vulkan_fuchsia.h" +#endif + +#ifdef VK_USE_PLATFORM_IOS_MVK +#include "vulkan_ios.h" +#endif + + +#ifdef VK_USE_PLATFORM_MACOS_MVK +#include "vulkan_macos.h" +#endif + +#ifdef VK_USE_PLATFORM_METAL_EXT +#include "vulkan_metal.h" +#endif + +#ifdef VK_USE_PLATFORM_VI_NN +#include "vulkan_vi.h" +#endif + + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR +#include "vulkan_wayland.h" +#endif + + +#ifdef VK_USE_PLATFORM_WIN32_KHR +#include +#include "vulkan_win32.h" +#endif + + +#ifdef VK_USE_PLATFORM_XCB_KHR +#include +#include "vulkan_xcb.h" +#endif + + +#ifdef VK_USE_PLATFORM_XLIB_KHR +#include +#include "vulkan_xlib.h" +#endif + + +#ifdef VK_USE_PLATFORM_DIRECTFB_EXT +#include +#include "vulkan_directfb.h" +#endif + + +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT +#include +#include +#include "vulkan_xlib_xrandr.h" +#endif + + +#ifdef VK_USE_PLATFORM_GGP +#include +#include "vulkan_ggp.h" +#endif + + +#ifdef VK_USE_PLATFORM_SCREEN_QNX +#include +#include "vulkan_screen.h" +#endif + + +#ifdef VK_USE_PLATFORM_SCI +#include +#include +#include "vulkan_sci.h" +#endif + + +#ifdef VK_ENABLE_BETA_EXTENSIONS +#include "vulkan_beta.h" +#endif + +#ifdef VK_USE_PLATFORM_OHOS +#include "vulkan_ohos.h" +#endif + +#endif // VULKAN_H_ diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_android.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_android.h new file mode 100644 index 000000000..1e318dc71 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_android.h @@ -0,0 +1,159 @@ +#ifndef VULKAN_ANDROID_H_ +#define VULKAN_ANDROID_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_KHR_android_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_android_surface 1 +struct ANativeWindow; +#define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6 +#define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "VK_KHR_android_surface" +typedef VkFlags VkAndroidSurfaceCreateFlagsKHR; +typedef struct VkAndroidSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkAndroidSurfaceCreateFlagsKHR flags; + struct ANativeWindow* window; +} VkAndroidSurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateAndroidSurfaceKHR)(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR( + VkInstance instance, + const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif +#endif + + +// VK_ANDROID_external_memory_android_hardware_buffer is a preprocessor guard. Do not pass it to API calls. +#define VK_ANDROID_external_memory_android_hardware_buffer 1 +struct AHardwareBuffer; +#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION 5 +#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME "VK_ANDROID_external_memory_android_hardware_buffer" +typedef struct VkAndroidHardwareBufferUsageANDROID { + VkStructureType sType; + void* pNext; + uint64_t androidHardwareBufferUsage; +} VkAndroidHardwareBufferUsageANDROID; + +typedef struct VkAndroidHardwareBufferPropertiesANDROID { + VkStructureType sType; + void* pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeBits; +} VkAndroidHardwareBufferPropertiesANDROID; + +typedef struct VkAndroidHardwareBufferFormatPropertiesANDROID { + VkStructureType sType; + void* pNext; + VkFormat format; + uint64_t externalFormat; + VkFormatFeatureFlags formatFeatures; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkAndroidHardwareBufferFormatPropertiesANDROID; + +typedef struct VkImportAndroidHardwareBufferInfoANDROID { + VkStructureType sType; + const void* pNext; + struct AHardwareBuffer* buffer; +} VkImportAndroidHardwareBufferInfoANDROID; + +typedef struct VkMemoryGetAndroidHardwareBufferInfoANDROID { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; +} VkMemoryGetAndroidHardwareBufferInfoANDROID; + +typedef struct VkExternalFormatANDROID { + VkStructureType sType; + void* pNext; + uint64_t externalFormat; +} VkExternalFormatANDROID; + +typedef struct VkAndroidHardwareBufferFormatProperties2ANDROID { + VkStructureType sType; + void* pNext; + VkFormat format; + uint64_t externalFormat; + VkFormatFeatureFlags2 formatFeatures; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkAndroidHardwareBufferFormatProperties2ANDROID; + +typedef VkResult (VKAPI_PTR *PFN_vkGetAndroidHardwareBufferPropertiesANDROID)(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryAndroidHardwareBufferANDROID)(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetAndroidHardwareBufferPropertiesANDROID( + VkDevice device, + const struct AHardwareBuffer* buffer, + VkAndroidHardwareBufferPropertiesANDROID* pProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryAndroidHardwareBufferANDROID( + VkDevice device, + const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, + struct AHardwareBuffer** pBuffer); +#endif +#endif + + +// VK_ANDROID_external_format_resolve is a preprocessor guard. Do not pass it to API calls. +#define VK_ANDROID_external_format_resolve 1 +#define VK_ANDROID_EXTERNAL_FORMAT_RESOLVE_SPEC_VERSION 1 +#define VK_ANDROID_EXTERNAL_FORMAT_RESOLVE_EXTENSION_NAME "VK_ANDROID_external_format_resolve" +typedef struct VkPhysicalDeviceExternalFormatResolveFeaturesANDROID { + VkStructureType sType; + void* pNext; + VkBool32 externalFormatResolve; +} VkPhysicalDeviceExternalFormatResolveFeaturesANDROID; + +typedef struct VkPhysicalDeviceExternalFormatResolvePropertiesANDROID { + VkStructureType sType; + void* pNext; + VkBool32 nullColorAttachmentWithExternalFormatResolve; + VkChromaLocation externalFormatResolveChromaOffsetX; + VkChromaLocation externalFormatResolveChromaOffsetY; +} VkPhysicalDeviceExternalFormatResolvePropertiesANDROID; + +typedef struct VkAndroidHardwareBufferFormatResolvePropertiesANDROID { + VkStructureType sType; + void* pNext; + VkFormat colorAttachmentFormat; +} VkAndroidHardwareBufferFormatResolvePropertiesANDROID; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_beta.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_beta.h new file mode 100644 index 000000000..c84b1d48e --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_beta.h @@ -0,0 +1,375 @@ +#ifndef VULKAN_BETA_H_ +#define VULKAN_BETA_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_KHR_portability_subset is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_portability_subset 1 +#define VK_KHR_PORTABILITY_SUBSET_SPEC_VERSION 1 +#define VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME "VK_KHR_portability_subset" +typedef struct VkPhysicalDevicePortabilitySubsetFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 constantAlphaColorBlendFactors; + VkBool32 events; + VkBool32 imageViewFormatReinterpretation; + VkBool32 imageViewFormatSwizzle; + VkBool32 imageView2DOn3DImage; + VkBool32 multisampleArrayImage; + VkBool32 mutableComparisonSamplers; + VkBool32 pointPolygons; + VkBool32 samplerMipLodBias; + VkBool32 separateStencilMaskRef; + VkBool32 shaderSampleRateInterpolationFunctions; + VkBool32 tessellationIsolines; + VkBool32 tessellationPointMode; + VkBool32 triangleFans; + VkBool32 vertexAttributeAccessBeyondStride; +} VkPhysicalDevicePortabilitySubsetFeaturesKHR; + +typedef struct VkPhysicalDevicePortabilitySubsetPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t minVertexInputBindingStrideAlignment; +} VkPhysicalDevicePortabilitySubsetPropertiesKHR; + + + +// VK_AMDX_shader_enqueue is a preprocessor guard. Do not pass it to API calls. +#define VK_AMDX_shader_enqueue 1 +#define VK_AMDX_SHADER_ENQUEUE_SPEC_VERSION 2 +#define VK_AMDX_SHADER_ENQUEUE_EXTENSION_NAME "VK_AMDX_shader_enqueue" +#define VK_SHADER_INDEX_UNUSED_AMDX (~0U) +typedef struct VkPhysicalDeviceShaderEnqueueFeaturesAMDX { + VkStructureType sType; + void* pNext; + VkBool32 shaderEnqueue; + VkBool32 shaderMeshEnqueue; +} VkPhysicalDeviceShaderEnqueueFeaturesAMDX; + +typedef struct VkPhysicalDeviceShaderEnqueuePropertiesAMDX { + VkStructureType sType; + void* pNext; + uint32_t maxExecutionGraphDepth; + uint32_t maxExecutionGraphShaderOutputNodes; + uint32_t maxExecutionGraphShaderPayloadSize; + uint32_t maxExecutionGraphShaderPayloadCount; + uint32_t executionGraphDispatchAddressAlignment; + uint32_t maxExecutionGraphWorkgroupCount[3]; + uint32_t maxExecutionGraphWorkgroups; +} VkPhysicalDeviceShaderEnqueuePropertiesAMDX; + +typedef struct VkExecutionGraphPipelineScratchSizeAMDX { + VkStructureType sType; + void* pNext; + VkDeviceSize minSize; + VkDeviceSize maxSize; + VkDeviceSize sizeGranularity; +} VkExecutionGraphPipelineScratchSizeAMDX; + +typedef struct VkExecutionGraphPipelineCreateInfoAMDX { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + const VkPipelineLibraryCreateInfoKHR* pLibraryInfo; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkExecutionGraphPipelineCreateInfoAMDX; + +typedef union VkDeviceOrHostAddressConstAMDX { + VkDeviceAddress deviceAddress; + const void* hostAddress; +} VkDeviceOrHostAddressConstAMDX; + +typedef struct VkDispatchGraphInfoAMDX { + uint32_t nodeIndex; + uint32_t payloadCount; + VkDeviceOrHostAddressConstAMDX payloads; + uint64_t payloadStride; +} VkDispatchGraphInfoAMDX; + +typedef struct VkDispatchGraphCountInfoAMDX { + uint32_t count; + VkDeviceOrHostAddressConstAMDX infos; + uint64_t stride; +} VkDispatchGraphCountInfoAMDX; + +typedef struct VkPipelineShaderStageNodeCreateInfoAMDX { + VkStructureType sType; + const void* pNext; + const char* pName; + uint32_t index; +} VkPipelineShaderStageNodeCreateInfoAMDX; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateExecutionGraphPipelinesAMDX)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkExecutionGraphPipelineCreateInfoAMDX* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkGetExecutionGraphPipelineScratchSizeAMDX)(VkDevice device, VkPipeline executionGraph, VkExecutionGraphPipelineScratchSizeAMDX* pSizeInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetExecutionGraphPipelineNodeIndexAMDX)(VkDevice device, VkPipeline executionGraph, const VkPipelineShaderStageNodeCreateInfoAMDX* pNodeInfo, uint32_t* pNodeIndex); +typedef void (VKAPI_PTR *PFN_vkCmdInitializeGraphScratchMemoryAMDX)(VkCommandBuffer commandBuffer, VkPipeline executionGraph, VkDeviceAddress scratch, VkDeviceSize scratchSize); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchGraphAMDX)(VkCommandBuffer commandBuffer, VkDeviceAddress scratch, VkDeviceSize scratchSize, const VkDispatchGraphCountInfoAMDX* pCountInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchGraphIndirectAMDX)(VkCommandBuffer commandBuffer, VkDeviceAddress scratch, VkDeviceSize scratchSize, const VkDispatchGraphCountInfoAMDX* pCountInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchGraphIndirectCountAMDX)(VkCommandBuffer commandBuffer, VkDeviceAddress scratch, VkDeviceSize scratchSize, VkDeviceAddress countInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateExecutionGraphPipelinesAMDX( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkExecutionGraphPipelineCreateInfoAMDX* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetExecutionGraphPipelineScratchSizeAMDX( + VkDevice device, + VkPipeline executionGraph, + VkExecutionGraphPipelineScratchSizeAMDX* pSizeInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetExecutionGraphPipelineNodeIndexAMDX( + VkDevice device, + VkPipeline executionGraph, + const VkPipelineShaderStageNodeCreateInfoAMDX* pNodeInfo, + uint32_t* pNodeIndex); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdInitializeGraphScratchMemoryAMDX( + VkCommandBuffer commandBuffer, + VkPipeline executionGraph, + VkDeviceAddress scratch, + VkDeviceSize scratchSize); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchGraphAMDX( + VkCommandBuffer commandBuffer, + VkDeviceAddress scratch, + VkDeviceSize scratchSize, + const VkDispatchGraphCountInfoAMDX* pCountInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchGraphIndirectAMDX( + VkCommandBuffer commandBuffer, + VkDeviceAddress scratch, + VkDeviceSize scratchSize, + const VkDispatchGraphCountInfoAMDX* pCountInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchGraphIndirectCountAMDX( + VkCommandBuffer commandBuffer, + VkDeviceAddress scratch, + VkDeviceSize scratchSize, + VkDeviceAddress countInfo); +#endif +#endif + + +// VK_NV_cuda_kernel_launch is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_cuda_kernel_launch 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCudaModuleNV) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCudaFunctionNV) +#define VK_NV_CUDA_KERNEL_LAUNCH_SPEC_VERSION 2 +#define VK_NV_CUDA_KERNEL_LAUNCH_EXTENSION_NAME "VK_NV_cuda_kernel_launch" +typedef struct VkCudaModuleCreateInfoNV { + VkStructureType sType; + const void* pNext; + size_t dataSize; + const void* pData; +} VkCudaModuleCreateInfoNV; + +typedef struct VkCudaFunctionCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkCudaModuleNV module; + const char* pName; +} VkCudaFunctionCreateInfoNV; + +typedef struct VkCudaLaunchInfoNV { + VkStructureType sType; + const void* pNext; + VkCudaFunctionNV function; + uint32_t gridDimX; + uint32_t gridDimY; + uint32_t gridDimZ; + uint32_t blockDimX; + uint32_t blockDimY; + uint32_t blockDimZ; + uint32_t sharedMemBytes; + size_t paramCount; + const void* const * pParams; + size_t extraCount; + const void* const * pExtras; +} VkCudaLaunchInfoNV; + +typedef struct VkPhysicalDeviceCudaKernelLaunchFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 cudaKernelLaunchFeatures; +} VkPhysicalDeviceCudaKernelLaunchFeaturesNV; + +typedef struct VkPhysicalDeviceCudaKernelLaunchPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t computeCapabilityMinor; + uint32_t computeCapabilityMajor; +} VkPhysicalDeviceCudaKernelLaunchPropertiesNV; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateCudaModuleNV)(VkDevice device, const VkCudaModuleCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCudaModuleNV* pModule); +typedef VkResult (VKAPI_PTR *PFN_vkGetCudaModuleCacheNV)(VkDevice device, VkCudaModuleNV module, size_t* pCacheSize, void* pCacheData); +typedef VkResult (VKAPI_PTR *PFN_vkCreateCudaFunctionNV)(VkDevice device, const VkCudaFunctionCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCudaFunctionNV* pFunction); +typedef void (VKAPI_PTR *PFN_vkDestroyCudaModuleNV)(VkDevice device, VkCudaModuleNV module, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkDestroyCudaFunctionNV)(VkDevice device, VkCudaFunctionNV function, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkCmdCudaLaunchKernelNV)(VkCommandBuffer commandBuffer, const VkCudaLaunchInfoNV* pLaunchInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateCudaModuleNV( + VkDevice device, + const VkCudaModuleCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkCudaModuleNV* pModule); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetCudaModuleCacheNV( + VkDevice device, + VkCudaModuleNV module, + size_t* pCacheSize, + void* pCacheData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateCudaFunctionNV( + VkDevice device, + const VkCudaFunctionCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkCudaFunctionNV* pFunction); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyCudaModuleNV( + VkDevice device, + VkCudaModuleNV module, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyCudaFunctionNV( + VkDevice device, + VkCudaFunctionNV function, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCudaLaunchKernelNV( + VkCommandBuffer commandBuffer, + const VkCudaLaunchInfoNV* pLaunchInfo); +#endif +#endif + + +// VK_NV_displacement_micromap is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_displacement_micromap 1 +#define VK_NV_DISPLACEMENT_MICROMAP_SPEC_VERSION 2 +#define VK_NV_DISPLACEMENT_MICROMAP_EXTENSION_NAME "VK_NV_displacement_micromap" + +typedef enum VkDisplacementMicromapFormatNV { + VK_DISPLACEMENT_MICROMAP_FORMAT_64_TRIANGLES_64_BYTES_NV = 1, + VK_DISPLACEMENT_MICROMAP_FORMAT_256_TRIANGLES_128_BYTES_NV = 2, + VK_DISPLACEMENT_MICROMAP_FORMAT_1024_TRIANGLES_128_BYTES_NV = 3, + VK_DISPLACEMENT_MICROMAP_FORMAT_MAX_ENUM_NV = 0x7FFFFFFF +} VkDisplacementMicromapFormatNV; +typedef struct VkPhysicalDeviceDisplacementMicromapFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 displacementMicromap; +} VkPhysicalDeviceDisplacementMicromapFeaturesNV; + +typedef struct VkPhysicalDeviceDisplacementMicromapPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t maxDisplacementMicromapSubdivisionLevel; +} VkPhysicalDeviceDisplacementMicromapPropertiesNV; + +typedef struct VkAccelerationStructureTrianglesDisplacementMicromapNV { + VkStructureType sType; + void* pNext; + VkFormat displacementBiasAndScaleFormat; + VkFormat displacementVectorFormat; + VkDeviceOrHostAddressConstKHR displacementBiasAndScaleBuffer; + VkDeviceSize displacementBiasAndScaleStride; + VkDeviceOrHostAddressConstKHR displacementVectorBuffer; + VkDeviceSize displacementVectorStride; + VkDeviceOrHostAddressConstKHR displacedMicromapPrimitiveFlags; + VkDeviceSize displacedMicromapPrimitiveFlagsStride; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexBuffer; + VkDeviceSize indexStride; + uint32_t baseTriangle; + uint32_t usageCountsCount; + const VkMicromapUsageEXT* pUsageCounts; + const VkMicromapUsageEXT* const* ppUsageCounts; + VkMicromapEXT micromap; +} VkAccelerationStructureTrianglesDisplacementMicromapNV; + + + +// VK_AMDX_dense_geometry_format is a preprocessor guard. Do not pass it to API calls. +#define VK_AMDX_dense_geometry_format 1 +#define VK_AMDX_DENSE_GEOMETRY_FORMAT_SPEC_VERSION 1 +#define VK_AMDX_DENSE_GEOMETRY_FORMAT_EXTENSION_NAME "VK_AMDX_dense_geometry_format" +#define VK_COMPRESSED_TRIANGLE_FORMAT_DGF1_BYTE_ALIGNMENT_AMDX 128U +#define VK_COMPRESSED_TRIANGLE_FORMAT_DGF1_BYTE_STRIDE_AMDX 128U + +typedef enum VkCompressedTriangleFormatAMDX { + VK_COMPRESSED_TRIANGLE_FORMAT_DGF1_AMDX = 0, + VK_COMPRESSED_TRIANGLE_FORMAT_MAX_ENUM_AMDX = 0x7FFFFFFF +} VkCompressedTriangleFormatAMDX; +typedef struct VkPhysicalDeviceDenseGeometryFormatFeaturesAMDX { + VkStructureType sType; + void* pNext; + VkBool32 denseGeometryFormat; +} VkPhysicalDeviceDenseGeometryFormatFeaturesAMDX; + +typedef struct VkAccelerationStructureDenseGeometryFormatTrianglesDataAMDX { + VkStructureType sType; + const void* pNext; + VkDeviceOrHostAddressConstKHR compressedData; + VkDeviceSize dataSize; + uint32_t numTriangles; + uint32_t numVertices; + uint32_t maxPrimitiveIndex; + uint32_t maxGeometryIndex; + VkCompressedTriangleFormatAMDX format; +} VkAccelerationStructureDenseGeometryFormatTrianglesDataAMDX; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_core.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_core.h new file mode 100644 index 000000000..64b8803d8 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_core.h @@ -0,0 +1,27045 @@ +#ifndef VULKAN_CORE_H_ +#define VULKAN_CORE_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_VERSION_1_0 is a preprocessor guard. Do not pass it to API calls. +#define VK_VERSION_1_0 1 +#include "vk_platform.h" + +#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; + + +#ifndef VK_USE_64_BIT_PTR_DEFINES + #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) || (defined(__riscv) && __riscv_xlen == 64) + #define VK_USE_64_BIT_PTR_DEFINES 1 + #else + #define VK_USE_64_BIT_PTR_DEFINES 0 + #endif +#endif + + +#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE + #if (VK_USE_64_BIT_PTR_DEFINES==1) + #if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)) + #define VK_NULL_HANDLE nullptr + #else + #define VK_NULL_HANDLE ((void*)0) + #endif + #else + #define VK_NULL_HANDLE 0ULL + #endif +#endif +#ifndef VK_NULL_HANDLE + #define VK_NULL_HANDLE 0 +#endif + + +#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE + #if (VK_USE_64_BIT_PTR_DEFINES==1) + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; + #else + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; + #endif +#endif + +#define VK_MAKE_API_VERSION(variant, major, minor, patch) \ + ((((uint32_t)(variant)) << 29U) | (((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(patch))) + + +//#define VK_API_VERSION VK_MAKE_API_VERSION(0, 1, 0, 0) // Patch version should always be set to 0 + +// Version of this file +#define VK_HEADER_VERSION 357 + +// Complete version of this file +#define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, 1, 4, VK_HEADER_VERSION) + + +#define VK_MAKE_VERSION(major, minor, patch) \ + ((((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(patch))) + + +#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22U) + + +#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12U) & 0x3FFU) + + +#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) + +#define VK_API_VERSION_VARIANT(version) ((uint32_t)(version) >> 29U) +#define VK_API_VERSION_MAJOR(version) (((uint32_t)(version) >> 22U) & 0x7FU) +#define VK_API_VERSION_MINOR(version) (((uint32_t)(version) >> 12U) & 0x3FFU) +#define VK_API_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) +// Vulkan 1.0 version number +#define VK_API_VERSION_1_0 VK_MAKE_API_VERSION(0, 1, 0, 0)// Patch version should always be set to 0 + +typedef uint32_t VkBool32; +typedef uint64_t VkDeviceAddress; +typedef uint64_t VkDeviceSize; +typedef uint32_t VkFlags; +typedef uint32_t VkSampleMask; +VK_DEFINE_HANDLE(VkInstance) +VK_DEFINE_HANDLE(VkPhysicalDevice) +VK_DEFINE_HANDLE(VkDevice) +VK_DEFINE_HANDLE(VkQueue) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) +VK_DEFINE_HANDLE(VkCommandBuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool) +#define VK_FALSE 0U +#define VK_LOD_CLAMP_NONE 1000.0F +#define VK_QUEUE_FAMILY_IGNORED (~0U) +#define VK_REMAINING_ARRAY_LAYERS (~0U) +#define VK_REMAINING_MIP_LEVELS (~0U) +#define VK_TRUE 1U +#define VK_WHOLE_SIZE (~0ULL) +#define VK_MAX_MEMORY_TYPES 32U +#define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256U +#define VK_UUID_SIZE 16U +#define VK_MAX_EXTENSION_NAME_SIZE 256U +#define VK_MAX_DESCRIPTION_SIZE 256U +#define VK_MAX_MEMORY_HEAPS 16U +#define VK_ATTACHMENT_UNUSED (~0U) +#define VK_SUBPASS_EXTERNAL (~0U) + +typedef enum VkResult { + VK_SUCCESS = 0, + VK_NOT_READY = 1, + VK_TIMEOUT = 2, + VK_EVENT_SET = 3, + VK_EVENT_RESET = 4, + VK_INCOMPLETE = 5, + VK_ERROR_OUT_OF_HOST_MEMORY = -1, + VK_ERROR_OUT_OF_DEVICE_MEMORY = -2, + VK_ERROR_INITIALIZATION_FAILED = -3, + VK_ERROR_DEVICE_LOST = -4, + VK_ERROR_MEMORY_MAP_FAILED = -5, + VK_ERROR_LAYER_NOT_PRESENT = -6, + VK_ERROR_EXTENSION_NOT_PRESENT = -7, + VK_ERROR_FEATURE_NOT_PRESENT = -8, + VK_ERROR_INCOMPATIBLE_DRIVER = -9, + VK_ERROR_TOO_MANY_OBJECTS = -10, + VK_ERROR_FORMAT_NOT_SUPPORTED = -11, + VK_ERROR_FRAGMENTED_POOL = -12, + VK_ERROR_UNKNOWN = -13, + VK_ERROR_VALIDATION_FAILED = -1000011001, + VK_ERROR_OUT_OF_POOL_MEMORY = -1000069000, + VK_ERROR_INVALID_EXTERNAL_HANDLE = -1000072003, + VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS = -1000257000, + VK_ERROR_FRAGMENTATION = -1000161000, + VK_PIPELINE_COMPILE_REQUIRED = 1000297000, + VK_ERROR_NOT_PERMITTED = -1000174001, + VK_ERROR_SURFACE_LOST_KHR = -1000000000, + VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, + VK_SUBOPTIMAL_KHR = 1000001003, + VK_ERROR_OUT_OF_DATE_KHR = -1000001004, + VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, + VK_ERROR_INVALID_SHADER_NV = -1000012000, + VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR = -1000023000, + VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR = -1000023001, + VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR = -1000023002, + VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR = -1000023003, + VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR = -1000023004, + VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR = -1000023005, + VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = -1000158000, + VK_ERROR_PRESENT_TIMING_QUEUE_FULL_EXT = -1000208000, + VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT = -1000255000, + VK_THREAD_IDLE_KHR = 1000268000, + VK_THREAD_DONE_KHR = 1000268001, + VK_OPERATION_DEFERRED_KHR = 1000268002, + VK_OPERATION_NOT_DEFERRED_KHR = 1000268003, + VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR = -1000299000, + VK_ERROR_COMPRESSION_EXHAUSTED_EXT = -1000338000, + VK_INCOMPATIBLE_SHADER_BINARY_EXT = 1000482000, + VK_PIPELINE_BINARY_MISSING_KHR = 1000483000, + VK_ERROR_NOT_ENOUGH_SPACE_KHR = -1000483000, + VK_ERROR_VALIDATION_FAILED_EXT = VK_ERROR_VALIDATION_FAILED, + VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY, + VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = VK_ERROR_INVALID_EXTERNAL_HANDLE, + VK_ERROR_FRAGMENTATION_EXT = VK_ERROR_FRAGMENTATION, + VK_ERROR_NOT_PERMITTED_EXT = VK_ERROR_NOT_PERMITTED, + VK_ERROR_NOT_PERMITTED_KHR = VK_ERROR_NOT_PERMITTED, + VK_ERROR_INVALID_DEVICE_ADDRESS_EXT = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, + VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, + VK_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED, + VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED, + // VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT is a legacy alias + VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT = VK_INCOMPATIBLE_SHADER_BINARY_EXT, + VK_RESULT_MAX_ENUM = 0x7FFFFFFF +} VkResult; + +typedef enum VkStructureType { + VK_STRUCTURE_TYPE_APPLICATION_INFO = 0, + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2, + VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3, + VK_STRUCTURE_TYPE_SUBMIT_INFO = 4, + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5, + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6, + VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7, + VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8, + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9, + VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10, + VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11, + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12, + VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13, + VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14, + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15, + VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16, + VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19, + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20, + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23, + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24, + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25, + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26, + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27, + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28, + VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29, + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30, + VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35, + VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36, + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38, + VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42, + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45, + VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46, + VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47, + VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO = 1000157000, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO = 1000157001, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS = 1000127000, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO = 1000127001, + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO = 1000060000, + VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO = 1000060004, + VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO = 1000060005, + VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO = 1000060006, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO = 1000060013, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO = 1000060014, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES = 1000070000, + VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO = 1000070001, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 = 1000146000, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 = 1000146001, + VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 = 1000146002, + VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 = 1000146003, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 = 1000146004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 = 1000059000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 = 1000059002, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 = 1000059003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 = 1000059004, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 = 1000059005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2 = 1000059007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 = 1000059008, + VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO = 1000117002, + VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO = 1000145000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES = 1000145001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES = 1000145002, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2 = 1000145003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO = 1000071000, + VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES = 1000071001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO = 1000071002, + VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES = 1000071003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO = 1000072000, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO = 1000072001, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO = 1000072002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO = 1000112000, + VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES = 1000112001, + VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO = 1000113000, + VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO = 1000077000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO = 1000076000, + VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES = 1000076001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES = 1000094000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES = 1000083000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES = 1000120000, + VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO = 1000085000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO = 1000156000, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO = 1000156001, + VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO = 1000156002, + VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO = 1000156003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES = 1000156005, + VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO = 1000060003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES = 1000117000, + VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO = 1000117001, + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003, + VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO = 1000053000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES = 1000053001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES = 1000053002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES = 1000063000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES = 1000196000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES = 49, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES = 50, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES = 51, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES = 52, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO = 1000147000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES = 1000211000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES = 1000261000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES = 1000207000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES = 1000207001, + VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO = 1000207002, + VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO = 1000207003, + VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO = 1000207004, + VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO = 1000207005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES = 1000257000, + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO = 1000244001, + VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO = 1000257002, + VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO = 1000257003, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO = 1000257004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES = 1000177000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES = 1000180000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES = 1000082000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES = 1000197000, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO = 1000161000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES = 1000161001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES = 1000161002, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO = 1000161003, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT = 1000161004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES = 1000221000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES = 1000130000, + VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO = 1000130001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES = 1000253000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES = 1000175000, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2 = 1000109000, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2 = 1000109001, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2 = 1000109002, + VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2 = 1000109003, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2 = 1000109004, + VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO = 1000109005, + VK_STRUCTURE_TYPE_SUBPASS_END_INFO = 1000109006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES = 1000199000, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE = 1000199001, + VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO = 1000246000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES = 1000108000, + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO = 1000108001, + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO = 1000108002, + VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO = 1000108003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES = 1000241000, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT = 1000241001, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT = 1000241002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES = 53, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES = 54, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES = 1000245000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES = 1000295000, + VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO = 1000295001, + VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO = 1000295002, + VK_STRUCTURE_TYPE_MEMORY_BARRIER_2 = 1000314000, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 = 1000314001, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 = 1000314002, + VK_STRUCTURE_TYPE_DEPENDENCY_INFO = 1000314003, + VK_STRUCTURE_TYPE_SUBMIT_INFO_2 = 1000314004, + VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO = 1000314005, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO = 1000314006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES = 1000314007, + VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2 = 1000337000, + VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2 = 1000337001, + VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2 = 1000337002, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2 = 1000337003, + VK_STRUCTURE_TYPE_BUFFER_COPY_2 = 1000337006, + VK_STRUCTURE_TYPE_IMAGE_COPY_2 = 1000337007, + VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2 = 1000337009, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES = 1000066000, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3 = 1000360000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES = 1000413000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES = 1000413001, + VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS = 1000413002, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS = 1000413003, + VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO = 1000192000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES = 1000215000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES = 1000276000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES = 1000297000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES = 1000325000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES = 1000335000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES = 1000225000, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO = 1000225001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES = 1000225002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES = 1000138000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES = 1000138001, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK = 1000138002, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO = 1000138003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES = 1000280000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES = 1000280001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES = 1000281001, + VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2 = 1000337004, + VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2 = 1000337005, + VK_STRUCTURE_TYPE_IMAGE_BLIT_2 = 1000337008, + VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2 = 1000337010, + VK_STRUCTURE_TYPE_RENDERING_INFO = 1000044000, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO = 1000044001, + VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO = 1000044002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES = 1000044003, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO = 1000044004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES = 55, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_PROPERTIES = 56, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO = 1000174000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES = 1000388000, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES = 1000388001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES = 1000265000, + VK_STRUCTURE_TYPE_MEMORY_MAP_INFO = 1000271000, + VK_STRUCTURE_TYPE_MEMORY_UNMAP_INFO = 1000271001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES = 1000470000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES = 1000470001, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_SUBRESOURCE_INFO = 1000470004, + VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2 = 1000338002, + VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2 = 1000338003, + VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO = 1000470006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_FEATURES = 1000545000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_PROPERTIES = 1000545001, + VK_STRUCTURE_TYPE_BIND_MEMORY_STATUS = 1000545002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES = 1000270000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES = 1000270001, + VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY = 1000270002, + VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY = 1000270003, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO = 1000270004, + VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO = 1000270005, + VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO = 1000270006, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_IMAGE_INFO = 1000270007, + VK_STRUCTURE_TYPE_SUBRESOURCE_HOST_MEMCPY_SIZE = 1000270008, + VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY = 1000270009, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES = 1000416000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT_CONTROLS_2_FEATURES = 1000528000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EXPECT_ASSUME_FEATURES = 1000544000, + VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO = 1000470005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES = 1000080000, + VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_SETS_INFO = 1000545003, + VK_STRUCTURE_TYPE_PUSH_CONSTANTS_INFO = 1000545004, + VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_INFO = 1000545005, + VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_WITH_TEMPLATE_INFO = 1000545006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES = 1000466000, + VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO = 1000068000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES = 1000068001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES = 1000068002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES = 1000259000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO = 1000259001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES = 1000259002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES = 1000525000, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO = 1000190001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES = 1000190002, + VK_STRUCTURE_TYPE_RENDERING_AREA_INFO = 1000470003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES = 1000232000, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO = 1000232001, + VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO = 1000232002, + VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, + VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, + VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, + VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR = 1000060008, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR = 1000060009, + VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR = 1000060010, + VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR = 1000060011, + VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR = 1000060012, + VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000, + VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001, + VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR = 1000003000, + VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, + VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, + VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, + VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, + VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, + VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000, + VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000, + VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001, + VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002, + VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR = 1000023000, + VK_STRUCTURE_TYPE_VIDEO_CAPABILITIES_KHR = 1000023001, + VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR = 1000023002, + VK_STRUCTURE_TYPE_VIDEO_SESSION_MEMORY_REQUIREMENTS_KHR = 1000023003, + VK_STRUCTURE_TYPE_BIND_VIDEO_SESSION_MEMORY_INFO_KHR = 1000023004, + VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR = 1000023005, + VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000023006, + VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_UPDATE_INFO_KHR = 1000023007, + VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR = 1000023008, + VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR = 1000023009, + VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR = 1000023010, + VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR = 1000023011, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR = 1000023012, + VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR = 1000023013, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_FORMAT_INFO_KHR = 1000023014, + VK_STRUCTURE_TYPE_VIDEO_FORMAT_PROPERTIES_KHR = 1000023015, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_QUERY_RESULT_STATUS_PROPERTIES_KHR = 1000023016, + VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR = 1000024000, + VK_STRUCTURE_TYPE_VIDEO_DECODE_CAPABILITIES_KHR = 1000024001, + VK_STRUCTURE_TYPE_VIDEO_DECODE_USAGE_INFO_KHR = 1000024002, + VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000, + VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001, + VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002, + VK_STRUCTURE_TYPE_CU_MODULE_CREATE_INFO_NVX = 1000029000, + VK_STRUCTURE_TYPE_CU_FUNCTION_CREATE_INFO_NVX = 1000029001, + VK_STRUCTURE_TYPE_CU_LAUNCH_INFO_NVX = 1000029002, + VK_STRUCTURE_TYPE_CU_MODULE_TEXTURING_MODE_CREATE_INFO_NVX = 1000029004, + VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX = 1000030000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX = 1000030001, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_CAPABILITIES_KHR = 1000038000, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000038001, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR = 1000038002, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PICTURE_INFO_KHR = 1000038003, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_DPB_SLOT_INFO_KHR = 1000038004, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_NALU_SLICE_INFO_KHR = 1000038005, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_GOP_REMAINING_FRAME_INFO_KHR = 1000038006, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_INFO_KHR = 1000038007, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_INFO_KHR = 1000038008, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_LAYER_INFO_KHR = 1000038009, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_CREATE_INFO_KHR = 1000038010, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_QUALITY_LEVEL_PROPERTIES_KHR = 1000038011, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_GET_INFO_KHR = 1000038012, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_FEEDBACK_INFO_KHR = 1000038013, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_CAPABILITIES_KHR = 1000039000, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000039001, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR = 1000039002, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PICTURE_INFO_KHR = 1000039003, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_DPB_SLOT_INFO_KHR = 1000039004, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_NALU_SLICE_SEGMENT_INFO_KHR = 1000039005, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_GOP_REMAINING_FRAME_INFO_KHR = 1000039006, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PROFILE_INFO_KHR = 1000039007, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_INFO_KHR = 1000039009, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_LAYER_INFO_KHR = 1000039010, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_CREATE_INFO_KHR = 1000039011, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_QUALITY_LEVEL_PROPERTIES_KHR = 1000039012, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_GET_INFO_KHR = 1000039013, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_FEEDBACK_INFO_KHR = 1000039014, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_CAPABILITIES_KHR = 1000040000, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_KHR = 1000040001, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_INFO_KHR = 1000040003, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000040004, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR = 1000040005, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_KHR = 1000040006, + VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, + VK_STRUCTURE_TYPE_STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP = 1000049000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001, + VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000, + VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000, + VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT = 1000067000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT = 1000067001, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001, + VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002, + VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR = 1000073003, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR = 1000074000, + VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR = 1000074001, + VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR = 1000074002, + VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR = 1000075000, + VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078000, + VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078001, + VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR = 1000078002, + VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR = 1000078003, + VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000, + VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR = 1000079001, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT = 1000081000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT = 1000081001, + VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT = 1000081002, + VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT = 1000090000, + VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000, + VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT = 1000091001, + VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT = 1000091002, + VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003, + VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX = 1000097000, + VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX = 1000044009, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000, + VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT = 1000101000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT = 1000101001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT = 1000102000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT = 1000102001, + VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RELAXED_LINE_RASTERIZATION_FEATURES_IMG = 1000110000, + VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000, + VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000, + VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001, + VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR = 1000114002, + VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR = 1000115000, + VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR = 1000115001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR = 1000116000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR = 1000116001, + VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_CREATE_INFO_KHR = 1000116002, + VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR = 1000116003, + VK_STRUCTURE_TYPE_ACQUIRE_PROFILING_LOCK_INFO_KHR = 1000116004, + VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_KHR = 1000116005, + VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_DESCRIPTION_KHR = 1000116006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001, + VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002, + VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR = 1000121000, + VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR = 1000121001, + VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR = 1000121002, + VK_STRUCTURE_TYPE_DISPLAY_PLANE_INFO_2_KHR = 1000121003, + VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR = 1000121004, + VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000, + VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000, + VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000128000, + VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT = 1000128001, + VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT = 1000128002, + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000128003, + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000128004, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID = 1000129000, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID = 1000129001, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID = 1000129002, + VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129003, + VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129004, + VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID = 1000129005, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_2_ANDROID = 1000129006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GPA_FEATURES_AMD = 1000133000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GPA_PROPERTIES_AMD = 1000133001, + VK_STRUCTURE_TYPE_GPA_SAMPLE_BEGIN_INFO_AMD = 1000133002, + VK_STRUCTURE_TYPE_GPA_SESSION_CREATE_INFO_AMD = 1000133003, + VK_STRUCTURE_TYPE_GPA_DEVICE_CLOCK_MODE_INFO_AMD = 1000133004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GPA_PROPERTIES_2_AMD = 1000133005, + VK_STRUCTURE_TYPE_GPA_DEVICE_GET_CLOCK_INFO_AMD = 1000133006, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ENQUEUE_FEATURES_AMDX = 1000134000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ENQUEUE_PROPERTIES_AMDX = 1000134001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_EXECUTION_GRAPH_PIPELINE_SCRATCH_SIZE_AMDX = 1000134002, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_EXECUTION_GRAPH_PIPELINE_CREATE_INFO_AMDX = 1000134003, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_NODE_CREATE_INFO_AMDX = 1000134004, +#endif + VK_STRUCTURE_TYPE_TEXEL_BUFFER_DESCRIPTOR_INFO_EXT = 1000135000, + VK_STRUCTURE_TYPE_IMAGE_DESCRIPTOR_INFO_EXT = 1000135001, + VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT = 1000135002, + VK_STRUCTURE_TYPE_BIND_HEAP_INFO_EXT = 1000135003, + VK_STRUCTURE_TYPE_PUSH_DATA_INFO_EXT = 1000135004, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_AND_BINDING_MAPPING_EXT = 1000135005, + VK_STRUCTURE_TYPE_SHADER_DESCRIPTOR_SET_AND_BINDING_MAPPING_INFO_EXT = 1000135006, + VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DATA_CREATE_INFO_EXT = 1000135007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_HEAP_PROPERTIES_EXT = 1000135008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_HEAP_FEATURES_EXT = 1000135009, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_DESCRIPTOR_HEAP_INFO_EXT = 1000135010, + VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_INDEX_CREATE_INFO_EXT = 1000135011, + VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_PUSH_DATA_TOKEN_NV = 1000135012, + VK_STRUCTURE_TYPE_SUBSAMPLED_IMAGE_FORMAT_PROPERTIES_EXT = 1000135013, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_HEAP_TENSOR_PROPERTIES_ARM = 1000135014, + VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD = 1000044008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_BFLOAT16_FEATURES_KHR = 1000141000, + VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000, + VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001, + VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT = 1000143003, + VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT = 1000143004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001, + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002, + VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR = 1000150007, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR = 1000150000, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR = 1000150002, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR = 1000150003, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR = 1000150004, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR = 1000150005, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR = 1000150006, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_VERSION_INFO_KHR = 1000150009, + VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR = 1000150010, + VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_TO_MEMORY_INFO_KHR = 1000150011, + VK_STRUCTURE_TYPE_COPY_MEMORY_TO_ACCELERATION_STRUCTURE_INFO_KHR = 1000150012, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR = 1000150013, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR = 1000150014, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR = 1000150017, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR = 1000150020, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR = 1000347000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR = 1000347001, + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR = 1000150015, + VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR = 1000150016, + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR = 1000150018, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR = 1000348013, + VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV = 1000154000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV = 1000154001, + VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005, + VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT = 1000158006, + VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, + VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR = 1000163000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR = 1000163001, +#endif + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV = 1000164000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005, + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV = 1000165000, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000165001, + VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003, + VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004, + VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005, + VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009, + VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV = 1000165012, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000, + VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV = 1000166001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT = 1000170000, + VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT = 1000170001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_CONVERSION_FEATURES_QCOM = 1000172000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ELAPSED_TIMER_QUERY_FEATURES_QCOM = 1000173000, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000, + VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR = 1000181000, + VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD = 1000183000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_CAPABILITIES_KHR = 1000187000, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000187001, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR = 1000187002, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_INFO_KHR = 1000187003, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_KHR = 1000187004, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_KHR = 1000187005, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000, + VK_STRUCTURE_TYPE_PRESENT_FRAME_TOKEN_GGP = 1000191000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV = 1000202000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV = 1000202001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV = 1000204000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV = 1000205000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV = 1000205002, + VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV = 1000314008, + VK_STRUCTURE_TYPE_CHECKPOINT_DATA_2_NV = 1000314009, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_TIMING_FEATURES_EXT = 1000208000, + VK_STRUCTURE_TYPE_SWAPCHAIN_TIMING_PROPERTIES_EXT = 1000208001, + VK_STRUCTURE_TYPE_SWAPCHAIN_TIME_DOMAIN_PROPERTIES_EXT = 1000208002, + VK_STRUCTURE_TYPE_PRESENT_TIMINGS_INFO_EXT = 1000208003, + VK_STRUCTURE_TYPE_PRESENT_TIMING_INFO_EXT = 1000208004, + VK_STRUCTURE_TYPE_PAST_PRESENTATION_TIMING_INFO_EXT = 1000208005, + VK_STRUCTURE_TYPE_PAST_PRESENTATION_TIMING_PROPERTIES_EXT = 1000208006, + VK_STRUCTURE_TYPE_PAST_PRESENTATION_TIMING_EXT = 1000208007, + VK_STRUCTURE_TYPE_PRESENT_TIMING_SURFACE_CAPABILITIES_EXT = 1000208008, + VK_STRUCTURE_TYPE_SWAPCHAIN_CALIBRATED_TIMESTAMP_INFO_EXT = 1000208009, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL = 1000209000, + VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL = 1000210000, + VK_STRUCTURE_TYPE_INITIALIZE_PERFORMANCE_API_INFO_INTEL = 1000210001, + VK_STRUCTURE_TYPE_PERFORMANCE_MARKER_INFO_INTEL = 1000210002, + VK_STRUCTURE_TYPE_PERFORMANCE_STREAM_MARKER_INFO_INTEL = 1000210003, + VK_STRUCTURE_TYPE_PERFORMANCE_OVERRIDE_INFO_INTEL = 1000210004, + VK_STRUCTURE_TYPE_PERFORMANCE_CONFIGURATION_ACQUIRE_INFO_INTEL = 1000210005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000, + VK_STRUCTURE_TYPE_DISPLAY_NATIVE_HDR_SURFACE_CAPABILITIES_AMD = 1000213000, + VK_STRUCTURE_TYPE_SWAPCHAIN_DISPLAY_NATIVE_HDR_CREATE_INFO_AMD = 1000213001, + VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000, + VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT = 1000218000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT = 1000218001, + VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT = 1000218002, + VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_INFO_EXT = 1000044007, + VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000226000, + VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR = 1000226001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR = 1000226002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR = 1000226003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR = 1000226004, + VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000044006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD = 1000227000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD = 1000229000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CONSTANT_DATA_FEATURES_KHR = 1000231000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_FEATURES_KHR = 1000233000, + VK_STRUCTURE_TYPE_DEVICE_FAULT_SHADER_ABORT_MESSAGE_INFO_KHR = 1000233001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_PROPERTIES_KHR = 1000233002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT = 1000234000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_QUAD_CONTROL_FEATURES_KHR = 1000235000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT = 1000237000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT = 1000238000, + VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT = 1000238001, + VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR = 1000239000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV = 1000240000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT = 1000244000, + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT = 1000244002, + VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT = 1000247000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR = 1000248000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV = 1000249000, + VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV = 1000250000, + VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_REDUCTION_STATE_CREATE_INFO_NV = 1000250001, + VK_STRUCTURE_TYPE_FRAMEBUFFER_MIXED_SAMPLES_COMBINATION_NV = 1000250002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT = 1000251000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT = 1000252000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT = 1000254000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT = 1000254001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT = 1000254002, + VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT = 1000255000, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT = 1000255002, + VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT = 1000255001, + VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT = 1000256000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT = 1000260000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT = 1000267000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR = 1000269000, + VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR = 1000269001, + VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR = 1000269002, + VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR = 1000269003, + VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR = 1000269004, + VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR = 1000269005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAP_MEMORY_PLACED_FEATURES_EXT = 1000272000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAP_MEMORY_PLACED_PROPERTIES_EXT = 1000272001, + VK_STRUCTURE_TYPE_MEMORY_MAP_PLACED_INFO_EXT = 1000272002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT = 1000273000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV = 1000277000, + VK_STRUCTURE_TYPE_GRAPHICS_SHADER_GROUP_CREATE_INFO_NV = 1000277001, + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV = 1000277002, + VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_TOKEN_NV = 1000277003, + VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NV = 1000277004, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_INFO_NV = 1000277005, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_MEMORY_REQUIREMENTS_INFO_NV = 1000277006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV = 1000277007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV = 1000278000, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV = 1000278001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT = 1000281000, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDER_PASS_TRANSFORM_INFO_QCOM = 1000282000, + VK_STRUCTURE_TYPE_RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM = 1000282001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_BIAS_CONTROL_FEATURES_EXT = 1000283000, + VK_STRUCTURE_TYPE_DEPTH_BIAS_INFO_EXT = 1000283001, + VK_STRUCTURE_TYPE_DEPTH_BIAS_REPRESENTATION_INFO_EXT = 1000283002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT = 1000284000, + VK_STRUCTURE_TYPE_DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT = 1000284001, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_REPORT_CALLBACK_DATA_EXT = 1000284002, + VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT = 1000287000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT = 1000287001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT = 1000287002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_3D_FEATURES_EXT = 1000288000, + VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR = 1000290000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV = 1000292000, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_PRESENT_BARRIER_NV = 1000292001, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_BARRIER_CREATE_INFO_NV = 1000292002, + VK_STRUCTURE_TYPE_PRESENT_ID_KHR = 1000294000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR = 1000294001, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_INFO_KHR = 1000299000, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_INFO_KHR = 1000299001, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_LAYER_INFO_KHR = 1000299002, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_CAPABILITIES_KHR = 1000299003, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_USAGE_INFO_KHR = 1000299004, + VK_STRUCTURE_TYPE_QUERY_POOL_VIDEO_ENCODE_FEEDBACK_CREATE_INFO_KHR = 1000299005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_ENCODE_QUALITY_LEVEL_INFO_KHR = 1000299006, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUALITY_LEVEL_PROPERTIES_KHR = 1000299007, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUALITY_LEVEL_INFO_KHR = 1000299008, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_SESSION_PARAMETERS_GET_INFO_KHR = 1000299009, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_SESSION_PARAMETERS_FEEDBACK_INFO_KHR = 1000299010, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV = 1000300000, + VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV = 1000300001, + VK_STRUCTURE_TYPE_PERF_HINT_INFO_QCOM = 1000302000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_QUEUE_PERF_HINT_FEATURES_QCOM = 1000302001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_QUEUE_PERF_HINT_PROPERTIES_QCOM = 1000302002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_3_FEATURES_QCOM = 1000303000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MULTIPLE_WAIT_QUEUES_FEATURES_QCOM = 1000304000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MULTIPLE_WAIT_QUEUES_PROPERTIES_QCOM = 1000304001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SPLIT_BARRIER_FEATURES_EXT = 1000305000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SPLIT_BARRIER_PROPERTIES_EXT = 1000305001, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_CUDA_MODULE_CREATE_INFO_NV = 1000307000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_CUDA_FUNCTION_CREATE_INFO_NV = 1000307001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_CUDA_LAUNCH_INFO_NV = 1000307002, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUDA_KERNEL_LAUNCH_FEATURES_NV = 1000307003, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUDA_KERNEL_LAUNCH_PROPERTIES_NV = 1000307004, +#endif + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_SHADING_FEATURES_QCOM = 1000309000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_SHADING_PROPERTIES_QCOM = 1000309001, + VK_STRUCTURE_TYPE_RENDER_PASS_TILE_SHADING_CREATE_INFO_QCOM = 1000309002, + VK_STRUCTURE_TYPE_PER_TILE_BEGIN_INFO_QCOM = 1000309003, + VK_STRUCTURE_TYPE_PER_TILE_END_INFO_QCOM = 1000309004, + VK_STRUCTURE_TYPE_DISPATCH_TILE_INFO_QCOM = 1000309005, + VK_STRUCTURE_TYPE_QUERY_LOW_LATENCY_SUPPORT_NV = 1000310000, + VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECT_CREATE_INFO_EXT = 1000311000, + VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECTS_INFO_EXT = 1000311001, + VK_STRUCTURE_TYPE_EXPORT_METAL_DEVICE_INFO_EXT = 1000311002, + VK_STRUCTURE_TYPE_EXPORT_METAL_COMMAND_QUEUE_INFO_EXT = 1000311003, + VK_STRUCTURE_TYPE_EXPORT_METAL_BUFFER_INFO_EXT = 1000311004, + VK_STRUCTURE_TYPE_IMPORT_METAL_BUFFER_INFO_EXT = 1000311005, + VK_STRUCTURE_TYPE_EXPORT_METAL_TEXTURE_INFO_EXT = 1000311006, + VK_STRUCTURE_TYPE_IMPORT_METAL_TEXTURE_INFO_EXT = 1000311007, + VK_STRUCTURE_TYPE_EXPORT_METAL_IO_SURFACE_INFO_EXT = 1000311008, + VK_STRUCTURE_TYPE_IMPORT_METAL_IO_SURFACE_INFO_EXT = 1000311009, + VK_STRUCTURE_TYPE_EXPORT_METAL_SHARED_EVENT_INFO_EXT = 1000311010, + VK_STRUCTURE_TYPE_IMPORT_METAL_SHARED_EVENT_INFO_EXT = 1000311011, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT = 1000316000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT = 1000316001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT = 1000316002, + VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT = 1000316003, + VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT = 1000316004, + VK_STRUCTURE_TYPE_BUFFER_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316005, + VK_STRUCTURE_TYPE_IMAGE_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316006, + VK_STRUCTURE_TYPE_IMAGE_VIEW_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316007, + VK_STRUCTURE_TYPE_SAMPLER_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316008, + VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT = 1000316010, + VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT = 1000316011, + VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_PUSH_DESCRIPTOR_BUFFER_HANDLE_EXT = 1000316012, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316009, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_COPY_KHR = 1000318000, + VK_STRUCTURE_TYPE_COPY_DEVICE_MEMORY_INFO_KHR = 1000318001, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_IMAGE_COPY_KHR = 1000318002, + VK_STRUCTURE_TYPE_COPY_DEVICE_MEMORY_IMAGE_INFO_KHR = 1000318003, + VK_STRUCTURE_TYPE_MEMORY_RANGE_BARRIERS_INFO_KHR = 1000318004, + VK_STRUCTURE_TYPE_MEMORY_RANGE_BARRIER_KHR = 1000318005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_ADDRESS_COMMANDS_FEATURES_KHR = 1000318006, + VK_STRUCTURE_TYPE_BIND_INDEX_BUFFER_3_INFO_KHR = 1000318007, + VK_STRUCTURE_TYPE_BIND_VERTEX_BUFFER_3_INFO_KHR = 1000318008, + VK_STRUCTURE_TYPE_DRAW_INDIRECT_2_INFO_KHR = 1000318009, + VK_STRUCTURE_TYPE_DRAW_INDIRECT_COUNT_2_INFO_KHR = 1000318010, + VK_STRUCTURE_TYPE_DISPATCH_INDIRECT_2_INFO_KHR = 1000318011, + VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_2_EXT = 1000318012, + VK_STRUCTURE_TYPE_BIND_TRANSFORM_FEEDBACK_BUFFER_2_INFO_EXT = 1000318013, + VK_STRUCTURE_TYPE_MEMORY_MARKER_INFO_AMD = 1000318014, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_2_KHR = 1000318015, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT = 1000320000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT = 1000320001, + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT = 1000320002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD = 1000321000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR = 1000203000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR = 1000322000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR = 1000323000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV = 1000326000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV = 1000326001, + VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV = 1000326002, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_MOTION_TRIANGLES_DATA_NV = 1000327000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV = 1000327001, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MOTION_INFO_NV = 1000327002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT = 1000328000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT = 1000328001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT = 1000330000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT = 1000332000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT = 1000332001, + VK_STRUCTURE_TYPE_COPY_COMMAND_TRANSFORM_INFO_QCOM = 1000333000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR = 1000336000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT = 1000338000, + VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT = 1000338001, + VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT = 1000338004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT = 1000339000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT = 1000340000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT = 1000341000, + VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT = 1000341001, + VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT = 1000341002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT = 1000344000, + VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT = 1000346000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT = 1000352000, + VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT = 1000352001, + VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT = 1000352002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT = 1000353000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT = 1000354000, + VK_STRUCTURE_TYPE_DEVICE_ADDRESS_BINDING_CALLBACK_DATA_EXT = 1000354001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT = 1000355000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT = 1000355001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT = 1000356000, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA = 1000364000, + VK_STRUCTURE_TYPE_MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA = 1000364001, + VK_STRUCTURE_TYPE_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA = 1000364002, + VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA = 1000365000, + VK_STRUCTURE_TYPE_SEMAPHORE_GET_ZIRCON_HANDLE_INFO_FUCHSIA = 1000365001, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CREATE_INFO_FUCHSIA = 1000366000, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA = 1000366001, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA = 1000366002, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_PROPERTIES_FUCHSIA = 1000366003, + VK_STRUCTURE_TYPE_BUFFER_CONSTRAINTS_INFO_FUCHSIA = 1000366004, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_BUFFER_CREATE_INFO_FUCHSIA = 1000366005, + VK_STRUCTURE_TYPE_IMAGE_CONSTRAINTS_INFO_FUCHSIA = 1000366006, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_CONSTRAINTS_INFO_FUCHSIA = 1000366007, + VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA = 1000366008, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CONSTRAINTS_INFO_FUCHSIA = 1000366009, + VK_STRUCTURE_TYPE_SUBPASS_SHADING_PIPELINE_CREATE_INFO_HUAWEI = 1000369000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI = 1000369001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI = 1000369002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI = 1000370000, + VK_STRUCTURE_TYPE_MEMORY_GET_REMOTE_ADDRESS_INFO_NV = 1000371000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_RDMA_FEATURES_NV = 1000371001, + VK_STRUCTURE_TYPE_PIPELINE_PROPERTIES_IDENTIFIER_EXT = 1000372000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT = 1000372001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAME_BOUNDARY_FEATURES_EXT = 1000375000, + VK_STRUCTURE_TYPE_FRAME_BOUNDARY_EXT = 1000375001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT = 1000376000, + VK_STRUCTURE_TYPE_SUBPASS_RESOLVE_PERFORMANCE_QUERY_EXT = 1000376001, + VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT = 1000376002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT = 1000377000, + VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX = 1000378000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT = 1000381000, + VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT = 1000381001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT = 1000382000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR = 1000386000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_UNTYPED_POINTERS_FEATURES_KHR = 1000387000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_ENCODE_RGB_CONVERSION_FEATURES_VALVE = 1000390000, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_RGB_CONVERSION_CAPABILITIES_VALVE = 1000390001, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_PROFILE_RGB_CONVERSION_INFO_VALVE = 1000390002, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_SESSION_RGB_CONVERSION_CREATE_INFO_VALVE = 1000390003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT = 1000391000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT = 1000391001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT = 1000392000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT = 1000392001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT = 1000393000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TILE_IMAGE_FEATURES_EXT = 1000395000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TILE_IMAGE_PROPERTIES_EXT = 1000395001, + VK_STRUCTURE_TYPE_MICROMAP_BUILD_INFO_EXT = 1000396000, + VK_STRUCTURE_TYPE_MICROMAP_VERSION_INFO_EXT = 1000396001, + VK_STRUCTURE_TYPE_COPY_MICROMAP_INFO_EXT = 1000396002, + VK_STRUCTURE_TYPE_COPY_MICROMAP_TO_MEMORY_INFO_EXT = 1000396003, + VK_STRUCTURE_TYPE_COPY_MEMORY_TO_MICROMAP_INFO_EXT = 1000396004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT = 1000396005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT = 1000396006, + VK_STRUCTURE_TYPE_MICROMAP_CREATE_INFO_EXT = 1000396007, + VK_STRUCTURE_TYPE_MICROMAP_BUILD_SIZES_INFO_EXT = 1000396008, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_TRIANGLES_OPACITY_MICROMAP_EXT = 1000396009, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISPLACEMENT_MICROMAP_FEATURES_NV = 1000397000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISPLACEMENT_MICROMAP_PROPERTIES_NV = 1000397001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_TRIANGLES_DISPLACEMENT_MICROMAP_NV = 1000397002, +#endif + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_FEATURES_HUAWEI = 1000404000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_PROPERTIES_HUAWEI = 1000404001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_VRS_FEATURES_HUAWEI = 1000404002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT = 1000411000, + VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT = 1000411001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT = 1000412000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_ARM = 1000415000, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_SHADER_CORE_CONTROL_CREATE_INFO_ARM = 1000417000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_FEATURES_ARM = 1000417001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_PROPERTIES_ARM = 1000417002, + VK_STRUCTURE_TYPE_DISPATCH_PARAMETERS_ARM = 1000417003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_DISPATCH_PARAMETERS_PROPERTIES_ARM = 1000417004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_SLICED_VIEW_OF_3D_FEATURES_EXT = 1000418000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_SLICED_CREATE_INFO_EXT = 1000418001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE = 1000420000, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_BINDING_REFERENCE_VALVE = 1000420001, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_HOST_MAPPING_INFO_VALVE = 1000420002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT = 1000422000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RENDER_PASS_STRIPED_FEATURES_ARM = 1000424000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RENDER_PASS_STRIPED_PROPERTIES_ARM = 1000424001, + VK_STRUCTURE_TYPE_RENDER_PASS_STRIPE_BEGIN_INFO_ARM = 1000424002, + VK_STRUCTURE_TYPE_RENDER_PASS_STRIPE_INFO_ARM = 1000424003, + VK_STRUCTURE_TYPE_RENDER_PASS_STRIPE_SUBMIT_INFO_ARM = 1000424004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV = 1000426000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_COMPUTE_FEATURES_NV = 1000428000, + VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_INDIRECT_BUFFER_INFO_NV = 1000428001, + VK_STRUCTURE_TYPE_PIPELINE_INDIRECT_DEVICE_ADDRESS_INFO_NV = 1000428002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_LINEAR_SWEPT_SPHERES_FEATURES_NV = 1000429008, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_LINEAR_SWEPT_SPHERES_DATA_NV = 1000429009, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_SPHERES_DATA_NV = 1000429010, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV = 1000430000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MAXIMAL_RECONVERGENCE_FEATURES_KHR = 1000434000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT = 1000437000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM = 1000440000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM = 1000440001, + VK_STRUCTURE_TYPE_IMAGE_VIEW_SAMPLE_WEIGHT_CREATE_INFO_QCOM = 1000440002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NESTED_COMMAND_BUFFER_FEATURES_EXT = 1000451000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NESTED_COMMAND_BUFFER_PROPERTIES_EXT = 1000451001, + VK_STRUCTURE_TYPE_NATIVE_BUFFER_USAGE_OHOS = 1000452000, + VK_STRUCTURE_TYPE_NATIVE_BUFFER_PROPERTIES_OHOS = 1000452001, + VK_STRUCTURE_TYPE_NATIVE_BUFFER_FORMAT_PROPERTIES_OHOS = 1000452002, + VK_STRUCTURE_TYPE_IMPORT_NATIVE_BUFFER_INFO_OHOS = 1000452003, + VK_STRUCTURE_TYPE_MEMORY_GET_NATIVE_BUFFER_INFO_OHOS = 1000452004, + VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_OHOS = 1000452005, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_ACQUIRE_UNMODIFIED_EXT = 1000453000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT = 1000455000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT = 1000455001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT = 1000458000, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_CONTROL_EXT = 1000458001, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_FEEDBACK_CREATE_INFO_EXT = 1000458002, + VK_STRUCTURE_TYPE_RENDER_PASS_SUBPASS_FEEDBACK_CREATE_INFO_EXT = 1000458003, + VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_INFO_LUNARG = 1000459000, + VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_LIST_LUNARG = 1000459001, + VK_STRUCTURE_TYPE_TENSOR_CREATE_INFO_ARM = 1000460000, + VK_STRUCTURE_TYPE_TENSOR_VIEW_CREATE_INFO_ARM = 1000460001, + VK_STRUCTURE_TYPE_BIND_TENSOR_MEMORY_INFO_ARM = 1000460002, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_TENSOR_ARM = 1000460003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TENSOR_PROPERTIES_ARM = 1000460004, + VK_STRUCTURE_TYPE_TENSOR_FORMAT_PROPERTIES_ARM = 1000460005, + VK_STRUCTURE_TYPE_TENSOR_DESCRIPTION_ARM = 1000460006, + VK_STRUCTURE_TYPE_TENSOR_MEMORY_REQUIREMENTS_INFO_ARM = 1000460007, + VK_STRUCTURE_TYPE_TENSOR_MEMORY_BARRIER_ARM = 1000460008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TENSOR_FEATURES_ARM = 1000460009, + VK_STRUCTURE_TYPE_DEVICE_TENSOR_MEMORY_REQUIREMENTS_ARM = 1000460010, + VK_STRUCTURE_TYPE_COPY_TENSOR_INFO_ARM = 1000460011, + VK_STRUCTURE_TYPE_TENSOR_COPY_ARM = 1000460012, + VK_STRUCTURE_TYPE_TENSOR_DEPENDENCY_INFO_ARM = 1000460013, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_TENSOR_ARM = 1000460014, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_TENSOR_INFO_ARM = 1000460015, + VK_STRUCTURE_TYPE_EXTERNAL_TENSOR_PROPERTIES_ARM = 1000460016, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_TENSOR_CREATE_INFO_ARM = 1000460017, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_TENSOR_FEATURES_ARM = 1000460018, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_TENSOR_PROPERTIES_ARM = 1000460019, + VK_STRUCTURE_TYPE_DESCRIPTOR_GET_TENSOR_INFO_ARM = 1000460020, + VK_STRUCTURE_TYPE_TENSOR_CAPTURE_DESCRIPTOR_DATA_INFO_ARM = 1000460021, + VK_STRUCTURE_TYPE_TENSOR_VIEW_CAPTURE_DESCRIPTOR_DATA_INFO_ARM = 1000460022, + VK_STRUCTURE_TYPE_FRAME_BOUNDARY_TENSORS_ARM = 1000460023, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT = 1000462000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT = 1000462001, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_MODULE_IDENTIFIER_CREATE_INFO_EXT = 1000462002, + VK_STRUCTURE_TYPE_SHADER_MODULE_IDENTIFIER_EXT = 1000462003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT = 1000342000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV = 1000464000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV = 1000464001, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_INFO_NV = 1000464002, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_PROPERTIES_NV = 1000464003, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_INFO_NV = 1000464004, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_EXECUTE_INFO_NV = 1000464005, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_PRIVATE_DATA_INFO_NV = 1000464010, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT = 1000465000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FORMAT_RESOLVE_FEATURES_ANDROID = 1000468000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FORMAT_RESOLVE_PROPERTIES_ANDROID = 1000468001, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_RESOLVE_PROPERTIES_ANDROID = 1000468002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ANTI_LAG_FEATURES_AMD = 1000476000, + VK_STRUCTURE_TYPE_ANTI_LAG_DATA_AMD = 1000476001, + VK_STRUCTURE_TYPE_ANTI_LAG_PRESENTATION_INFO_AMD = 1000476002, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DENSE_GEOMETRY_FORMAT_FEATURES_AMDX = 1000478000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DENSE_GEOMETRY_FORMAT_TRIANGLES_DATA_AMDX = 1000478001, +#endif + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_PRESENT_ID_2_KHR = 1000479000, + VK_STRUCTURE_TYPE_PRESENT_ID_2_KHR = 1000479001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_2_FEATURES_KHR = 1000479002, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_PRESENT_WAIT_2_KHR = 1000480000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_2_FEATURES_KHR = 1000480001, + VK_STRUCTURE_TYPE_PRESENT_WAIT_2_INFO_KHR = 1000480002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_POSITION_FETCH_FEATURES_KHR = 1000481000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT = 1000482000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_PROPERTIES_EXT = 1000482001, + VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT = 1000482002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_BINARY_FEATURES_KHR = 1000483000, + VK_STRUCTURE_TYPE_PIPELINE_BINARY_CREATE_INFO_KHR = 1000483001, + VK_STRUCTURE_TYPE_PIPELINE_BINARY_INFO_KHR = 1000483002, + VK_STRUCTURE_TYPE_PIPELINE_BINARY_KEY_KHR = 1000483003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_BINARY_PROPERTIES_KHR = 1000483004, + VK_STRUCTURE_TYPE_RELEASE_CAPTURED_PIPELINE_DATA_INFO_KHR = 1000483005, + VK_STRUCTURE_TYPE_PIPELINE_BINARY_DATA_INFO_KHR = 1000483006, + VK_STRUCTURE_TYPE_PIPELINE_CREATE_INFO_KHR = 1000483007, + VK_STRUCTURE_TYPE_DEVICE_PIPELINE_BINARY_INTERNAL_CACHE_CONTROL_KHR = 1000483008, + VK_STRUCTURE_TYPE_PIPELINE_BINARY_HANDLES_INFO_KHR = 1000483009, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM = 1000484000, + VK_STRUCTURE_TYPE_TILE_PROPERTIES_QCOM = 1000484001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_AMIGO_PROFILING_FEATURES_SEC = 1000485000, + VK_STRUCTURE_TYPE_AMIGO_PROFILING_SUBMIT_INFO_SEC = 1000485001, + VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_KHR = 1000274000, + VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_KHR = 1000274001, + VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_KHR = 1000274002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_KHR = 1000275000, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_KHR = 1000275001, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_KHR = 1000275002, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_KHR = 1000275003, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_SCALING_CREATE_INFO_KHR = 1000275004, + VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_KHR = 1000275005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM = 1000488000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV = 1000490000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV = 1000490001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_VECTOR_FEATURES_NV = 1000491000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_VECTOR_PROPERTIES_NV = 1000491001, + VK_STRUCTURE_TYPE_COOPERATIVE_VECTOR_PROPERTIES_NV = 1000491002, + VK_STRUCTURE_TYPE_CONVERT_COOPERATIVE_VECTOR_MATRIX_INFO_NV = 1000491004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_FEATURES_NV = 1000492000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_PROPERTIES_NV = 1000492001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT = 1000351000, + VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT = 1000351002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_VERTEX_ATTRIBUTES_FEATURES_EXT = 1000495000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_VERTEX_ATTRIBUTES_PROPERTIES_EXT = 1000495001, + VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT = 1000496000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM = 1000497000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM = 1000497001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_LIBRARY_GROUP_HANDLES_FEATURES_EXT = 1000498000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_FEATURES_EXT = 1000499000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INTERNALLY_SYNCHRONIZED_QUEUES_FEATURES_KHR = 1000504000, + VK_STRUCTURE_TYPE_LATENCY_SLEEP_MODE_INFO_NV = 1000505000, + VK_STRUCTURE_TYPE_LATENCY_SLEEP_INFO_NV = 1000505001, + VK_STRUCTURE_TYPE_SET_LATENCY_MARKER_INFO_NV = 1000505002, + VK_STRUCTURE_TYPE_GET_LATENCY_MARKER_INFO_NV = 1000505003, + VK_STRUCTURE_TYPE_LATENCY_TIMINGS_FRAME_REPORT_NV = 1000505004, + VK_STRUCTURE_TYPE_LATENCY_SUBMISSION_PRESENT_ID_NV = 1000505005, + VK_STRUCTURE_TYPE_OUT_OF_BAND_QUEUE_TYPE_INFO_NV = 1000505006, + VK_STRUCTURE_TYPE_SWAPCHAIN_LATENCY_CREATE_INFO_NV = 1000505007, + VK_STRUCTURE_TYPE_LATENCY_SURFACE_CAPABILITIES_NV = 1000505008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR = 1000506000, + VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_KHR = 1000506001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR = 1000506002, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_CREATE_INFO_ARM = 1000507000, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_SESSION_CREATE_INFO_ARM = 1000507001, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_RESOURCE_INFO_ARM = 1000507002, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_CONSTANT_ARM = 1000507003, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_SESSION_MEMORY_REQUIREMENTS_INFO_ARM = 1000507004, + VK_STRUCTURE_TYPE_BIND_DATA_GRAPH_PIPELINE_SESSION_MEMORY_INFO_ARM = 1000507005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DATA_GRAPH_FEATURES_ARM = 1000507006, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_SHADER_MODULE_CREATE_INFO_ARM = 1000507007, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_PROPERTY_QUERY_RESULT_ARM = 1000507008, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_INFO_ARM = 1000507009, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_COMPILER_CONTROL_CREATE_INFO_ARM = 1000507010, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_SESSION_BIND_POINT_REQUIREMENTS_INFO_ARM = 1000507011, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_SESSION_BIND_POINT_REQUIREMENT_ARM = 1000507012, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_IDENTIFIER_CREATE_INFO_ARM = 1000507013, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_DISPATCH_INFO_ARM = 1000507014, + VK_STRUCTURE_TYPE_DATA_GRAPH_PROCESSING_ENGINE_CREATE_INFO_ARM = 1000507016, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_DATA_GRAPH_PROCESSING_ENGINE_PROPERTIES_ARM = 1000507017, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_DATA_GRAPH_PROPERTIES_ARM = 1000507018, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_QUEUE_FAMILY_DATA_GRAPH_PROCESSING_ENGINE_INFO_ARM = 1000507019, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_CONSTANT_TENSOR_SEMI_STRUCTURED_SPARSITY_INFO_ARM = 1000507015, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_DATA_GRAPH_TOSA_PROPERTIES_ARM = 1000508000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_RENDER_AREAS_FEATURES_QCOM = 1000510000, + VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_RENDER_AREAS_RENDER_PASS_BEGIN_INFO_QCOM = 1000510001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_KHR = 1000201000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_PROPERTIES_KHR = 1000511000, + VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_CAPABILITIES_KHR = 1000512000, + VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_PICTURE_INFO_KHR = 1000512001, + VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_PROFILE_INFO_KHR = 1000512003, + VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000512004, + VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_DPB_SLOT_INFO_KHR = 1000512005, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_CAPABILITIES_KHR = 1000513000, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000513001, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_PICTURE_INFO_KHR = 1000513002, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_DPB_SLOT_INFO_KHR = 1000513003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_ENCODE_AV1_FEATURES_KHR = 1000513004, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_PROFILE_INFO_KHR = 1000513005, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_RATE_CONTROL_INFO_KHR = 1000513006, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_RATE_CONTROL_LAYER_INFO_KHR = 1000513007, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_QUALITY_LEVEL_PROPERTIES_KHR = 1000513008, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_SESSION_CREATE_INFO_KHR = 1000513009, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_GOP_REMAINING_FRAME_INFO_KHR = 1000513010, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_DECODE_VP9_FEATURES_KHR = 1000514000, + VK_STRUCTURE_TYPE_VIDEO_DECODE_VP9_CAPABILITIES_KHR = 1000514001, + VK_STRUCTURE_TYPE_VIDEO_DECODE_VP9_PICTURE_INFO_KHR = 1000514002, + VK_STRUCTURE_TYPE_VIDEO_DECODE_VP9_PROFILE_INFO_KHR = 1000514003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_1_FEATURES_KHR = 1000515000, + VK_STRUCTURE_TYPE_VIDEO_INLINE_QUERY_INFO_KHR = 1000515001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PER_STAGE_DESCRIPTOR_SET_FEATURES_NV = 1000516000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_2_FEATURES_QCOM = 1000518000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_2_PROPERTIES_QCOM = 1000518001, + VK_STRUCTURE_TYPE_SAMPLER_BLOCK_MATCH_WINDOW_CREATE_INFO_QCOM = 1000518002, + VK_STRUCTURE_TYPE_SAMPLER_CUBIC_WEIGHTS_CREATE_INFO_QCOM = 1000519000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUBIC_WEIGHTS_FEATURES_QCOM = 1000519001, + VK_STRUCTURE_TYPE_BLIT_IMAGE_CUBIC_WEIGHTS_INFO_QCOM = 1000519002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_DEGAMMA_FEATURES_QCOM = 1000520000, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_YCBCR_DEGAMMA_CREATE_INFO_QCOM = 1000520001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUBIC_CLAMP_FEATURES_QCOM = 1000521000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_FEATURES_EXT = 1000524000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFIED_IMAGE_LAYOUTS_FEATURES_KHR = 1000527000, + VK_STRUCTURE_TYPE_ATTACHMENT_FEEDBACK_LOOP_INFO_EXT = 1000527001, + VK_STRUCTURE_TYPE_SCREEN_BUFFER_PROPERTIES_QNX = 1000529000, + VK_STRUCTURE_TYPE_SCREEN_BUFFER_FORMAT_PROPERTIES_QNX = 1000529001, + VK_STRUCTURE_TYPE_IMPORT_SCREEN_BUFFER_INFO_QNX = 1000529002, + VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_QNX = 1000529003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_SCREEN_BUFFER_FEATURES_QNX = 1000529004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT = 1000530000, + VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_KHR = 1000184000, + VK_STRUCTURE_TYPE_SET_DESCRIPTOR_BUFFER_OFFSETS_INFO_EXT = 1000545007, + VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_BUFFER_EMBEDDED_SAMPLERS_INFO_EXT = 1000545008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_POOL_OVERALLOCATION_FEATURES_NV = 1000546000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_MEMORY_HEAP_FEATURES_QCOM = 1000547000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_MEMORY_HEAP_PROPERTIES_QCOM = 1000547001, + VK_STRUCTURE_TYPE_TILE_MEMORY_REQUIREMENTS_QCOM = 1000547002, + VK_STRUCTURE_TYPE_TILE_MEMORY_BIND_INFO_QCOM = 1000547003, + VK_STRUCTURE_TYPE_TILE_MEMORY_SIZE_INFO_QCOM = 1000547004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_KHR = 1000549000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_KHR = 1000426001, + VK_STRUCTURE_TYPE_COPY_MEMORY_INDIRECT_INFO_KHR = 1000549002, + VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INDIRECT_INFO_KHR = 1000549003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_EXT = 1000427000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_EXT = 1000427001, + VK_STRUCTURE_TYPE_DECOMPRESS_MEMORY_INFO_EXT = 1000550002, + VK_STRUCTURE_TYPE_DISPLAY_SURFACE_STEREO_CREATE_INFO_NV = 1000551000, + VK_STRUCTURE_TYPE_DISPLAY_MODE_STEREO_PROPERTIES_NV = 1000551001, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_INTRA_REFRESH_CAPABILITIES_KHR = 1000552000, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_SESSION_INTRA_REFRESH_CREATE_INFO_KHR = 1000552001, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_INTRA_REFRESH_INFO_KHR = 1000552002, + VK_STRUCTURE_TYPE_VIDEO_REFERENCE_INTRA_REFRESH_INFO_KHR = 1000552003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_ENCODE_INTRA_REFRESH_FEATURES_KHR = 1000552004, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUANTIZATION_MAP_CAPABILITIES_KHR = 1000553000, + VK_STRUCTURE_TYPE_VIDEO_FORMAT_QUANTIZATION_MAP_PROPERTIES_KHR = 1000553001, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUANTIZATION_MAP_INFO_KHR = 1000553002, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUANTIZATION_MAP_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000553005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_ENCODE_QUANTIZATION_MAP_FEATURES_KHR = 1000553009, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_QUANTIZATION_MAP_CAPABILITIES_KHR = 1000553003, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_QUANTIZATION_MAP_CAPABILITIES_KHR = 1000553004, + VK_STRUCTURE_TYPE_VIDEO_FORMAT_H265_QUANTIZATION_MAP_PROPERTIES_KHR = 1000553006, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_QUANTIZATION_MAP_CAPABILITIES_KHR = 1000553007, + VK_STRUCTURE_TYPE_VIDEO_FORMAT_AV1_QUANTIZATION_MAP_PROPERTIES_KHR = 1000553008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV = 1000555000, + VK_STRUCTURE_TYPE_EXTERNAL_COMPUTE_QUEUE_DEVICE_CREATE_INFO_NV = 1000556000, + VK_STRUCTURE_TYPE_EXTERNAL_COMPUTE_QUEUE_CREATE_INFO_NV = 1000556001, + VK_STRUCTURE_TYPE_EXTERNAL_COMPUTE_QUEUE_DATA_PARAMS_NV = 1000556002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_COMPUTE_QUEUE_PROPERTIES_NV = 1000556003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_RELAXED_EXTENDED_INSTRUCTION_FEATURES_KHR = 1000558000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMMAND_BUFFER_INHERITANCE_FEATURES_NV = 1000559000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_7_FEATURES_KHR = 1000562000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_7_PROPERTIES_KHR = 1000562001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_LIST_KHR = 1000562002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_KHR = 1000562003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_VULKAN_PROPERTIES_KHR = 1000562004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT16_VECTOR_FEATURES_NV = 1000563000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_REPLICATED_COMPOSITES_FEATURES_EXT = 1000564000, + VK_STRUCTURE_TYPE_TENSOR_EXPLICIT_TILING_FORMAT_PROPERTIES_ARM = 1000565000, + VK_STRUCTURE_TYPE_TENSOR_ROLLING_BACKING_CREATE_INFO_ARM = 1000565001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT8_FEATURES_EXT = 1000567000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_VALIDATION_FEATURES_NV = 1000568000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_FEATURES_NV = 1000569000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_PROPERTIES_NV = 1000569001, + VK_STRUCTURE_TYPE_CLUSTER_ACCELERATION_STRUCTURE_CLUSTERS_BOTTOM_LEVEL_INPUT_NV = 1000569002, + VK_STRUCTURE_TYPE_CLUSTER_ACCELERATION_STRUCTURE_TRIANGLE_CLUSTER_INPUT_NV = 1000569003, + VK_STRUCTURE_TYPE_CLUSTER_ACCELERATION_STRUCTURE_MOVE_OBJECTS_INPUT_NV = 1000569004, + VK_STRUCTURE_TYPE_CLUSTER_ACCELERATION_STRUCTURE_INPUT_INFO_NV = 1000569005, + VK_STRUCTURE_TYPE_CLUSTER_ACCELERATION_STRUCTURE_COMMANDS_INFO_NV = 1000569006, + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CLUSTER_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000569007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PARTITIONED_ACCELERATION_STRUCTURE_FEATURES_NV = 1000570000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PARTITIONED_ACCELERATION_STRUCTURE_PROPERTIES_NV = 1000570001, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_PARTITIONED_ACCELERATION_STRUCTURE_NV = 1000570002, + VK_STRUCTURE_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCES_INPUT_NV = 1000570003, + VK_STRUCTURE_TYPE_BUILD_PARTITIONED_ACCELERATION_STRUCTURE_INFO_NV = 1000570004, + VK_STRUCTURE_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_FLAGS_NV = 1000570005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_EXT = 1000572000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_EXT = 1000572001, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_MEMORY_REQUIREMENTS_INFO_EXT = 1000572002, + VK_STRUCTURE_TYPE_INDIRECT_EXECUTION_SET_CREATE_INFO_EXT = 1000572003, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_INFO_EXT = 1000572004, + VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_EXT = 1000572006, + VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_TOKEN_EXT = 1000572007, + VK_STRUCTURE_TYPE_WRITE_INDIRECT_EXECUTION_SET_PIPELINE_EXT = 1000572008, + VK_STRUCTURE_TYPE_WRITE_INDIRECT_EXECUTION_SET_SHADER_EXT = 1000572009, + VK_STRUCTURE_TYPE_INDIRECT_EXECUTION_SET_PIPELINE_INFO_EXT = 1000572010, + VK_STRUCTURE_TYPE_INDIRECT_EXECUTION_SET_SHADER_INFO_EXT = 1000572011, + VK_STRUCTURE_TYPE_INDIRECT_EXECUTION_SET_SHADER_LAYOUT_INFO_EXT = 1000572012, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_PIPELINE_INFO_EXT = 1000572013, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_SHADER_INFO_EXT = 1000572014, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_KHR = 1000573000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_PROPERTIES_KHR = 1000573001, + VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_KHR = 1000573002, + VK_STRUCTURE_TYPE_DEVICE_FAULT_DEBUG_INFO_KHR = 1000573003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_8_FEATURES_KHR = 1000574000, + VK_STRUCTURE_TYPE_MEMORY_BARRIER_ACCESS_FLAGS_3_KHR = 1000574002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ALIGNMENT_CONTROL_FEATURES_MESA = 1000575000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ALIGNMENT_CONTROL_PROPERTIES_MESA = 1000575001, + VK_STRUCTURE_TYPE_IMAGE_ALIGNMENT_CONTROL_CREATE_INFO_MESA = 1000575002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FMA_FEATURES_KHR = 1000579000, + VK_STRUCTURE_TYPE_PUSH_CONSTANT_BANK_INFO_NV = 1000580000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_CONSTANT_BANK_FEATURES_NV = 1000580001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_CONSTANT_BANK_PROPERTIES_NV = 1000580002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_EXT = 1000581000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_EXT = 1000581001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_CONTROL_FEATURES_EXT = 1000582000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLAMP_CONTROL_CREATE_INFO_EXT = 1000582001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_9_FEATURES_KHR = 1000584000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_9_PROPERTIES_KHR = 1000584001, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_OWNERSHIP_TRANSFER_PROPERTIES_KHR = 1000584002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_2_FEATURES_KHR = 1000586000, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_INLINE_SESSION_PARAMETERS_INFO_KHR = 1000586001, + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_INLINE_SESSION_PARAMETERS_INFO_KHR = 1000586002, + VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_INLINE_SESSION_PARAMETERS_INFO_KHR = 1000586003, + VK_STRUCTURE_TYPE_SURFACE_CREATE_INFO_OHOS = 1000685000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HDR_VIVID_FEATURES_HUAWEI = 1000590000, + VK_STRUCTURE_TYPE_HDR_VIVID_DYNAMIC_METADATA_HUAWEI = 1000590001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_2_FEATURES_NV = 1000593000, + VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_FLEXIBLE_DIMENSIONS_PROPERTIES_NV = 1000593001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_2_PROPERTIES_NV = 1000593002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_OPACITY_MICROMAP_FEATURES_ARM = 1000596000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_ENCODE_FEEDBACK_2_FEATURES_KHR = 1000598000, + VK_STRUCTURE_TYPE_VIDEO_ENCODE_FEEDBACK_2_CAPABILITIES_KHR = 1000598001, + VK_STRUCTURE_TYPE_QUERY_POOL_VIDEO_ENCODE_PER_PARTITION_FEEDBACK_CREATE_INFO_KHR = 1000598002, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_METAL_HANDLE_INFO_EXT = 1000602000, + VK_STRUCTURE_TYPE_MEMORY_METAL_HANDLE_PROPERTIES_EXT = 1000602001, + VK_STRUCTURE_TYPE_MEMORY_GET_METAL_HANDLE_INFO_EXT = 1000602002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_KHR = 1000421000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_COUNTERS_BY_REGION_FEATURES_ARM = 1000605000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_COUNTERS_BY_REGION_PROPERTIES_ARM = 1000605001, + VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_ARM = 1000605002, + VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_DESCRIPTION_ARM = 1000605003, + VK_STRUCTURE_TYPE_RENDER_PASS_PERFORMANCE_COUNTERS_BY_REGION_BEGIN_INFO_ARM = 1000605004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INSTRUMENTATION_FEATURES_ARM = 1000607000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INSTRUMENTATION_PROPERTIES_ARM = 1000607001, + VK_STRUCTURE_TYPE_SHADER_INSTRUMENTATION_CREATE_INFO_ARM = 1000607002, + VK_STRUCTURE_TYPE_SHADER_INSTRUMENTATION_METRIC_DESCRIPTION_ARM = 1000607003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_ROBUSTNESS_FEATURES_EXT = 1000608000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FORMAT_PACK_FEATURES_ARM = 1000609000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_LAYERED_FEATURES_VALVE = 1000611000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_LAYERED_PROPERTIES_VALVE = 1000611001, + VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_DENSITY_MAP_LAYERED_CREATE_INFO_VALVE = 1000611002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_KHR = 1000286000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_KHR = 1000286001, + VK_STRUCTURE_TYPE_SET_PRESENT_CONFIG_NV = 1000613000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_METERING_FEATURES_NV = 1000613001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SWAPCHAIN_FEATURES_EXT = 1000616000, + VK_STRUCTURE_TYPE_SWAPCHAIN_FLAGS_SURFACE_CAPABILITIES_EXT = 1000616001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_EXT = 1000425000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_EXT = 1000425001, + VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_EXT = 1000425002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_DEVICE_MEMORY_FEATURES_EXT = 1000620000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_MODE_FIFO_LATEST_READY_FEATURES_KHR = 1000361000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_KHR = 1000623000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_KHR = 1000623001, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_MICROMAP_DATA_KHR = 1000623002, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_TRIANGLES_OPACITY_MICROMAP_KHR = 1000623003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_64_BIT_INDEXING_FEATURES_EXT = 1000627000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_RESOLVE_FEATURES_EXT = 1000628000, + VK_STRUCTURE_TYPE_BEGIN_CUSTOM_RESOLVE_INFO_EXT = 1000628001, + VK_STRUCTURE_TYPE_CUSTOM_RESOLVE_CREATE_INFO_EXT = 1000628002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DATA_GRAPH_MODEL_FEATURES_QCOM = 1000629000, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_BUILTIN_MODEL_CREATE_INFO_QCOM = 1000629001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_10_FEATURES_KHR = 1000630000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_10_PROPERTIES_KHR = 1000630001, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_FLAGS_INFO_KHR = 1000630002, + VK_STRUCTURE_TYPE_RENDERING_END_INFO_KHR = 1000619003, + VK_STRUCTURE_TYPE_RESOLVE_IMAGE_MODE_INFO_KHR = 1000630004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DATA_GRAPH_OPTICAL_FLOW_FEATURES_ARM = 1000631000, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_DATA_GRAPH_OPTICAL_FLOW_PROPERTIES_ARM = 1000631001, + VK_STRUCTURE_TYPE_DATA_GRAPH_OPTICAL_FLOW_IMAGE_FORMAT_INFO_ARM = 1000631003, + VK_STRUCTURE_TYPE_DATA_GRAPH_OPTICAL_FLOW_IMAGE_FORMAT_PROPERTIES_ARM = 1000631004, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_OPTICAL_FLOW_DISPATCH_INFO_ARM = 1000631005, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_OPTICAL_FLOW_CREATE_INFO_ARM = 1000631002, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_RESOURCE_INFO_IMAGE_LAYOUT_ARM = 1000631006, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_SINGLE_NODE_CREATE_INFO_ARM = 1000631007, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_SINGLE_NODE_CONNECTION_ARM = 1000631008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_LONG_VECTOR_FEATURES_EXT = 1000635000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_LONG_VECTOR_PROPERTIES_EXT = 1000635001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CACHE_INCREMENTAL_MODE_FEATURES_SEC = 1000637000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_UNIFORM_BUFFER_UNSIZED_ARRAY_FEATURES_EXT = 1000642000, + VK_STRUCTURE_TYPE_COMPUTE_OCCUPANCY_PRIORITY_PARAMETERS_NV = 1000645000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_OCCUPANCY_PRIORITY_FEATURES_NV = 1000645001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_11_FEATURES_KHR = 1000657000, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_OPTIMAL_IMAGE_TRANSFER_GRANULARITY_PROPERTIES_KHR = 1000657001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_PARTITIONED_FEATURES_EXT = 1000662000, + VK_STRUCTURE_TYPE_UBM_SURFACE_CREATE_INFO_SEC = 1000664000, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_4_KHR = 1000668000, + VK_STRUCTURE_TYPE_IMAGE_CREATE_FLAGS_2_CREATE_INFO_KHR = 1000668001, + VK_STRUCTURE_TYPE_IMAGE_USAGE_FLAGS_2_CREATE_INFO_KHR = 1000668002, + VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_2_CREATE_INFO_KHR = 1000668003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_FLAGS_FEATURES_KHR = 1000668004, + VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_2_CREATE_INFO_KHR = 1000668005, + VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_2_KHR = 1000668006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OCP_MICROSCALING_TYPES_FEATURES_EXT = 1000672000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MIXED_FLOAT_DOT_PRODUCT_FEATURES_VALVE = 1000673000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_THROTTLE_HINT_FEATURES_SEC = 1000674000, + VK_STRUCTURE_TYPE_THROTTLE_HINT_SUBMIT_INFO_SEC = 1000674001, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_NEURAL_STATISTICS_CREATE_INFO_ARM = 1000676000, + VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_SESSION_NEURAL_STATISTICS_CREATE_INFO_ARM = 1000676001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DATA_GRAPH_NEURAL_ACCELERATOR_STATISTICS_FEATURES_ARM = 1000676002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_RESTART_INDEX_FEATURES_EXT = 1000678000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_DECODE_VECTOR_FEATURES_NV = 1000689000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES, + // VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT is a legacy alias + VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, + VK_STRUCTURE_TYPE_RENDERING_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_INFO, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO, + VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2, + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO, + VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO, + VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO, + VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO, + VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES, + VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES, + VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, + VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO, + VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, + VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, + VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES, + VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO, + // VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT is a legacy alias + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES, + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO, + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO, + VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2, + VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2, + VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO, + VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR = VK_STRUCTURE_TYPE_SUBPASS_END_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, + VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, + VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES, + VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO, + VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES, + VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2, + VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2, + VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO, + VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_NV = VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, + VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO, + VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES, + VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_KHR, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES, + VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES, + VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, + VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO, + VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, + VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, + // VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO_INTEL is a legacy alias + VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO_INTEL = VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO, + VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT, + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES, + VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES, + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO, + VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES, + VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY, + VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY_EXT = VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO_EXT = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO, + VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO, + VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_IMAGE_INFO_EXT = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_IMAGE_INFO, + VK_STRUCTURE_TYPE_SUBRESOURCE_HOST_MEMCPY_SIZE_EXT = VK_STRUCTURE_TYPE_SUBRESOURCE_HOST_MEMCPY_SIZE, + VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY_EXT = VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY, + VK_STRUCTURE_TYPE_MEMORY_MAP_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_MAP_INFO, + VK_STRUCTURE_TYPE_MEMORY_UNMAP_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_UNMAP_INFO, + VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT = VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_KHR, + VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT = VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_KHR, + VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT = VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_KHR, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_KHR, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_KHR, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_KHR, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_SCALING_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_SCALING_CREATE_INFO_KHR, + VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_EXT = VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES, + VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO, + VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES, + VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES, + VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2, + VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2, + VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR = VK_STRUCTURE_TYPE_BUFFER_COPY_2, + VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR = VK_STRUCTURE_TYPE_IMAGE_COPY_2, + VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR = VK_STRUCTURE_TYPE_IMAGE_BLIT_2, + VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR = VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2, + VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR = VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2, + VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_EXT = VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2, + VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2_EXT = VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_VALVE = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT, + VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE = VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3_KHR = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_MODE_FIFO_LATEST_READY_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_MODE_FIFO_LATEST_READY_FEATURES_KHR, + VK_STRUCTURE_TYPE_PIPELINE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES, + VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_EXT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_EXT, + VK_STRUCTURE_TYPE_SUBPASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_QCOM = VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_EXT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_NV = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_EXT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_NV = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_EXT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES, + VK_STRUCTURE_TYPE_RENDERING_AREA_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_AREA_INFO, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_SUBRESOURCE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_IMAGE_SUBRESOURCE_INFO, + VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_KHR = VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2, + VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2_KHR = VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2, + VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO, + VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO, + VK_STRUCTURE_TYPE_SHADER_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT_CONTROLS_2_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT_CONTROLS_2_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EXPECT_ASSUME_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EXPECT_ASSUME_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_PROPERTIES, + VK_STRUCTURE_TYPE_BIND_MEMORY_STATUS_KHR = VK_STRUCTURE_TYPE_BIND_MEMORY_STATUS, + VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_SETS_INFO_KHR = VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_SETS_INFO, + VK_STRUCTURE_TYPE_PUSH_CONSTANTS_INFO_KHR = VK_STRUCTURE_TYPE_PUSH_CONSTANTS_INFO, + VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_INFO_KHR = VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_INFO, + VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_WITH_TEMPLATE_INFO_KHR = VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_WITH_TEMPLATE_INFO, + VK_STRUCTURE_TYPE_RENDERING_END_INFO_EXT = VK_STRUCTURE_TYPE_RENDERING_END_INFO_KHR, + VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkStructureType; + +typedef enum VkObjectType { + VK_OBJECT_TYPE_UNKNOWN = 0, + VK_OBJECT_TYPE_INSTANCE = 1, + VK_OBJECT_TYPE_PHYSICAL_DEVICE = 2, + VK_OBJECT_TYPE_DEVICE = 3, + VK_OBJECT_TYPE_QUEUE = 4, + VK_OBJECT_TYPE_SEMAPHORE = 5, + VK_OBJECT_TYPE_COMMAND_BUFFER = 6, + VK_OBJECT_TYPE_FENCE = 7, + VK_OBJECT_TYPE_DEVICE_MEMORY = 8, + VK_OBJECT_TYPE_BUFFER = 9, + VK_OBJECT_TYPE_IMAGE = 10, + VK_OBJECT_TYPE_EVENT = 11, + VK_OBJECT_TYPE_QUERY_POOL = 12, + VK_OBJECT_TYPE_BUFFER_VIEW = 13, + VK_OBJECT_TYPE_IMAGE_VIEW = 14, + VK_OBJECT_TYPE_SHADER_MODULE = 15, + VK_OBJECT_TYPE_PIPELINE_CACHE = 16, + VK_OBJECT_TYPE_PIPELINE_LAYOUT = 17, + VK_OBJECT_TYPE_RENDER_PASS = 18, + VK_OBJECT_TYPE_PIPELINE = 19, + VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 20, + VK_OBJECT_TYPE_SAMPLER = 21, + VK_OBJECT_TYPE_DESCRIPTOR_POOL = 22, + VK_OBJECT_TYPE_DESCRIPTOR_SET = 23, + VK_OBJECT_TYPE_FRAMEBUFFER = 24, + VK_OBJECT_TYPE_COMMAND_POOL = 25, + VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000, + VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000, + VK_OBJECT_TYPE_PRIVATE_DATA_SLOT = 1000295000, + VK_OBJECT_TYPE_SURFACE_KHR = 1000000000, + VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000, + VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000, + VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001, + VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000, + VK_OBJECT_TYPE_VIDEO_SESSION_KHR = 1000023000, + VK_OBJECT_TYPE_VIDEO_SESSION_PARAMETERS_KHR = 1000023001, + VK_OBJECT_TYPE_CU_MODULE_NVX = 1000029000, + VK_OBJECT_TYPE_CU_FUNCTION_NVX = 1000029001, + VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000, + VK_OBJECT_TYPE_GPA_SESSION_AMD = 1000133000, + VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR = 1000150000, + VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000, + VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, + VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL = 1000210000, + VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR = 1000268000, + VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV = 1000277000, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_OBJECT_TYPE_CUDA_MODULE_NV = 1000307000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_OBJECT_TYPE_CUDA_FUNCTION_NV = 1000307001, +#endif + VK_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA = 1000366000, + VK_OBJECT_TYPE_MICROMAP_EXT = 1000396000, + VK_OBJECT_TYPE_TENSOR_ARM = 1000460000, + VK_OBJECT_TYPE_TENSOR_VIEW_ARM = 1000460001, + VK_OBJECT_TYPE_OPTICAL_FLOW_SESSION_NV = 1000464000, + VK_OBJECT_TYPE_SHADER_EXT = 1000482000, + VK_OBJECT_TYPE_PIPELINE_BINARY_KHR = 1000483000, + VK_OBJECT_TYPE_DATA_GRAPH_PIPELINE_SESSION_ARM = 1000507000, + VK_OBJECT_TYPE_EXTERNAL_COMPUTE_QUEUE_NV = 1000556000, + VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_EXT = 1000572000, + VK_OBJECT_TYPE_INDIRECT_EXECUTION_SET_EXT = 1000572001, + VK_OBJECT_TYPE_SHADER_INSTRUMENTATION_ARM = 1000607000, + VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE, + VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION, + VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT = VK_OBJECT_TYPE_PRIVATE_DATA_SLOT, + VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkObjectType; + +typedef enum VkVendorId { + VK_VENDOR_ID_KHRONOS = 0x10000, + VK_VENDOR_ID_VIV = 0x10001, + VK_VENDOR_ID_VSI = 0x10002, + VK_VENDOR_ID_KAZAN = 0x10003, + VK_VENDOR_ID_CODEPLAY = 0x10004, + VK_VENDOR_ID_MESA = 0x10005, + VK_VENDOR_ID_POCL = 0x10006, + VK_VENDOR_ID_MOBILEYE = 0x10007, + VK_VENDOR_ID_APE = 0x10008, + VK_VENDOR_ID_MAX_ENUM = 0x7FFFFFFF +} VkVendorId; + +typedef enum VkSystemAllocationScope { + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1, + VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2, + VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3, + VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4, + VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7FFFFFFF +} VkSystemAllocationScope; + +typedef enum VkInternalAllocationType { + VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0, + VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkInternalAllocationType; + +typedef enum VkFormat { + VK_FORMAT_UNDEFINED = 0, + VK_FORMAT_R4G4_UNORM_PACK8 = 1, + VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2, + VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3, + VK_FORMAT_R5G6B5_UNORM_PACK16 = 4, + VK_FORMAT_B5G6R5_UNORM_PACK16 = 5, + VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6, + VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7, + VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8, + VK_FORMAT_R8_UNORM = 9, + VK_FORMAT_R8_SNORM = 10, + VK_FORMAT_R8_USCALED = 11, + VK_FORMAT_R8_SSCALED = 12, + VK_FORMAT_R8_UINT = 13, + VK_FORMAT_R8_SINT = 14, + VK_FORMAT_R8_SRGB = 15, + VK_FORMAT_R8G8_UNORM = 16, + VK_FORMAT_R8G8_SNORM = 17, + VK_FORMAT_R8G8_USCALED = 18, + VK_FORMAT_R8G8_SSCALED = 19, + VK_FORMAT_R8G8_UINT = 20, + VK_FORMAT_R8G8_SINT = 21, + VK_FORMAT_R8G8_SRGB = 22, + VK_FORMAT_R8G8B8_UNORM = 23, + VK_FORMAT_R8G8B8_SNORM = 24, + VK_FORMAT_R8G8B8_USCALED = 25, + VK_FORMAT_R8G8B8_SSCALED = 26, + VK_FORMAT_R8G8B8_UINT = 27, + VK_FORMAT_R8G8B8_SINT = 28, + VK_FORMAT_R8G8B8_SRGB = 29, + VK_FORMAT_B8G8R8_UNORM = 30, + VK_FORMAT_B8G8R8_SNORM = 31, + VK_FORMAT_B8G8R8_USCALED = 32, + VK_FORMAT_B8G8R8_SSCALED = 33, + VK_FORMAT_B8G8R8_UINT = 34, + VK_FORMAT_B8G8R8_SINT = 35, + VK_FORMAT_B8G8R8_SRGB = 36, + VK_FORMAT_R8G8B8A8_UNORM = 37, + VK_FORMAT_R8G8B8A8_SNORM = 38, + VK_FORMAT_R8G8B8A8_USCALED = 39, + VK_FORMAT_R8G8B8A8_SSCALED = 40, + VK_FORMAT_R8G8B8A8_UINT = 41, + VK_FORMAT_R8G8B8A8_SINT = 42, + VK_FORMAT_R8G8B8A8_SRGB = 43, + VK_FORMAT_B8G8R8A8_UNORM = 44, + VK_FORMAT_B8G8R8A8_SNORM = 45, + VK_FORMAT_B8G8R8A8_USCALED = 46, + VK_FORMAT_B8G8R8A8_SSCALED = 47, + VK_FORMAT_B8G8R8A8_UINT = 48, + VK_FORMAT_B8G8R8A8_SINT = 49, + VK_FORMAT_B8G8R8A8_SRGB = 50, + VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51, + VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52, + VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53, + VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54, + VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55, + VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56, + VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57, + VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58, + VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59, + VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60, + VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61, + VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62, + VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63, + VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64, + VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65, + VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66, + VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67, + VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68, + VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69, + VK_FORMAT_R16_UNORM = 70, + VK_FORMAT_R16_SNORM = 71, + VK_FORMAT_R16_USCALED = 72, + VK_FORMAT_R16_SSCALED = 73, + VK_FORMAT_R16_UINT = 74, + VK_FORMAT_R16_SINT = 75, + VK_FORMAT_R16_SFLOAT = 76, + VK_FORMAT_R16G16_UNORM = 77, + VK_FORMAT_R16G16_SNORM = 78, + VK_FORMAT_R16G16_USCALED = 79, + VK_FORMAT_R16G16_SSCALED = 80, + VK_FORMAT_R16G16_UINT = 81, + VK_FORMAT_R16G16_SINT = 82, + VK_FORMAT_R16G16_SFLOAT = 83, + VK_FORMAT_R16G16B16_UNORM = 84, + VK_FORMAT_R16G16B16_SNORM = 85, + VK_FORMAT_R16G16B16_USCALED = 86, + VK_FORMAT_R16G16B16_SSCALED = 87, + VK_FORMAT_R16G16B16_UINT = 88, + VK_FORMAT_R16G16B16_SINT = 89, + VK_FORMAT_R16G16B16_SFLOAT = 90, + VK_FORMAT_R16G16B16A16_UNORM = 91, + VK_FORMAT_R16G16B16A16_SNORM = 92, + VK_FORMAT_R16G16B16A16_USCALED = 93, + VK_FORMAT_R16G16B16A16_SSCALED = 94, + VK_FORMAT_R16G16B16A16_UINT = 95, + VK_FORMAT_R16G16B16A16_SINT = 96, + VK_FORMAT_R16G16B16A16_SFLOAT = 97, + VK_FORMAT_R32_UINT = 98, + VK_FORMAT_R32_SINT = 99, + VK_FORMAT_R32_SFLOAT = 100, + VK_FORMAT_R32G32_UINT = 101, + VK_FORMAT_R32G32_SINT = 102, + VK_FORMAT_R32G32_SFLOAT = 103, + VK_FORMAT_R32G32B32_UINT = 104, + VK_FORMAT_R32G32B32_SINT = 105, + VK_FORMAT_R32G32B32_SFLOAT = 106, + VK_FORMAT_R32G32B32A32_UINT = 107, + VK_FORMAT_R32G32B32A32_SINT = 108, + VK_FORMAT_R32G32B32A32_SFLOAT = 109, + VK_FORMAT_R64_UINT = 110, + VK_FORMAT_R64_SINT = 111, + VK_FORMAT_R64_SFLOAT = 112, + VK_FORMAT_R64G64_UINT = 113, + VK_FORMAT_R64G64_SINT = 114, + VK_FORMAT_R64G64_SFLOAT = 115, + VK_FORMAT_R64G64B64_UINT = 116, + VK_FORMAT_R64G64B64_SINT = 117, + VK_FORMAT_R64G64B64_SFLOAT = 118, + VK_FORMAT_R64G64B64A64_UINT = 119, + VK_FORMAT_R64G64B64A64_SINT = 120, + VK_FORMAT_R64G64B64A64_SFLOAT = 121, + VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122, + VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123, + VK_FORMAT_D16_UNORM = 124, + VK_FORMAT_X8_D24_UNORM_PACK32 = 125, + VK_FORMAT_D32_SFLOAT = 126, + VK_FORMAT_S8_UINT = 127, + VK_FORMAT_D16_UNORM_S8_UINT = 128, + VK_FORMAT_D24_UNORM_S8_UINT = 129, + VK_FORMAT_D32_SFLOAT_S8_UINT = 130, + VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131, + VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132, + VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133, + VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134, + VK_FORMAT_BC2_UNORM_BLOCK = 135, + VK_FORMAT_BC2_SRGB_BLOCK = 136, + VK_FORMAT_BC3_UNORM_BLOCK = 137, + VK_FORMAT_BC3_SRGB_BLOCK = 138, + VK_FORMAT_BC4_UNORM_BLOCK = 139, + VK_FORMAT_BC4_SNORM_BLOCK = 140, + VK_FORMAT_BC5_UNORM_BLOCK = 141, + VK_FORMAT_BC5_SNORM_BLOCK = 142, + VK_FORMAT_BC6H_UFLOAT_BLOCK = 143, + VK_FORMAT_BC6H_SFLOAT_BLOCK = 144, + VK_FORMAT_BC7_UNORM_BLOCK = 145, + VK_FORMAT_BC7_SRGB_BLOCK = 146, + VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147, + VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148, + VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149, + VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150, + VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151, + VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152, + VK_FORMAT_EAC_R11_UNORM_BLOCK = 153, + VK_FORMAT_EAC_R11_SNORM_BLOCK = 154, + VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155, + VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156, + VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157, + VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158, + VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159, + VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160, + VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161, + VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162, + VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163, + VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164, + VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165, + VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166, + VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167, + VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168, + VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169, + VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170, + VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171, + VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172, + VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173, + VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174, + VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175, + VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176, + VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177, + VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178, + VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179, + VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180, + VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181, + VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182, + VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183, + VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184, + VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000, + VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001, + VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002, + VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003, + VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004, + VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005, + VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006, + VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007, + VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008, + VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009, + VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010, + VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016, + VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017, + VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018, + VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019, + VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020, + VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026, + VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027, + VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028, + VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029, + VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030, + VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031, + VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032, + VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033, + VK_FORMAT_G8_B8R8_2PLANE_444_UNORM = 1000330000, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 = 1000330001, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 = 1000330002, + VK_FORMAT_G16_B16R16_2PLANE_444_UNORM = 1000330003, + VK_FORMAT_A4R4G4B4_UNORM_PACK16 = 1000340000, + VK_FORMAT_A4B4G4R4_UNORM_PACK16 = 1000340001, + VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK = 1000066000, + VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK = 1000066001, + VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK = 1000066002, + VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK = 1000066003, + VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK = 1000066004, + VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK = 1000066005, + VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK = 1000066006, + VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK = 1000066007, + VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK = 1000066008, + VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK = 1000066009, + VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK = 1000066010, + VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK = 1000066011, + VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK = 1000066012, + VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK = 1000066013, + VK_FORMAT_A1B5G5R5_UNORM_PACK16 = 1000470000, + VK_FORMAT_A8_UNORM = 1000470001, + VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, + VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, + VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, + VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003, + VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004, + VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005, + VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006, + VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007, + VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT = 1000288000, + VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT = 1000288001, + VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT = 1000288002, + VK_FORMAT_ASTC_4x3x3_UNORM_BLOCK_EXT = 1000288003, + VK_FORMAT_ASTC_4x3x3_SRGB_BLOCK_EXT = 1000288004, + VK_FORMAT_ASTC_4x3x3_SFLOAT_BLOCK_EXT = 1000288005, + VK_FORMAT_ASTC_4x4x3_UNORM_BLOCK_EXT = 1000288006, + VK_FORMAT_ASTC_4x4x3_SRGB_BLOCK_EXT = 1000288007, + VK_FORMAT_ASTC_4x4x3_SFLOAT_BLOCK_EXT = 1000288008, + VK_FORMAT_ASTC_4x4x4_UNORM_BLOCK_EXT = 1000288009, + VK_FORMAT_ASTC_4x4x4_SRGB_BLOCK_EXT = 1000288010, + VK_FORMAT_ASTC_4x4x4_SFLOAT_BLOCK_EXT = 1000288011, + VK_FORMAT_ASTC_5x4x4_UNORM_BLOCK_EXT = 1000288012, + VK_FORMAT_ASTC_5x4x4_SRGB_BLOCK_EXT = 1000288013, + VK_FORMAT_ASTC_5x4x4_SFLOAT_BLOCK_EXT = 1000288014, + VK_FORMAT_ASTC_5x5x4_UNORM_BLOCK_EXT = 1000288015, + VK_FORMAT_ASTC_5x5x4_SRGB_BLOCK_EXT = 1000288016, + VK_FORMAT_ASTC_5x5x4_SFLOAT_BLOCK_EXT = 1000288017, + VK_FORMAT_ASTC_5x5x5_UNORM_BLOCK_EXT = 1000288018, + VK_FORMAT_ASTC_5x5x5_SRGB_BLOCK_EXT = 1000288019, + VK_FORMAT_ASTC_5x5x5_SFLOAT_BLOCK_EXT = 1000288020, + VK_FORMAT_ASTC_6x5x5_UNORM_BLOCK_EXT = 1000288021, + VK_FORMAT_ASTC_6x5x5_SRGB_BLOCK_EXT = 1000288022, + VK_FORMAT_ASTC_6x5x5_SFLOAT_BLOCK_EXT = 1000288023, + VK_FORMAT_ASTC_6x6x5_UNORM_BLOCK_EXT = 1000288024, + VK_FORMAT_ASTC_6x6x5_SRGB_BLOCK_EXT = 1000288025, + VK_FORMAT_ASTC_6x6x5_SFLOAT_BLOCK_EXT = 1000288026, + VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT = 1000288027, + VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT = 1000288028, + VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT = 1000288029, + VK_FORMAT_R8_BOOL_ARM = 1000460000, + VK_FORMAT_R16_SFLOAT_FPENCODING_BFLOAT16_ARM = 1000460001, + VK_FORMAT_R8_SFLOAT_FPENCODING_FLOAT8E4M3_ARM = 1000460002, + VK_FORMAT_R8_SFLOAT_FPENCODING_FLOAT8E5M2_ARM = 1000460003, + VK_FORMAT_R16G16_SFIXED5_NV = 1000464000, + VK_FORMAT_R10X6_UINT_PACK16_ARM = 1000609000, + VK_FORMAT_R10X6G10X6_UINT_2PACK16_ARM = 1000609001, + VK_FORMAT_R10X6G10X6B10X6A10X6_UINT_4PACK16_ARM = 1000609002, + VK_FORMAT_R12X4_UINT_PACK16_ARM = 1000609003, + VK_FORMAT_R12X4G12X4_UINT_2PACK16_ARM = 1000609004, + VK_FORMAT_R12X4G12X4B12X4A12X4_UINT_4PACK16_ARM = 1000609005, + VK_FORMAT_R14X2_UINT_PACK16_ARM = 1000609006, + VK_FORMAT_R14X2G14X2_UINT_2PACK16_ARM = 1000609007, + VK_FORMAT_R14X2G14X2B14X2A14X2_UINT_4PACK16_ARM = 1000609008, + VK_FORMAT_R14X2_UNORM_PACK16_ARM = 1000609009, + VK_FORMAT_R14X2G14X2_UNORM_2PACK16_ARM = 1000609010, + VK_FORMAT_R14X2G14X2B14X2A14X2_UNORM_4PACK16_ARM = 1000609011, + VK_FORMAT_G14X2_B14X2R14X2_2PLANE_420_UNORM_3PACK16_ARM = 1000609012, + VK_FORMAT_G14X2_B14X2R14X2_2PLANE_422_UNORM_3PACK16_ARM = 1000609013, + VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK, + VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK, + VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK, + VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK, + VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK, + VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK, + VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK, + VK_FORMAT_G8B8G8R8_422_UNORM_KHR = VK_FORMAT_G8B8G8R8_422_UNORM, + VK_FORMAT_B8G8R8G8_422_UNORM_KHR = VK_FORMAT_B8G8R8G8_422_UNORM, + VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, + VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, + VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, + VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, + VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, + VK_FORMAT_R10X6_UNORM_PACK16_KHR = VK_FORMAT_R10X6_UNORM_PACK16, + VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR = VK_FORMAT_R10X6G10X6_UNORM_2PACK16, + VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR = VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, + VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, + VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, + VK_FORMAT_R12X4_UNORM_PACK16_KHR = VK_FORMAT_R12X4_UNORM_PACK16, + VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR = VK_FORMAT_R12X4G12X4_UNORM_2PACK16, + VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR = VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, + VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, + VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16, + VK_FORMAT_G16B16G16R16_422_UNORM_KHR = VK_FORMAT_G16B16G16R16_422_UNORM, + VK_FORMAT_B16G16R16G16_422_UNORM_KHR = VK_FORMAT_B16G16R16G16_422_UNORM, + VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, + VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, + VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, + VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, + VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, + VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16, + VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT = VK_FORMAT_G16_B16R16_2PLANE_444_UNORM, + VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT = VK_FORMAT_A4R4G4B4_UNORM_PACK16, + VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT = VK_FORMAT_A4B4G4R4_UNORM_PACK16, + // VK_FORMAT_R16G16_S10_5_NV is a legacy alias + VK_FORMAT_R16G16_S10_5_NV = VK_FORMAT_R16G16_SFIXED5_NV, + VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR = VK_FORMAT_A1B5G5R5_UNORM_PACK16, + VK_FORMAT_A8_UNORM_KHR = VK_FORMAT_A8_UNORM, + VK_FORMAT_MAX_ENUM = 0x7FFFFFFF +} VkFormat; + +typedef enum VkImageTiling { + VK_IMAGE_TILING_OPTIMAL = 0, + VK_IMAGE_TILING_LINEAR = 1, + VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000, + VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF +} VkImageTiling; + +typedef enum VkImageType { + VK_IMAGE_TYPE_1D = 0, + VK_IMAGE_TYPE_2D = 1, + VK_IMAGE_TYPE_3D = 2, + VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkImageType; + +typedef enum VkPhysicalDeviceType { + VK_PHYSICAL_DEVICE_TYPE_OTHER = 0, + VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1, + VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2, + VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3, + VK_PHYSICAL_DEVICE_TYPE_CPU = 4, + VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkPhysicalDeviceType; + +typedef enum VkQueryType { + VK_QUERY_TYPE_OCCLUSION = 0, + VK_QUERY_TYPE_PIPELINE_STATISTICS = 1, + VK_QUERY_TYPE_TIMESTAMP = 2, + VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR = 1000023000, + VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004, + VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR = 1000116000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR = 1000150000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR = 1000150001, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000, + VK_QUERY_TYPE_TIME_ELAPSED_QCOM = 1000173000, + VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL = 1000210000, + VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR = 1000299000, + VK_QUERY_TYPE_MESH_PRIMITIVES_GENERATED_EXT = 1000328000, + VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT = 1000382000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR = 1000386000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR = 1000386001, + VK_QUERY_TYPE_MICROMAP_SERIALIZATION_SIZE_EXT = 1000396000, + VK_QUERY_TYPE_MICROMAP_COMPACTED_SIZE_EXT = 1000396001, + VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkQueryType; + +typedef enum VkSharingMode { + VK_SHARING_MODE_EXCLUSIVE = 0, + VK_SHARING_MODE_CONCURRENT = 1, + VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSharingMode; + +typedef enum VkImageLayout { + VK_IMAGE_LAYOUT_UNDEFINED = 0, + VK_IMAGE_LAYOUT_GENERAL = 1, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 2, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 3, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 4, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 5, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7, + VK_IMAGE_LAYOUT_PREINITIALIZED = 8, + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = 1000117000, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL = 1000241000, + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL = 1000241001, + VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL = 1000241002, + VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL = 1000241003, + VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL = 1000314000, + VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL = 1000314001, + VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ = 1000232000, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, + VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR = 1000024000, + VK_IMAGE_LAYOUT_VIDEO_DECODE_SRC_KHR = 1000024001, + VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR = 1000024002, + VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000, + VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT = 1000218000, + VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR = 1000164003, + VK_IMAGE_LAYOUT_VIDEO_ENCODE_DST_KHR = 1000299000, + VK_IMAGE_LAYOUT_VIDEO_ENCODE_SRC_KHR = 1000299001, + VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR = 1000299002, + VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT = 1000339000, + VK_IMAGE_LAYOUT_TENSOR_ALIASING_ARM = 1000460000, + VK_IMAGE_LAYOUT_VIDEO_ENCODE_QUANTIZATION_MAP_KHR = 1000553000, + VK_IMAGE_LAYOUT_ZERO_INITIALIZED_EXT = 1000620000, + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, + VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR = VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF +} VkImageLayout; + +typedef enum VkComponentSwizzle { + VK_COMPONENT_SWIZZLE_IDENTITY = 0, + VK_COMPONENT_SWIZZLE_ZERO = 1, + VK_COMPONENT_SWIZZLE_ONE = 2, + VK_COMPONENT_SWIZZLE_R = 3, + VK_COMPONENT_SWIZZLE_G = 4, + VK_COMPONENT_SWIZZLE_B = 5, + VK_COMPONENT_SWIZZLE_A = 6, + VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7FFFFFFF +} VkComponentSwizzle; + +typedef enum VkImageViewType { + VK_IMAGE_VIEW_TYPE_1D = 0, + VK_IMAGE_VIEW_TYPE_2D = 1, + VK_IMAGE_VIEW_TYPE_3D = 2, + VK_IMAGE_VIEW_TYPE_CUBE = 3, + VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4, + VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5, + VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6, + VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkImageViewType; + +typedef enum VkCommandBufferLevel { + VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0, + VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1, + VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF +} VkCommandBufferLevel; + +typedef enum VkIndexType { + VK_INDEX_TYPE_UINT16 = 0, + VK_INDEX_TYPE_UINT32 = 1, + VK_INDEX_TYPE_UINT8 = 1000265000, + VK_INDEX_TYPE_NONE_KHR = 1000165000, + VK_INDEX_TYPE_NONE_NV = VK_INDEX_TYPE_NONE_KHR, + VK_INDEX_TYPE_UINT8_EXT = VK_INDEX_TYPE_UINT8, + VK_INDEX_TYPE_UINT8_KHR = VK_INDEX_TYPE_UINT8, + VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkIndexType; + +typedef enum VkPipelineCacheHeaderVersion { + VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1, + VK_PIPELINE_CACHE_HEADER_VERSION_DATA_GRAPH_QCOM = 1000629000, + VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCacheHeaderVersion; + +typedef enum VkBorderColor { + VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0, + VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1, + VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 2, + VK_BORDER_COLOR_INT_OPAQUE_BLACK = 3, + VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4, + VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5, + VK_BORDER_COLOR_FLOAT_CUSTOM_EXT = 1000287003, + VK_BORDER_COLOR_INT_CUSTOM_EXT = 1000287004, + VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF +} VkBorderColor; + +typedef enum VkFilter { + VK_FILTER_NEAREST = 0, + VK_FILTER_LINEAR = 1, + VK_FILTER_CUBIC_EXT = 1000015000, + VK_FILTER_CUBIC_IMG = VK_FILTER_CUBIC_EXT, + VK_FILTER_MAX_ENUM = 0x7FFFFFFF +} VkFilter; + +typedef enum VkSamplerAddressMode { + VK_SAMPLER_ADDRESS_MODE_REPEAT = 0, + VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3, + VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4, + // VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE_KHR is a legacy alias + VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE_KHR = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE, + VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerAddressMode; + +typedef enum VkCompareOp { + VK_COMPARE_OP_NEVER = 0, + VK_COMPARE_OP_LESS = 1, + VK_COMPARE_OP_EQUAL = 2, + VK_COMPARE_OP_LESS_OR_EQUAL = 3, + VK_COMPARE_OP_GREATER = 4, + VK_COMPARE_OP_NOT_EQUAL = 5, + VK_COMPARE_OP_GREATER_OR_EQUAL = 6, + VK_COMPARE_OP_ALWAYS = 7, + VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF +} VkCompareOp; + +typedef enum VkSamplerMipmapMode { + VK_SAMPLER_MIPMAP_MODE_NEAREST = 0, + VK_SAMPLER_MIPMAP_MODE_LINEAR = 1, + VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerMipmapMode; + +typedef enum VkDescriptorType { + VK_DESCRIPTOR_TYPE_SAMPLER = 0, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1, + VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2, + VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 3, + VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4, + VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6, + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 7, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8, + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, + VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10, + VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK = 1000138000, + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR = 1000150000, + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, + VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM = 1000440000, + VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM = 1000440001, + VK_DESCRIPTOR_TYPE_TENSOR_ARM = 1000460000, + VK_DESCRIPTOR_TYPE_MUTABLE_EXT = 1000351000, + VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV = 1000570000, + VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, + VK_DESCRIPTOR_TYPE_MUTABLE_VALVE = VK_DESCRIPTOR_TYPE_MUTABLE_EXT, + VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorType; + +typedef enum VkPipelineBindPoint { + VK_PIPELINE_BIND_POINT_GRAPHICS = 0, + VK_PIPELINE_BIND_POINT_COMPUTE = 1, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_PIPELINE_BIND_POINT_EXECUTION_GRAPH_AMDX = 1000134000, +#endif + VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR = 1000165000, + VK_PIPELINE_BIND_POINT_SUBPASS_SHADING_HUAWEI = 1000369003, + VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM = 1000507000, + VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, + VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7FFFFFFF +} VkPipelineBindPoint; + +typedef enum VkBlendFactor { + VK_BLEND_FACTOR_ZERO = 0, + VK_BLEND_FACTOR_ONE = 1, + VK_BLEND_FACTOR_SRC_COLOR = 2, + VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3, + VK_BLEND_FACTOR_DST_COLOR = 4, + VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5, + VK_BLEND_FACTOR_SRC_ALPHA = 6, + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7, + VK_BLEND_FACTOR_DST_ALPHA = 8, + VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9, + VK_BLEND_FACTOR_CONSTANT_COLOR = 10, + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11, + VK_BLEND_FACTOR_CONSTANT_ALPHA = 12, + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13, + VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14, + VK_BLEND_FACTOR_SRC1_COLOR = 15, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16, + VK_BLEND_FACTOR_SRC1_ALPHA = 17, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18, + VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF +} VkBlendFactor; + +typedef enum VkBlendOp { + VK_BLEND_OP_ADD = 0, + VK_BLEND_OP_SUBTRACT = 1, + VK_BLEND_OP_REVERSE_SUBTRACT = 2, + VK_BLEND_OP_MIN = 3, + VK_BLEND_OP_MAX = 4, + VK_BLEND_OP_ZERO_EXT = 1000148000, + VK_BLEND_OP_SRC_EXT = 1000148001, + VK_BLEND_OP_DST_EXT = 1000148002, + VK_BLEND_OP_SRC_OVER_EXT = 1000148003, + VK_BLEND_OP_DST_OVER_EXT = 1000148004, + VK_BLEND_OP_SRC_IN_EXT = 1000148005, + VK_BLEND_OP_DST_IN_EXT = 1000148006, + VK_BLEND_OP_SRC_OUT_EXT = 1000148007, + VK_BLEND_OP_DST_OUT_EXT = 1000148008, + VK_BLEND_OP_SRC_ATOP_EXT = 1000148009, + VK_BLEND_OP_DST_ATOP_EXT = 1000148010, + VK_BLEND_OP_XOR_EXT = 1000148011, + VK_BLEND_OP_MULTIPLY_EXT = 1000148012, + VK_BLEND_OP_SCREEN_EXT = 1000148013, + VK_BLEND_OP_OVERLAY_EXT = 1000148014, + VK_BLEND_OP_DARKEN_EXT = 1000148015, + VK_BLEND_OP_LIGHTEN_EXT = 1000148016, + VK_BLEND_OP_COLORDODGE_EXT = 1000148017, + VK_BLEND_OP_COLORBURN_EXT = 1000148018, + VK_BLEND_OP_HARDLIGHT_EXT = 1000148019, + VK_BLEND_OP_SOFTLIGHT_EXT = 1000148020, + VK_BLEND_OP_DIFFERENCE_EXT = 1000148021, + VK_BLEND_OP_EXCLUSION_EXT = 1000148022, + VK_BLEND_OP_INVERT_EXT = 1000148023, + VK_BLEND_OP_INVERT_RGB_EXT = 1000148024, + VK_BLEND_OP_LINEARDODGE_EXT = 1000148025, + VK_BLEND_OP_LINEARBURN_EXT = 1000148026, + VK_BLEND_OP_VIVIDLIGHT_EXT = 1000148027, + VK_BLEND_OP_LINEARLIGHT_EXT = 1000148028, + VK_BLEND_OP_PINLIGHT_EXT = 1000148029, + VK_BLEND_OP_HARDMIX_EXT = 1000148030, + VK_BLEND_OP_HSL_HUE_EXT = 1000148031, + VK_BLEND_OP_HSL_SATURATION_EXT = 1000148032, + VK_BLEND_OP_HSL_COLOR_EXT = 1000148033, + VK_BLEND_OP_HSL_LUMINOSITY_EXT = 1000148034, + VK_BLEND_OP_PLUS_EXT = 1000148035, + VK_BLEND_OP_PLUS_CLAMPED_EXT = 1000148036, + VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT = 1000148037, + VK_BLEND_OP_PLUS_DARKER_EXT = 1000148038, + VK_BLEND_OP_MINUS_EXT = 1000148039, + VK_BLEND_OP_MINUS_CLAMPED_EXT = 1000148040, + VK_BLEND_OP_CONTRAST_EXT = 1000148041, + VK_BLEND_OP_INVERT_OVG_EXT = 1000148042, + VK_BLEND_OP_RED_EXT = 1000148043, + VK_BLEND_OP_GREEN_EXT = 1000148044, + VK_BLEND_OP_BLUE_EXT = 1000148045, + VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF +} VkBlendOp; + +typedef enum VkDynamicState { + VK_DYNAMIC_STATE_VIEWPORT = 0, + VK_DYNAMIC_STATE_SCISSOR = 1, + VK_DYNAMIC_STATE_LINE_WIDTH = 2, + VK_DYNAMIC_STATE_DEPTH_BIAS = 3, + VK_DYNAMIC_STATE_BLEND_CONSTANTS = 4, + VK_DYNAMIC_STATE_DEPTH_BOUNDS = 5, + VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6, + VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7, + VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8, + VK_DYNAMIC_STATE_CULL_MODE = 1000267000, + VK_DYNAMIC_STATE_FRONT_FACE = 1000267001, + VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY = 1000267002, + VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT = 1000267003, + VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT = 1000267004, + VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE = 1000267005, + VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE = 1000267006, + VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE = 1000267007, + VK_DYNAMIC_STATE_DEPTH_COMPARE_OP = 1000267008, + VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE = 1000267009, + VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE = 1000267010, + VK_DYNAMIC_STATE_STENCIL_OP = 1000267011, + VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE = 1000377001, + VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE = 1000377002, + VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE = 1000377004, + VK_DYNAMIC_STATE_LINE_STIPPLE = 1000259000, + VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000, + VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000, + VK_DYNAMIC_STATE_DISCARD_RECTANGLE_ENABLE_EXT = 1000099001, + VK_DYNAMIC_STATE_DISCARD_RECTANGLE_MODE_EXT = 1000099002, + VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT = 1000143000, + VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR = 1000347000, + VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV = 1000164004, + VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV = 1000164006, + VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_ENABLE_NV = 1000205000, + VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV = 1000205001, + VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR = 1000226000, + VK_DYNAMIC_STATE_VERTEX_INPUT_EXT = 1000352000, + VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT = 1000377000, + VK_DYNAMIC_STATE_LOGIC_OP_EXT = 1000377003, + VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT = 1000381000, + VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT = 1000455003, + VK_DYNAMIC_STATE_POLYGON_MODE_EXT = 1000455004, + VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT = 1000455005, + VK_DYNAMIC_STATE_SAMPLE_MASK_EXT = 1000455006, + VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT = 1000455007, + VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT = 1000455008, + VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT = 1000455009, + VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT = 1000455010, + VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT = 1000455011, + VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT = 1000455012, + VK_DYNAMIC_STATE_TESSELLATION_DOMAIN_ORIGIN_EXT = 1000455002, + VK_DYNAMIC_STATE_RASTERIZATION_STREAM_EXT = 1000455013, + VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT = 1000455014, + VK_DYNAMIC_STATE_EXTRA_PRIMITIVE_OVERESTIMATION_SIZE_EXT = 1000455015, + VK_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT = 1000455016, + VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_ENABLE_EXT = 1000455017, + VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT = 1000455018, + VK_DYNAMIC_STATE_PROVOKING_VERTEX_MODE_EXT = 1000455019, + VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT = 1000455020, + VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT = 1000455021, + VK_DYNAMIC_STATE_DEPTH_CLIP_NEGATIVE_ONE_TO_ONE_EXT = 1000455022, + VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_ENABLE_NV = 1000455023, + VK_DYNAMIC_STATE_VIEWPORT_SWIZZLE_NV = 1000455024, + VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_ENABLE_NV = 1000455025, + VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_LOCATION_NV = 1000455026, + VK_DYNAMIC_STATE_COVERAGE_MODULATION_MODE_NV = 1000455027, + VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_ENABLE_NV = 1000455028, + VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_NV = 1000455029, + VK_DYNAMIC_STATE_SHADING_RATE_IMAGE_ENABLE_NV = 1000455030, + VK_DYNAMIC_STATE_REPRESENTATIVE_FRAGMENT_TEST_ENABLE_NV = 1000455031, + VK_DYNAMIC_STATE_COVERAGE_REDUCTION_MODE_NV = 1000455032, + VK_DYNAMIC_STATE_ATTACHMENT_FEEDBACK_LOOP_ENABLE_EXT = 1000524000, + VK_DYNAMIC_STATE_DEPTH_CLAMP_RANGE_EXT = 1000582000, + VK_DYNAMIC_STATE_LINE_STIPPLE_EXT = VK_DYNAMIC_STATE_LINE_STIPPLE, + VK_DYNAMIC_STATE_CULL_MODE_EXT = VK_DYNAMIC_STATE_CULL_MODE, + VK_DYNAMIC_STATE_FRONT_FACE_EXT = VK_DYNAMIC_STATE_FRONT_FACE, + VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT = VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY, + VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT = VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT, + VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT = VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT, + VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT = VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE, + VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE, + VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE, + VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT = VK_DYNAMIC_STATE_DEPTH_COMPARE_OP, + VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE, + VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE, + VK_DYNAMIC_STATE_STENCIL_OP_EXT = VK_DYNAMIC_STATE_STENCIL_OP, + VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT = VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE, + VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE, + VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT = VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE, + VK_DYNAMIC_STATE_LINE_STIPPLE_KHR = VK_DYNAMIC_STATE_LINE_STIPPLE, + VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF +} VkDynamicState; + +typedef enum VkFrontFace { + VK_FRONT_FACE_COUNTER_CLOCKWISE = 0, + VK_FRONT_FACE_CLOCKWISE = 1, + VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF +} VkFrontFace; + +typedef enum VkLogicOp { + VK_LOGIC_OP_CLEAR = 0, + VK_LOGIC_OP_AND = 1, + VK_LOGIC_OP_AND_REVERSE = 2, + VK_LOGIC_OP_COPY = 3, + VK_LOGIC_OP_AND_INVERTED = 4, + VK_LOGIC_OP_NO_OP = 5, + VK_LOGIC_OP_XOR = 6, + VK_LOGIC_OP_OR = 7, + VK_LOGIC_OP_NOR = 8, + VK_LOGIC_OP_EQUIVALENT = 9, + VK_LOGIC_OP_INVERT = 10, + VK_LOGIC_OP_OR_REVERSE = 11, + VK_LOGIC_OP_COPY_INVERTED = 12, + VK_LOGIC_OP_OR_INVERTED = 13, + VK_LOGIC_OP_NAND = 14, + VK_LOGIC_OP_SET = 15, + VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF +} VkLogicOp; + +typedef enum VkStencilOp { + VK_STENCIL_OP_KEEP = 0, + VK_STENCIL_OP_ZERO = 1, + VK_STENCIL_OP_REPLACE = 2, + VK_STENCIL_OP_INCREMENT_AND_CLAMP = 3, + VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4, + VK_STENCIL_OP_INVERT = 5, + VK_STENCIL_OP_INCREMENT_AND_WRAP = 6, + VK_STENCIL_OP_DECREMENT_AND_WRAP = 7, + VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF +} VkStencilOp; + +typedef enum VkVertexInputRate { + VK_VERTEX_INPUT_RATE_VERTEX = 0, + VK_VERTEX_INPUT_RATE_INSTANCE = 1, + VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7FFFFFFF +} VkVertexInputRate; + +typedef enum VkPrimitiveTopology { + VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1, + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 2, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 6, + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9, + VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10, + VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF +} VkPrimitiveTopology; + +typedef enum VkPolygonMode { + VK_POLYGON_MODE_FILL = 0, + VK_POLYGON_MODE_LINE = 1, + VK_POLYGON_MODE_POINT = 2, + VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000, + VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF +} VkPolygonMode; + +typedef enum VkAttachmentLoadOp { + VK_ATTACHMENT_LOAD_OP_LOAD = 0, + VK_ATTACHMENT_LOAD_OP_CLEAR = 1, + VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2, + VK_ATTACHMENT_LOAD_OP_NONE = 1000400000, + VK_ATTACHMENT_LOAD_OP_NONE_EXT = VK_ATTACHMENT_LOAD_OP_NONE, + VK_ATTACHMENT_LOAD_OP_NONE_KHR = VK_ATTACHMENT_LOAD_OP_NONE, + VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF +} VkAttachmentLoadOp; + +typedef enum VkAttachmentStoreOp { + VK_ATTACHMENT_STORE_OP_STORE = 0, + VK_ATTACHMENT_STORE_OP_DONT_CARE = 1, + VK_ATTACHMENT_STORE_OP_NONE = 1000301000, + VK_ATTACHMENT_STORE_OP_NONE_KHR = VK_ATTACHMENT_STORE_OP_NONE, + VK_ATTACHMENT_STORE_OP_NONE_QCOM = VK_ATTACHMENT_STORE_OP_NONE, + VK_ATTACHMENT_STORE_OP_NONE_EXT = VK_ATTACHMENT_STORE_OP_NONE, + VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF +} VkAttachmentStoreOp; + +typedef enum VkSubpassContents { + VK_SUBPASS_CONTENTS_INLINE = 0, + VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1, + VK_SUBPASS_CONTENTS_INLINE_AND_SECONDARY_COMMAND_BUFFERS_KHR = 1000451000, + VK_SUBPASS_CONTENTS_INLINE_AND_SECONDARY_COMMAND_BUFFERS_EXT = VK_SUBPASS_CONTENTS_INLINE_AND_SECONDARY_COMMAND_BUFFERS_KHR, + VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF +} VkSubpassContents; + +typedef enum VkFormatFeatureFlagBits { + VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001, + VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002, + VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004, + VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008, + VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010, + VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020, + VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040, + VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080, + VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200, + VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400, + VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000, + VK_FORMAT_FEATURE_TRANSFER_SRC_BIT = 0x00004000, + VK_FORMAT_FEATURE_TRANSFER_DST_BIT = 0x00008000, + VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000, + VK_FORMAT_FEATURE_DISJOINT_BIT = 0x00400000, + VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 0x00800000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT = 0x00010000, + VK_FORMAT_FEATURE_VIDEO_DECODE_OUTPUT_BIT_KHR = 0x02000000, + VK_FORMAT_FEATURE_VIDEO_DECODE_DPB_BIT_KHR = 0x04000000, + VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR = 0x20000000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = 0x00002000, + VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x01000000, + VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x40000000, + VK_FORMAT_FEATURE_VIDEO_ENCODE_INPUT_BIT_KHR = 0x08000000, + VK_FORMAT_FEATURE_VIDEO_ENCODE_DPB_BIT_KHR = 0x10000000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT, + VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, + VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_DST_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT, + VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT, + VK_FORMAT_FEATURE_DISJOINT_BIT_KHR = VK_FORMAT_FEATURE_DISJOINT_BIT, + VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT, + VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFormatFeatureFlagBits; +typedef VkFlags VkFormatFeatureFlags; + +typedef enum VkImageCreateFlagBits { + VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 0x00000001, + VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, + VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004, + VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, + VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, + VK_IMAGE_CREATE_ALIAS_BIT = 0x00000400, + VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT = 0x00000040, + VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT = 0x00000020, + VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT = 0x00000080, + VK_IMAGE_CREATE_EXTENDED_USAGE_BIT = 0x00000100, + VK_IMAGE_CREATE_PROTECTED_BIT = 0x00000800, + VK_IMAGE_CREATE_DISJOINT_BIT = 0x00000200, + VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV = 0x00002000, + VK_IMAGE_CREATE_DESCRIPTOR_HEAP_CAPTURE_REPLAY_BIT_EXT = 0x00010000, + VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000, + VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT = 0x00004000, + VK_IMAGE_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT = 0x00040000, + VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT = 0x00020000, + VK_IMAGE_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR = 0x00100000, + VK_IMAGE_CREATE_FRAGMENT_DENSITY_MAP_OFFSET_BIT_EXT = 0x00008000, + VK_IMAGE_CREATE_ALIAS_SINGLE_LAYER_DESCRIPTOR_BIT_KHR = 0x00400000, + VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT, + VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT, + VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT, + VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR = VK_IMAGE_CREATE_EXTENDED_USAGE_BIT, + VK_IMAGE_CREATE_DISJOINT_BIT_KHR = VK_IMAGE_CREATE_DISJOINT_BIT, + VK_IMAGE_CREATE_ALIAS_BIT_KHR = VK_IMAGE_CREATE_ALIAS_BIT, + VK_IMAGE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = VK_IMAGE_CREATE_DESCRIPTOR_HEAP_CAPTURE_REPLAY_BIT_EXT, + VK_IMAGE_CREATE_FRAGMENT_DENSITY_MAP_OFFSET_BIT_QCOM = VK_IMAGE_CREATE_FRAGMENT_DENSITY_MAP_OFFSET_BIT_EXT, + VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageCreateFlagBits; +typedef VkFlags VkImageCreateFlags; + +typedef enum VkSampleCountFlagBits { + VK_SAMPLE_COUNT_1_BIT = 0x00000001, + VK_SAMPLE_COUNT_2_BIT = 0x00000002, + VK_SAMPLE_COUNT_4_BIT = 0x00000004, + VK_SAMPLE_COUNT_8_BIT = 0x00000008, + VK_SAMPLE_COUNT_16_BIT = 0x00000010, + VK_SAMPLE_COUNT_32_BIT = 0x00000020, + VK_SAMPLE_COUNT_64_BIT = 0x00000040, + VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSampleCountFlagBits; +typedef VkFlags VkSampleCountFlags; + +typedef enum VkImageUsageFlagBits { + VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001, + VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002, + VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004, + VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020, + VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040, + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080, + VK_IMAGE_USAGE_HOST_TRANSFER_BIT = 0x00400000, + VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR = 0x00000400, + VK_IMAGE_USAGE_VIDEO_DECODE_SRC_BIT_KHR = 0x00000800, + VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR = 0x00001000, + VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x00000200, + VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00000100, + VK_IMAGE_USAGE_VIDEO_ENCODE_DST_BIT_KHR = 0x00002000, + VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR = 0x00004000, + VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR = 0x00008000, + VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x00080000, + VK_IMAGE_USAGE_INVOCATION_MASK_BIT_HUAWEI = 0x00040000, + VK_IMAGE_USAGE_SAMPLE_WEIGHT_BIT_QCOM = 0x00100000, + VK_IMAGE_USAGE_SAMPLE_BLOCK_MATCH_BIT_QCOM = 0x00200000, + VK_IMAGE_USAGE_TENSOR_ALIASING_BIT_ARM = 0x00800000, + VK_IMAGE_USAGE_TILE_MEMORY_BIT_QCOM = 0x08000000, + VK_IMAGE_USAGE_VIDEO_ENCODE_QUANTIZATION_DELTA_MAP_BIT_KHR = 0x02000000, + VK_IMAGE_USAGE_VIDEO_ENCODE_EMPHASIS_MAP_BIT_KHR = 0x04000000, + VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV = VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, + VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT = VK_IMAGE_USAGE_HOST_TRANSFER_BIT, + VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageUsageFlagBits; +typedef VkFlags VkImageUsageFlags; + +typedef enum VkInstanceCreateFlagBits { + VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR = 0x00000001, + VK_INSTANCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkInstanceCreateFlagBits; +typedef VkFlags VkInstanceCreateFlags; + +typedef enum VkMemoryHeapFlagBits { + VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001, + VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 0x00000002, + VK_MEMORY_HEAP_TILE_MEMORY_BIT_QCOM = 0x00000008, + VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT, + VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryHeapFlagBits; +typedef VkFlags VkMemoryHeapFlags; + +typedef enum VkMemoryPropertyFlagBits { + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002, + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008, + VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010, + VK_MEMORY_PROPERTY_PROTECTED_BIT = 0x00000020, + VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD = 0x00000040, + VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD = 0x00000080, + VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV = 0x00000100, + VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryPropertyFlagBits; +typedef VkFlags VkMemoryPropertyFlags; + +typedef enum VkQueueFlagBits { + VK_QUEUE_GRAPHICS_BIT = 0x00000001, + VK_QUEUE_COMPUTE_BIT = 0x00000002, + VK_QUEUE_TRANSFER_BIT = 0x00000004, + VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, + VK_QUEUE_PROTECTED_BIT = 0x00000010, + VK_QUEUE_VIDEO_DECODE_BIT_KHR = 0x00000020, + VK_QUEUE_VIDEO_ENCODE_BIT_KHR = 0x00000040, + VK_QUEUE_OPTICAL_FLOW_BIT_NV = 0x00000100, + VK_QUEUE_DATA_GRAPH_BIT_ARM = 0x00000400, + VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueueFlagBits; +typedef VkFlags VkQueueFlags; + +typedef enum VkShaderStageFlagBits { + VK_SHADER_STAGE_VERTEX_BIT = 0x00000001, + VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002, + VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004, + VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008, + VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010, + VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020, + VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, + VK_SHADER_STAGE_ALL = 0x7FFFFFFF, + VK_SHADER_STAGE_RAYGEN_BIT_KHR = 0x00000100, + VK_SHADER_STAGE_ANY_HIT_BIT_KHR = 0x00000200, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR = 0x00000400, + VK_SHADER_STAGE_MISS_BIT_KHR = 0x00000800, + VK_SHADER_STAGE_INTERSECTION_BIT_KHR = 0x00001000, + VK_SHADER_STAGE_CALLABLE_BIT_KHR = 0x00002000, + VK_SHADER_STAGE_TASK_BIT_EXT = 0x00000040, + VK_SHADER_STAGE_MESH_BIT_EXT = 0x00000080, + VK_SHADER_STAGE_SUBPASS_SHADING_BIT_HUAWEI = 0x00004000, + VK_SHADER_STAGE_CLUSTER_CULLING_BIT_HUAWEI = 0x00080000, + VK_SHADER_STAGE_RAYGEN_BIT_NV = VK_SHADER_STAGE_RAYGEN_BIT_KHR, + VK_SHADER_STAGE_ANY_HIT_BIT_NV = VK_SHADER_STAGE_ANY_HIT_BIT_KHR, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, + VK_SHADER_STAGE_MISS_BIT_NV = VK_SHADER_STAGE_MISS_BIT_KHR, + VK_SHADER_STAGE_INTERSECTION_BIT_NV = VK_SHADER_STAGE_INTERSECTION_BIT_KHR, + VK_SHADER_STAGE_CALLABLE_BIT_NV = VK_SHADER_STAGE_CALLABLE_BIT_KHR, + VK_SHADER_STAGE_TASK_BIT_NV = VK_SHADER_STAGE_TASK_BIT_EXT, + VK_SHADER_STAGE_MESH_BIT_NV = VK_SHADER_STAGE_MESH_BIT_EXT, + VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkShaderStageFlagBits; +typedef VkFlags VkShaderStageFlags; +typedef VkFlags VkDeviceCreateFlags; + +typedef enum VkDeviceQueueCreateFlagBits { + VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 0x00000001, + VK_DEVICE_QUEUE_CREATE_INTERNALLY_SYNCHRONIZED_BIT_KHR = 0x00000004, + VK_DEVICE_QUEUE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDeviceQueueCreateFlagBits; +typedef VkFlags VkDeviceQueueCreateFlags; + +typedef enum VkPipelineStageFlagBits { + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001, + VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004, + VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008, + VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010, + VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020, + VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100, + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800, + VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000, + VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, + VK_PIPELINE_STAGE_NONE = 0, + VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000, + VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 0x02000000, + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR = 0x00200000, + VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000, + VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00400000, + VK_PIPELINE_STAGE_TASK_SHADER_BIT_EXT = 0x00080000, + VK_PIPELINE_STAGE_MESH_SHADER_BIT_EXT = 0x00100000, + VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_EXT = 0x00020000, + VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, + VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = VK_PIPELINE_STAGE_TASK_SHADER_BIT_EXT, + VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = VK_PIPELINE_STAGE_MESH_SHADER_BIT_EXT, + VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV = VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_EXT, + VK_PIPELINE_STAGE_NONE_KHR = VK_PIPELINE_STAGE_NONE, + VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineStageFlagBits; +typedef VkFlags VkPipelineStageFlags; + +typedef enum VkMemoryMapFlagBits { + VK_MEMORY_MAP_PLACED_BIT_EXT = 0x00000001, + VK_MEMORY_MAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryMapFlagBits; +typedef VkFlags VkMemoryMapFlags; + +typedef enum VkImageAspectFlagBits { + VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001, + VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002, + VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004, + VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008, + VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010, + VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020, + VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040, + VK_IMAGE_ASPECT_NONE = 0, + VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 0x00000080, + VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 0x00000100, + VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 0x00000200, + VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 0x00000400, + VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = VK_IMAGE_ASPECT_PLANE_0_BIT, + VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = VK_IMAGE_ASPECT_PLANE_1_BIT, + VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = VK_IMAGE_ASPECT_PLANE_2_BIT, + VK_IMAGE_ASPECT_NONE_KHR = VK_IMAGE_ASPECT_NONE, + VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageAspectFlagBits; +typedef VkFlags VkImageAspectFlags; + +typedef enum VkSparseImageFormatFlagBits { + VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001, + VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002, + VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004, + VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSparseImageFormatFlagBits; +typedef VkFlags VkSparseImageFormatFlags; + +typedef enum VkSparseMemoryBindFlagBits { + VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001, + VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSparseMemoryBindFlagBits; +typedef VkFlags VkSparseMemoryBindFlags; + +typedef enum VkFenceCreateFlagBits { + VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001, + VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFenceCreateFlagBits; +typedef VkFlags VkFenceCreateFlags; +typedef VkFlags VkSemaphoreCreateFlags; + +typedef enum VkQueryPoolCreateFlagBits { + VK_QUERY_POOL_CREATE_RESET_BIT_KHR = 0x00000001, + VK_QUERY_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueryPoolCreateFlagBits; +typedef VkFlags VkQueryPoolCreateFlags; + +typedef enum VkQueryPipelineStatisticFlagBits { + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 0x00000001, + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 0x00000002, + VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 0x00000004, + VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 0x00000008, + VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 0x00000010, + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 0x00000020, + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 0x00000040, + VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 0x00000080, + VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100, + VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200, + VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400, + VK_QUERY_PIPELINE_STATISTIC_TASK_SHADER_INVOCATIONS_BIT_EXT = 0x00000800, + VK_QUERY_PIPELINE_STATISTIC_MESH_SHADER_INVOCATIONS_BIT_EXT = 0x00001000, + VK_QUERY_PIPELINE_STATISTIC_CLUSTER_CULLING_SHADER_INVOCATIONS_BIT_HUAWEI = 0x00002000, + VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueryPipelineStatisticFlagBits; +typedef VkFlags VkQueryPipelineStatisticFlags; + +typedef enum VkQueryResultFlagBits { + VK_QUERY_RESULT_64_BIT = 0x00000001, + VK_QUERY_RESULT_WAIT_BIT = 0x00000002, + VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004, + VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008, + VK_QUERY_RESULT_WITH_STATUS_BIT_KHR = 0x00000010, + VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueryResultFlagBits; +typedef VkFlags VkQueryResultFlags; + +typedef enum VkBufferCreateFlagBits { + VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, + VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, + VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, + VK_BUFFER_CREATE_PROTECTED_BIT = 0x00000008, + VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 0x00000010, + VK_BUFFER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 0x00000020, + VK_BUFFER_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR = 0x00000040, + VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, + VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, + VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkBufferCreateFlagBits; +typedef VkFlags VkBufferCreateFlags; + +typedef enum VkBufferUsageFlagBits { + VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001, + VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002, + VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004, + VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, + VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT = 0x00020000, + VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR = 0x00002000, + VK_BUFFER_USAGE_VIDEO_DECODE_DST_BIT_KHR = 0x00004000, + VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800, + VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000, + VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_BUFFER_USAGE_EXECUTION_GRAPH_SCRATCH_BIT_AMDX = 0x02000000, +#endif + VK_BUFFER_USAGE_DESCRIPTOR_HEAP_BIT_EXT = 0x10000000, + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR = 0x00080000, + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR = 0x00100000, + VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR = 0x00000400, + VK_BUFFER_USAGE_VIDEO_ENCODE_DST_BIT_KHR = 0x00008000, + VK_BUFFER_USAGE_VIDEO_ENCODE_SRC_BIT_KHR = 0x00010000, + VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT = 0x00200000, + VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT = 0x00400000, + VK_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT = 0x04000000, + VK_BUFFER_USAGE_MICROMAP_BUILD_INPUT_READ_ONLY_BIT_EXT = 0x00800000, + VK_BUFFER_USAGE_MICROMAP_STORAGE_BIT_EXT = 0x01000000, + VK_BUFFER_USAGE_TILE_MEMORY_BIT_QCOM = 0x08000000, + VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkBufferUsageFlagBits; +typedef VkFlags VkBufferUsageFlags; + +typedef enum VkImageViewCreateFlagBits { + VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT = 0x00000001, + VK_IMAGE_VIEW_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 0x00000004, + VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT = 0x00000002, + VK_IMAGE_VIEW_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageViewCreateFlagBits; +typedef VkFlags VkImageViewCreateFlags; + +typedef enum VkAccessFlagBits { + VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001, + VK_ACCESS_INDEX_READ_BIT = 0x00000002, + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004, + VK_ACCESS_UNIFORM_READ_BIT = 0x00000008, + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010, + VK_ACCESS_SHADER_READ_BIT = 0x00000020, + VK_ACCESS_SHADER_WRITE_BIT = 0x00000040, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400, + VK_ACCESS_TRANSFER_READ_BIT = 0x00000800, + VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000, + VK_ACCESS_HOST_READ_BIT = 0x00002000, + VK_ACCESS_HOST_WRITE_BIT = 0x00004000, + VK_ACCESS_MEMORY_READ_BIT = 0x00008000, + VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000, + VK_ACCESS_NONE = 0, + VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000, + VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000, + VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000, + VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000, + VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000, + VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR = 0x00200000, + VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR = 0x00400000, + VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000, + VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR = 0x00800000, + VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_EXT = 0x00020000, + VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_EXT = 0x00040000, + VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR, + VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, + VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, + VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_NV = VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_EXT, + VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV = VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_EXT, + VK_ACCESS_NONE_KHR = VK_ACCESS_NONE, + VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkAccessFlagBits; +typedef VkFlags VkAccessFlags; + +typedef enum VkDependencyFlagBits { + VK_DEPENDENCY_BY_REGION_BIT = 0x00000001, + VK_DEPENDENCY_DEVICE_GROUP_BIT = 0x00000004, + VK_DEPENDENCY_VIEW_LOCAL_BIT = 0x00000002, + VK_DEPENDENCY_FEEDBACK_LOOP_BIT_EXT = 0x00000008, + VK_DEPENDENCY_QUEUE_FAMILY_OWNERSHIP_TRANSFER_USE_ALL_STAGES_BIT_KHR = 0x00000020, + VK_DEPENDENCY_ASYMMETRIC_EVENT_BIT_KHR = 0x00000040, + VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR = VK_DEPENDENCY_VIEW_LOCAL_BIT, + VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR = VK_DEPENDENCY_DEVICE_GROUP_BIT, + VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDependencyFlagBits; +typedef VkFlags VkDependencyFlags; + +typedef enum VkCommandPoolCreateFlagBits { + VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, + VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, + VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 0x00000004, + VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandPoolCreateFlagBits; +typedef VkFlags VkCommandPoolCreateFlags; + +typedef enum VkCommandPoolResetFlagBits { + VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001, + VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandPoolResetFlagBits; +typedef VkFlags VkCommandPoolResetFlags; + +typedef enum VkQueryControlFlagBits { + VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001, + VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueryControlFlagBits; +typedef VkFlags VkQueryControlFlags; + +typedef enum VkCommandBufferUsageFlagBits { + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001, + VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002, + VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004, + VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandBufferUsageFlagBits; +typedef VkFlags VkCommandBufferUsageFlags; + +typedef enum VkCommandBufferResetFlagBits { + VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001, + VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandBufferResetFlagBits; +typedef VkFlags VkCommandBufferResetFlags; + +typedef enum VkEventCreateFlagBits { + VK_EVENT_CREATE_DEVICE_ONLY_BIT = 0x00000001, + VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR = VK_EVENT_CREATE_DEVICE_ONLY_BIT, + VK_EVENT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkEventCreateFlagBits; +typedef VkFlags VkEventCreateFlags; +typedef VkFlags VkBufferViewCreateFlags; +typedef VkFlags VkShaderModuleCreateFlags; + +typedef enum VkPipelineCacheCreateFlagBits { + VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 0x00000001, + VK_PIPELINE_CACHE_CREATE_INTERNALLY_SYNCHRONIZED_MERGE_BIT_KHR = 0x00000008, + VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT = VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT, + VK_PIPELINE_CACHE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCacheCreateFlagBits; +typedef VkFlags VkPipelineCacheCreateFlags; + +typedef enum VkPipelineCreateFlagBits { + VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001, + VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002, + VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, + VK_PIPELINE_CREATE_DISPATCH_BASE_BIT = 0x00000010, + VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008, + VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT = 0x00000100, + VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT = 0x00000200, + VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT = 0x08000000, + VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT = 0x40000000, + VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR = 0x00004000, + VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR = 0x00008000, + VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR = 0x00010000, + VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR = 0x00020000, + VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR = 0x00001000, + VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR = 0x00002000, + VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR = 0x00080000, + VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 0x00000020, + VK_PIPELINE_CREATE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 0x00400000, + VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00200000, + VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR = 0x00000040, + VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR = 0x00000080, + VK_PIPELINE_CREATE_INDIRECT_BINDABLE_BIT_NV = 0x00040000, + VK_PIPELINE_CREATE_LIBRARY_BIT_KHR = 0x00000800, + VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT = 0x20000000, + VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT = 0x00800000, + VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT = 0x00000400, + VK_PIPELINE_CREATE_RAY_TRACING_ALLOW_MOTION_BIT_NV = 0x00100000, + VK_PIPELINE_CREATE_COLOR_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x02000000, + VK_PIPELINE_CREATE_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x04000000, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_PIPELINE_CREATE_RAY_TRACING_DISPLACEMENT_MICROMAP_BIT_NV = 0x10000000, +#endif + VK_PIPELINE_CREATE_RAY_TRACING_OPACITY_MICROMAP_BIT_KHR = 0x01000000, + // VK_PIPELINE_CREATE_DISPATCH_BASE is a legacy alias + VK_PIPELINE_CREATE_DISPATCH_BASE = VK_PIPELINE_CREATE_DISPATCH_BASE_BIT, + VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT, + VK_PIPELINE_CREATE_DISPATCH_BASE_BIT_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE_BIT, + // VK_PIPELINE_CREATE_DISPATCH_BASE_KHR is a legacy alias + VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE_BIT, + // VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT is a legacy alias + VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = VK_PIPELINE_CREATE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT, + // VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR is a legacy alias + VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, + VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT = VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT, + VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT = VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT, + VK_PIPELINE_CREATE_RAY_TRACING_OPACITY_MICROMAP_BIT_EXT = VK_PIPELINE_CREATE_RAY_TRACING_OPACITY_MICROMAP_BIT_KHR, + VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT_EXT = VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT, + VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT_EXT = VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT, + VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCreateFlagBits; +typedef VkFlags VkPipelineCreateFlags; + +typedef enum VkPipelineLayoutCreateFlagBits { + VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT = 0x00000002, + VK_PIPELINE_LAYOUT_CREATE_NO_TASK_SHADER_BIT_KHR = 0x00000004, + VK_PIPELINE_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineLayoutCreateFlagBits; +typedef VkFlags VkPipelineLayoutCreateFlags; + +typedef enum VkPipelineShaderStageCreateFlagBits { + VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT = 0x00000001, + VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT = 0x00000002, + VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT = VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT, + VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT = VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT, + VK_PIPELINE_SHADER_STAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineShaderStageCreateFlagBits; +typedef VkFlags VkPipelineShaderStageCreateFlags; + +typedef enum VkSamplerCreateFlagBits { + VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT = 0x00000001, + VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT = 0x00000002, + VK_SAMPLER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 0x00000008, + VK_SAMPLER_CREATE_NON_SEAMLESS_CUBE_MAP_BIT_EXT = 0x00000004, + VK_SAMPLER_CREATE_IMAGE_PROCESSING_BIT_QCOM = 0x00000010, + VK_SAMPLER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSamplerCreateFlagBits; +typedef VkFlags VkSamplerCreateFlags; + +typedef enum VkDescriptorPoolCreateFlagBits { + VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001, + VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT = 0x00000002, + VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT = 0x00000004, + VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_SETS_BIT_NV = 0x00000008, + VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_POOLS_BIT_NV = 0x00000010, + VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT, + VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE = VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT, + VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorPoolCreateFlagBits; +typedef VkFlags VkDescriptorPoolCreateFlags; +typedef VkFlags VkDescriptorPoolResetFlags; + +typedef enum VkDescriptorSetLayoutCreateFlagBits { + VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT = 0x00000002, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT = 0x00000001, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT = 0x00000010, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_EMBEDDED_IMMUTABLE_SAMPLERS_BIT_EXT = 0x00000020, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_INDIRECT_BINDABLE_BIT_NV = 0x00000080, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT = 0x00000004, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_PER_STAGE_BIT_NV = 0x00000040, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE = VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorSetLayoutCreateFlagBits; +typedef VkFlags VkDescriptorSetLayoutCreateFlags; + +typedef enum VkColorComponentFlagBits { + VK_COLOR_COMPONENT_R_BIT = 0x00000001, + VK_COLOR_COMPONENT_G_BIT = 0x00000002, + VK_COLOR_COMPONENT_B_BIT = 0x00000004, + VK_COLOR_COMPONENT_A_BIT = 0x00000008, + VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkColorComponentFlagBits; +typedef VkFlags VkColorComponentFlags; + +typedef enum VkCullModeFlagBits { + VK_CULL_MODE_NONE = 0, + VK_CULL_MODE_FRONT_BIT = 0x00000001, + VK_CULL_MODE_BACK_BIT = 0x00000002, + VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, + VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCullModeFlagBits; +typedef VkFlags VkCullModeFlags; + +typedef enum VkPipelineColorBlendStateCreateFlagBits { + VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT = 0x00000001, + VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_ARM = VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT, + VK_PIPELINE_COLOR_BLEND_STATE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineColorBlendStateCreateFlagBits; +typedef VkFlags VkPipelineColorBlendStateCreateFlags; + +typedef enum VkPipelineDepthStencilStateCreateFlagBits { + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT = 0x00000001, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT = 0x00000002, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM = VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM = VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineDepthStencilStateCreateFlagBits; +typedef VkFlags VkPipelineDepthStencilStateCreateFlags; +typedef VkFlags VkPipelineDynamicStateCreateFlags; +typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; +typedef VkFlags VkPipelineMultisampleStateCreateFlags; +typedef VkFlags VkPipelineRasterizationStateCreateFlags; +typedef VkFlags VkPipelineTessellationStateCreateFlags; +typedef VkFlags VkPipelineVertexInputStateCreateFlags; +typedef VkFlags VkPipelineViewportStateCreateFlags; + +typedef enum VkAttachmentDescriptionFlagBits { + VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001, + VK_ATTACHMENT_DESCRIPTION_RESOLVE_SKIP_TRANSFER_FUNCTION_BIT_KHR = 0x00000002, + VK_ATTACHMENT_DESCRIPTION_RESOLVE_ENABLE_TRANSFER_FUNCTION_BIT_KHR = 0x00000004, + VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkAttachmentDescriptionFlagBits; +typedef VkFlags VkAttachmentDescriptionFlags; + +typedef enum VkFramebufferCreateFlagBits { + VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT = 0x00000001, + VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, + VK_FRAMEBUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFramebufferCreateFlagBits; +typedef VkFlags VkFramebufferCreateFlags; + +typedef enum VkRenderPassCreateFlagBits { + VK_RENDER_PASS_CREATE_TRANSFORM_BIT_QCOM = 0x00000002, + VK_RENDER_PASS_CREATE_PER_LAYER_FRAGMENT_DENSITY_BIT_VALVE = 0x00000004, + VK_RENDER_PASS_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkRenderPassCreateFlagBits; +typedef VkFlags VkRenderPassCreateFlags; + +typedef enum VkSubpassDescriptionFlagBits { + VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX = 0x00000001, + VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 0x00000002, + VK_SUBPASS_DESCRIPTION_TILE_SHADING_APRON_BIT_QCOM = 0x00000100, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT = 0x00000010, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT = 0x00000020, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT = 0x00000040, + VK_SUBPASS_DESCRIPTION_ENABLE_LEGACY_DITHERING_BIT_EXT = 0x00000080, + VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_EXT = 0x00000004, + VK_SUBPASS_DESCRIPTION_CUSTOM_RESOLVE_BIT_EXT = 0x00000008, + VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM = VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_EXT, + VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM = VK_SUBPASS_DESCRIPTION_CUSTOM_RESOLVE_BIT_EXT, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_ARM = VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM = VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM = VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT, + VK_SUBPASS_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubpassDescriptionFlagBits; +typedef VkFlags VkSubpassDescriptionFlags; + +typedef enum VkStencilFaceFlagBits { + VK_STENCIL_FACE_FRONT_BIT = 0x00000001, + VK_STENCIL_FACE_BACK_BIT = 0x00000002, + VK_STENCIL_FACE_FRONT_AND_BACK = 0x00000003, + // VK_STENCIL_FRONT_AND_BACK is a legacy alias + VK_STENCIL_FRONT_AND_BACK = VK_STENCIL_FACE_FRONT_AND_BACK, + VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkStencilFaceFlagBits; +typedef VkFlags VkStencilFaceFlags; +typedef struct VkExtent2D { + uint32_t width; + uint32_t height; +} VkExtent2D; + +typedef struct VkExtent3D { + uint32_t width; + uint32_t height; + uint32_t depth; +} VkExtent3D; + +typedef struct VkOffset2D { + int32_t x; + int32_t y; +} VkOffset2D; + +typedef struct VkOffset3D { + int32_t x; + int32_t y; + int32_t z; +} VkOffset3D; + +typedef struct VkRect2D { + VkOffset2D offset; + VkExtent2D extent; +} VkRect2D; + +typedef struct VkBaseInStructure { + VkStructureType sType; + const struct VkBaseInStructure* pNext; +} VkBaseInStructure; + +typedef struct VkBaseOutStructure { + VkStructureType sType; + struct VkBaseOutStructure* pNext; +} VkBaseOutStructure; + +typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)( + void* pUserData, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope); + +typedef void (VKAPI_PTR *PFN_vkFreeFunction)( + void* pUserData, + void* pMemory); + +typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)( + void* pUserData, + size_t size, + VkInternalAllocationType allocationType, + VkSystemAllocationScope allocationScope); + +typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)( + void* pUserData, + size_t size, + VkInternalAllocationType allocationType, + VkSystemAllocationScope allocationScope); + +typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)( + void* pUserData, + void* pOriginal, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope); + +typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void); +typedef struct VkAllocationCallbacks { + void* pUserData; + PFN_vkAllocationFunction pfnAllocation; + PFN_vkReallocationFunction pfnReallocation; + PFN_vkFreeFunction pfnFree; + PFN_vkInternalAllocationNotification pfnInternalAllocation; + PFN_vkInternalFreeNotification pfnInternalFree; +} VkAllocationCallbacks; + +typedef struct VkApplicationInfo { + VkStructureType sType; + const void* pNext; + const char* pApplicationName; + uint32_t applicationVersion; + const char* pEngineName; + uint32_t engineVersion; + uint32_t apiVersion; +} VkApplicationInfo; + +typedef struct VkFormatProperties { + VkFormatFeatureFlags linearTilingFeatures; + VkFormatFeatureFlags optimalTilingFeatures; + VkFormatFeatureFlags bufferFeatures; +} VkFormatProperties; + +typedef struct VkImageFormatProperties { + VkExtent3D maxExtent; + uint32_t maxMipLevels; + uint32_t maxArrayLayers; + VkSampleCountFlags sampleCounts; + VkDeviceSize maxResourceSize; +} VkImageFormatProperties; + +typedef struct VkInstanceCreateInfo { + VkStructureType sType; + const void* pNext; + VkInstanceCreateFlags flags; + const VkApplicationInfo* pApplicationInfo; + uint32_t enabledLayerCount; + const char* const* ppEnabledLayerNames; + uint32_t enabledExtensionCount; + const char* const* ppEnabledExtensionNames; +} VkInstanceCreateInfo; + +typedef struct VkMemoryHeap { + VkDeviceSize size; + VkMemoryHeapFlags flags; +} VkMemoryHeap; + +typedef struct VkMemoryType { + VkMemoryPropertyFlags propertyFlags; + uint32_t heapIndex; +} VkMemoryType; + +typedef struct VkPhysicalDeviceFeatures { + VkBool32 robustBufferAccess; + VkBool32 fullDrawIndexUint32; + VkBool32 imageCubeArray; + VkBool32 independentBlend; + VkBool32 geometryShader; + VkBool32 tessellationShader; + VkBool32 sampleRateShading; + VkBool32 dualSrcBlend; + VkBool32 logicOp; + VkBool32 multiDrawIndirect; + VkBool32 drawIndirectFirstInstance; + VkBool32 depthClamp; + VkBool32 depthBiasClamp; + VkBool32 fillModeNonSolid; + VkBool32 depthBounds; + VkBool32 wideLines; + VkBool32 largePoints; + VkBool32 alphaToOne; + VkBool32 multiViewport; + VkBool32 samplerAnisotropy; + VkBool32 textureCompressionETC2; + VkBool32 textureCompressionASTC_LDR; + VkBool32 textureCompressionBC; + VkBool32 occlusionQueryPrecise; + VkBool32 pipelineStatisticsQuery; + VkBool32 vertexPipelineStoresAndAtomics; + VkBool32 fragmentStoresAndAtomics; + VkBool32 shaderTessellationAndGeometryPointSize; + VkBool32 shaderImageGatherExtended; + VkBool32 shaderStorageImageExtendedFormats; + VkBool32 shaderStorageImageMultisample; + VkBool32 shaderStorageImageReadWithoutFormat; + VkBool32 shaderStorageImageWriteWithoutFormat; + VkBool32 shaderUniformBufferArrayDynamicIndexing; + VkBool32 shaderSampledImageArrayDynamicIndexing; + VkBool32 shaderStorageBufferArrayDynamicIndexing; + VkBool32 shaderStorageImageArrayDynamicIndexing; + VkBool32 shaderClipDistance; + VkBool32 shaderCullDistance; + VkBool32 shaderFloat64; + VkBool32 shaderInt64; + VkBool32 shaderInt16; + VkBool32 shaderResourceResidency; + VkBool32 shaderResourceMinLod; + VkBool32 sparseBinding; + VkBool32 sparseResidencyBuffer; + VkBool32 sparseResidencyImage2D; + VkBool32 sparseResidencyImage3D; + VkBool32 sparseResidency2Samples; + VkBool32 sparseResidency4Samples; + VkBool32 sparseResidency8Samples; + VkBool32 sparseResidency16Samples; + VkBool32 sparseResidencyAliased; + VkBool32 variableMultisampleRate; + VkBool32 inheritedQueries; +} VkPhysicalDeviceFeatures; + +typedef struct VkPhysicalDeviceLimits { + uint32_t maxImageDimension1D; + uint32_t maxImageDimension2D; + uint32_t maxImageDimension3D; + uint32_t maxImageDimensionCube; + uint32_t maxImageArrayLayers; + uint32_t maxTexelBufferElements; + uint32_t maxUniformBufferRange; + uint32_t maxStorageBufferRange; + uint32_t maxPushConstantsSize; + uint32_t maxMemoryAllocationCount; + uint32_t maxSamplerAllocationCount; + VkDeviceSize bufferImageGranularity; + VkDeviceSize sparseAddressSpaceSize; + uint32_t maxBoundDescriptorSets; + uint32_t maxPerStageDescriptorSamplers; + uint32_t maxPerStageDescriptorUniformBuffers; + uint32_t maxPerStageDescriptorStorageBuffers; + uint32_t maxPerStageDescriptorSampledImages; + uint32_t maxPerStageDescriptorStorageImages; + uint32_t maxPerStageDescriptorInputAttachments; + uint32_t maxPerStageResources; + uint32_t maxDescriptorSetSamplers; + uint32_t maxDescriptorSetUniformBuffers; + uint32_t maxDescriptorSetUniformBuffersDynamic; + uint32_t maxDescriptorSetStorageBuffers; + uint32_t maxDescriptorSetStorageBuffersDynamic; + uint32_t maxDescriptorSetSampledImages; + uint32_t maxDescriptorSetStorageImages; + uint32_t maxDescriptorSetInputAttachments; + uint32_t maxVertexInputAttributes; + uint32_t maxVertexInputBindings; + uint32_t maxVertexInputAttributeOffset; + uint32_t maxVertexInputBindingStride; + uint32_t maxVertexOutputComponents; + uint32_t maxTessellationGenerationLevel; + uint32_t maxTessellationPatchSize; + uint32_t maxTessellationControlPerVertexInputComponents; + uint32_t maxTessellationControlPerVertexOutputComponents; + uint32_t maxTessellationControlPerPatchOutputComponents; + uint32_t maxTessellationControlTotalOutputComponents; + uint32_t maxTessellationEvaluationInputComponents; + uint32_t maxTessellationEvaluationOutputComponents; + uint32_t maxGeometryShaderInvocations; + uint32_t maxGeometryInputComponents; + uint32_t maxGeometryOutputComponents; + uint32_t maxGeometryOutputVertices; + uint32_t maxGeometryTotalOutputComponents; + uint32_t maxFragmentInputComponents; + uint32_t maxFragmentOutputAttachments; + uint32_t maxFragmentDualSrcAttachments; + uint32_t maxFragmentCombinedOutputResources; + uint32_t maxComputeSharedMemorySize; + uint32_t maxComputeWorkGroupCount[3]; + uint32_t maxComputeWorkGroupInvocations; + uint32_t maxComputeWorkGroupSize[3]; + uint32_t subPixelPrecisionBits; + uint32_t subTexelPrecisionBits; + uint32_t mipmapPrecisionBits; + uint32_t maxDrawIndexedIndexValue; + uint32_t maxDrawIndirectCount; + float maxSamplerLodBias; + float maxSamplerAnisotropy; + uint32_t maxViewports; + uint32_t maxViewportDimensions[2]; + float viewportBoundsRange[2]; + uint32_t viewportSubPixelBits; + size_t minMemoryMapAlignment; + VkDeviceSize minTexelBufferOffsetAlignment; + VkDeviceSize minUniformBufferOffsetAlignment; + VkDeviceSize minStorageBufferOffsetAlignment; + int32_t minTexelOffset; + uint32_t maxTexelOffset; + int32_t minTexelGatherOffset; + uint32_t maxTexelGatherOffset; + float minInterpolationOffset; + float maxInterpolationOffset; + uint32_t subPixelInterpolationOffsetBits; + uint32_t maxFramebufferWidth; + uint32_t maxFramebufferHeight; + uint32_t maxFramebufferLayers; + VkSampleCountFlags framebufferColorSampleCounts; + VkSampleCountFlags framebufferDepthSampleCounts; + VkSampleCountFlags framebufferStencilSampleCounts; + VkSampleCountFlags framebufferNoAttachmentsSampleCounts; + uint32_t maxColorAttachments; + VkSampleCountFlags sampledImageColorSampleCounts; + VkSampleCountFlags sampledImageIntegerSampleCounts; + VkSampleCountFlags sampledImageDepthSampleCounts; + VkSampleCountFlags sampledImageStencilSampleCounts; + VkSampleCountFlags storageImageSampleCounts; + uint32_t maxSampleMaskWords; + VkBool32 timestampComputeAndGraphics; + float timestampPeriod; + uint32_t maxClipDistances; + uint32_t maxCullDistances; + uint32_t maxCombinedClipAndCullDistances; + uint32_t discreteQueuePriorities; + float pointSizeRange[2]; + float lineWidthRange[2]; + float pointSizeGranularity; + float lineWidthGranularity; + VkBool32 strictLines; + VkBool32 standardSampleLocations; + VkDeviceSize optimalBufferCopyOffsetAlignment; + VkDeviceSize optimalBufferCopyRowPitchAlignment; + VkDeviceSize nonCoherentAtomSize; +} VkPhysicalDeviceLimits; + +typedef struct VkPhysicalDeviceMemoryProperties { + uint32_t memoryTypeCount; + VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES]; + uint32_t memoryHeapCount; + VkMemoryHeap memoryHeaps[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryProperties; + +typedef struct VkPhysicalDeviceSparseProperties { + VkBool32 residencyStandard2DBlockShape; + VkBool32 residencyStandard2DMultisampleBlockShape; + VkBool32 residencyStandard3DBlockShape; + VkBool32 residencyAlignedMipSize; + VkBool32 residencyNonResidentStrict; +} VkPhysicalDeviceSparseProperties; + +typedef struct VkPhysicalDeviceProperties { + uint32_t apiVersion; + uint32_t driverVersion; + uint32_t vendorID; + uint32_t deviceID; + VkPhysicalDeviceType deviceType; + char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]; + uint8_t pipelineCacheUUID[VK_UUID_SIZE]; + VkPhysicalDeviceLimits limits; + VkPhysicalDeviceSparseProperties sparseProperties; +} VkPhysicalDeviceProperties; + +typedef struct VkQueueFamilyProperties { + VkQueueFlags queueFlags; + uint32_t queueCount; + uint32_t timestampValidBits; + VkExtent3D minImageTransferGranularity; +} VkQueueFamilyProperties; + +typedef struct VkDeviceQueueCreateInfo { + VkStructureType sType; + const void* pNext; + VkDeviceQueueCreateFlags flags; + uint32_t queueFamilyIndex; + uint32_t queueCount; + const float* pQueuePriorities; +} VkDeviceQueueCreateInfo; + +typedef struct VkDeviceCreateInfo { + VkStructureType sType; + const void* pNext; + VkDeviceCreateFlags flags; + uint32_t queueCreateInfoCount; + const VkDeviceQueueCreateInfo* pQueueCreateInfos; + // enabledLayerCount is legacy and not used + uint32_t enabledLayerCount; + // ppEnabledLayerNames is legacy and not used + const char* const* ppEnabledLayerNames; + uint32_t enabledExtensionCount; + const char* const* ppEnabledExtensionNames; + const VkPhysicalDeviceFeatures* pEnabledFeatures; +} VkDeviceCreateInfo; + +typedef struct VkExtensionProperties { + char extensionName[VK_MAX_EXTENSION_NAME_SIZE]; + uint32_t specVersion; +} VkExtensionProperties; + +typedef struct VkLayerProperties { + char layerName[VK_MAX_EXTENSION_NAME_SIZE]; + uint32_t specVersion; + uint32_t implementationVersion; + char description[VK_MAX_DESCRIPTION_SIZE]; +} VkLayerProperties; + +typedef struct VkSubmitInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore* pWaitSemaphores; + const VkPipelineStageFlags* pWaitDstStageMask; + uint32_t commandBufferCount; + const VkCommandBuffer* pCommandBuffers; + uint32_t signalSemaphoreCount; + const VkSemaphore* pSignalSemaphores; +} VkSubmitInfo; + +typedef struct VkMappedMemoryRange { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkDeviceSize offset; + VkDeviceSize size; +} VkMappedMemoryRange; + +typedef struct VkMemoryAllocateInfo { + VkStructureType sType; + const void* pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeIndex; +} VkMemoryAllocateInfo; + +typedef struct VkMemoryRequirements { + VkDeviceSize size; + VkDeviceSize alignment; + uint32_t memoryTypeBits; +} VkMemoryRequirements; + +typedef struct VkImageSubresource { + VkImageAspectFlags aspectMask; + uint32_t mipLevel; + uint32_t arrayLayer; +} VkImageSubresource; + +typedef struct VkSparseImageFormatProperties { + VkImageAspectFlags aspectMask; + VkExtent3D imageGranularity; + VkSparseImageFormatFlags flags; +} VkSparseImageFormatProperties; + +typedef struct VkSparseImageMemoryBind { + VkImageSubresource subresource; + VkOffset3D offset; + VkExtent3D extent; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkSparseMemoryBindFlags flags; +} VkSparseImageMemoryBind; + +typedef struct VkSparseImageMemoryBindInfo { + VkImage image; + uint32_t bindCount; + const VkSparseImageMemoryBind* pBinds; +} VkSparseImageMemoryBindInfo; + +typedef struct VkSparseImageMemoryRequirements { + VkSparseImageFormatProperties formatProperties; + uint32_t imageMipTailFirstLod; + VkDeviceSize imageMipTailSize; + VkDeviceSize imageMipTailOffset; + VkDeviceSize imageMipTailStride; +} VkSparseImageMemoryRequirements; + +typedef struct VkSparseMemoryBind { + VkDeviceSize resourceOffset; + VkDeviceSize size; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkSparseMemoryBindFlags flags; +} VkSparseMemoryBind; + +typedef struct VkSparseBufferMemoryBindInfo { + VkBuffer buffer; + uint32_t bindCount; + const VkSparseMemoryBind* pBinds; +} VkSparseBufferMemoryBindInfo; + +typedef struct VkSparseImageOpaqueMemoryBindInfo { + VkImage image; + uint32_t bindCount; + const VkSparseMemoryBind* pBinds; +} VkSparseImageOpaqueMemoryBindInfo; + +typedef struct VkBindSparseInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore* pWaitSemaphores; + uint32_t bufferBindCount; + const VkSparseBufferMemoryBindInfo* pBufferBinds; + uint32_t imageOpaqueBindCount; + const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds; + uint32_t imageBindCount; + const VkSparseImageMemoryBindInfo* pImageBinds; + uint32_t signalSemaphoreCount; + const VkSemaphore* pSignalSemaphores; +} VkBindSparseInfo; + +typedef struct VkFenceCreateInfo { + VkStructureType sType; + const void* pNext; + VkFenceCreateFlags flags; +} VkFenceCreateInfo; + +typedef struct VkSemaphoreCreateInfo { + VkStructureType sType; + const void* pNext; + VkSemaphoreCreateFlags flags; +} VkSemaphoreCreateInfo; + +typedef struct VkQueryPoolCreateInfo { + VkStructureType sType; + const void* pNext; + VkQueryPoolCreateFlags flags; + VkQueryType queryType; + uint32_t queryCount; + VkQueryPipelineStatisticFlags pipelineStatistics; +} VkQueryPoolCreateInfo; + +typedef struct VkBufferCreateInfo { + VkStructureType sType; + const void* pNext; + VkBufferCreateFlags flags; + VkDeviceSize size; + VkBufferUsageFlags usage; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; +} VkBufferCreateInfo; + +typedef struct VkImageCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageCreateFlags flags; + VkImageType imageType; + VkFormat format; + VkExtent3D extent; + uint32_t mipLevels; + uint32_t arrayLayers; + VkSampleCountFlagBits samples; + VkImageTiling tiling; + VkImageUsageFlags usage; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; + VkImageLayout initialLayout; +} VkImageCreateInfo; + +typedef struct VkSubresourceLayout { + VkDeviceSize offset; + VkDeviceSize size; + VkDeviceSize rowPitch; + VkDeviceSize arrayPitch; + VkDeviceSize depthPitch; +} VkSubresourceLayout; + +typedef struct VkComponentMapping { + VkComponentSwizzle r; + VkComponentSwizzle g; + VkComponentSwizzle b; + VkComponentSwizzle a; +} VkComponentMapping; + +typedef struct VkImageSubresourceRange { + VkImageAspectFlags aspectMask; + uint32_t baseMipLevel; + uint32_t levelCount; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkImageSubresourceRange; + +typedef struct VkImageViewCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageViewCreateFlags flags; + VkImage image; + VkImageViewType viewType; + VkFormat format; + VkComponentMapping components; + VkImageSubresourceRange subresourceRange; +} VkImageViewCreateInfo; + +typedef struct VkCommandPoolCreateInfo { + VkStructureType sType; + const void* pNext; + VkCommandPoolCreateFlags flags; + uint32_t queueFamilyIndex; +} VkCommandPoolCreateInfo; + +typedef struct VkCommandBufferAllocateInfo { + VkStructureType sType; + const void* pNext; + VkCommandPool commandPool; + VkCommandBufferLevel level; + uint32_t commandBufferCount; +} VkCommandBufferAllocateInfo; + +typedef struct VkCommandBufferInheritanceInfo { + VkStructureType sType; + const void* pNext; + VkRenderPass renderPass; + uint32_t subpass; + VkFramebuffer framebuffer; + VkBool32 occlusionQueryEnable; + VkQueryControlFlags queryFlags; + VkQueryPipelineStatisticFlags pipelineStatistics; +} VkCommandBufferInheritanceInfo; + +typedef struct VkCommandBufferBeginInfo { + VkStructureType sType; + const void* pNext; + VkCommandBufferUsageFlags flags; + const VkCommandBufferInheritanceInfo* pInheritanceInfo; +} VkCommandBufferBeginInfo; + +typedef struct VkBufferCopy { + VkDeviceSize srcOffset; + VkDeviceSize dstOffset; + VkDeviceSize size; +} VkBufferCopy; + +typedef struct VkImageSubresourceLayers { + VkImageAspectFlags aspectMask; + uint32_t mipLevel; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkImageSubresourceLayers; + +typedef struct VkBufferImageCopy { + VkDeviceSize bufferOffset; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkBufferImageCopy; + +typedef struct VkImageCopy { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageCopy; + +typedef struct VkBufferMemoryBarrier { + VkStructureType sType; + const void* pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; +} VkBufferMemoryBarrier; + +typedef struct VkImageMemoryBarrier { + VkStructureType sType; + const void* pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkImage image; + VkImageSubresourceRange subresourceRange; +} VkImageMemoryBarrier; + +typedef struct VkMemoryBarrier { + VkStructureType sType; + const void* pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; +} VkMemoryBarrier; + +typedef struct VkDispatchIndirectCommand { + uint32_t x; + uint32_t y; + uint32_t z; +} VkDispatchIndirectCommand; + +typedef struct VkPipelineCacheHeaderVersionOne { + uint32_t headerSize; + VkPipelineCacheHeaderVersion headerVersion; + uint32_t vendorID; + uint32_t deviceID; + uint8_t pipelineCacheUUID[VK_UUID_SIZE]; +} VkPipelineCacheHeaderVersionOne; + +typedef struct VkEventCreateInfo { + VkStructureType sType; + const void* pNext; + VkEventCreateFlags flags; +} VkEventCreateInfo; + +typedef struct VkBufferViewCreateInfo { + VkStructureType sType; + const void* pNext; + VkBufferViewCreateFlags flags; + VkBuffer buffer; + VkFormat format; + VkDeviceSize offset; + VkDeviceSize range; +} VkBufferViewCreateInfo; + +typedef struct VkShaderModuleCreateInfo { + VkStructureType sType; + const void* pNext; + VkShaderModuleCreateFlags flags; + size_t codeSize; + const uint32_t* pCode; +} VkShaderModuleCreateInfo; + +typedef struct VkPipelineCacheCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCacheCreateFlags flags; + size_t initialDataSize; + const void* pInitialData; +} VkPipelineCacheCreateInfo; + +typedef struct VkSpecializationMapEntry { + uint32_t constantID; + uint32_t offset; + size_t size; +} VkSpecializationMapEntry; + +typedef struct VkSpecializationInfo { + uint32_t mapEntryCount; + const VkSpecializationMapEntry* pMapEntries; + size_t dataSize; + const void* pData; +} VkSpecializationInfo; + +typedef struct VkPipelineShaderStageCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineShaderStageCreateFlags flags; + VkShaderStageFlagBits stage; + VkShaderModule module; + const char* pName; + const VkSpecializationInfo* pSpecializationInfo; +} VkPipelineShaderStageCreateInfo; + +typedef struct VkComputePipelineCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + VkPipelineShaderStageCreateInfo stage; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkComputePipelineCreateInfo; + +typedef struct VkPushConstantRange { + VkShaderStageFlags stageFlags; + uint32_t offset; + uint32_t size; +} VkPushConstantRange; + +typedef struct VkPipelineLayoutCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineLayoutCreateFlags flags; + uint32_t setLayoutCount; + const VkDescriptorSetLayout* pSetLayouts; + uint32_t pushConstantRangeCount; + const VkPushConstantRange* pPushConstantRanges; +} VkPipelineLayoutCreateInfo; + +typedef struct VkSamplerCreateInfo { + VkStructureType sType; + const void* pNext; + VkSamplerCreateFlags flags; + VkFilter magFilter; + VkFilter minFilter; + VkSamplerMipmapMode mipmapMode; + VkSamplerAddressMode addressModeU; + VkSamplerAddressMode addressModeV; + VkSamplerAddressMode addressModeW; + float mipLodBias; + VkBool32 anisotropyEnable; + float maxAnisotropy; + VkBool32 compareEnable; + VkCompareOp compareOp; + float minLod; + float maxLod; + VkBorderColor borderColor; + VkBool32 unnormalizedCoordinates; +} VkSamplerCreateInfo; + +typedef struct VkCopyDescriptorSet { + VkStructureType sType; + const void* pNext; + VkDescriptorSet srcSet; + uint32_t srcBinding; + uint32_t srcArrayElement; + VkDescriptorSet dstSet; + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; +} VkCopyDescriptorSet; + +typedef struct VkDescriptorBufferInfo { + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize range; +} VkDescriptorBufferInfo; + +typedef struct VkDescriptorImageInfo { + VkSampler sampler; + VkImageView imageView; + VkImageLayout imageLayout; +} VkDescriptorImageInfo; + +typedef struct VkDescriptorPoolSize { + VkDescriptorType type; + uint32_t descriptorCount; +} VkDescriptorPoolSize; + +typedef struct VkDescriptorPoolCreateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorPoolCreateFlags flags; + uint32_t maxSets; + uint32_t poolSizeCount; + const VkDescriptorPoolSize* pPoolSizes; +} VkDescriptorPoolCreateInfo; + +typedef struct VkDescriptorSetAllocateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorPool descriptorPool; + uint32_t descriptorSetCount; + const VkDescriptorSetLayout* pSetLayouts; +} VkDescriptorSetAllocateInfo; + +typedef struct VkDescriptorSetLayoutBinding { + uint32_t binding; + VkDescriptorType descriptorType; + uint32_t descriptorCount; + VkShaderStageFlags stageFlags; + const VkSampler* pImmutableSamplers; +} VkDescriptorSetLayoutBinding; + +typedef struct VkDescriptorSetLayoutCreateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorSetLayoutCreateFlags flags; + uint32_t bindingCount; + const VkDescriptorSetLayoutBinding* pBindings; +} VkDescriptorSetLayoutCreateInfo; + +typedef struct VkWriteDescriptorSet { + VkStructureType sType; + const void* pNext; + VkDescriptorSet dstSet; + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; + VkDescriptorType descriptorType; + const VkDescriptorImageInfo* pImageInfo; + const VkDescriptorBufferInfo* pBufferInfo; + const VkBufferView* pTexelBufferView; +} VkWriteDescriptorSet; + +typedef union VkClearColorValue { + float float32[4]; + int32_t int32[4]; + uint32_t uint32[4]; +} VkClearColorValue; + +typedef struct VkDrawIndexedIndirectCommand { + uint32_t indexCount; + uint32_t instanceCount; + uint32_t firstIndex; + int32_t vertexOffset; + uint32_t firstInstance; +} VkDrawIndexedIndirectCommand; + +typedef struct VkDrawIndirectCommand { + uint32_t vertexCount; + uint32_t instanceCount; + uint32_t firstVertex; + uint32_t firstInstance; +} VkDrawIndirectCommand; + +typedef struct VkStencilOpState { + VkStencilOp failOp; + VkStencilOp passOp; + VkStencilOp depthFailOp; + VkCompareOp compareOp; + uint32_t compareMask; + uint32_t writeMask; + uint32_t reference; +} VkStencilOpState; + +typedef struct VkVertexInputAttributeDescription { + uint32_t location; + uint32_t binding; + VkFormat format; + uint32_t offset; +} VkVertexInputAttributeDescription; + +typedef struct VkVertexInputBindingDescription { + uint32_t binding; + uint32_t stride; + VkVertexInputRate inputRate; +} VkVertexInputBindingDescription; + +typedef struct VkViewport { + float x; + float y; + float width; + float height; + float minDepth; + float maxDepth; +} VkViewport; + +typedef struct VkPipelineColorBlendAttachmentState { + VkBool32 blendEnable; + VkBlendFactor srcColorBlendFactor; + VkBlendFactor dstColorBlendFactor; + VkBlendOp colorBlendOp; + VkBlendFactor srcAlphaBlendFactor; + VkBlendFactor dstAlphaBlendFactor; + VkBlendOp alphaBlendOp; + VkColorComponentFlags colorWriteMask; +} VkPipelineColorBlendAttachmentState; + +typedef struct VkPipelineColorBlendStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineColorBlendStateCreateFlags flags; + VkBool32 logicOpEnable; + VkLogicOp logicOp; + uint32_t attachmentCount; + const VkPipelineColorBlendAttachmentState* pAttachments; + float blendConstants[4]; +} VkPipelineColorBlendStateCreateInfo; + +typedef struct VkPipelineDepthStencilStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineDepthStencilStateCreateFlags flags; + VkBool32 depthTestEnable; + VkBool32 depthWriteEnable; + VkCompareOp depthCompareOp; + VkBool32 depthBoundsTestEnable; + VkBool32 stencilTestEnable; + VkStencilOpState front; + VkStencilOpState back; + float minDepthBounds; + float maxDepthBounds; +} VkPipelineDepthStencilStateCreateInfo; + +typedef struct VkPipelineDynamicStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineDynamicStateCreateFlags flags; + uint32_t dynamicStateCount; + const VkDynamicState* pDynamicStates; +} VkPipelineDynamicStateCreateInfo; + +typedef struct VkPipelineInputAssemblyStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineInputAssemblyStateCreateFlags flags; + VkPrimitiveTopology topology; + VkBool32 primitiveRestartEnable; +} VkPipelineInputAssemblyStateCreateInfo; + +typedef struct VkPipelineMultisampleStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineMultisampleStateCreateFlags flags; + VkSampleCountFlagBits rasterizationSamples; + VkBool32 sampleShadingEnable; + float minSampleShading; + const VkSampleMask* pSampleMask; + VkBool32 alphaToCoverageEnable; + VkBool32 alphaToOneEnable; +} VkPipelineMultisampleStateCreateInfo; + +typedef struct VkPipelineRasterizationStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineRasterizationStateCreateFlags flags; + VkBool32 depthClampEnable; + VkBool32 rasterizerDiscardEnable; + VkPolygonMode polygonMode; + VkCullModeFlags cullMode; + VkFrontFace frontFace; + VkBool32 depthBiasEnable; + float depthBiasConstantFactor; + float depthBiasClamp; + float depthBiasSlopeFactor; + float lineWidth; +} VkPipelineRasterizationStateCreateInfo; + +typedef struct VkPipelineTessellationStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineTessellationStateCreateFlags flags; + uint32_t patchControlPoints; +} VkPipelineTessellationStateCreateInfo; + +typedef struct VkPipelineVertexInputStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineVertexInputStateCreateFlags flags; + uint32_t vertexBindingDescriptionCount; + const VkVertexInputBindingDescription* pVertexBindingDescriptions; + uint32_t vertexAttributeDescriptionCount; + const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; +} VkPipelineVertexInputStateCreateInfo; + +typedef struct VkPipelineViewportStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineViewportStateCreateFlags flags; + uint32_t viewportCount; + const VkViewport* pViewports; + uint32_t scissorCount; + const VkRect2D* pScissors; +} VkPipelineViewportStateCreateInfo; + +typedef struct VkGraphicsPipelineCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + const VkPipelineVertexInputStateCreateInfo* pVertexInputState; + const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; + const VkPipelineTessellationStateCreateInfo* pTessellationState; + const VkPipelineViewportStateCreateInfo* pViewportState; + const VkPipelineRasterizationStateCreateInfo* pRasterizationState; + const VkPipelineMultisampleStateCreateInfo* pMultisampleState; + const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; + const VkPipelineColorBlendStateCreateInfo* pColorBlendState; + const VkPipelineDynamicStateCreateInfo* pDynamicState; + VkPipelineLayout layout; + VkRenderPass renderPass; + uint32_t subpass; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkGraphicsPipelineCreateInfo; + +typedef struct VkAttachmentDescription { + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription; + +typedef struct VkAttachmentReference { + uint32_t attachment; + VkImageLayout layout; +} VkAttachmentReference; + +typedef struct VkFramebufferCreateInfo { + VkStructureType sType; + const void* pNext; + VkFramebufferCreateFlags flags; + VkRenderPass renderPass; + uint32_t attachmentCount; + const VkImageView* pAttachments; + uint32_t width; + uint32_t height; + uint32_t layers; +} VkFramebufferCreateInfo; + +typedef struct VkSubpassDependency { + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; +} VkSubpassDependency; + +typedef struct VkSubpassDescription { + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t inputAttachmentCount; + const VkAttachmentReference* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference* pColorAttachments; + const VkAttachmentReference* pResolveAttachments; + const VkAttachmentReference* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription; + +typedef struct VkRenderPassCreateInfo { + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency* pDependencies; +} VkRenderPassCreateInfo; + +typedef struct VkClearDepthStencilValue { + float depth; + uint32_t stencil; +} VkClearDepthStencilValue; + +typedef struct VkClearRect { + VkRect2D rect; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkClearRect; + +typedef union VkClearValue { + VkClearColorValue color; + VkClearDepthStencilValue depthStencil; +} VkClearValue; + +typedef struct VkClearAttachment { + VkImageAspectFlags aspectMask; + uint32_t colorAttachment; + VkClearValue clearValue; +} VkClearAttachment; + +typedef struct VkImageBlit { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffsets[2]; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffsets[2]; +} VkImageBlit; + +typedef struct VkImageResolve { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageResolve; + +typedef struct VkRenderPassBeginInfo { + VkStructureType sType; + const void* pNext; + VkRenderPass renderPass; + VkFramebuffer framebuffer; + VkRect2D renderArea; + uint32_t clearValueCount; + const VkClearValue* pClearValues; +} VkRenderPassBeginInfo; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance); +typedef void (VKAPI_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties); +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName); +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetDeviceProcAddr)(VkDevice device, const char* pName); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDevice)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice); +typedef void (VKAPI_PTR *PFN_vkDestroyDevice)(VkDevice device, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceExtensionProperties)(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceLayerProperties)(uint32_t* pPropertyCount, VkLayerProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue); +typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence); +typedef VkResult (VKAPI_PTR *PFN_vkQueueWaitIdle)(VkQueue queue); +typedef VkResult (VKAPI_PTR *PFN_vkDeviceWaitIdle)(VkDevice device); +typedef VkResult (VKAPI_PTR *PFN_vkAllocateMemory)(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory); +typedef void (VKAPI_PTR *PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData); +typedef void (VKAPI_PTR *PFN_vkUnmapMemory)(VkDevice device, VkDeviceMemory memory); +typedef VkResult (VKAPI_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); +typedef VkResult (VKAPI_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); +typedef void (VKAPI_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes); +typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory)(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset); +typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory)(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset); +typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements)(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence); +typedef VkResult (VKAPI_PTR *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); +typedef void (VKAPI_PTR *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences); +typedef VkResult (VKAPI_PTR *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence); +typedef VkResult (VKAPI_PTR *PFN_vkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout); +typedef VkResult (VKAPI_PTR *PFN_vkCreateSemaphore)(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore); +typedef void (VKAPI_PTR *PFN_vkDestroySemaphore)(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateQueryPool)(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool); +typedef void (VKAPI_PTR *PFN_vkDestroyQueryPool)(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetQueryPoolResults)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags); +typedef VkResult (VKAPI_PTR *PFN_vkCreateBuffer)(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer); +typedef void (VKAPI_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateImage)(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage); +typedef void (VKAPI_PTR *PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout); +typedef VkResult (VKAPI_PTR *PFN_vkCreateImageView)(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView); +typedef void (VKAPI_PTR *PFN_vkDestroyImageView)(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateCommandPool)(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool); +typedef void (VKAPI_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkResetCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags); +typedef VkResult (VKAPI_PTR *PFN_vkAllocateCommandBuffers)(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers); +typedef void (VKAPI_PTR *PFN_vkFreeCommandBuffers)(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); +typedef VkResult (VKAPI_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo); +typedef VkResult (VKAPI_PTR *PFN_vkEndCommandBuffer)(VkCommandBuffer commandBuffer); +typedef VkResult (VKAPI_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); +typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier)(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); +typedef void (VKAPI_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); +typedef void (VKAPI_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query); +typedef void (VKAPI_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); +typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); +typedef void (VKAPI_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); +typedef void (VKAPI_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); +typedef VkResult (VKAPI_PTR *PFN_vkCreateEvent)(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent); +typedef void (VKAPI_PTR *PFN_vkDestroyEvent)(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetEventStatus)(VkDevice device, VkEvent event); +typedef VkResult (VKAPI_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event); +typedef VkResult (VKAPI_PTR *PFN_vkResetEvent)(VkDevice device, VkEvent event); +typedef VkResult (VKAPI_PTR *PFN_vkCreateBufferView)(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView); +typedef void (VKAPI_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule); +typedef void (VKAPI_PTR *PFN_vkDestroyShaderModule)(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache); +typedef void (VKAPI_PTR *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches); +typedef VkResult (VKAPI_PTR *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef void (VKAPI_PTR *PFN_vkDestroyPipeline)(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout); +typedef void (VKAPI_PTR *PFN_vkDestroyPipelineLayout)(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler); +typedef void (VKAPI_PTR *PFN_vkDestroySampler)(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorPool)(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkResetDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags); +typedef VkResult (VKAPI_PTR *PFN_vkAllocateDescriptorSets)(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets); +typedef VkResult (VKAPI_PTR *PFN_vkFreeDescriptorSets)(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets); +typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSets)(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies); +typedef void (VKAPI_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); +typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorSets)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); +typedef void (VKAPI_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); +typedef void (VKAPI_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); +typedef void (VKAPI_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); +typedef VkResult (VKAPI_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkCreateFramebuffer)(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer); +typedef void (VKAPI_PTR *PFN_vkDestroyFramebuffer)(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void (VKAPI_PTR *PFN_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports); +typedef void (VKAPI_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors); +typedef void (VKAPI_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer commandBuffer, float lineWidth); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); +typedef void (VKAPI_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer commandBuffer, const float blendConstants[4]); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference); +typedef void (VKAPI_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); +typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter); +typedef void (VKAPI_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); +typedef void (VKAPI_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects); +typedef void (VKAPI_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); +typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer commandBuffer, VkSubpassContents contents); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer commandBuffer); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance( + const VkInstanceCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkInstance* pInstance); + +VKAPI_ATTR void VKAPI_CALL vkDestroyInstance( + VkInstance instance, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices( + VkInstance instance, + uint32_t* pPhysicalDeviceCount, + VkPhysicalDevice* pPhysicalDevices); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures* pFeatures); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties* pFormatProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags flags, + VkImageFormatProperties* pImageFormatProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties( + VkPhysicalDevice physicalDevice, + uint32_t* pQueueFamilyPropertyCount, + VkQueueFamilyProperties* pQueueFamilyProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties* pMemoryProperties); + +VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr( + VkInstance instance, + const char* pName); + +VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr( + VkDevice device, + const char* pName); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice( + VkPhysicalDevice physicalDevice, + const VkDeviceCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDevice* pDevice); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDevice( + VkDevice device, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties( + const char* pLayerName, + uint32_t* pPropertyCount, + VkExtensionProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties( + VkPhysicalDevice physicalDevice, + const char* pLayerName, + uint32_t* pPropertyCount, + VkExtensionProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties( + uint32_t* pPropertyCount, + VkLayerProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkLayerProperties* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue( + VkDevice device, + uint32_t queueFamilyIndex, + uint32_t queueIndex, + VkQueue* pQueue); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit( + VkQueue queue, + uint32_t submitCount, + const VkSubmitInfo* pSubmits, + VkFence fence); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle( + VkQueue queue); + +VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle( + VkDevice device); + +VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory( + VkDevice device, + const VkMemoryAllocateInfo* pAllocateInfo, + const VkAllocationCallbacks* pAllocator, + VkDeviceMemory* pMemory); + +VKAPI_ATTR void VKAPI_CALL vkFreeMemory( + VkDevice device, + VkDeviceMemory memory, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory( + VkDevice device, + VkDeviceMemory memory, + VkDeviceSize offset, + VkDeviceSize size, + VkMemoryMapFlags flags, + void** ppData); + +VKAPI_ATTR void VKAPI_CALL vkUnmapMemory( + VkDevice device, + VkDeviceMemory memory); + +VKAPI_ATTR VkResult VKAPI_CALL vkFlushMappedMemoryRanges( + VkDevice device, + uint32_t memoryRangeCount, + const VkMappedMemoryRange* pMemoryRanges); + +VKAPI_ATTR VkResult VKAPI_CALL vkInvalidateMappedMemoryRanges( + VkDevice device, + uint32_t memoryRangeCount, + const VkMappedMemoryRange* pMemoryRanges); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceMemoryCommitment( + VkDevice device, + VkDeviceMemory memory, + VkDeviceSize* pCommittedMemoryInBytes); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory( + VkDevice device, + VkBuffer buffer, + VkDeviceMemory memory, + VkDeviceSize memoryOffset); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory( + VkDevice device, + VkImage image, + VkDeviceMemory memory, + VkDeviceSize memoryOffset); + +VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements( + VkDevice device, + VkBuffer buffer, + VkMemoryRequirements* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements( + VkDevice device, + VkImage image, + VkMemoryRequirements* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements( + VkDevice device, + VkImage image, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements* pSparseMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkSampleCountFlagBits samples, + VkImageUsageFlags usage, + VkImageTiling tiling, + uint32_t* pPropertyCount, + VkSparseImageFormatProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueBindSparse( + VkQueue queue, + uint32_t bindInfoCount, + const VkBindSparseInfo* pBindInfo, + VkFence fence); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateFence( + VkDevice device, + const VkFenceCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkFence* pFence); + +VKAPI_ATTR void VKAPI_CALL vkDestroyFence( + VkDevice device, + VkFence fence, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetFences( + VkDevice device, + uint32_t fenceCount, + const VkFence* pFences); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus( + VkDevice device, + VkFence fence); + +VKAPI_ATTR VkResult VKAPI_CALL vkWaitForFences( + VkDevice device, + uint32_t fenceCount, + const VkFence* pFences, + VkBool32 waitAll, + uint64_t timeout); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore( + VkDevice device, + const VkSemaphoreCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSemaphore* pSemaphore); + +VKAPI_ATTR void VKAPI_CALL vkDestroySemaphore( + VkDevice device, + VkSemaphore semaphore, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool( + VkDevice device, + const VkQueryPoolCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkQueryPool* pQueryPool); + +VKAPI_ATTR void VKAPI_CALL vkDestroyQueryPool( + VkDevice device, + VkQueryPool queryPool, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults( + VkDevice device, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount, + size_t dataSize, + void* pData, + VkDeviceSize stride, + VkQueryResultFlags flags); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer( + VkDevice device, + const VkBufferCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkBuffer* pBuffer); + +VKAPI_ATTR void VKAPI_CALL vkDestroyBuffer( + VkDevice device, + VkBuffer buffer, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage( + VkDevice device, + const VkImageCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkImage* pImage); + +VKAPI_ATTR void VKAPI_CALL vkDestroyImage( + VkDevice device, + VkImage image, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout( + VkDevice device, + VkImage image, + const VkImageSubresource* pSubresource, + VkSubresourceLayout* pLayout); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView( + VkDevice device, + const VkImageViewCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkImageView* pView); + +VKAPI_ATTR void VKAPI_CALL vkDestroyImageView( + VkDevice device, + VkImageView imageView, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool( + VkDevice device, + const VkCommandPoolCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkCommandPool* pCommandPool); + +VKAPI_ATTR void VKAPI_CALL vkDestroyCommandPool( + VkDevice device, + VkCommandPool commandPool, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandPool( + VkDevice device, + VkCommandPool commandPool, + VkCommandPoolResetFlags flags); + +VKAPI_ATTR VkResult VKAPI_CALL vkAllocateCommandBuffers( + VkDevice device, + const VkCommandBufferAllocateInfo* pAllocateInfo, + VkCommandBuffer* pCommandBuffers); + +VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers( + VkDevice device, + VkCommandPool commandPool, + uint32_t commandBufferCount, + const VkCommandBuffer* pCommandBuffers); + +VKAPI_ATTR VkResult VKAPI_CALL vkBeginCommandBuffer( + VkCommandBuffer commandBuffer, + const VkCommandBufferBeginInfo* pBeginInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandBuffer( + VkCommandBuffer commandBuffer, + VkCommandBufferResetFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer( + VkCommandBuffer commandBuffer, + VkBuffer srcBuffer, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage( + VkCommandBuffer commandBuffer, + VkBuffer srcBuffer, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkBufferImageCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferImageCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer( + VkCommandBuffer commandBuffer, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize dataSize, + const void* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer( + VkCommandBuffer commandBuffer, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize size, + uint32_t data); + +VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + uint32_t memoryBarrierCount, + const VkMemoryBarrier* pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier* pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier* pImageMemoryBarriers); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginQuery( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + VkQueryControlFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query); + +VKAPI_ATTR void VKAPI_CALL vkCmdResetQueryPool( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp( + VkCommandBuffer commandBuffer, + VkPipelineStageFlagBits pipelineStage, + VkQueryPool queryPool, + uint32_t query); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyQueryPoolResults( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize stride, + VkQueryResultFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkCmdExecuteCommands( + VkCommandBuffer commandBuffer, + uint32_t commandBufferCount, + const VkCommandBuffer* pCommandBuffers); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateEvent( + VkDevice device, + const VkEventCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkEvent* pEvent); + +VKAPI_ATTR void VKAPI_CALL vkDestroyEvent( + VkDevice device, + VkEvent event, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetEventStatus( + VkDevice device, + VkEvent event); + +VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent( + VkDevice device, + VkEvent event); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetEvent( + VkDevice device, + VkEvent event); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView( + VkDevice device, + const VkBufferViewCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkBufferView* pView); + +VKAPI_ATTR void VKAPI_CALL vkDestroyBufferView( + VkDevice device, + VkBufferView bufferView, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule( + VkDevice device, + const VkShaderModuleCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkShaderModule* pShaderModule); + +VKAPI_ATTR void VKAPI_CALL vkDestroyShaderModule( + VkDevice device, + VkShaderModule shaderModule, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache( + VkDevice device, + const VkPipelineCacheCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPipelineCache* pPipelineCache); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineCache( + VkDevice device, + VkPipelineCache pipelineCache, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineCacheData( + VkDevice device, + VkPipelineCache pipelineCache, + size_t* pDataSize, + void* pData); + +VKAPI_ATTR VkResult VKAPI_CALL vkMergePipelineCaches( + VkDevice device, + VkPipelineCache dstCache, + uint32_t srcCacheCount, + const VkPipelineCache* pSrcCaches); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateComputePipelines( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkComputePipelineCreateInfo* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPipeline( + VkDevice device, + VkPipeline pipeline, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout( + VkDevice device, + const VkPipelineLayoutCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPipelineLayout* pPipelineLayout); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineLayout( + VkDevice device, + VkPipelineLayout pipelineLayout, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler( + VkDevice device, + const VkSamplerCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSampler* pSampler); + +VKAPI_ATTR void VKAPI_CALL vkDestroySampler( + VkDevice device, + VkSampler sampler, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout( + VkDevice device, + const VkDescriptorSetLayoutCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorSetLayout* pSetLayout); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorSetLayout( + VkDevice device, + VkDescriptorSetLayout descriptorSetLayout, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorPool( + VkDevice device, + const VkDescriptorPoolCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorPool* pDescriptorPool); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorPool( + VkDevice device, + VkDescriptorPool descriptorPool, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetDescriptorPool( + VkDevice device, + VkDescriptorPool descriptorPool, + VkDescriptorPoolResetFlags flags); + +VKAPI_ATTR VkResult VKAPI_CALL vkAllocateDescriptorSets( + VkDevice device, + const VkDescriptorSetAllocateInfo* pAllocateInfo, + VkDescriptorSet* pDescriptorSets); + +VKAPI_ATTR VkResult VKAPI_CALL vkFreeDescriptorSets( + VkDevice device, + VkDescriptorPool descriptorPool, + uint32_t descriptorSetCount, + const VkDescriptorSet* pDescriptorSets); + +VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSets( + VkDevice device, + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet* pDescriptorWrites, + uint32_t descriptorCopyCount, + const VkCopyDescriptorSet* pDescriptorCopies); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindPipeline( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipeline pipeline); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorSets( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, + uint32_t firstSet, + uint32_t descriptorSetCount, + const VkDescriptorSet* pDescriptorSets, + uint32_t dynamicOffsetCount, + const uint32_t* pDynamicOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage( + VkCommandBuffer commandBuffer, + VkImage image, + VkImageLayout imageLayout, + const VkClearColorValue* pColor, + uint32_t rangeCount, + const VkImageSubresourceRange* pRanges); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatch( + VkCommandBuffer commandBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchIndirect( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags stageMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags stageMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents( + VkCommandBuffer commandBuffer, + uint32_t eventCount, + const VkEvent* pEvents, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + uint32_t memoryBarrierCount, + const VkMemoryBarrier* pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier* pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier* pImageMemoryBarriers); + +VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants( + VkCommandBuffer commandBuffer, + VkPipelineLayout layout, + VkShaderStageFlags stageFlags, + uint32_t offset, + uint32_t size, + const void* pValues); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateGraphicsPipelines( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkGraphicsPipelineCreateInfo* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer( + VkDevice device, + const VkFramebufferCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkFramebuffer* pFramebuffer); + +VKAPI_ATTR void VKAPI_CALL vkDestroyFramebuffer( + VkDevice device, + VkFramebuffer framebuffer, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass( + VkDevice device, + const VkRenderPassCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkRenderPass* pRenderPass); + +VKAPI_ATTR void VKAPI_CALL vkDestroyRenderPass( + VkDevice device, + VkRenderPass renderPass, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkGetRenderAreaGranularity( + VkDevice device, + VkRenderPass renderPass, + VkExtent2D* pGranularity); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewport( + VkCommandBuffer commandBuffer, + uint32_t firstViewport, + uint32_t viewportCount, + const VkViewport* pViewports); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetScissor( + VkCommandBuffer commandBuffer, + uint32_t firstScissor, + uint32_t scissorCount, + const VkRect2D* pScissors); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth( + VkCommandBuffer commandBuffer, + float lineWidth); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBias( + VkCommandBuffer commandBuffer, + float depthBiasConstantFactor, + float depthBiasClamp, + float depthBiasSlopeFactor); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants( + VkCommandBuffer commandBuffer, + const float blendConstants[4]); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBounds( + VkCommandBuffer commandBuffer, + float minDepthBounds, + float maxDepthBounds); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilCompareMask( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t compareMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilWriteMask( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t writeMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilReference( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t reference); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkIndexType indexType); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdDraw( + VkCommandBuffer commandBuffer, + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed( + VkCommandBuffer commandBuffer, + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirect( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirect( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageBlit* pRegions, + VkFilter filter); + +VKAPI_ATTR void VKAPI_CALL vkCmdClearDepthStencilImage( + VkCommandBuffer commandBuffer, + VkImage image, + VkImageLayout imageLayout, + const VkClearDepthStencilValue* pDepthStencil, + uint32_t rangeCount, + const VkImageSubresourceRange* pRanges); + +VKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments( + VkCommandBuffer commandBuffer, + uint32_t attachmentCount, + const VkClearAttachment* pAttachments, + uint32_t rectCount, + const VkClearRect* pRects); + +VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageResolve* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass( + VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo* pRenderPassBegin, + VkSubpassContents contents); + +VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass( + VkCommandBuffer commandBuffer, + VkSubpassContents contents); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass( + VkCommandBuffer commandBuffer); +#endif + + +// VK_VERSION_1_1 is a preprocessor guard. Do not pass it to API calls. +#define VK_VERSION_1_1 1 +// Vulkan 1.1 version number +#define VK_API_VERSION_1_1 VK_MAKE_API_VERSION(0, 1, 1, 0)// Patch version should always be set to 0 + +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplate) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSamplerYcbcrConversion) +#define VK_MAX_DEVICE_GROUP_SIZE 32U +#define VK_LUID_SIZE 8U +#define VK_QUEUE_FAMILY_EXTERNAL (~1U) + +typedef enum VkPointClippingBehavior { + VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0, + VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1, + VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES, + VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY, + VK_POINT_CLIPPING_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF +} VkPointClippingBehavior; + +typedef enum VkDescriptorUpdateTemplateType { + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS = 1, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorUpdateTemplateType; + +typedef enum VkSamplerYcbcrModelConversion { + VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY = 1, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 = 2, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 = 3, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 = 4, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_MAX_ENUM = 0x7FFFFFFF +} VkSamplerYcbcrModelConversion; + +typedef enum VkSamplerYcbcrRange { + VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0, + VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1, + VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_FULL, + VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, + VK_SAMPLER_YCBCR_RANGE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerYcbcrRange; + +typedef enum VkChromaLocation { + VK_CHROMA_LOCATION_COSITED_EVEN = 0, + VK_CHROMA_LOCATION_MIDPOINT = 1, + VK_CHROMA_LOCATION_COSITED_EVEN_KHR = VK_CHROMA_LOCATION_COSITED_EVEN, + VK_CHROMA_LOCATION_MIDPOINT_KHR = VK_CHROMA_LOCATION_MIDPOINT, + VK_CHROMA_LOCATION_MAX_ENUM = 0x7FFFFFFF +} VkChromaLocation; + +typedef enum VkTessellationDomainOrigin { + VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0, + VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1, + VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, + VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT, + VK_TESSELLATION_DOMAIN_ORIGIN_MAX_ENUM = 0x7FFFFFFF +} VkTessellationDomainOrigin; + +typedef enum VkSubgroupFeatureFlagBits { + VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, + VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, + VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, + VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, + VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, + VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, + VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, + VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, + VK_SUBGROUP_FEATURE_ROTATE_BIT = 0x00000200, + VK_SUBGROUP_FEATURE_ROTATE_CLUSTERED_BIT = 0x00000400, + VK_SUBGROUP_FEATURE_PARTITIONED_BIT_EXT = 0x00000100, + VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = VK_SUBGROUP_FEATURE_PARTITIONED_BIT_EXT, + VK_SUBGROUP_FEATURE_ROTATE_BIT_KHR = VK_SUBGROUP_FEATURE_ROTATE_BIT, + VK_SUBGROUP_FEATURE_ROTATE_CLUSTERED_BIT_KHR = VK_SUBGROUP_FEATURE_ROTATE_CLUSTERED_BIT, + VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubgroupFeatureFlagBits; +typedef VkFlags VkSubgroupFeatureFlags; + +typedef enum VkPeerMemoryFeatureFlagBits { + VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 0x00000001, + VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 0x00000002, + VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT = 0x00000004, + VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT = 0x00000008, + VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT, + VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_DST_BIT, + VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT, + VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT, + VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPeerMemoryFeatureFlagBits; +typedef VkFlags VkPeerMemoryFeatureFlags; + +typedef enum VkMemoryAllocateFlagBits { + VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 0x00000001, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT = 0x00000002, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 0x00000004, + VK_MEMORY_ALLOCATE_ZERO_INITIALIZE_BIT_EXT = 0x00000008, + VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, + VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryAllocateFlagBits; +typedef VkFlags VkMemoryAllocateFlags; +typedef VkFlags VkCommandPoolTrimFlags; + +typedef enum VkExternalMemoryHandleTypeFlagBits { + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT = 0x00000008, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT = 0x00000010, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT = 0x00000020, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT = 0x00000040, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT = 0x00000200, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID = 0x00000400, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT = 0x00000080, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT = 0x00000100, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA = 0x00000800, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_RDMA_ADDRESS_BIT_NV = 0x00001000, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OH_NATIVE_BUFFER_BIT_OHOS = 0x00008000, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_SCREEN_BUFFER_BIT_QNX = 0x00004000, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_EXT = 0x00010000, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT = 0x00020000, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT = 0x00040000, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalMemoryHandleTypeFlagBits; +typedef VkFlags VkExternalMemoryHandleTypeFlags; + +typedef enum VkExternalMemoryFeatureFlagBits { + VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT = 0x00000001, + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT = 0x00000002, + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 0x00000004, + VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT, + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT, + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT, + VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalMemoryFeatureFlagBits; +typedef VkFlags VkExternalMemoryFeatureFlags; + +typedef enum VkExternalFenceHandleTypeFlagBits { + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000008, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalFenceHandleTypeFlagBits; +typedef VkFlags VkExternalFenceHandleTypeFlags; + +typedef enum VkExternalFenceFeatureFlagBits { + VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 0x00000001, + VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 0x00000002, + VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT, + VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT, + VK_EXTERNAL_FENCE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalFenceFeatureFlagBits; +typedef VkFlags VkExternalFenceFeatureFlags; + +typedef enum VkFenceImportFlagBits { + VK_FENCE_IMPORT_TEMPORARY_BIT = 0x00000001, + VK_FENCE_IMPORT_TEMPORARY_BIT_KHR = VK_FENCE_IMPORT_TEMPORARY_BIT, + VK_FENCE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFenceImportFlagBits; +typedef VkFlags VkFenceImportFlags; + +typedef enum VkSemaphoreImportFlagBits { + VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 0x00000001, + VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT, + VK_SEMAPHORE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSemaphoreImportFlagBits; +typedef VkFlags VkSemaphoreImportFlags; + +typedef enum VkExternalSemaphoreHandleTypeFlagBits { + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT = 0x00000008, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000010, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA = 0x00000080, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D11_FENCE_BIT = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalSemaphoreHandleTypeFlagBits; +typedef VkFlags VkExternalSemaphoreHandleTypeFlags; + +typedef enum VkExternalSemaphoreFeatureFlagBits { + VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 0x00000001, + VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 0x00000002, + VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT, + VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT, + VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalSemaphoreFeatureFlagBits; +typedef VkFlags VkExternalSemaphoreFeatureFlags; +typedef VkFlags VkDescriptorUpdateTemplateCreateFlags; +typedef struct VkBindBufferMemoryInfo { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; +} VkBindBufferMemoryInfo; + +typedef struct VkBindImageMemoryInfo { + VkStructureType sType; + const void* pNext; + VkImage image; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; +} VkBindImageMemoryInfo; + +typedef struct VkMemoryDedicatedRequirements { + VkStructureType sType; + void* pNext; + VkBool32 prefersDedicatedAllocation; + VkBool32 requiresDedicatedAllocation; +} VkMemoryDedicatedRequirements; + +typedef struct VkMemoryDedicatedAllocateInfo { + VkStructureType sType; + const void* pNext; + VkImage image; + VkBuffer buffer; +} VkMemoryDedicatedAllocateInfo; + +typedef struct VkMemoryAllocateFlagsInfo { + VkStructureType sType; + const void* pNext; + VkMemoryAllocateFlags flags; + uint32_t deviceMask; +} VkMemoryAllocateFlagsInfo; + +typedef struct VkDeviceGroupCommandBufferBeginInfo { + VkStructureType sType; + const void* pNext; + uint32_t deviceMask; +} VkDeviceGroupCommandBufferBeginInfo; + +typedef struct VkDeviceGroupSubmitInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const uint32_t* pWaitSemaphoreDeviceIndices; + uint32_t commandBufferCount; + const uint32_t* pCommandBufferDeviceMasks; + uint32_t signalSemaphoreCount; + const uint32_t* pSignalSemaphoreDeviceIndices; +} VkDeviceGroupSubmitInfo; + +typedef struct VkDeviceGroupBindSparseInfo { + VkStructureType sType; + const void* pNext; + uint32_t resourceDeviceIndex; + uint32_t memoryDeviceIndex; +} VkDeviceGroupBindSparseInfo; + +typedef struct VkBindBufferMemoryDeviceGroupInfo { + VkStructureType sType; + const void* pNext; + uint32_t deviceIndexCount; + const uint32_t* pDeviceIndices; +} VkBindBufferMemoryDeviceGroupInfo; + +typedef struct VkBindImageMemoryDeviceGroupInfo { + VkStructureType sType; + const void* pNext; + uint32_t deviceIndexCount; + const uint32_t* pDeviceIndices; + uint32_t splitInstanceBindRegionCount; + const VkRect2D* pSplitInstanceBindRegions; +} VkBindImageMemoryDeviceGroupInfo; + +typedef struct VkPhysicalDeviceGroupProperties { + VkStructureType sType; + void* pNext; + uint32_t physicalDeviceCount; + VkPhysicalDevice physicalDevices[VK_MAX_DEVICE_GROUP_SIZE]; + VkBool32 subsetAllocation; +} VkPhysicalDeviceGroupProperties; + +typedef struct VkDeviceGroupDeviceCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t physicalDeviceCount; + const VkPhysicalDevice* pPhysicalDevices; +} VkDeviceGroupDeviceCreateInfo; + +typedef struct VkBufferMemoryRequirementsInfo2 { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferMemoryRequirementsInfo2; + +typedef struct VkImageMemoryRequirementsInfo2 { + VkStructureType sType; + const void* pNext; + VkImage image; +} VkImageMemoryRequirementsInfo2; + +typedef struct VkImageSparseMemoryRequirementsInfo2 { + VkStructureType sType; + const void* pNext; + VkImage image; +} VkImageSparseMemoryRequirementsInfo2; + +typedef struct VkMemoryRequirements2 { + VkStructureType sType; + void* pNext; + VkMemoryRequirements memoryRequirements; +} VkMemoryRequirements2; + +typedef struct VkSparseImageMemoryRequirements2 { + VkStructureType sType; + void* pNext; + VkSparseImageMemoryRequirements memoryRequirements; +} VkSparseImageMemoryRequirements2; + +typedef struct VkPhysicalDeviceFeatures2 { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceFeatures features; +} VkPhysicalDeviceFeatures2; + +typedef struct VkPhysicalDeviceProperties2 { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceProperties properties; +} VkPhysicalDeviceProperties2; + +typedef struct VkFormatProperties2 { + VkStructureType sType; + void* pNext; + VkFormatProperties formatProperties; +} VkFormatProperties2; + +typedef struct VkImageFormatProperties2 { + VkStructureType sType; + void* pNext; + VkImageFormatProperties imageFormatProperties; +} VkImageFormatProperties2; + +typedef struct VkPhysicalDeviceImageFormatInfo2 { + VkStructureType sType; + const void* pNext; + VkFormat format; + VkImageType type; + VkImageTiling tiling; + VkImageUsageFlags usage; + VkImageCreateFlags flags; +} VkPhysicalDeviceImageFormatInfo2; + +typedef struct VkQueueFamilyProperties2 { + VkStructureType sType; + void* pNext; + VkQueueFamilyProperties queueFamilyProperties; +} VkQueueFamilyProperties2; + +typedef struct VkPhysicalDeviceMemoryProperties2 { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceMemoryProperties memoryProperties; +} VkPhysicalDeviceMemoryProperties2; + +typedef struct VkSparseImageFormatProperties2 { + VkStructureType sType; + void* pNext; + VkSparseImageFormatProperties properties; +} VkSparseImageFormatProperties2; + +typedef struct VkPhysicalDeviceSparseImageFormatInfo2 { + VkStructureType sType; + const void* pNext; + VkFormat format; + VkImageType type; + VkSampleCountFlagBits samples; + VkImageUsageFlags usage; + VkImageTiling tiling; +} VkPhysicalDeviceSparseImageFormatInfo2; + +typedef struct VkImageViewUsageCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageUsageFlags usage; +} VkImageViewUsageCreateInfo; + +typedef struct VkPhysicalDeviceProtectedMemoryFeatures { + VkStructureType sType; + void* pNext; + VkBool32 protectedMemory; +} VkPhysicalDeviceProtectedMemoryFeatures; + +typedef struct VkPhysicalDeviceProtectedMemoryProperties { + VkStructureType sType; + void* pNext; + VkBool32 protectedNoFault; +} VkPhysicalDeviceProtectedMemoryProperties; + +typedef struct VkDeviceQueueInfo2 { + VkStructureType sType; + const void* pNext; + VkDeviceQueueCreateFlags flags; + uint32_t queueFamilyIndex; + uint32_t queueIndex; +} VkDeviceQueueInfo2; + +typedef struct VkProtectedSubmitInfo { + VkStructureType sType; + const void* pNext; + VkBool32 protectedSubmit; +} VkProtectedSubmitInfo; + +typedef struct VkBindImagePlaneMemoryInfo { + VkStructureType sType; + const void* pNext; + VkImageAspectFlagBits planeAspect; +} VkBindImagePlaneMemoryInfo; + +typedef struct VkImagePlaneMemoryRequirementsInfo { + VkStructureType sType; + const void* pNext; + VkImageAspectFlagBits planeAspect; +} VkImagePlaneMemoryRequirementsInfo; + +typedef struct VkExternalMemoryProperties { + VkExternalMemoryFeatureFlags externalMemoryFeatures; + VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes; + VkExternalMemoryHandleTypeFlags compatibleHandleTypes; +} VkExternalMemoryProperties; + +typedef struct VkPhysicalDeviceExternalImageFormatInfo { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalImageFormatInfo; + +typedef struct VkExternalImageFormatProperties { + VkStructureType sType; + void* pNext; + VkExternalMemoryProperties externalMemoryProperties; +} VkExternalImageFormatProperties; + +typedef struct VkPhysicalDeviceExternalBufferInfo { + VkStructureType sType; + const void* pNext; + VkBufferCreateFlags flags; + VkBufferUsageFlags usage; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalBufferInfo; + +typedef struct VkExternalBufferProperties { + VkStructureType sType; + void* pNext; + VkExternalMemoryProperties externalMemoryProperties; +} VkExternalBufferProperties; + +typedef struct VkPhysicalDeviceIDProperties { + VkStructureType sType; + void* pNext; + uint8_t deviceUUID[VK_UUID_SIZE]; + uint8_t driverUUID[VK_UUID_SIZE]; + uint8_t deviceLUID[VK_LUID_SIZE]; + uint32_t deviceNodeMask; + VkBool32 deviceLUIDValid; +} VkPhysicalDeviceIDProperties; + +typedef struct VkExternalMemoryImageCreateInfo { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExternalMemoryImageCreateInfo; + +typedef struct VkExternalMemoryBufferCreateInfo { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExternalMemoryBufferCreateInfo; + +typedef struct VkExportMemoryAllocateInfo { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExportMemoryAllocateInfo; + +typedef struct VkPhysicalDeviceExternalFenceInfo { + VkStructureType sType; + const void* pNext; + VkExternalFenceHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalFenceInfo; + +typedef struct VkExternalFenceProperties { + VkStructureType sType; + void* pNext; + VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes; + VkExternalFenceHandleTypeFlags compatibleHandleTypes; + VkExternalFenceFeatureFlags externalFenceFeatures; +} VkExternalFenceProperties; + +typedef struct VkExportFenceCreateInfo { + VkStructureType sType; + const void* pNext; + VkExternalFenceHandleTypeFlags handleTypes; +} VkExportFenceCreateInfo; + +typedef struct VkExportSemaphoreCreateInfo { + VkStructureType sType; + const void* pNext; + VkExternalSemaphoreHandleTypeFlags handleTypes; +} VkExportSemaphoreCreateInfo; + +typedef struct VkPhysicalDeviceExternalSemaphoreInfo { + VkStructureType sType; + const void* pNext; + VkExternalSemaphoreHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalSemaphoreInfo; + +typedef struct VkExternalSemaphoreProperties { + VkStructureType sType; + void* pNext; + VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes; + VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes; + VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures; +} VkExternalSemaphoreProperties; + +typedef struct VkPhysicalDeviceSubgroupProperties { + VkStructureType sType; + void* pNext; + uint32_t subgroupSize; + VkShaderStageFlags supportedStages; + VkSubgroupFeatureFlags supportedOperations; + VkBool32 quadOperationsInAllStages; +} VkPhysicalDeviceSubgroupProperties; + +typedef struct VkPhysicalDevice16BitStorageFeatures { + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer16BitAccess; + VkBool32 uniformAndStorageBuffer16BitAccess; + VkBool32 storagePushConstant16; + VkBool32 storageInputOutput16; +} VkPhysicalDevice16BitStorageFeatures; + +typedef struct VkPhysicalDeviceVariablePointersFeatures { + VkStructureType sType; + void* pNext; + VkBool32 variablePointersStorageBuffer; + VkBool32 variablePointers; +} VkPhysicalDeviceVariablePointersFeatures; + +typedef VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeatures; + +typedef struct VkDescriptorUpdateTemplateEntry { + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; + VkDescriptorType descriptorType; + size_t offset; + size_t stride; +} VkDescriptorUpdateTemplateEntry; + +typedef struct VkDescriptorUpdateTemplateCreateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorUpdateTemplateCreateFlags flags; + uint32_t descriptorUpdateEntryCount; + const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntries; + VkDescriptorUpdateTemplateType templateType; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineBindPoint pipelineBindPoint; + VkPipelineLayout pipelineLayout; + uint32_t set; +} VkDescriptorUpdateTemplateCreateInfo; + +typedef struct VkPhysicalDeviceMaintenance3Properties { + VkStructureType sType; + void* pNext; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceMaintenance3Properties; + +typedef struct VkDescriptorSetLayoutSupport { + VkStructureType sType; + void* pNext; + VkBool32 supported; +} VkDescriptorSetLayoutSupport; + +typedef struct VkSamplerYcbcrConversionCreateInfo { + VkStructureType sType; + const void* pNext; + VkFormat format; + VkSamplerYcbcrModelConversion ycbcrModel; + VkSamplerYcbcrRange ycbcrRange; + VkComponentMapping components; + VkChromaLocation xChromaOffset; + VkChromaLocation yChromaOffset; + VkFilter chromaFilter; + VkBool32 forceExplicitReconstruction; +} VkSamplerYcbcrConversionCreateInfo; + +typedef struct VkSamplerYcbcrConversionInfo { + VkStructureType sType; + const void* pNext; + VkSamplerYcbcrConversion conversion; +} VkSamplerYcbcrConversionInfo; + +typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures { + VkStructureType sType; + void* pNext; + VkBool32 samplerYcbcrConversion; +} VkPhysicalDeviceSamplerYcbcrConversionFeatures; + +typedef struct VkSamplerYcbcrConversionImageFormatProperties { + VkStructureType sType; + void* pNext; + uint32_t combinedImageSamplerDescriptorCount; +} VkSamplerYcbcrConversionImageFormatProperties; + +typedef struct VkDeviceGroupRenderPassBeginInfo { + VkStructureType sType; + const void* pNext; + uint32_t deviceMask; + uint32_t deviceRenderAreaCount; + const VkRect2D* pDeviceRenderAreas; +} VkDeviceGroupRenderPassBeginInfo; + +typedef struct VkPhysicalDevicePointClippingProperties { + VkStructureType sType; + void* pNext; + VkPointClippingBehavior pointClippingBehavior; +} VkPhysicalDevicePointClippingProperties; + +typedef struct VkInputAttachmentAspectReference { + uint32_t subpass; + uint32_t inputAttachmentIndex; + VkImageAspectFlags aspectMask; +} VkInputAttachmentAspectReference; + +typedef struct VkRenderPassInputAttachmentAspectCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t aspectReferenceCount; + const VkInputAttachmentAspectReference* pAspectReferences; +} VkRenderPassInputAttachmentAspectCreateInfo; + +typedef struct VkPipelineTessellationDomainOriginStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkTessellationDomainOrigin domainOrigin; +} VkPipelineTessellationDomainOriginStateCreateInfo; + +typedef struct VkRenderPassMultiviewCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t subpassCount; + const uint32_t* pViewMasks; + uint32_t dependencyCount; + const int32_t* pViewOffsets; + uint32_t correlationMaskCount; + const uint32_t* pCorrelationMasks; +} VkRenderPassMultiviewCreateInfo; + +typedef struct VkPhysicalDeviceMultiviewFeatures { + VkStructureType sType; + void* pNext; + VkBool32 multiview; + VkBool32 multiviewGeometryShader; + VkBool32 multiviewTessellationShader; +} VkPhysicalDeviceMultiviewFeatures; + +typedef struct VkPhysicalDeviceMultiviewProperties { + VkStructureType sType; + void* pNext; + uint32_t maxMultiviewViewCount; + uint32_t maxMultiviewInstanceIndex; +} VkPhysicalDeviceMultiviewProperties; + +typedef struct VkPhysicalDeviceShaderDrawParametersFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderDrawParameters; +} VkPhysicalDeviceShaderDrawParametersFeatures; + +typedef VkPhysicalDeviceShaderDrawParametersFeatures VkPhysicalDeviceShaderDrawParameterFeatures; + +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceVersion)(uint32_t* pApiVersion); +typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); +typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); +typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); +typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMask)(VkCommandBuffer commandBuffer, uint32_t deviceMask); +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroups)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); +typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2)(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2)(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); +typedef void (VKAPI_PTR *PFN_vkTrimCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); +typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue2)(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFenceProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphoreProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchBase)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplate)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplate)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplate)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupport)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); +typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversion)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); +typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversion)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceVersion( + uint32_t* pApiVersion); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2( + VkDevice device, + uint32_t bindInfoCount, + const VkBindBufferMemoryInfo* pBindInfos); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2( + VkDevice device, + uint32_t bindInfoCount, + const VkBindImageMemoryInfo* pBindInfos); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeatures( + VkDevice device, + uint32_t heapIndex, + uint32_t localDeviceIndex, + uint32_t remoteDeviceIndex, + VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMask( + VkCommandBuffer commandBuffer, + uint32_t deviceMask); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroups( + VkInstance instance, + uint32_t* pPhysicalDeviceGroupCount, + VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2( + VkDevice device, + const VkImageMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2( + VkDevice device, + const VkBufferMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2( + VkDevice device, + const VkImageSparseMemoryRequirementsInfo2* pInfo, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures2* pFeatures); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties2* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties2* pFormatProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, + VkImageFormatProperties2* pImageFormatProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2( + VkPhysicalDevice physicalDevice, + uint32_t* pQueueFamilyPropertyCount, + VkQueueFamilyProperties2* pQueueFamilyProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties2* pMemoryProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, + uint32_t* pPropertyCount, + VkSparseImageFormatProperties2* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkTrimCommandPool( + VkDevice device, + VkCommandPool commandPool, + VkCommandPoolTrimFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue2( + VkDevice device, + const VkDeviceQueueInfo2* pQueueInfo, + VkQueue* pQueue); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, + VkExternalBufferProperties* pExternalBufferProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFenceProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, + VkExternalFenceProperties* pExternalFenceProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphoreProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, + VkExternalSemaphoreProperties* pExternalSemaphoreProperties); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBase( + VkCommandBuffer commandBuffer, + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplate( + VkDevice device, + const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplate( + VkDevice device, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplate( + VkDevice device, + VkDescriptorSet descriptorSet, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const void* pData); + +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupport( + VkDevice device, + const VkDescriptorSetLayoutCreateInfo* pCreateInfo, + VkDescriptorSetLayoutSupport* pSupport); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversion( + VkDevice device, + const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSamplerYcbcrConversion* pYcbcrConversion); + +VKAPI_ATTR void VKAPI_CALL vkDestroySamplerYcbcrConversion( + VkDevice device, + VkSamplerYcbcrConversion ycbcrConversion, + const VkAllocationCallbacks* pAllocator); +#endif + + +// VK_VERSION_1_2 is a preprocessor guard. Do not pass it to API calls. +#define VK_VERSION_1_2 1 +// Vulkan 1.2 version number +#define VK_API_VERSION_1_2 VK_MAKE_API_VERSION(0, 1, 2, 0)// Patch version should always be set to 0 + +#define VK_MAX_DRIVER_NAME_SIZE 256U +#define VK_MAX_DRIVER_INFO_SIZE 256U + +typedef enum VkDriverId { + VK_DRIVER_ID_AMD_PROPRIETARY = 1, + VK_DRIVER_ID_AMD_OPEN_SOURCE = 2, + VK_DRIVER_ID_MESA_RADV = 3, + VK_DRIVER_ID_NVIDIA_PROPRIETARY = 4, + VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS = 5, + VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA = 6, + VK_DRIVER_ID_IMAGINATION_PROPRIETARY = 7, + VK_DRIVER_ID_QUALCOMM_PROPRIETARY = 8, + VK_DRIVER_ID_ARM_PROPRIETARY = 9, + VK_DRIVER_ID_GOOGLE_SWIFTSHADER = 10, + VK_DRIVER_ID_GGP_PROPRIETARY = 11, + VK_DRIVER_ID_BROADCOM_PROPRIETARY = 12, + VK_DRIVER_ID_MESA_LLVMPIPE = 13, + VK_DRIVER_ID_MOLTENVK = 14, + VK_DRIVER_ID_COREAVI_PROPRIETARY = 15, + VK_DRIVER_ID_JUICE_PROPRIETARY = 16, + VK_DRIVER_ID_VERISILICON_PROPRIETARY = 17, + VK_DRIVER_ID_MESA_TURNIP = 18, + VK_DRIVER_ID_MESA_V3DV = 19, + VK_DRIVER_ID_MESA_PANVK = 20, + VK_DRIVER_ID_SAMSUNG_PROPRIETARY = 21, + VK_DRIVER_ID_MESA_VENUS = 22, + VK_DRIVER_ID_MESA_DOZEN = 23, + VK_DRIVER_ID_MESA_NVK = 24, + VK_DRIVER_ID_IMAGINATION_OPEN_SOURCE_MESA = 25, + VK_DRIVER_ID_MESA_HONEYKRISP = 26, + VK_DRIVER_ID_VULKAN_SC_EMULATION_ON_VULKAN = 27, + VK_DRIVER_ID_MESA_KOSMICKRISP = 28, + VK_DRIVER_ID_MESA_GFXSTREAM = 29, + VK_DRIVER_ID_APE_SOFT = 30, + VK_DRIVER_ID_AMD_PROPRIETARY_KHR = VK_DRIVER_ID_AMD_PROPRIETARY, + VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = VK_DRIVER_ID_AMD_OPEN_SOURCE, + VK_DRIVER_ID_MESA_RADV_KHR = VK_DRIVER_ID_MESA_RADV, + VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR = VK_DRIVER_ID_NVIDIA_PROPRIETARY, + VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR = VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS, + VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR = VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA, + VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = VK_DRIVER_ID_IMAGINATION_PROPRIETARY, + VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = VK_DRIVER_ID_QUALCOMM_PROPRIETARY, + VK_DRIVER_ID_ARM_PROPRIETARY_KHR = VK_DRIVER_ID_ARM_PROPRIETARY, + VK_DRIVER_ID_GOOGLE_SWIFTSHADER_KHR = VK_DRIVER_ID_GOOGLE_SWIFTSHADER, + VK_DRIVER_ID_GGP_PROPRIETARY_KHR = VK_DRIVER_ID_GGP_PROPRIETARY, + VK_DRIVER_ID_BROADCOM_PROPRIETARY_KHR = VK_DRIVER_ID_BROADCOM_PROPRIETARY, + VK_DRIVER_ID_MAX_ENUM = 0x7FFFFFFF +} VkDriverId; + +typedef enum VkShaderFloatControlsIndependence { + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY = 0, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL = 1, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE = 2, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_MAX_ENUM = 0x7FFFFFFF +} VkShaderFloatControlsIndependence; + +typedef enum VkSemaphoreType { + VK_SEMAPHORE_TYPE_BINARY = 0, + VK_SEMAPHORE_TYPE_TIMELINE = 1, + VK_SEMAPHORE_TYPE_BINARY_KHR = VK_SEMAPHORE_TYPE_BINARY, + VK_SEMAPHORE_TYPE_TIMELINE_KHR = VK_SEMAPHORE_TYPE_TIMELINE, + VK_SEMAPHORE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkSemaphoreType; + +typedef enum VkSamplerReductionMode { + VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE = 0, + VK_SAMPLER_REDUCTION_MODE_MIN = 1, + VK_SAMPLER_REDUCTION_MODE_MAX = 2, + VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_RANGECLAMP_QCOM = 1000521000, + VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE, + VK_SAMPLER_REDUCTION_MODE_MIN_EXT = VK_SAMPLER_REDUCTION_MODE_MIN, + VK_SAMPLER_REDUCTION_MODE_MAX_EXT = VK_SAMPLER_REDUCTION_MODE_MAX, + VK_SAMPLER_REDUCTION_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerReductionMode; + +typedef enum VkResolveModeFlagBits { + VK_RESOLVE_MODE_NONE = 0, + VK_RESOLVE_MODE_SAMPLE_ZERO_BIT = 0x00000001, + VK_RESOLVE_MODE_AVERAGE_BIT = 0x00000002, + VK_RESOLVE_MODE_MIN_BIT = 0x00000004, + VK_RESOLVE_MODE_MAX_BIT = 0x00000008, + VK_RESOLVE_MODE_EXTERNAL_FORMAT_DOWNSAMPLE_BIT_ANDROID = 0x00000010, + VK_RESOLVE_MODE_CUSTOM_BIT_EXT = 0x00000020, + VK_RESOLVE_MODE_NONE_KHR = VK_RESOLVE_MODE_NONE, + VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT, + VK_RESOLVE_MODE_AVERAGE_BIT_KHR = VK_RESOLVE_MODE_AVERAGE_BIT, + VK_RESOLVE_MODE_MIN_BIT_KHR = VK_RESOLVE_MODE_MIN_BIT, + VK_RESOLVE_MODE_MAX_BIT_KHR = VK_RESOLVE_MODE_MAX_BIT, + // VK_RESOLVE_MODE_EXTERNAL_FORMAT_DOWNSAMPLE_ANDROID is a legacy alias + VK_RESOLVE_MODE_EXTERNAL_FORMAT_DOWNSAMPLE_ANDROID = VK_RESOLVE_MODE_EXTERNAL_FORMAT_DOWNSAMPLE_BIT_ANDROID, + VK_RESOLVE_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkResolveModeFlagBits; +typedef VkFlags VkResolveModeFlags; + +typedef enum VkSemaphoreWaitFlagBits { + VK_SEMAPHORE_WAIT_ANY_BIT = 0x00000001, + VK_SEMAPHORE_WAIT_ANY_BIT_KHR = VK_SEMAPHORE_WAIT_ANY_BIT, + VK_SEMAPHORE_WAIT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSemaphoreWaitFlagBits; +typedef VkFlags VkSemaphoreWaitFlags; + +typedef enum VkDescriptorBindingFlagBits { + VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT = 0x00000001, + VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT = 0x00000002, + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT = 0x00000004, + VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT = 0x00000008, + VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, + VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT = VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, + VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT, + VK_DESCRIPTOR_BINDING_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorBindingFlagBits; +typedef VkFlags VkDescriptorBindingFlags; +typedef struct VkConformanceVersion { + uint8_t major; + uint8_t minor; + uint8_t subminor; + uint8_t patch; +} VkConformanceVersion; + +typedef struct VkPhysicalDeviceDriverProperties { + VkStructureType sType; + void* pNext; + VkDriverId driverID; + char driverName[VK_MAX_DRIVER_NAME_SIZE]; + char driverInfo[VK_MAX_DRIVER_INFO_SIZE]; + VkConformanceVersion conformanceVersion; +} VkPhysicalDeviceDriverProperties; + +typedef struct VkPhysicalDeviceVulkan11Features { + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer16BitAccess; + VkBool32 uniformAndStorageBuffer16BitAccess; + VkBool32 storagePushConstant16; + VkBool32 storageInputOutput16; + VkBool32 multiview; + VkBool32 multiviewGeometryShader; + VkBool32 multiviewTessellationShader; + VkBool32 variablePointersStorageBuffer; + VkBool32 variablePointers; + VkBool32 protectedMemory; + VkBool32 samplerYcbcrConversion; + VkBool32 shaderDrawParameters; +} VkPhysicalDeviceVulkan11Features; + +typedef struct VkPhysicalDeviceVulkan11Properties { + VkStructureType sType; + void* pNext; + uint8_t deviceUUID[VK_UUID_SIZE]; + uint8_t driverUUID[VK_UUID_SIZE]; + uint8_t deviceLUID[VK_LUID_SIZE]; + uint32_t deviceNodeMask; + VkBool32 deviceLUIDValid; + uint32_t subgroupSize; + VkShaderStageFlags subgroupSupportedStages; + VkSubgroupFeatureFlags subgroupSupportedOperations; + VkBool32 subgroupQuadOperationsInAllStages; + VkPointClippingBehavior pointClippingBehavior; + uint32_t maxMultiviewViewCount; + uint32_t maxMultiviewInstanceIndex; + VkBool32 protectedNoFault; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceVulkan11Properties; + +typedef struct VkPhysicalDeviceVulkan12Features { + VkStructureType sType; + void* pNext; + VkBool32 samplerMirrorClampToEdge; + VkBool32 drawIndirectCount; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; + VkBool32 shaderBufferInt64Atomics; + VkBool32 shaderSharedInt64Atomics; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; + VkBool32 descriptorIndexing; + VkBool32 shaderInputAttachmentArrayDynamicIndexing; + VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; + VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; + VkBool32 shaderUniformBufferArrayNonUniformIndexing; + VkBool32 shaderSampledImageArrayNonUniformIndexing; + VkBool32 shaderStorageBufferArrayNonUniformIndexing; + VkBool32 shaderStorageImageArrayNonUniformIndexing; + VkBool32 shaderInputAttachmentArrayNonUniformIndexing; + VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; + VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; + VkBool32 descriptorBindingUniformBufferUpdateAfterBind; + VkBool32 descriptorBindingSampledImageUpdateAfterBind; + VkBool32 descriptorBindingStorageImageUpdateAfterBind; + VkBool32 descriptorBindingStorageBufferUpdateAfterBind; + VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingUpdateUnusedWhilePending; + VkBool32 descriptorBindingPartiallyBound; + VkBool32 descriptorBindingVariableDescriptorCount; + VkBool32 runtimeDescriptorArray; + VkBool32 samplerFilterMinmax; + VkBool32 scalarBlockLayout; + VkBool32 imagelessFramebuffer; + VkBool32 uniformBufferStandardLayout; + VkBool32 shaderSubgroupExtendedTypes; + VkBool32 separateDepthStencilLayouts; + VkBool32 hostQueryReset; + VkBool32 timelineSemaphore; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; + VkBool32 vulkanMemoryModel; + VkBool32 vulkanMemoryModelDeviceScope; + VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; + VkBool32 shaderOutputViewportIndex; + VkBool32 shaderOutputLayer; + VkBool32 subgroupBroadcastDynamicId; +} VkPhysicalDeviceVulkan12Features; + +typedef struct VkPhysicalDeviceVulkan12Properties { + VkStructureType sType; + void* pNext; + VkDriverId driverID; + char driverName[VK_MAX_DRIVER_NAME_SIZE]; + char driverInfo[VK_MAX_DRIVER_INFO_SIZE]; + VkConformanceVersion conformanceVersion; + VkShaderFloatControlsIndependence denormBehaviorIndependence; + VkShaderFloatControlsIndependence roundingModeIndependence; + VkBool32 shaderSignedZeroInfNanPreserveFloat16; + VkBool32 shaderSignedZeroInfNanPreserveFloat32; + VkBool32 shaderSignedZeroInfNanPreserveFloat64; + VkBool32 shaderDenormPreserveFloat16; + VkBool32 shaderDenormPreserveFloat32; + VkBool32 shaderDenormPreserveFloat64; + VkBool32 shaderDenormFlushToZeroFloat16; + VkBool32 shaderDenormFlushToZeroFloat32; + VkBool32 shaderDenormFlushToZeroFloat64; + VkBool32 shaderRoundingModeRTEFloat16; + VkBool32 shaderRoundingModeRTEFloat32; + VkBool32 shaderRoundingModeRTEFloat64; + VkBool32 shaderRoundingModeRTZFloat16; + VkBool32 shaderRoundingModeRTZFloat32; + VkBool32 shaderRoundingModeRTZFloat64; + uint32_t maxUpdateAfterBindDescriptorsInAllPools; + VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; + VkBool32 shaderSampledImageArrayNonUniformIndexingNative; + VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; + VkBool32 shaderStorageImageArrayNonUniformIndexingNative; + VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; + VkBool32 robustBufferAccessUpdateAfterBind; + VkBool32 quadDivergentImplicitLod; + uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; + uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; + uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; + uint32_t maxPerStageUpdateAfterBindResources; + uint32_t maxDescriptorSetUpdateAfterBindSamplers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindSampledImages; + uint32_t maxDescriptorSetUpdateAfterBindStorageImages; + uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; + VkResolveModeFlags supportedDepthResolveModes; + VkResolveModeFlags supportedStencilResolveModes; + VkBool32 independentResolveNone; + VkBool32 independentResolve; + VkBool32 filterMinmaxSingleComponentFormats; + VkBool32 filterMinmaxImageComponentMapping; + uint64_t maxTimelineSemaphoreValueDifference; + VkSampleCountFlags framebufferIntegerColorSampleCounts; +} VkPhysicalDeviceVulkan12Properties; + +typedef struct VkImageFormatListCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t viewFormatCount; + const VkFormat* pViewFormats; +} VkImageFormatListCreateInfo; + +typedef struct VkPhysicalDeviceVulkanMemoryModelFeatures { + VkStructureType sType; + void* pNext; + VkBool32 vulkanMemoryModel; + VkBool32 vulkanMemoryModelDeviceScope; + VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; +} VkPhysicalDeviceVulkanMemoryModelFeatures; + +typedef struct VkPhysicalDeviceHostQueryResetFeatures { + VkStructureType sType; + void* pNext; + VkBool32 hostQueryReset; +} VkPhysicalDeviceHostQueryResetFeatures; + +typedef struct VkPhysicalDeviceTimelineSemaphoreFeatures { + VkStructureType sType; + void* pNext; + VkBool32 timelineSemaphore; +} VkPhysicalDeviceTimelineSemaphoreFeatures; + +typedef struct VkPhysicalDeviceTimelineSemaphoreProperties { + VkStructureType sType; + void* pNext; + uint64_t maxTimelineSemaphoreValueDifference; +} VkPhysicalDeviceTimelineSemaphoreProperties; + +typedef struct VkSemaphoreTypeCreateInfo { + VkStructureType sType; + const void* pNext; + VkSemaphoreType semaphoreType; + uint64_t initialValue; +} VkSemaphoreTypeCreateInfo; + +typedef struct VkTimelineSemaphoreSubmitInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreValueCount; + const uint64_t* pWaitSemaphoreValues; + uint32_t signalSemaphoreValueCount; + const uint64_t* pSignalSemaphoreValues; +} VkTimelineSemaphoreSubmitInfo; + +typedef struct VkSemaphoreWaitInfo { + VkStructureType sType; + const void* pNext; + VkSemaphoreWaitFlags flags; + uint32_t semaphoreCount; + const VkSemaphore* pSemaphores; + const uint64_t* pValues; +} VkSemaphoreWaitInfo; + +typedef struct VkSemaphoreSignalInfo { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + uint64_t value; +} VkSemaphoreSignalInfo; + +typedef struct VkPhysicalDeviceBufferDeviceAddressFeatures { + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferDeviceAddressFeatures; + +typedef struct VkBufferDeviceAddressInfo { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferDeviceAddressInfo; + +typedef struct VkBufferOpaqueCaptureAddressCreateInfo { + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkBufferOpaqueCaptureAddressCreateInfo; + +typedef struct VkMemoryOpaqueCaptureAddressAllocateInfo { + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkMemoryOpaqueCaptureAddressAllocateInfo; + +typedef struct VkDeviceMemoryOpaqueCaptureAddressInfo { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; +} VkDeviceMemoryOpaqueCaptureAddressInfo; + +typedef struct VkPhysicalDevice8BitStorageFeatures { + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; +} VkPhysicalDevice8BitStorageFeatures; + +typedef struct VkPhysicalDeviceShaderAtomicInt64Features { + VkStructureType sType; + void* pNext; + VkBool32 shaderBufferInt64Atomics; + VkBool32 shaderSharedInt64Atomics; +} VkPhysicalDeviceShaderAtomicInt64Features; + +typedef struct VkPhysicalDeviceShaderFloat16Int8Features { + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; +} VkPhysicalDeviceShaderFloat16Int8Features; + +typedef struct VkPhysicalDeviceFloatControlsProperties { + VkStructureType sType; + void* pNext; + VkShaderFloatControlsIndependence denormBehaviorIndependence; + VkShaderFloatControlsIndependence roundingModeIndependence; + VkBool32 shaderSignedZeroInfNanPreserveFloat16; + VkBool32 shaderSignedZeroInfNanPreserveFloat32; + VkBool32 shaderSignedZeroInfNanPreserveFloat64; + VkBool32 shaderDenormPreserveFloat16; + VkBool32 shaderDenormPreserveFloat32; + VkBool32 shaderDenormPreserveFloat64; + VkBool32 shaderDenormFlushToZeroFloat16; + VkBool32 shaderDenormFlushToZeroFloat32; + VkBool32 shaderDenormFlushToZeroFloat64; + VkBool32 shaderRoundingModeRTEFloat16; + VkBool32 shaderRoundingModeRTEFloat32; + VkBool32 shaderRoundingModeRTEFloat64; + VkBool32 shaderRoundingModeRTZFloat16; + VkBool32 shaderRoundingModeRTZFloat32; + VkBool32 shaderRoundingModeRTZFloat64; +} VkPhysicalDeviceFloatControlsProperties; + +typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t bindingCount; + const VkDescriptorBindingFlags* pBindingFlags; +} VkDescriptorSetLayoutBindingFlagsCreateInfo; + +typedef struct VkPhysicalDeviceDescriptorIndexingFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderInputAttachmentArrayDynamicIndexing; + VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; + VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; + VkBool32 shaderUniformBufferArrayNonUniformIndexing; + VkBool32 shaderSampledImageArrayNonUniformIndexing; + VkBool32 shaderStorageBufferArrayNonUniformIndexing; + VkBool32 shaderStorageImageArrayNonUniformIndexing; + VkBool32 shaderInputAttachmentArrayNonUniformIndexing; + VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; + VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; + VkBool32 descriptorBindingUniformBufferUpdateAfterBind; + VkBool32 descriptorBindingSampledImageUpdateAfterBind; + VkBool32 descriptorBindingStorageImageUpdateAfterBind; + VkBool32 descriptorBindingStorageBufferUpdateAfterBind; + VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingUpdateUnusedWhilePending; + VkBool32 descriptorBindingPartiallyBound; + VkBool32 descriptorBindingVariableDescriptorCount; + VkBool32 runtimeDescriptorArray; +} VkPhysicalDeviceDescriptorIndexingFeatures; + +typedef struct VkPhysicalDeviceDescriptorIndexingProperties { + VkStructureType sType; + void* pNext; + uint32_t maxUpdateAfterBindDescriptorsInAllPools; + VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; + VkBool32 shaderSampledImageArrayNonUniformIndexingNative; + VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; + VkBool32 shaderStorageImageArrayNonUniformIndexingNative; + VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; + VkBool32 robustBufferAccessUpdateAfterBind; + VkBool32 quadDivergentImplicitLod; + uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; + uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; + uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; + uint32_t maxPerStageUpdateAfterBindResources; + uint32_t maxDescriptorSetUpdateAfterBindSamplers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindSampledImages; + uint32_t maxDescriptorSetUpdateAfterBindStorageImages; + uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; +} VkPhysicalDeviceDescriptorIndexingProperties; + +typedef struct VkDescriptorSetVariableDescriptorCountAllocateInfo { + VkStructureType sType; + const void* pNext; + uint32_t descriptorSetCount; + const uint32_t* pDescriptorCounts; +} VkDescriptorSetVariableDescriptorCountAllocateInfo; + +typedef struct VkDescriptorSetVariableDescriptorCountLayoutSupport { + VkStructureType sType; + void* pNext; + uint32_t maxVariableDescriptorCount; +} VkDescriptorSetVariableDescriptorCountLayoutSupport; + +typedef struct VkPhysicalDeviceScalarBlockLayoutFeatures { + VkStructureType sType; + void* pNext; + VkBool32 scalarBlockLayout; +} VkPhysicalDeviceScalarBlockLayoutFeatures; + +typedef struct VkSamplerReductionModeCreateInfo { + VkStructureType sType; + const void* pNext; + VkSamplerReductionMode reductionMode; +} VkSamplerReductionModeCreateInfo; + +typedef struct VkPhysicalDeviceSamplerFilterMinmaxProperties { + VkStructureType sType; + void* pNext; + VkBool32 filterMinmaxSingleComponentFormats; + VkBool32 filterMinmaxImageComponentMapping; +} VkPhysicalDeviceSamplerFilterMinmaxProperties; + +typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeatures { + VkStructureType sType; + void* pNext; + VkBool32 uniformBufferStandardLayout; +} VkPhysicalDeviceUniformBufferStandardLayoutFeatures; + +typedef struct VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderSubgroupExtendedTypes; +} VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures; + +typedef struct VkAttachmentDescription2 { + VkStructureType sType; + const void* pNext; + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription2; + +typedef struct VkAttachmentReference2 { + VkStructureType sType; + const void* pNext; + uint32_t attachment; + VkImageLayout layout; + VkImageAspectFlags aspectMask; +} VkAttachmentReference2; + +typedef struct VkSubpassDescription2 { + VkStructureType sType; + const void* pNext; + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t viewMask; + uint32_t inputAttachmentCount; + const VkAttachmentReference2* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference2* pColorAttachments; + const VkAttachmentReference2* pResolveAttachments; + const VkAttachmentReference2* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription2; + +typedef struct VkSubpassDependency2 { + VkStructureType sType; + const void* pNext; + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; + int32_t viewOffset; +} VkSubpassDependency2; + +typedef struct VkSubpassBeginInfo { + VkStructureType sType; + const void* pNext; + VkSubpassContents contents; +} VkSubpassBeginInfo; + +typedef struct VkSubpassEndInfo { + VkStructureType sType; + const void* pNext; +} VkSubpassEndInfo; + +typedef struct VkRenderPassCreateInfo2 { + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription2* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription2* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency2* pDependencies; + uint32_t correlatedViewMaskCount; + const uint32_t* pCorrelatedViewMasks; +} VkRenderPassCreateInfo2; + +typedef struct VkSubpassDescriptionDepthStencilResolve { + VkStructureType sType; + const void* pNext; + VkResolveModeFlagBits depthResolveMode; + VkResolveModeFlagBits stencilResolveMode; + const VkAttachmentReference2* pDepthStencilResolveAttachment; +} VkSubpassDescriptionDepthStencilResolve; + +typedef struct VkPhysicalDeviceDepthStencilResolveProperties { + VkStructureType sType; + void* pNext; + VkResolveModeFlags supportedDepthResolveModes; + VkResolveModeFlags supportedStencilResolveModes; + VkBool32 independentResolveNone; + VkBool32 independentResolve; +} VkPhysicalDeviceDepthStencilResolveProperties; + +typedef struct VkImageStencilUsageCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageUsageFlags stencilUsage; +} VkImageStencilUsageCreateInfo; + +typedef struct VkPhysicalDeviceImagelessFramebufferFeatures { + VkStructureType sType; + void* pNext; + VkBool32 imagelessFramebuffer; +} VkPhysicalDeviceImagelessFramebufferFeatures; + +typedef struct VkFramebufferAttachmentImageInfo { + VkStructureType sType; + const void* pNext; + VkImageCreateFlags flags; + VkImageUsageFlags usage; + uint32_t width; + uint32_t height; + uint32_t layerCount; + uint32_t viewFormatCount; + const VkFormat* pViewFormats; +} VkFramebufferAttachmentImageInfo; + +typedef struct VkRenderPassAttachmentBeginInfo { + VkStructureType sType; + const void* pNext; + uint32_t attachmentCount; + const VkImageView* pAttachments; +} VkRenderPassAttachmentBeginInfo; + +typedef struct VkFramebufferAttachmentsCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t attachmentImageInfoCount; + const VkFramebufferAttachmentImageInfo* pAttachmentImageInfos; +} VkFramebufferAttachmentsCreateInfo; + +typedef struct VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures { + VkStructureType sType; + void* pNext; + VkBool32 separateDepthStencilLayouts; +} VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures; + +typedef struct VkAttachmentReferenceStencilLayout { + VkStructureType sType; + void* pNext; + VkImageLayout stencilLayout; +} VkAttachmentReferenceStencilLayout; + +typedef struct VkAttachmentDescriptionStencilLayout { + VkStructureType sType; + void* pNext; + VkImageLayout stencilInitialLayout; + VkImageLayout stencilFinalLayout; +} VkAttachmentDescriptionStencilLayout; + +typedef void (VKAPI_PTR *PFN_vkResetQueryPool)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); +typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreCounterValue)(VkDevice device, VkSemaphore semaphore, uint64_t* pValue); +typedef VkResult (VKAPI_PTR *PFN_vkWaitSemaphores)(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout); +typedef VkResult (VKAPI_PTR *PFN_vkSignalSemaphore)(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo); +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddress)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetBufferOpaqueCaptureAddress)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetDeviceMemoryOpaqueCaptureAddress)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCount)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCount)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass2)(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass2)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo); +typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass2)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass2)(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkResetQueryPool( + VkDevice device, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreCounterValue( + VkDevice device, + VkSemaphore semaphore, + uint64_t* pValue); + +VKAPI_ATTR VkResult VKAPI_CALL vkWaitSemaphores( + VkDevice device, + const VkSemaphoreWaitInfo* pWaitInfo, + uint64_t timeout); + +VKAPI_ATTR VkResult VKAPI_CALL vkSignalSemaphore( + VkDevice device, + const VkSemaphoreSignalInfo* pSignalInfo); + +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddress( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); + +VKAPI_ATTR uint64_t VKAPI_CALL vkGetBufferOpaqueCaptureAddress( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); + +VKAPI_ATTR uint64_t VKAPI_CALL vkGetDeviceMemoryOpaqueCaptureAddress( + VkDevice device, + const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCount( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCount( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass2( + VkDevice device, + const VkRenderPassCreateInfo2* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkRenderPass* pRenderPass); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass2( + VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo* pRenderPassBegin, + const VkSubpassBeginInfo* pSubpassBeginInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass2( + VkCommandBuffer commandBuffer, + const VkSubpassBeginInfo* pSubpassBeginInfo, + const VkSubpassEndInfo* pSubpassEndInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass2( + VkCommandBuffer commandBuffer, + const VkSubpassEndInfo* pSubpassEndInfo); +#endif + + +// VK_VERSION_1_3 is a preprocessor guard. Do not pass it to API calls. +#define VK_VERSION_1_3 1 +// Vulkan 1.3 version number +#define VK_API_VERSION_1_3 VK_MAKE_API_VERSION(0, 1, 3, 0)// Patch version should always be set to 0 + +typedef uint64_t VkFlags64; +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPrivateDataSlot) + +typedef enum VkToolPurposeFlagBits { + VK_TOOL_PURPOSE_VALIDATION_BIT = 0x00000001, + VK_TOOL_PURPOSE_PROFILING_BIT = 0x00000002, + VK_TOOL_PURPOSE_TRACING_BIT = 0x00000004, + VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT = 0x00000008, + VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT = 0x00000010, + VK_TOOL_PURPOSE_DEBUG_REPORTING_BIT_EXT = 0x00000020, + VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT = 0x00000040, + VK_TOOL_PURPOSE_VALIDATION_BIT_EXT = VK_TOOL_PURPOSE_VALIDATION_BIT, + VK_TOOL_PURPOSE_PROFILING_BIT_EXT = VK_TOOL_PURPOSE_PROFILING_BIT, + VK_TOOL_PURPOSE_TRACING_BIT_EXT = VK_TOOL_PURPOSE_TRACING_BIT, + VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT = VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT, + VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT = VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT, + VK_TOOL_PURPOSE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkToolPurposeFlagBits; +typedef VkFlags VkToolPurposeFlags; +typedef VkFlags VkPrivateDataSlotCreateFlags; +typedef VkFlags64 VkPipelineStageFlags2; + +// Flag bits for VkPipelineStageFlagBits2 +typedef VkFlags64 VkPipelineStageFlagBits2; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_NONE = 0ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT = 0x00000001ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT = 0x00000002ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT = 0x00000004ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT = 0x00000008ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT = 0x00000040ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT = 0x00000080ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT = 0x00000100ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT = 0x00000200ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT = 0x00000800ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT = 0x00001000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFER_BIT = 0x00001000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT = 0x00002000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_HOST_BIT = 0x00004000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT = 0x00008000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT = 0x00010000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COPY_BIT = 0x100000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RESOLVE_BIT = 0x200000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BLIT_BIT = 0x400000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLEAR_BIT = 0x800000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT = 0x1000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT = 0x2000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT = 0x4000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR = 0x04000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR = 0x08000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_NONE_KHR = 0ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR = 0x00000001ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR = 0x00000002ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR = 0x00000004ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR = 0x00000008ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT_KHR = 0x00000010ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT_KHR = 0x00000020ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT_KHR = 0x00000040ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR = 0x00000080ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR = 0x00000100ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR = 0x00000200ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR = 0x00000400ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR = 0x00000800ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR = 0x00001000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR = 0x00001000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR = 0x00002000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_HOST_BIT_KHR = 0x00004000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT_KHR = 0x00008000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR = 0x00010000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COPY_BIT_KHR = 0x100000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RESOLVE_BIT_KHR = 0x200000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BLIT_BIT_KHR = 0x400000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR = 0x800000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR = 0x1000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT_KHR = 0x2000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR = 0x4000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_NV = 0x00020000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_EXT = 0x00020000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00400000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SHADING_RATE_IMAGE_BIT_NV = 0x00400000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 0x02000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR = 0x00200000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_NV = 0x00200000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_NV = 0x00080000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_NV = 0x00100000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT = 0x00080000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT = 0x00100000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SUBPASS_SHADER_BIT_HUAWEI = 0x8000000000ULL; +// VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI is a legacy alias +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI = 0x8000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INVOCATION_MASK_BIT_HUAWEI = 0x10000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_COPY_BIT_KHR = 0x10000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MICROMAP_BUILD_BIT_EXT = 0x40000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLUSTER_CULLING_SHADER_BIT_HUAWEI = 0x20000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_OPTICAL_FLOW_BIT_NV = 0x20000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CONVERT_COOPERATIVE_VECTOR_MATRIX_BIT_NV = 0x100000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_DATA_GRAPH_BIT_ARM = 0x40000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COPY_INDIRECT_BIT_KHR = 0x400000000000ULL; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MEMORY_DECOMPRESSION_BIT_EXT = 0x200000000000ULL; + +typedef VkFlags64 VkAccessFlags2; + +// Flag bits for VkAccessFlagBits2 +typedef VkFlags64 VkAccessFlagBits2; +static const VkAccessFlagBits2 VK_ACCESS_2_NONE = 0ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT = 0x00000001ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INDEX_READ_BIT = 0x00000002ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_UNIFORM_READ_BIT = 0x00000008ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT = 0x00000010ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_READ_BIT = 0x00000020ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_WRITE_BIT = 0x00000040ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT = 0x00000080ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_READ_BIT = 0x00000800ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_WRITE_BIT = 0x00001000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_READ_BIT = 0x00002000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_WRITE_BIT = 0x00004000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_READ_BIT = 0x00008000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_WRITE_BIT = 0x00010000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT = 0x100000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_READ_BIT = 0x200000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT = 0x400000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR = 0x800000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR = 0x1000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SAMPLER_HEAP_READ_BIT_EXT = 0x200000000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_RESOURCE_HEAP_READ_BIT_EXT = 0x400000000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_VIDEO_ENCODE_READ_BIT_KHR = 0x2000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_VIDEO_ENCODE_WRITE_BIT_KHR = 0x4000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_TILE_ATTACHMENT_READ_BIT_QCOM = 0x8000000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_TILE_ATTACHMENT_WRITE_BIT_QCOM = 0x10000000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_NONE_KHR = 0ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR = 0x00000001ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INDEX_READ_BIT_KHR = 0x00000002ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR = 0x00000004ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_UNIFORM_READ_BIT_KHR = 0x00000008ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT_KHR = 0x00000010ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_READ_BIT_KHR = 0x00000020ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_WRITE_BIT_KHR = 0x00000040ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR = 0x00000080ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR = 0x00000100ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR = 0x00000200ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR = 0x00000400ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_READ_BIT_KHR = 0x00000800ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR = 0x00001000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_READ_BIT_KHR = 0x00002000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_WRITE_BIT_KHR = 0x00004000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_READ_BIT_KHR = 0x00008000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_WRITE_BIT_KHR = 0x00010000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT_KHR = 0x100000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_READ_BIT_KHR = 0x200000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR = 0x400000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_READ_BIT_NV = 0x00020000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_WRITE_BIT_NV = 0x00040000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_READ_BIT_EXT = 0x00020000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_WRITE_BIT_EXT = 0x00040000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR = 0x00800000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR = 0x00200000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR = 0x00400000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT = 0x20000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_INVOCATION_MASK_READ_BIT_HUAWEI = 0x8000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_BINDING_TABLE_READ_BIT_KHR = 0x10000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MICROMAP_READ_BIT_EXT = 0x100000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MICROMAP_WRITE_BIT_EXT = 0x200000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_OPTICAL_FLOW_READ_BIT_NV = 0x40000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_OPTICAL_FLOW_WRITE_BIT_NV = 0x80000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_DATA_GRAPH_READ_BIT_ARM = 0x800000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_DATA_GRAPH_WRITE_BIT_ARM = 0x1000000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_DECOMPRESSION_READ_BIT_EXT = 0x80000000000000ULL; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_DECOMPRESSION_WRITE_BIT_EXT = 0x100000000000000ULL; + + +typedef enum VkSubmitFlagBits { + VK_SUBMIT_PROTECTED_BIT = 0x00000001, + VK_SUBMIT_PROTECTED_BIT_KHR = VK_SUBMIT_PROTECTED_BIT, + VK_SUBMIT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubmitFlagBits; +typedef VkFlags VkSubmitFlags; +typedef VkFlags64 VkFormatFeatureFlags2; + +// Flag bits for VkFormatFeatureFlagBits2 +typedef VkFlags64 VkFormatFeatureFlagBits2; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT = 0x00000001ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT = 0x00000002ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT = 0x00000010ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT = 0x00000040ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT = 0x00000080ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_SRC_BIT = 0x00000400ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_DST_BIT = 0x00000800ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT = 0x00004000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT = 0x00008000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT = 0x00010000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DISJOINT_BIT = 0x00400000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT = 0x00800000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT = 0x80000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT = 0x100000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT = 0x200000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT = 0x00002000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT = 0x400000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_DECODE_OUTPUT_BIT_KHR = 0x02000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_DECODE_DPB_BIT_KHR = 0x04000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR = 0x20000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x01000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x40000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT = 0x400000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_ENCODE_INPUT_BIT_KHR = 0x08000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_ENCODE_DPB_BIT_KHR = 0x10000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLOCK_MATCHING_SXD_BIT_QCOM = 0x100000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT_KHR = 0x00000001ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT_KHR = 0x00000002ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT_KHR = 0x00000004ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT_KHR = 0x00000008ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT_KHR = 0x00000010ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT_KHR = 0x00000020ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT_KHR = 0x00000040ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT_KHR = 0x00000080ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT_KHR = 0x00000100ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT_KHR = 0x00000200ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_SRC_BIT_KHR = 0x00000400ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_DST_BIT_KHR = 0x00000800ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT_KHR = 0x00001000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT_KHR = 0x00004000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT_KHR = 0x00008000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = 0x00020000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = 0x00040000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = 0x00080000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = 0x00100000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = 0x00200000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DISJOINT_BIT_KHR = 0x00400000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT_KHR = 0x00800000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT_KHR = 0x80000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR = 0x100000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT_KHR = 0x200000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT_KHR = 0x00010000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = 0x00002000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_ACCELERATION_STRUCTURE_RADIUS_BUFFER_BIT_NV = 0x8000000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_LINEAR_COLOR_ATTACHMENT_BIT_NV = 0x4000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_WEIGHT_IMAGE_BIT_QCOM = 0x400000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_WEIGHT_SAMPLED_IMAGE_BIT_QCOM = 0x800000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLOCK_MATCHING_BIT_QCOM = 0x1000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BOX_FILTER_SAMPLED_BIT_QCOM = 0x2000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TENSOR_SHADER_BIT_ARM = 0x8000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TENSOR_IMAGE_ALIASING_BIT_ARM = 0x80000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_IMAGE_BIT_NV = 0x10000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_VECTOR_BIT_NV = 0x20000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_COST_BIT_NV = 0x40000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TENSOR_DATA_GRAPH_BIT_ARM = 0x1000000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COPY_IMAGE_INDIRECT_DST_BIT_KHR = 0x800000000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_ENCODE_QUANTIZATION_DELTA_MAP_BIT_KHR = 0x2000000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_ENCODE_EMPHASIS_MAP_BIT_KHR = 0x4000000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_2D_BIT_IMG = 0x200000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DEPTH_COPY_ON_COMPUTE_QUEUE_BIT_KHR = 0x10000000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DEPTH_COPY_ON_TRANSFER_QUEUE_BIT_KHR = 0x20000000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STENCIL_COPY_ON_COMPUTE_QUEUE_BIT_KHR = 0x40000000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STENCIL_COPY_ON_TRANSFER_QUEUE_BIT_KHR = 0x80000000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DATA_GRAPH_OPTICAL_FLOW_IMAGE_BIT_ARM = 0x100000000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DATA_GRAPH_OPTICAL_FLOW_VECTOR_BIT_ARM = 0x200000000000000ULL; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DATA_GRAPH_OPTICAL_FLOW_COST_BIT_ARM = 0x400000000000000ULL; + + +typedef enum VkPipelineCreationFeedbackFlagBits { + VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT = 0x00000001, + VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT = 0x00000002, + VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT = 0x00000004, + VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT, + VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT, + VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT, + VK_PIPELINE_CREATION_FEEDBACK_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCreationFeedbackFlagBits; +typedef VkFlags VkPipelineCreationFeedbackFlags; + +typedef enum VkRenderingFlagBits { + VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT = 0x00000001, + VK_RENDERING_SUSPENDING_BIT = 0x00000002, + VK_RENDERING_RESUMING_BIT = 0x00000004, + VK_RENDERING_ENABLE_LEGACY_DITHERING_BIT_EXT = 0x00000008, + VK_RENDERING_CONTENTS_INLINE_BIT_KHR = 0x00000010, + VK_RENDERING_PER_LAYER_FRAGMENT_DENSITY_BIT_VALVE = 0x00000020, + VK_RENDERING_FRAGMENT_REGION_BIT_EXT = 0x00000040, + VK_RENDERING_CUSTOM_RESOLVE_BIT_EXT = 0x00000080, + VK_RENDERING_LOCAL_READ_CONCURRENT_ACCESS_CONTROL_BIT_KHR = 0x00000100, + VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR = VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT, + VK_RENDERING_SUSPENDING_BIT_KHR = VK_RENDERING_SUSPENDING_BIT, + VK_RENDERING_RESUMING_BIT_KHR = VK_RENDERING_RESUMING_BIT, + VK_RENDERING_CONTENTS_INLINE_BIT_EXT = VK_RENDERING_CONTENTS_INLINE_BIT_KHR, + VK_RENDERING_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkRenderingFlagBits; +typedef VkFlags VkRenderingFlags; +typedef struct VkPhysicalDeviceVulkan13Features { + VkStructureType sType; + void* pNext; + VkBool32 robustImageAccess; + VkBool32 inlineUniformBlock; + VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; + VkBool32 pipelineCreationCacheControl; + VkBool32 privateData; + VkBool32 shaderDemoteToHelperInvocation; + VkBool32 shaderTerminateInvocation; + VkBool32 subgroupSizeControl; + VkBool32 computeFullSubgroups; + VkBool32 synchronization2; + VkBool32 textureCompressionASTC_HDR; + VkBool32 shaderZeroInitializeWorkgroupMemory; + VkBool32 dynamicRendering; + VkBool32 shaderIntegerDotProduct; + VkBool32 maintenance4; +} VkPhysicalDeviceVulkan13Features; + +typedef struct VkPhysicalDeviceVulkan13Properties { + VkStructureType sType; + void* pNext; + uint32_t minSubgroupSize; + uint32_t maxSubgroupSize; + uint32_t maxComputeWorkgroupSubgroups; + VkShaderStageFlags requiredSubgroupSizeStages; + uint32_t maxInlineUniformBlockSize; + uint32_t maxPerStageDescriptorInlineUniformBlocks; + uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; + uint32_t maxDescriptorSetInlineUniformBlocks; + uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; + uint32_t maxInlineUniformTotalSize; + VkBool32 integerDotProduct8BitUnsignedAccelerated; + VkBool32 integerDotProduct8BitSignedAccelerated; + VkBool32 integerDotProduct8BitMixedSignednessAccelerated; + VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedSignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProduct16BitUnsignedAccelerated; + VkBool32 integerDotProduct16BitSignedAccelerated; + VkBool32 integerDotProduct16BitMixedSignednessAccelerated; + VkBool32 integerDotProduct32BitUnsignedAccelerated; + VkBool32 integerDotProduct32BitSignedAccelerated; + VkBool32 integerDotProduct32BitMixedSignednessAccelerated; + VkBool32 integerDotProduct64BitUnsignedAccelerated; + VkBool32 integerDotProduct64BitSignedAccelerated; + VkBool32 integerDotProduct64BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; + VkDeviceSize storageTexelBufferOffsetAlignmentBytes; + VkBool32 storageTexelBufferOffsetSingleTexelAlignment; + VkDeviceSize uniformTexelBufferOffsetAlignmentBytes; + VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; + VkDeviceSize maxBufferSize; +} VkPhysicalDeviceVulkan13Properties; + +typedef struct VkPhysicalDeviceToolProperties { + VkStructureType sType; + void* pNext; + char name[VK_MAX_EXTENSION_NAME_SIZE]; + char version[VK_MAX_EXTENSION_NAME_SIZE]; + VkToolPurposeFlags purposes; + char description[VK_MAX_DESCRIPTION_SIZE]; + char layer[VK_MAX_EXTENSION_NAME_SIZE]; +} VkPhysicalDeviceToolProperties; + +typedef struct VkPhysicalDevicePrivateDataFeatures { + VkStructureType sType; + void* pNext; + VkBool32 privateData; +} VkPhysicalDevicePrivateDataFeatures; + +typedef struct VkDevicePrivateDataCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t privateDataSlotRequestCount; +} VkDevicePrivateDataCreateInfo; + +typedef struct VkPrivateDataSlotCreateInfo { + VkStructureType sType; + const void* pNext; + VkPrivateDataSlotCreateFlags flags; +} VkPrivateDataSlotCreateInfo; + +typedef struct VkMemoryBarrier2 { + VkStructureType sType; + const void* pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; +} VkMemoryBarrier2; + +typedef struct VkBufferMemoryBarrier2 { + VkStructureType sType; + const void* pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; +} VkBufferMemoryBarrier2; + +typedef struct VkImageMemoryBarrier2 { + VkStructureType sType; + const void* pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkImage image; + VkImageSubresourceRange subresourceRange; +} VkImageMemoryBarrier2; + +typedef struct VkDependencyInfo { + VkStructureType sType; + const void* pNext; + VkDependencyFlags dependencyFlags; + uint32_t memoryBarrierCount; + const VkMemoryBarrier2* pMemoryBarriers; + uint32_t bufferMemoryBarrierCount; + const VkBufferMemoryBarrier2* pBufferMemoryBarriers; + uint32_t imageMemoryBarrierCount; + const VkImageMemoryBarrier2* pImageMemoryBarriers; +} VkDependencyInfo; + +typedef struct VkSemaphoreSubmitInfo { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + uint64_t value; + VkPipelineStageFlags2 stageMask; + uint32_t deviceIndex; +} VkSemaphoreSubmitInfo; + +typedef struct VkCommandBufferSubmitInfo { + VkStructureType sType; + const void* pNext; + VkCommandBuffer commandBuffer; + uint32_t deviceMask; +} VkCommandBufferSubmitInfo; + +typedef struct VkSubmitInfo2 { + VkStructureType sType; + const void* pNext; + VkSubmitFlags flags; + uint32_t waitSemaphoreInfoCount; + const VkSemaphoreSubmitInfo* pWaitSemaphoreInfos; + uint32_t commandBufferInfoCount; + const VkCommandBufferSubmitInfo* pCommandBufferInfos; + uint32_t signalSemaphoreInfoCount; + const VkSemaphoreSubmitInfo* pSignalSemaphoreInfos; +} VkSubmitInfo2; + +typedef struct VkPhysicalDeviceSynchronization2Features { + VkStructureType sType; + void* pNext; + VkBool32 synchronization2; +} VkPhysicalDeviceSynchronization2Features; + +typedef struct VkBufferCopy2 { + VkStructureType sType; + const void* pNext; + VkDeviceSize srcOffset; + VkDeviceSize dstOffset; + VkDeviceSize size; +} VkBufferCopy2; + +typedef struct VkCopyBufferInfo2 { + VkStructureType sType; + const void* pNext; + VkBuffer srcBuffer; + VkBuffer dstBuffer; + uint32_t regionCount; + const VkBufferCopy2* pRegions; +} VkCopyBufferInfo2; + +typedef struct VkImageCopy2 { + VkStructureType sType; + const void* pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageCopy2; + +typedef struct VkCopyImageInfo2 { + VkStructureType sType; + const void* pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageCopy2* pRegions; +} VkCopyImageInfo2; + +typedef struct VkBufferImageCopy2 { + VkStructureType sType; + const void* pNext; + VkDeviceSize bufferOffset; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkBufferImageCopy2; + +typedef struct VkCopyBufferToImageInfo2 { + VkStructureType sType; + const void* pNext; + VkBuffer srcBuffer; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkBufferImageCopy2* pRegions; +} VkCopyBufferToImageInfo2; + +typedef struct VkCopyImageToBufferInfo2 { + VkStructureType sType; + const void* pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkBuffer dstBuffer; + uint32_t regionCount; + const VkBufferImageCopy2* pRegions; +} VkCopyImageToBufferInfo2; + +typedef struct VkPhysicalDeviceTextureCompressionASTCHDRFeatures { + VkStructureType sType; + void* pNext; + VkBool32 textureCompressionASTC_HDR; +} VkPhysicalDeviceTextureCompressionASTCHDRFeatures; + +typedef struct VkFormatProperties3 { + VkStructureType sType; + void* pNext; + VkFormatFeatureFlags2 linearTilingFeatures; + VkFormatFeatureFlags2 optimalTilingFeatures; + VkFormatFeatureFlags2 bufferFeatures; +} VkFormatProperties3; + +typedef struct VkPhysicalDeviceMaintenance4Features { + VkStructureType sType; + void* pNext; + VkBool32 maintenance4; +} VkPhysicalDeviceMaintenance4Features; + +typedef struct VkPhysicalDeviceMaintenance4Properties { + VkStructureType sType; + void* pNext; + VkDeviceSize maxBufferSize; +} VkPhysicalDeviceMaintenance4Properties; + +typedef struct VkDeviceBufferMemoryRequirements { + VkStructureType sType; + const void* pNext; + const VkBufferCreateInfo* pCreateInfo; +} VkDeviceBufferMemoryRequirements; + +typedef struct VkDeviceImageMemoryRequirements { + VkStructureType sType; + const void* pNext; + const VkImageCreateInfo* pCreateInfo; + VkImageAspectFlagBits planeAspect; +} VkDeviceImageMemoryRequirements; + +typedef struct VkPipelineCreationFeedback { + VkPipelineCreationFeedbackFlags flags; + uint64_t duration; +} VkPipelineCreationFeedback; + +typedef struct VkPipelineCreationFeedbackCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCreationFeedback* pPipelineCreationFeedback; + uint32_t pipelineStageCreationFeedbackCount; + VkPipelineCreationFeedback* pPipelineStageCreationFeedbacks; +} VkPipelineCreationFeedbackCreateInfo; + +typedef struct VkPhysicalDeviceShaderTerminateInvocationFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderTerminateInvocation; +} VkPhysicalDeviceShaderTerminateInvocationFeatures; + +typedef struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderDemoteToHelperInvocation; +} VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures; + +typedef struct VkPhysicalDevicePipelineCreationCacheControlFeatures { + VkStructureType sType; + void* pNext; + VkBool32 pipelineCreationCacheControl; +} VkPhysicalDevicePipelineCreationCacheControlFeatures; + +typedef struct VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderZeroInitializeWorkgroupMemory; +} VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures; + +typedef struct VkPhysicalDeviceImageRobustnessFeatures { + VkStructureType sType; + void* pNext; + VkBool32 robustImageAccess; +} VkPhysicalDeviceImageRobustnessFeatures; + +typedef struct VkPhysicalDeviceSubgroupSizeControlFeatures { + VkStructureType sType; + void* pNext; + VkBool32 subgroupSizeControl; + VkBool32 computeFullSubgroups; +} VkPhysicalDeviceSubgroupSizeControlFeatures; + +typedef struct VkPhysicalDeviceSubgroupSizeControlProperties { + VkStructureType sType; + void* pNext; + uint32_t minSubgroupSize; + uint32_t maxSubgroupSize; + uint32_t maxComputeWorkgroupSubgroups; + VkShaderStageFlags requiredSubgroupSizeStages; +} VkPhysicalDeviceSubgroupSizeControlProperties; + +typedef struct VkPipelineShaderStageRequiredSubgroupSizeCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t requiredSubgroupSize; +} VkPipelineShaderStageRequiredSubgroupSizeCreateInfo; + +typedef struct VkPhysicalDeviceInlineUniformBlockFeatures { + VkStructureType sType; + void* pNext; + VkBool32 inlineUniformBlock; + VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; +} VkPhysicalDeviceInlineUniformBlockFeatures; + +typedef struct VkPhysicalDeviceInlineUniformBlockProperties { + VkStructureType sType; + void* pNext; + uint32_t maxInlineUniformBlockSize; + uint32_t maxPerStageDescriptorInlineUniformBlocks; + uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; + uint32_t maxDescriptorSetInlineUniformBlocks; + uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; +} VkPhysicalDeviceInlineUniformBlockProperties; + +typedef struct VkWriteDescriptorSetInlineUniformBlock { + VkStructureType sType; + const void* pNext; + uint32_t dataSize; + const void* pData; +} VkWriteDescriptorSetInlineUniformBlock; + +typedef struct VkDescriptorPoolInlineUniformBlockCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t maxInlineUniformBlockBindings; +} VkDescriptorPoolInlineUniformBlockCreateInfo; + +typedef struct VkPhysicalDeviceShaderIntegerDotProductFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderIntegerDotProduct; +} VkPhysicalDeviceShaderIntegerDotProductFeatures; + +typedef struct VkPhysicalDeviceShaderIntegerDotProductProperties { + VkStructureType sType; + void* pNext; + VkBool32 integerDotProduct8BitUnsignedAccelerated; + VkBool32 integerDotProduct8BitSignedAccelerated; + VkBool32 integerDotProduct8BitMixedSignednessAccelerated; + VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedSignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProduct16BitUnsignedAccelerated; + VkBool32 integerDotProduct16BitSignedAccelerated; + VkBool32 integerDotProduct16BitMixedSignednessAccelerated; + VkBool32 integerDotProduct32BitUnsignedAccelerated; + VkBool32 integerDotProduct32BitSignedAccelerated; + VkBool32 integerDotProduct32BitMixedSignednessAccelerated; + VkBool32 integerDotProduct64BitUnsignedAccelerated; + VkBool32 integerDotProduct64BitSignedAccelerated; + VkBool32 integerDotProduct64BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; +} VkPhysicalDeviceShaderIntegerDotProductProperties; + +typedef struct VkPhysicalDeviceTexelBufferAlignmentProperties { + VkStructureType sType; + void* pNext; + VkDeviceSize storageTexelBufferOffsetAlignmentBytes; + VkBool32 storageTexelBufferOffsetSingleTexelAlignment; + VkDeviceSize uniformTexelBufferOffsetAlignmentBytes; + VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; +} VkPhysicalDeviceTexelBufferAlignmentProperties; + +typedef struct VkImageBlit2 { + VkStructureType sType; + const void* pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffsets[2]; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffsets[2]; +} VkImageBlit2; + +typedef struct VkBlitImageInfo2 { + VkStructureType sType; + const void* pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageBlit2* pRegions; + VkFilter filter; +} VkBlitImageInfo2; + +typedef struct VkImageResolve2 { + VkStructureType sType; + const void* pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageResolve2; + +typedef struct VkResolveImageInfo2 { + VkStructureType sType; + const void* pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageResolve2* pRegions; +} VkResolveImageInfo2; + +typedef struct VkRenderingAttachmentInfo { + VkStructureType sType; + const void* pNext; + VkImageView imageView; + VkImageLayout imageLayout; + VkResolveModeFlagBits resolveMode; + VkImageView resolveImageView; + VkImageLayout resolveImageLayout; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkClearValue clearValue; +} VkRenderingAttachmentInfo; + +typedef struct VkRenderingInfo { + VkStructureType sType; + const void* pNext; + VkRenderingFlags flags; + VkRect2D renderArea; + uint32_t layerCount; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkRenderingAttachmentInfo* pColorAttachments; + const VkRenderingAttachmentInfo* pDepthAttachment; + const VkRenderingAttachmentInfo* pStencilAttachment; +} VkRenderingInfo; + +typedef struct VkPipelineRenderingCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkFormat* pColorAttachmentFormats; + VkFormat depthAttachmentFormat; + VkFormat stencilAttachmentFormat; +} VkPipelineRenderingCreateInfo; + +typedef struct VkPhysicalDeviceDynamicRenderingFeatures { + VkStructureType sType; + void* pNext; + VkBool32 dynamicRendering; +} VkPhysicalDeviceDynamicRenderingFeatures; + +typedef struct VkCommandBufferInheritanceRenderingInfo { + VkStructureType sType; + const void* pNext; + VkRenderingFlags flags; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkFormat* pColorAttachmentFormats; + VkFormat depthAttachmentFormat; + VkFormat stencilAttachmentFormat; + VkSampleCountFlagBits rasterizationSamples; +} VkCommandBufferInheritanceRenderingInfo; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceToolProperties)(VkPhysicalDevice physicalDevice, uint32_t* pToolCount, VkPhysicalDeviceToolProperties* pToolProperties); +typedef VkResult (VKAPI_PTR *PFN_vkCreatePrivateDataSlot)(VkDevice device, const VkPrivateDataSlotCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPrivateDataSlot* pPrivateDataSlot); +typedef void (VKAPI_PTR *PFN_vkDestroyPrivateDataSlot)(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkSetPrivateData)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data); +typedef void (VKAPI_PTR *PFN_vkGetPrivateData)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t* pData); +typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier2)(VkCommandBuffer commandBuffer, const VkDependencyInfo* pDependencyInfo); +typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp2)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkQueryPool queryPool, uint32_t query); +typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit2)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2* pSubmits, VkFence fence); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer2)(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2* pCopyBufferInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImage2)(VkCommandBuffer commandBuffer, const VkCopyImageInfo2* pCopyImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage2)(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2* pCopyBufferToImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer2)(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2* pCopyImageToBufferInfo); +typedef void (VKAPI_PTR *PFN_vkGetDeviceBufferMemoryRequirements)(VkDevice device, const VkDeviceBufferMemoryRequirements* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetDeviceImageMemoryRequirements)(VkDevice device, const VkDeviceImageMemoryRequirements* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetDeviceImageSparseMemoryRequirements)(VkDevice device, const VkDeviceImageMemoryRequirements* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkCmdSetEvent2)(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfo* pDependencyInfo); +typedef void (VKAPI_PTR *PFN_vkCmdResetEvent2)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2 stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents2)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, const VkDependencyInfo* pDependencyInfos); +typedef void (VKAPI_PTR *PFN_vkCmdBlitImage2)(VkCommandBuffer commandBuffer, const VkBlitImageInfo2* pBlitImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdResolveImage2)(VkCommandBuffer commandBuffer, const VkResolveImageInfo2* pResolveImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRendering)(VkCommandBuffer commandBuffer, const VkRenderingInfo* pRenderingInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndRendering)(VkCommandBuffer commandBuffer); +typedef void (VKAPI_PTR *PFN_vkCmdSetCullMode)(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode); +typedef void (VKAPI_PTR *PFN_vkCmdSetFrontFace)(VkCommandBuffer commandBuffer, VkFrontFace frontFace); +typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveTopology)(VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWithCount)(VkCommandBuffer commandBuffer, uint32_t viewportCount, const VkViewport* pViewports); +typedef void (VKAPI_PTR *PFN_vkCmdSetScissorWithCount)(VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D* pScissors); +typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers2)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets, const VkDeviceSize* pSizes, const VkDeviceSize* pStrides); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthTestEnable)(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthWriteEnable)(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthCompareOp)(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBoundsTestEnable)(VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilTestEnable)(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilOp)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp); +typedef void (VKAPI_PTR *PFN_vkCmdSetRasterizerDiscardEnable)(VkCommandBuffer commandBuffer, VkBool32 rasterizerDiscardEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBiasEnable)(VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveRestartEnable)(VkCommandBuffer commandBuffer, VkBool32 primitiveRestartEnable); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceToolProperties( + VkPhysicalDevice physicalDevice, + uint32_t* pToolCount, + VkPhysicalDeviceToolProperties* pToolProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePrivateDataSlot( + VkDevice device, + const VkPrivateDataSlotCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPrivateDataSlot* pPrivateDataSlot); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPrivateDataSlot( + VkDevice device, + VkPrivateDataSlot privateDataSlot, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkSetPrivateData( + VkDevice device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlot privateDataSlot, + uint64_t data); + +VKAPI_ATTR void VKAPI_CALL vkGetPrivateData( + VkDevice device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlot privateDataSlot, + uint64_t* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier2( + VkCommandBuffer commandBuffer, + const VkDependencyInfo* pDependencyInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp2( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags2 stage, + VkQueryPool queryPool, + uint32_t query); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit2( + VkQueue queue, + uint32_t submitCount, + const VkSubmitInfo2* pSubmits, + VkFence fence); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer2( + VkCommandBuffer commandBuffer, + const VkCopyBufferInfo2* pCopyBufferInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage2( + VkCommandBuffer commandBuffer, + const VkCopyImageInfo2* pCopyImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage2( + VkCommandBuffer commandBuffer, + const VkCopyBufferToImageInfo2* pCopyBufferToImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer2( + VkCommandBuffer commandBuffer, + const VkCopyImageToBufferInfo2* pCopyImageToBufferInfo); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceBufferMemoryRequirements( + VkDevice device, + const VkDeviceBufferMemoryRequirements* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceImageMemoryRequirements( + VkDevice device, + const VkDeviceImageMemoryRequirements* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceImageSparseMemoryRequirements( + VkDevice device, + const VkDeviceImageMemoryRequirements* pInfo, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent2( + VkCommandBuffer commandBuffer, + VkEvent event, + const VkDependencyInfo* pDependencyInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent2( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags2 stageMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents2( + VkCommandBuffer commandBuffer, + uint32_t eventCount, + const VkEvent* pEvents, + const VkDependencyInfo* pDependencyInfos); + +VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage2( + VkCommandBuffer commandBuffer, + const VkBlitImageInfo2* pBlitImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage2( + VkCommandBuffer commandBuffer, + const VkResolveImageInfo2* pResolveImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRendering( + VkCommandBuffer commandBuffer, + const VkRenderingInfo* pRenderingInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRendering( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetCullMode( + VkCommandBuffer commandBuffer, + VkCullModeFlags cullMode); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetFrontFace( + VkCommandBuffer commandBuffer, + VkFrontFace frontFace); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetPrimitiveTopology( + VkCommandBuffer commandBuffer, + VkPrimitiveTopology primitiveTopology); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWithCount( + VkCommandBuffer commandBuffer, + uint32_t viewportCount, + const VkViewport* pViewports); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetScissorWithCount( + VkCommandBuffer commandBuffer, + uint32_t scissorCount, + const VkRect2D* pScissors); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers2( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets, + const VkDeviceSize* pSizes, + const VkDeviceSize* pStrides); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthTestEnable( + VkCommandBuffer commandBuffer, + VkBool32 depthTestEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthWriteEnable( + VkCommandBuffer commandBuffer, + VkBool32 depthWriteEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthCompareOp( + VkCommandBuffer commandBuffer, + VkCompareOp depthCompareOp); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBoundsTestEnable( + VkCommandBuffer commandBuffer, + VkBool32 depthBoundsTestEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilTestEnable( + VkCommandBuffer commandBuffer, + VkBool32 stencilTestEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilOp( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + VkStencilOp failOp, + VkStencilOp passOp, + VkStencilOp depthFailOp, + VkCompareOp compareOp); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetRasterizerDiscardEnable( + VkCommandBuffer commandBuffer, + VkBool32 rasterizerDiscardEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBiasEnable( + VkCommandBuffer commandBuffer, + VkBool32 depthBiasEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetPrimitiveRestartEnable( + VkCommandBuffer commandBuffer, + VkBool32 primitiveRestartEnable); +#endif + + +// VK_VERSION_1_4 is a preprocessor guard. Do not pass it to API calls. +#define VK_VERSION_1_4 1 +// Vulkan 1.4 version number +#define VK_API_VERSION_1_4 VK_MAKE_API_VERSION(0, 1, 4, 0)// Patch version should always be set to 0 + +#define VK_MAX_GLOBAL_PRIORITY_SIZE 16U + +typedef enum VkPipelineRobustnessBufferBehavior { + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT = 0, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED = 1, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS = 2, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2 = 3, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT_EXT = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED_EXT = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2_EXT = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF +} VkPipelineRobustnessBufferBehavior; + +typedef enum VkPipelineRobustnessImageBehavior { + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT = 0, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DISABLED = 1, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS = 2, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2 = 3, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT_EXT = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DISABLED_EXT = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DISABLED, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_EXT = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2_EXT = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF +} VkPipelineRobustnessImageBehavior; + +typedef enum VkQueueGlobalPriority { + VK_QUEUE_GLOBAL_PRIORITY_LOW = 128, + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM = 256, + VK_QUEUE_GLOBAL_PRIORITY_HIGH = 512, + VK_QUEUE_GLOBAL_PRIORITY_REALTIME = 1024, + VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT = VK_QUEUE_GLOBAL_PRIORITY_LOW, + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM, + VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT = VK_QUEUE_GLOBAL_PRIORITY_HIGH, + VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = VK_QUEUE_GLOBAL_PRIORITY_REALTIME, + VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR = VK_QUEUE_GLOBAL_PRIORITY_LOW, + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM, + VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR = VK_QUEUE_GLOBAL_PRIORITY_HIGH, + VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR = VK_QUEUE_GLOBAL_PRIORITY_REALTIME, + VK_QUEUE_GLOBAL_PRIORITY_MAX_ENUM = 0x7FFFFFFF +} VkQueueGlobalPriority; + +typedef enum VkLineRasterizationMode { + VK_LINE_RASTERIZATION_MODE_DEFAULT = 0, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR = 1, + VK_LINE_RASTERIZATION_MODE_BRESENHAM = 2, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH = 3, + VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT = VK_LINE_RASTERIZATION_MODE_DEFAULT, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT = VK_LINE_RASTERIZATION_MODE_RECTANGULAR, + VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT = VK_LINE_RASTERIZATION_MODE_BRESENHAM, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH, + VK_LINE_RASTERIZATION_MODE_DEFAULT_KHR = VK_LINE_RASTERIZATION_MODE_DEFAULT, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_KHR = VK_LINE_RASTERIZATION_MODE_RECTANGULAR, + VK_LINE_RASTERIZATION_MODE_BRESENHAM_KHR = VK_LINE_RASTERIZATION_MODE_BRESENHAM, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_KHR = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH, + VK_LINE_RASTERIZATION_MODE_MAX_ENUM = 0x7FFFFFFF +} VkLineRasterizationMode; + +typedef enum VkMemoryUnmapFlagBits { + VK_MEMORY_UNMAP_RESERVE_BIT_EXT = 0x00000001, + VK_MEMORY_UNMAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryUnmapFlagBits; +typedef VkFlags VkMemoryUnmapFlags; +typedef VkFlags64 VkBufferUsageFlags2; + +// Flag bits for VkBufferUsageFlagBits2 +typedef VkFlags64 VkBufferUsageFlagBits2; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFER_SRC_BIT = 0x00000001ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFER_DST_BIT = 0x00000002ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_STORAGE_TEXEL_BUFFER_BIT = 0x00000008ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_UNIFORM_BUFFER_BIT = 0x00000010ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT = 0x00000020ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_INDEX_BUFFER_BIT = 0x00000040ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VERTEX_BUFFER_BIT = 0x00000080ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_INDIRECT_BUFFER_BIT = 0x00000100ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT = 0x00020000ULL; +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_EXECUTION_GRAPH_SCRATCH_BIT_AMDX = 0x02000000ULL; +#endif +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_DESCRIPTOR_HEAP_BIT_EXT = 0x10000000ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_MICROMAP_BUILD_INPUT_READ_ONLY_BIT_EXT = 0x00800000ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_MICROMAP_STORAGE_BIT_EXT = 0x01000000ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFER_SRC_BIT_KHR = 0x00000001ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFER_DST_BIT_KHR = 0x00000002ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_UNIFORM_TEXEL_BUFFER_BIT_KHR = 0x00000004ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_STORAGE_TEXEL_BUFFER_BIT_KHR = 0x00000008ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_UNIFORM_BUFFER_BIT_KHR = 0x00000010ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR = 0x00000020ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_INDEX_BUFFER_BIT_KHR = 0x00000040ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VERTEX_BUFFER_BIT_KHR = 0x00000080ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_INDIRECT_BUFFER_BIT_KHR = 0x00000100ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_SHADER_BINDING_TABLE_BIT_KHR = 0x00000400ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_RAY_TRACING_BIT_NV = 0x00000400ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VIDEO_DECODE_SRC_BIT_KHR = 0x00002000ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VIDEO_DECODE_DST_BIT_KHR = 0x00004000ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VIDEO_ENCODE_DST_BIT_KHR = 0x00008000ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VIDEO_ENCODE_SRC_BIT_KHR = 0x00010000ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT_KHR = 0x00020000ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR = 0x00080000ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR = 0x00100000ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT = 0x00200000ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT = 0x00400000ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT = 0x04000000ULL; +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_COMPRESSED_DATA_DGF1_BIT_AMDX = 0x200000000ULL; +#endif +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_DATA_GRAPH_FOREIGN_DESCRIPTOR_BIT_ARM = 0x20000000ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TILE_MEMORY_BIT_QCOM = 0x08000000ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_MEMORY_DECOMPRESSION_BIT_EXT = 0x100000000ULL; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_PREPROCESS_BUFFER_BIT_EXT = 0x80000000ULL; + + +typedef enum VkHostImageCopyFlagBits { + VK_HOST_IMAGE_COPY_MEMCPY_BIT = 0x00000001, + // VK_HOST_IMAGE_COPY_MEMCPY is a legacy alias + VK_HOST_IMAGE_COPY_MEMCPY = VK_HOST_IMAGE_COPY_MEMCPY_BIT, + VK_HOST_IMAGE_COPY_MEMCPY_BIT_EXT = VK_HOST_IMAGE_COPY_MEMCPY_BIT, + // VK_HOST_IMAGE_COPY_MEMCPY_EXT is a legacy alias + VK_HOST_IMAGE_COPY_MEMCPY_EXT = VK_HOST_IMAGE_COPY_MEMCPY_BIT, + VK_HOST_IMAGE_COPY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkHostImageCopyFlagBits; +typedef VkFlags VkHostImageCopyFlags; +typedef VkFlags64 VkPipelineCreateFlags2; + +// Flag bits for VkPipelineCreateFlagBits2 +typedef VkFlags64 VkPipelineCreateFlagBits2; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DISABLE_OPTIMIZATION_BIT = 0x00000001ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_ALLOW_DERIVATIVES_BIT = 0x00000002ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DERIVATIVE_BIT = 0x00000004ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DISPATCH_BASE_BIT = 0x00000010ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT = 0x00000100ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_EARLY_RETURN_ON_FAILURE_BIT = 0x00000200ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_NO_PROTECTED_ACCESS_BIT = 0x08000000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_PROTECTED_ACCESS_ONLY_BIT = 0x40000000ULL; +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_EXECUTION_GRAPH_BIT_AMDX = 0x100000000ULL; +#endif +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT = 0x1000000000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_SKIP_BUILT_IN_PRIMITIVES_BIT_KHR = 0x00001000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_OPACITY_MICROMAP_BIT_EXT = 0x01000000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_ALLOW_SPHERES_AND_LINEAR_SWEPT_SPHERES_BIT_NV = 0x200000000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_ENABLE_LEGACY_DITHERING_BIT_EXT = 0x400000000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DISABLE_OPTIMIZATION_BIT_KHR = 0x00000001ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_ALLOW_DERIVATIVES_BIT_KHR = 0x00000002ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DERIVATIVE_BIT_KHR = 0x00000004ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = 0x00000008ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DISPATCH_BASE_BIT_KHR = 0x00000010ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DEFER_COMPILE_BIT_NV = 0x00000020ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_CAPTURE_STATISTICS_BIT_KHR = 0x00000040ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR = 0x00000080ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_KHR = 0x00000100ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_EARLY_RETURN_ON_FAILURE_BIT_KHR = 0x00000200ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_LINK_TIME_OPTIMIZATION_BIT_EXT = 0x00000400ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT = 0x00800000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_LIBRARY_BIT_KHR = 0x00000800ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR = 0x00001000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_SKIP_AABBS_BIT_KHR = 0x00002000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR = 0x00004000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR = 0x00008000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR = 0x00010000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR = 0x00020000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR = 0x00080000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_INDIRECT_BINDABLE_BIT_NV = 0x00040000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_ALLOW_MOTION_BIT_NV = 0x00100000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00200000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 0x00400000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_COLOR_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x02000000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x04000000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_NO_PROTECTED_ACCESS_BIT_EXT = 0x08000000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_PROTECTED_ACCESS_ONLY_BIT_EXT = 0x40000000ULL; +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_DISPLACEMENT_MICROMAP_BIT_NV = 0x10000000ULL; +#endif +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DESCRIPTOR_BUFFER_BIT_EXT = 0x20000000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DISALLOW_OPACITY_MICROMAP_BIT_ARM = 0x2000000000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_INSTRUMENT_SHADERS_BIT_ARM = 0x8000000000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_CAPTURE_DATA_BIT_KHR = 0x80000000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_INDIRECT_BINDABLE_BIT_EXT = 0x4000000000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_PER_LAYER_FRAGMENT_DENSITY_BIT_VALVE = 0x10000000000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_OPACITY_MICROMAP_BIT_KHR = 0x01000000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_OPACITY_MICROMAP_DISALLOW_MIXED_SPECIAL_INDEX_BIT_KHR = 0x20000000000ULL; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_64_BIT_INDEXING_BIT_EXT = 0x80000000000ULL; + +typedef struct VkPhysicalDeviceVulkan14Features { + VkStructureType sType; + void* pNext; + VkBool32 globalPriorityQuery; + VkBool32 shaderSubgroupRotate; + VkBool32 shaderSubgroupRotateClustered; + VkBool32 shaderFloatControls2; + VkBool32 shaderExpectAssume; + VkBool32 rectangularLines; + VkBool32 bresenhamLines; + VkBool32 smoothLines; + VkBool32 stippledRectangularLines; + VkBool32 stippledBresenhamLines; + VkBool32 stippledSmoothLines; + VkBool32 vertexAttributeInstanceRateDivisor; + VkBool32 vertexAttributeInstanceRateZeroDivisor; + VkBool32 indexTypeUint8; + VkBool32 dynamicRenderingLocalRead; + VkBool32 maintenance5; + VkBool32 maintenance6; + VkBool32 pipelineProtectedAccess; + VkBool32 pipelineRobustness; + VkBool32 hostImageCopy; + VkBool32 pushDescriptor; +} VkPhysicalDeviceVulkan14Features; + +typedef struct VkPhysicalDeviceVulkan14Properties { + VkStructureType sType; + void* pNext; + uint32_t lineSubPixelPrecisionBits; + uint32_t maxVertexAttribDivisor; + VkBool32 supportsNonZeroFirstInstance; + uint32_t maxPushDescriptors; + VkBool32 dynamicRenderingLocalReadDepthStencilAttachments; + VkBool32 dynamicRenderingLocalReadMultisampledAttachments; + VkBool32 earlyFragmentMultisampleCoverageAfterSampleCounting; + VkBool32 earlyFragmentSampleMaskTestBeforeSampleCounting; + VkBool32 depthStencilSwizzleOneSupport; + VkBool32 polygonModePointSize; + VkBool32 nonStrictSinglePixelWideLinesUseParallelogram; + VkBool32 nonStrictWideLinesUseParallelogram; + VkBool32 blockTexelViewCompatibleMultipleLayers; + uint32_t maxCombinedImageSamplerDescriptorCount; + VkBool32 fragmentShadingRateClampCombinerInputs; + VkPipelineRobustnessBufferBehavior defaultRobustnessStorageBuffers; + VkPipelineRobustnessBufferBehavior defaultRobustnessUniformBuffers; + VkPipelineRobustnessBufferBehavior defaultRobustnessVertexInputs; + VkPipelineRobustnessImageBehavior defaultRobustnessImages; + uint32_t copySrcLayoutCount; + VkImageLayout* pCopySrcLayouts; + uint32_t copyDstLayoutCount; + VkImageLayout* pCopyDstLayouts; + uint8_t optimalTilingLayoutUUID[VK_UUID_SIZE]; + VkBool32 identicalMemoryTypeRequirements; +} VkPhysicalDeviceVulkan14Properties; + +typedef struct VkDeviceQueueGlobalPriorityCreateInfo { + VkStructureType sType; + const void* pNext; + VkQueueGlobalPriority globalPriority; +} VkDeviceQueueGlobalPriorityCreateInfo; + +typedef struct VkPhysicalDeviceGlobalPriorityQueryFeatures { + VkStructureType sType; + void* pNext; + VkBool32 globalPriorityQuery; +} VkPhysicalDeviceGlobalPriorityQueryFeatures; + +typedef struct VkQueueFamilyGlobalPriorityProperties { + VkStructureType sType; + void* pNext; + uint32_t priorityCount; + VkQueueGlobalPriority priorities[VK_MAX_GLOBAL_PRIORITY_SIZE]; +} VkQueueFamilyGlobalPriorityProperties; + +typedef struct VkPhysicalDeviceIndexTypeUint8Features { + VkStructureType sType; + void* pNext; + VkBool32 indexTypeUint8; +} VkPhysicalDeviceIndexTypeUint8Features; + +typedef struct VkMemoryMapInfo { + VkStructureType sType; + const void* pNext; + VkMemoryMapFlags flags; + VkDeviceMemory memory; + VkDeviceSize offset; + VkDeviceSize size; +} VkMemoryMapInfo; + +typedef struct VkMemoryUnmapInfo { + VkStructureType sType; + const void* pNext; + VkMemoryUnmapFlags flags; + VkDeviceMemory memory; +} VkMemoryUnmapInfo; + +typedef struct VkPhysicalDeviceMaintenance5Features { + VkStructureType sType; + void* pNext; + VkBool32 maintenance5; +} VkPhysicalDeviceMaintenance5Features; + +typedef struct VkPhysicalDeviceMaintenance5Properties { + VkStructureType sType; + void* pNext; + VkBool32 earlyFragmentMultisampleCoverageAfterSampleCounting; + VkBool32 earlyFragmentSampleMaskTestBeforeSampleCounting; + VkBool32 depthStencilSwizzleOneSupport; + VkBool32 polygonModePointSize; + VkBool32 nonStrictSinglePixelWideLinesUseParallelogram; + VkBool32 nonStrictWideLinesUseParallelogram; +} VkPhysicalDeviceMaintenance5Properties; + +typedef struct VkSubresourceLayout2 { + VkStructureType sType; + void* pNext; + VkSubresourceLayout subresourceLayout; +} VkSubresourceLayout2; + +typedef struct VkImageSubresource2 { + VkStructureType sType; + void* pNext; + VkImageSubresource imageSubresource; +} VkImageSubresource2; + +typedef struct VkDeviceImageSubresourceInfo { + VkStructureType sType; + const void* pNext; + const VkImageCreateInfo* pCreateInfo; + const VkImageSubresource2* pSubresource; +} VkDeviceImageSubresourceInfo; + +typedef struct VkBufferUsageFlags2CreateInfo { + VkStructureType sType; + const void* pNext; + VkBufferUsageFlags2 usage; +} VkBufferUsageFlags2CreateInfo; + +typedef struct VkPhysicalDeviceMaintenance6Features { + VkStructureType sType; + void* pNext; + VkBool32 maintenance6; +} VkPhysicalDeviceMaintenance6Features; + +typedef struct VkPhysicalDeviceMaintenance6Properties { + VkStructureType sType; + void* pNext; + VkBool32 blockTexelViewCompatibleMultipleLayers; + uint32_t maxCombinedImageSamplerDescriptorCount; + VkBool32 fragmentShadingRateClampCombinerInputs; +} VkPhysicalDeviceMaintenance6Properties; + +typedef struct VkBindMemoryStatus { + VkStructureType sType; + const void* pNext; + VkResult* pResult; +} VkBindMemoryStatus; + +typedef struct VkPhysicalDeviceHostImageCopyFeatures { + VkStructureType sType; + void* pNext; + VkBool32 hostImageCopy; +} VkPhysicalDeviceHostImageCopyFeatures; + +typedef struct VkPhysicalDeviceHostImageCopyProperties { + VkStructureType sType; + void* pNext; + uint32_t copySrcLayoutCount; + VkImageLayout* pCopySrcLayouts; + uint32_t copyDstLayoutCount; + VkImageLayout* pCopyDstLayouts; + uint8_t optimalTilingLayoutUUID[VK_UUID_SIZE]; + VkBool32 identicalMemoryTypeRequirements; +} VkPhysicalDeviceHostImageCopyProperties; + +typedef struct VkMemoryToImageCopy { + VkStructureType sType; + const void* pNext; + const void* pHostPointer; + uint32_t memoryRowLength; + uint32_t memoryImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkMemoryToImageCopy; + +typedef struct VkImageToMemoryCopy { + VkStructureType sType; + const void* pNext; + void* pHostPointer; + uint32_t memoryRowLength; + uint32_t memoryImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkImageToMemoryCopy; + +typedef struct VkCopyMemoryToImageInfo { + VkStructureType sType; + const void* pNext; + VkHostImageCopyFlags flags; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkMemoryToImageCopy* pRegions; +} VkCopyMemoryToImageInfo; + +typedef struct VkCopyImageToMemoryInfo { + VkStructureType sType; + const void* pNext; + VkHostImageCopyFlags flags; + VkImage srcImage; + VkImageLayout srcImageLayout; + uint32_t regionCount; + const VkImageToMemoryCopy* pRegions; +} VkCopyImageToMemoryInfo; + +typedef struct VkCopyImageToImageInfo { + VkStructureType sType; + const void* pNext; + VkHostImageCopyFlags flags; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageCopy2* pRegions; +} VkCopyImageToImageInfo; + +typedef struct VkHostImageLayoutTransitionInfo { + VkStructureType sType; + const void* pNext; + VkImage image; + VkImageLayout oldLayout; + VkImageLayout newLayout; + VkImageSubresourceRange subresourceRange; +} VkHostImageLayoutTransitionInfo; + +typedef struct VkSubresourceHostMemcpySize { + VkStructureType sType; + void* pNext; + VkDeviceSize size; +} VkSubresourceHostMemcpySize; + +typedef struct VkHostImageCopyDevicePerformanceQuery { + VkStructureType sType; + void* pNext; + VkBool32 optimalDeviceAccess; + VkBool32 identicalMemoryLayout; +} VkHostImageCopyDevicePerformanceQuery; + +typedef struct VkPhysicalDeviceShaderSubgroupRotateFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderSubgroupRotate; + VkBool32 shaderSubgroupRotateClustered; +} VkPhysicalDeviceShaderSubgroupRotateFeatures; + +typedef struct VkPhysicalDeviceShaderFloatControls2Features { + VkStructureType sType; + void* pNext; + VkBool32 shaderFloatControls2; +} VkPhysicalDeviceShaderFloatControls2Features; + +typedef struct VkPhysicalDeviceShaderExpectAssumeFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderExpectAssume; +} VkPhysicalDeviceShaderExpectAssumeFeatures; + +typedef struct VkPipelineCreateFlags2CreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags2 flags; +} VkPipelineCreateFlags2CreateInfo; + +typedef struct VkPhysicalDevicePushDescriptorProperties { + VkStructureType sType; + void* pNext; + uint32_t maxPushDescriptors; +} VkPhysicalDevicePushDescriptorProperties; + +typedef struct VkBindDescriptorSetsInfo { + VkStructureType sType; + const void* pNext; + VkShaderStageFlags stageFlags; + VkPipelineLayout layout; + uint32_t firstSet; + uint32_t descriptorSetCount; + const VkDescriptorSet* pDescriptorSets; + uint32_t dynamicOffsetCount; + const uint32_t* pDynamicOffsets; +} VkBindDescriptorSetsInfo; + +typedef struct VkPushConstantsInfo { + VkStructureType sType; + const void* pNext; + VkPipelineLayout layout; + VkShaderStageFlags stageFlags; + uint32_t offset; + uint32_t size; + const void* pValues; +} VkPushConstantsInfo; + +typedef struct VkPushDescriptorSetInfo { + VkStructureType sType; + const void* pNext; + VkShaderStageFlags stageFlags; + VkPipelineLayout layout; + uint32_t set; + uint32_t descriptorWriteCount; + const VkWriteDescriptorSet* pDescriptorWrites; +} VkPushDescriptorSetInfo; + +typedef struct VkPushDescriptorSetWithTemplateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorUpdateTemplate descriptorUpdateTemplate; + VkPipelineLayout layout; + uint32_t set; + const void* pData; +} VkPushDescriptorSetWithTemplateInfo; + +typedef struct VkPhysicalDevicePipelineProtectedAccessFeatures { + VkStructureType sType; + void* pNext; + VkBool32 pipelineProtectedAccess; +} VkPhysicalDevicePipelineProtectedAccessFeatures; + +typedef struct VkPhysicalDevicePipelineRobustnessFeatures { + VkStructureType sType; + void* pNext; + VkBool32 pipelineRobustness; +} VkPhysicalDevicePipelineRobustnessFeatures; + +typedef struct VkPhysicalDevicePipelineRobustnessProperties { + VkStructureType sType; + void* pNext; + VkPipelineRobustnessBufferBehavior defaultRobustnessStorageBuffers; + VkPipelineRobustnessBufferBehavior defaultRobustnessUniformBuffers; + VkPipelineRobustnessBufferBehavior defaultRobustnessVertexInputs; + VkPipelineRobustnessImageBehavior defaultRobustnessImages; +} VkPhysicalDevicePipelineRobustnessProperties; + +typedef struct VkPipelineRobustnessCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineRobustnessBufferBehavior storageBuffers; + VkPipelineRobustnessBufferBehavior uniformBuffers; + VkPipelineRobustnessBufferBehavior vertexInputs; + VkPipelineRobustnessImageBehavior images; +} VkPipelineRobustnessCreateInfo; + +typedef struct VkPhysicalDeviceLineRasterizationFeatures { + VkStructureType sType; + void* pNext; + VkBool32 rectangularLines; + VkBool32 bresenhamLines; + VkBool32 smoothLines; + VkBool32 stippledRectangularLines; + VkBool32 stippledBresenhamLines; + VkBool32 stippledSmoothLines; +} VkPhysicalDeviceLineRasterizationFeatures; + +typedef struct VkPhysicalDeviceLineRasterizationProperties { + VkStructureType sType; + void* pNext; + uint32_t lineSubPixelPrecisionBits; +} VkPhysicalDeviceLineRasterizationProperties; + +typedef struct VkPipelineRasterizationLineStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkLineRasterizationMode lineRasterizationMode; + VkBool32 stippledLineEnable; + uint32_t lineStippleFactor; + uint16_t lineStipplePattern; +} VkPipelineRasterizationLineStateCreateInfo; + +typedef struct VkPhysicalDeviceVertexAttributeDivisorProperties { + VkStructureType sType; + void* pNext; + uint32_t maxVertexAttribDivisor; + VkBool32 supportsNonZeroFirstInstance; +} VkPhysicalDeviceVertexAttributeDivisorProperties; + +typedef struct VkVertexInputBindingDivisorDescription { + uint32_t binding; + uint32_t divisor; +} VkVertexInputBindingDivisorDescription; + +typedef struct VkPipelineVertexInputDivisorStateCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t vertexBindingDivisorCount; + const VkVertexInputBindingDivisorDescription* pVertexBindingDivisors; +} VkPipelineVertexInputDivisorStateCreateInfo; + +typedef struct VkPhysicalDeviceVertexAttributeDivisorFeatures { + VkStructureType sType; + void* pNext; + VkBool32 vertexAttributeInstanceRateDivisor; + VkBool32 vertexAttributeInstanceRateZeroDivisor; +} VkPhysicalDeviceVertexAttributeDivisorFeatures; + +typedef struct VkRenderingAreaInfo { + VkStructureType sType; + const void* pNext; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkFormat* pColorAttachmentFormats; + VkFormat depthAttachmentFormat; + VkFormat stencilAttachmentFormat; +} VkRenderingAreaInfo; + +typedef struct VkPhysicalDeviceDynamicRenderingLocalReadFeatures { + VkStructureType sType; + void* pNext; + VkBool32 dynamicRenderingLocalRead; +} VkPhysicalDeviceDynamicRenderingLocalReadFeatures; + +typedef struct VkRenderingAttachmentLocationInfo { + VkStructureType sType; + const void* pNext; + uint32_t colorAttachmentCount; + const uint32_t* pColorAttachmentLocations; +} VkRenderingAttachmentLocationInfo; + +typedef struct VkRenderingInputAttachmentIndexInfo { + VkStructureType sType; + const void* pNext; + uint32_t colorAttachmentCount; + const uint32_t* pColorAttachmentInputIndices; + const uint32_t* pDepthInputAttachmentIndex; + const uint32_t* pStencilInputAttachmentIndex; +} VkRenderingInputAttachmentIndexInfo; + +typedef VkResult (VKAPI_PTR *PFN_vkMapMemory2)(VkDevice device, const VkMemoryMapInfo* pMemoryMapInfo, void** ppData); +typedef VkResult (VKAPI_PTR *PFN_vkUnmapMemory2)(VkDevice device, const VkMemoryUnmapInfo* pMemoryUnmapInfo); +typedef void (VKAPI_PTR *PFN_vkGetDeviceImageSubresourceLayout)(VkDevice device, const VkDeviceImageSubresourceInfo* pInfo, VkSubresourceLayout2* pLayout); +typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout2)(VkDevice device, VkImage image, const VkImageSubresource2* pSubresource, VkSubresourceLayout2* pLayout); +typedef VkResult (VKAPI_PTR *PFN_vkCopyMemoryToImage)(VkDevice device, const VkCopyMemoryToImageInfo* pCopyMemoryToImageInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyImageToMemory)(VkDevice device, const VkCopyImageToMemoryInfo* pCopyImageToMemoryInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyImageToImage)(VkDevice device, const VkCopyImageToImageInfo* pCopyImageToImageInfo); +typedef VkResult (VKAPI_PTR *PFN_vkTransitionImageLayout)(VkDevice device, uint32_t transitionCount, const VkHostImageLayoutTransitionInfo* pTransitions); +typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSet)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites); +typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplate)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplate descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorSets2)(VkCommandBuffer commandBuffer, const VkBindDescriptorSetsInfo* pBindDescriptorSetsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdPushConstants2)(VkCommandBuffer commandBuffer, const VkPushConstantsInfo* pPushConstantsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSet2)(VkCommandBuffer commandBuffer, const VkPushDescriptorSetInfo* pPushDescriptorSetInfo); +typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplate2)(VkCommandBuffer commandBuffer, const VkPushDescriptorSetWithTemplateInfo* pPushDescriptorSetWithTemplateInfo); +typedef void (VKAPI_PTR *PFN_vkCmdSetLineStipple)(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern); +typedef void (VKAPI_PTR *PFN_vkCmdBindIndexBuffer2)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size, VkIndexType indexType); +typedef void (VKAPI_PTR *PFN_vkGetRenderingAreaGranularity)(VkDevice device, const VkRenderingAreaInfo* pRenderingAreaInfo, VkExtent2D* pGranularity); +typedef void (VKAPI_PTR *PFN_vkCmdSetRenderingAttachmentLocations)(VkCommandBuffer commandBuffer, const VkRenderingAttachmentLocationInfo* pLocationInfo); +typedef void (VKAPI_PTR *PFN_vkCmdSetRenderingInputAttachmentIndices)(VkCommandBuffer commandBuffer, const VkRenderingInputAttachmentIndexInfo* pInputAttachmentIndexInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory2( + VkDevice device, + const VkMemoryMapInfo* pMemoryMapInfo, + void** ppData); + +VKAPI_ATTR VkResult VKAPI_CALL vkUnmapMemory2( + VkDevice device, + const VkMemoryUnmapInfo* pMemoryUnmapInfo); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceImageSubresourceLayout( + VkDevice device, + const VkDeviceImageSubresourceInfo* pInfo, + VkSubresourceLayout2* pLayout); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout2( + VkDevice device, + VkImage image, + const VkImageSubresource2* pSubresource, + VkSubresourceLayout2* pLayout); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyMemoryToImage( + VkDevice device, + const VkCopyMemoryToImageInfo* pCopyMemoryToImageInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyImageToMemory( + VkDevice device, + const VkCopyImageToMemoryInfo* pCopyImageToMemoryInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyImageToImage( + VkDevice device, + const VkCopyImageToImageInfo* pCopyImageToImageInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkTransitionImageLayout( + VkDevice device, + uint32_t transitionCount, + const VkHostImageLayoutTransitionInfo* pTransitions); + +VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSet( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, + uint32_t set, + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet* pDescriptorWrites); + +VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplate( + VkCommandBuffer commandBuffer, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + VkPipelineLayout layout, + uint32_t set, + const void* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorSets2( + VkCommandBuffer commandBuffer, + const VkBindDescriptorSetsInfo* pBindDescriptorSetsInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants2( + VkCommandBuffer commandBuffer, + const VkPushConstantsInfo* pPushConstantsInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSet2( + VkCommandBuffer commandBuffer, + const VkPushDescriptorSetInfo* pPushDescriptorSetInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplate2( + VkCommandBuffer commandBuffer, + const VkPushDescriptorSetWithTemplateInfo* pPushDescriptorSetWithTemplateInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetLineStipple( + VkCommandBuffer commandBuffer, + uint32_t lineStippleFactor, + uint16_t lineStipplePattern); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer2( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkDeviceSize size, + VkIndexType indexType); + +VKAPI_ATTR void VKAPI_CALL vkGetRenderingAreaGranularity( + VkDevice device, + const VkRenderingAreaInfo* pRenderingAreaInfo, + VkExtent2D* pGranularity); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetRenderingAttachmentLocations( + VkCommandBuffer commandBuffer, + const VkRenderingAttachmentLocationInfo* pLocationInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetRenderingInputAttachmentIndices( + VkCommandBuffer commandBuffer, + const VkRenderingInputAttachmentIndexInfo* pInputAttachmentIndexInfo); +#endif + + +// VK_KHR_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_surface 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) +#define VK_KHR_SURFACE_SPEC_VERSION 25 +#define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" + +typedef enum VkPresentModeKHR { + VK_PRESENT_MODE_IMMEDIATE_KHR = 0, + VK_PRESENT_MODE_MAILBOX_KHR = 1, + VK_PRESENT_MODE_FIFO_KHR = 2, + VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3, + VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR = 1000111000, + VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001, + VK_PRESENT_MODE_FIFO_LATEST_READY_KHR = 1000361000, + VK_PRESENT_MODE_FIFO_LATEST_READY_EXT = VK_PRESENT_MODE_FIFO_LATEST_READY_KHR, + VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPresentModeKHR; + +typedef enum VkColorSpaceKHR { + VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0, + VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001, + VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002, + VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT = 1000104003, + VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104004, + VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104005, + VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104006, + VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104007, + VK_COLOR_SPACE_HDR10_ST2084_EXT = 1000104008, + // VK_COLOR_SPACE_DOLBYVISION_EXT is legacy, but no reason was given in the API XML + VK_COLOR_SPACE_DOLBYVISION_EXT = 1000104009, + VK_COLOR_SPACE_HDR10_HLG_EXT = 1000104010, + VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011, + VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012, + VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013, + VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014, + VK_COLOR_SPACE_DISPLAY_NATIVE_AMD = 1000213000, + // VK_COLORSPACE_SRGB_NONLINEAR_KHR is a legacy alias + VK_COLORSPACE_SRGB_NONLINEAR_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, + // VK_COLOR_SPACE_DCI_P3_LINEAR_EXT is a legacy alias + VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT, + VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkColorSpaceKHR; + +typedef enum VkSurfaceTransformFlagBitsKHR { + VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001, + VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002, + VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004, + VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080, + VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100, + VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkSurfaceTransformFlagBitsKHR; +typedef VkFlags VkSurfaceTransformFlagsKHR; + +typedef enum VkCompositeAlphaFlagBitsKHR { + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008, + VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkCompositeAlphaFlagBitsKHR; +typedef VkFlags VkCompositeAlphaFlagsKHR; +typedef struct VkSurfaceCapabilitiesKHR { + uint32_t minImageCount; + uint32_t maxImageCount; + VkExtent2D currentExtent; + VkExtent2D minImageExtent; + VkExtent2D maxImageExtent; + uint32_t maxImageArrayLayers; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkSurfaceTransformFlagBitsKHR currentTransform; + VkCompositeAlphaFlagsKHR supportedCompositeAlpha; + VkImageUsageFlags supportedUsageFlags; +} VkSurfaceCapabilitiesKHR; + +typedef struct VkSurfaceFormatKHR { + VkFormat format; + VkColorSpaceKHR colorSpace; +} VkSurfaceFormatKHR; + +typedef void (VKAPI_PTR *PFN_vkDestroySurfaceKHR)(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR( + VkInstance instance, + VkSurfaceKHR surface, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + VkSurfaceKHR surface, + VkBool32* pSupported); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormatsKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pSurfaceFormatCount, + VkSurfaceFormatKHR* pSurfaceFormats); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pPresentModeCount, + VkPresentModeKHR* pPresentModes); +#endif +#endif + + +// VK_KHR_swapchain is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_swapchain 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) +#define VK_KHR_SWAPCHAIN_SPEC_VERSION 70 +#define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain" + +typedef enum VkSwapchainCreateFlagBitsKHR { + VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = 0x00000001, + VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 0x00000002, + VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR = 0x00000004, + VK_SWAPCHAIN_CREATE_PRESENT_TIMING_BIT_EXT = 0x00000200, + VK_SWAPCHAIN_CREATE_PRESENT_ID_2_BIT_KHR = 0x00000040, + VK_SWAPCHAIN_CREATE_PRESENT_WAIT_2_BIT_KHR = 0x00000080, + VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_KHR = 0x00000008, + VK_SWAPCHAIN_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT = 0x00000100, + VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_EXT = VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_KHR, + VK_SWAPCHAIN_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkSwapchainCreateFlagBitsKHR; +typedef VkFlags VkSwapchainCreateFlagsKHR; + +typedef enum VkDeviceGroupPresentModeFlagBitsKHR { + VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 0x00000001, + VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 0x00000002, + VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 0x00000004, + VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 0x00000008, + VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkDeviceGroupPresentModeFlagBitsKHR; +typedef VkFlags VkDeviceGroupPresentModeFlagsKHR; +typedef struct VkSwapchainCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainCreateFlagsKHR flags; + VkSurfaceKHR surface; + uint32_t minImageCount; + VkFormat imageFormat; + VkColorSpaceKHR imageColorSpace; + VkExtent2D imageExtent; + uint32_t imageArrayLayers; + VkImageUsageFlags imageUsage; + VkSharingMode imageSharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; + VkSurfaceTransformFlagBitsKHR preTransform; + VkCompositeAlphaFlagBitsKHR compositeAlpha; + VkPresentModeKHR presentMode; + VkBool32 clipped; + VkSwapchainKHR oldSwapchain; +} VkSwapchainCreateInfoKHR; + +typedef struct VkPresentInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore* pWaitSemaphores; + uint32_t swapchainCount; + const VkSwapchainKHR* pSwapchains; + const uint32_t* pImageIndices; + VkResult* pResults; +} VkPresentInfoKHR; + +typedef struct VkImageSwapchainCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; +} VkImageSwapchainCreateInfoKHR; + +typedef struct VkBindImageMemorySwapchainInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; + uint32_t imageIndex; +} VkBindImageMemorySwapchainInfoKHR; + +typedef struct VkAcquireNextImageInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; + uint64_t timeout; + VkSemaphore semaphore; + VkFence fence; + uint32_t deviceMask; +} VkAcquireNextImageInfoKHR; + +typedef struct VkDeviceGroupPresentCapabilitiesKHR { + VkStructureType sType; + void* pNext; + uint32_t presentMask[VK_MAX_DEVICE_GROUP_SIZE]; + VkDeviceGroupPresentModeFlagsKHR modes; +} VkDeviceGroupPresentCapabilitiesKHR; + +typedef struct VkDeviceGroupPresentInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const uint32_t* pDeviceMasks; + VkDeviceGroupPresentModeFlagBitsKHR mode; +} VkDeviceGroupPresentInfoKHR; + +typedef struct VkDeviceGroupSwapchainCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceGroupPresentModeFlagsKHR modes; +} VkDeviceGroupSwapchainCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain); +typedef void (VKAPI_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages); +typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex); +typedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR* pPresentInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects); +typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImage2KHR)(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR( + VkDevice device, + const VkSwapchainCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSwapchainKHR* pSwapchain); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroySwapchainKHR( + VkDevice device, + VkSwapchainKHR swapchain, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainImagesKHR( + VkDevice device, + VkSwapchainKHR swapchain, + uint32_t* pSwapchainImageCount, + VkImage* pSwapchainImages); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR( + VkDevice device, + VkSwapchainKHR swapchain, + uint64_t timeout, + VkSemaphore semaphore, + VkFence fence, + uint32_t* pImageIndex); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR( + VkQueue queue, + const VkPresentInfoKHR* pPresentInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupPresentCapabilitiesKHR( + VkDevice device, + VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModesKHR( + VkDevice device, + VkSurfaceKHR surface, + VkDeviceGroupPresentModeFlagsKHR* pModes); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDevicePresentRectanglesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pRectCount, + VkRect2D* pRects); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImage2KHR( + VkDevice device, + const VkAcquireNextImageInfoKHR* pAcquireInfo, + uint32_t* pImageIndex); +#endif +#endif + + +// VK_KHR_display is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_display 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR) +#define VK_KHR_DISPLAY_SPEC_VERSION 23 +#define VK_KHR_DISPLAY_EXTENSION_NAME "VK_KHR_display" +typedef VkFlags VkDisplayModeCreateFlagsKHR; + +typedef enum VkDisplayPlaneAlphaFlagBitsKHR { + VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, + VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002, + VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 0x00000004, + VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008, + VK_DISPLAY_PLANE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkDisplayPlaneAlphaFlagBitsKHR; +typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; +typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; +typedef struct VkDisplayModeParametersKHR { + VkExtent2D visibleRegion; + uint32_t refreshRate; +} VkDisplayModeParametersKHR; + +typedef struct VkDisplayModeCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkDisplayModeCreateFlagsKHR flags; + VkDisplayModeParametersKHR parameters; +} VkDisplayModeCreateInfoKHR; + +typedef struct VkDisplayModePropertiesKHR { + VkDisplayModeKHR displayMode; + VkDisplayModeParametersKHR parameters; +} VkDisplayModePropertiesKHR; + +typedef struct VkDisplayPlaneCapabilitiesKHR { + VkDisplayPlaneAlphaFlagsKHR supportedAlpha; + VkOffset2D minSrcPosition; + VkOffset2D maxSrcPosition; + VkExtent2D minSrcExtent; + VkExtent2D maxSrcExtent; + VkOffset2D minDstPosition; + VkOffset2D maxDstPosition; + VkExtent2D minDstExtent; + VkExtent2D maxDstExtent; +} VkDisplayPlaneCapabilitiesKHR; + +typedef struct VkDisplayPlanePropertiesKHR { + VkDisplayKHR currentDisplay; + uint32_t currentStackIndex; +} VkDisplayPlanePropertiesKHR; + +typedef struct VkDisplayPropertiesKHR { + VkDisplayKHR display; + const char* displayName; + VkExtent2D physicalDimensions; + VkExtent2D physicalResolution; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkBool32 planeReorderPossible; + VkBool32 persistentContent; +} VkDisplayPropertiesKHR; + +typedef struct VkDisplaySurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkDisplaySurfaceCreateFlagsKHR flags; + VkDisplayModeKHR displayMode; + uint32_t planeIndex; + uint32_t planeStackIndex; + VkSurfaceTransformFlagBitsKHR transform; + float globalAlpha; + VkDisplayPlaneAlphaFlagBitsKHR alphaMode; + VkExtent2D imageExtent; +} VkDisplaySurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneSupportedDisplaysKHR)(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModePropertiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayModeKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR* pCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayPlaneSurfaceKHR)(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPropertiesKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayPropertiesKHR* pProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlanePropertiesKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayPlanePropertiesKHR* pProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneSupportedDisplaysKHR( + VkPhysicalDevice physicalDevice, + uint32_t planeIndex, + uint32_t* pDisplayCount, + VkDisplayKHR* pDisplays); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModePropertiesKHR( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + uint32_t* pPropertyCount, + VkDisplayModePropertiesKHR* pProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayModeKHR( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + const VkDisplayModeCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDisplayModeKHR* pMode); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilitiesKHR( + VkPhysicalDevice physicalDevice, + VkDisplayModeKHR mode, + uint32_t planeIndex, + VkDisplayPlaneCapabilitiesKHR* pCapabilities); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayPlaneSurfaceKHR( + VkInstance instance, + const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif +#endif + + +// VK_KHR_display_swapchain is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_display_swapchain 1 +#define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 10 +#define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME "VK_KHR_display_swapchain" +typedef struct VkDisplayPresentInfoKHR { + VkStructureType sType; + const void* pNext; + VkRect2D srcRect; + VkRect2D dstRect; + VkBool32 persistent; +} VkDisplayPresentInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateSharedSwapchainsKHR)(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSharedSwapchainsKHR( + VkDevice device, + uint32_t swapchainCount, + const VkSwapchainCreateInfoKHR* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkSwapchainKHR* pSwapchains); +#endif +#endif + + +// VK_KHR_sampler_mirror_clamp_to_edge is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_sampler_mirror_clamp_to_edge 1 +#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 3 +#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge" + + +// VK_KHR_video_queue is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_queue 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkVideoSessionKHR) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkVideoSessionParametersKHR) +#define VK_KHR_VIDEO_QUEUE_SPEC_VERSION 8 +#define VK_KHR_VIDEO_QUEUE_EXTENSION_NAME "VK_KHR_video_queue" + +typedef enum VkQueryResultStatusKHR { + VK_QUERY_RESULT_STATUS_ERROR_KHR = -1, + VK_QUERY_RESULT_STATUS_NOT_READY_KHR = 0, + VK_QUERY_RESULT_STATUS_COMPLETE_KHR = 1, + VK_QUERY_RESULT_STATUS_INSUFFICIENT_BITSTREAM_BUFFER_RANGE_KHR = -1000299000, + VK_QUERY_RESULT_STATUS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkQueryResultStatusKHR; + +typedef enum VkVideoCodecOperationFlagBitsKHR { + VK_VIDEO_CODEC_OPERATION_NONE_KHR = 0, + VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR = 0x00010000, + VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR = 0x00020000, + VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR = 0x00000001, + VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR = 0x00000002, + VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR = 0x00000004, + VK_VIDEO_CODEC_OPERATION_ENCODE_AV1_BIT_KHR = 0x00040000, + VK_VIDEO_CODEC_OPERATION_DECODE_VP9_BIT_KHR = 0x00000008, + VK_VIDEO_CODEC_OPERATION_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoCodecOperationFlagBitsKHR; +typedef VkFlags VkVideoCodecOperationFlagsKHR; + +typedef enum VkVideoChromaSubsamplingFlagBitsKHR { + VK_VIDEO_CHROMA_SUBSAMPLING_INVALID_KHR = 0, + VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR = 0x00000001, + VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR = 0x00000002, + VK_VIDEO_CHROMA_SUBSAMPLING_422_BIT_KHR = 0x00000004, + VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR = 0x00000008, + VK_VIDEO_CHROMA_SUBSAMPLING_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoChromaSubsamplingFlagBitsKHR; +typedef VkFlags VkVideoChromaSubsamplingFlagsKHR; + +typedef enum VkVideoComponentBitDepthFlagBitsKHR { + VK_VIDEO_COMPONENT_BIT_DEPTH_INVALID_KHR = 0, + VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR = 0x00000001, + VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR = 0x00000004, + VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR = 0x00000010, + VK_VIDEO_COMPONENT_BIT_DEPTH_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoComponentBitDepthFlagBitsKHR; +typedef VkFlags VkVideoComponentBitDepthFlagsKHR; + +typedef enum VkVideoCapabilityFlagBitsKHR { + VK_VIDEO_CAPABILITY_PROTECTED_CONTENT_BIT_KHR = 0x00000001, + VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR = 0x00000002, + VK_VIDEO_CAPABILITY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoCapabilityFlagBitsKHR; +typedef VkFlags VkVideoCapabilityFlagsKHR; + +typedef enum VkVideoSessionCreateFlagBitsKHR { + VK_VIDEO_SESSION_CREATE_PROTECTED_CONTENT_BIT_KHR = 0x00000001, + VK_VIDEO_SESSION_CREATE_ALLOW_ENCODE_PARAMETER_OPTIMIZATIONS_BIT_KHR = 0x00000002, + VK_VIDEO_SESSION_CREATE_INLINE_QUERIES_BIT_KHR = 0x00000004, + VK_VIDEO_SESSION_CREATE_ALLOW_ENCODE_QUANTIZATION_DELTA_MAP_BIT_KHR = 0x00000008, + VK_VIDEO_SESSION_CREATE_ALLOW_ENCODE_EMPHASIS_MAP_BIT_KHR = 0x00000010, + VK_VIDEO_SESSION_CREATE_INLINE_SESSION_PARAMETERS_BIT_KHR = 0x00000020, + VK_VIDEO_SESSION_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoSessionCreateFlagBitsKHR; +typedef VkFlags VkVideoSessionCreateFlagsKHR; + +typedef enum VkVideoSessionParametersCreateFlagBitsKHR { + VK_VIDEO_SESSION_PARAMETERS_CREATE_QUANTIZATION_MAP_COMPATIBLE_BIT_KHR = 0x00000001, + VK_VIDEO_SESSION_PARAMETERS_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoSessionParametersCreateFlagBitsKHR; +typedef VkFlags VkVideoSessionParametersCreateFlagsKHR; +typedef VkFlags VkVideoBeginCodingFlagsKHR; +typedef VkFlags VkVideoEndCodingFlagsKHR; + +typedef enum VkVideoCodingControlFlagBitsKHR { + VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR = 0x00000001, + VK_VIDEO_CODING_CONTROL_ENCODE_RATE_CONTROL_BIT_KHR = 0x00000002, + VK_VIDEO_CODING_CONTROL_ENCODE_QUALITY_LEVEL_BIT_KHR = 0x00000004, + VK_VIDEO_CODING_CONTROL_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoCodingControlFlagBitsKHR; +typedef VkFlags VkVideoCodingControlFlagsKHR; +typedef struct VkQueueFamilyQueryResultStatusPropertiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 queryResultStatusSupport; +} VkQueueFamilyQueryResultStatusPropertiesKHR; + +typedef struct VkQueueFamilyVideoPropertiesKHR { + VkStructureType sType; + void* pNext; + VkVideoCodecOperationFlagsKHR videoCodecOperations; +} VkQueueFamilyVideoPropertiesKHR; + +typedef struct VkVideoProfileInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoCodecOperationFlagBitsKHR videoCodecOperation; + VkVideoChromaSubsamplingFlagsKHR chromaSubsampling; + VkVideoComponentBitDepthFlagsKHR lumaBitDepth; + VkVideoComponentBitDepthFlagsKHR chromaBitDepth; +} VkVideoProfileInfoKHR; + +typedef struct VkVideoProfileListInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t profileCount; + const VkVideoProfileInfoKHR* pProfiles; +} VkVideoProfileListInfoKHR; + +typedef struct VkVideoCapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkVideoCapabilityFlagsKHR flags; + VkDeviceSize minBitstreamBufferOffsetAlignment; + VkDeviceSize minBitstreamBufferSizeAlignment; + VkExtent2D pictureAccessGranularity; + VkExtent2D minCodedExtent; + VkExtent2D maxCodedExtent; + uint32_t maxDpbSlots; + uint32_t maxActiveReferencePictures; + VkExtensionProperties stdHeaderVersion; +} VkVideoCapabilitiesKHR; + +typedef struct VkPhysicalDeviceVideoFormatInfoKHR { + VkStructureType sType; + const void* pNext; + VkImageUsageFlags imageUsage; +} VkPhysicalDeviceVideoFormatInfoKHR; + +typedef struct VkVideoFormatPropertiesKHR { + VkStructureType sType; + void* pNext; + VkFormat format; + VkComponentMapping componentMapping; + VkImageCreateFlags imageCreateFlags; + VkImageType imageType; + VkImageTiling imageTiling; + VkImageUsageFlags imageUsageFlags; +} VkVideoFormatPropertiesKHR; + +typedef struct VkVideoPictureResourceInfoKHR { + VkStructureType sType; + const void* pNext; + VkOffset2D codedOffset; + VkExtent2D codedExtent; + uint32_t baseArrayLayer; + VkImageView imageViewBinding; +} VkVideoPictureResourceInfoKHR; + +typedef struct VkVideoReferenceSlotInfoKHR { + VkStructureType sType; + const void* pNext; + int32_t slotIndex; + const VkVideoPictureResourceInfoKHR* pPictureResource; +} VkVideoReferenceSlotInfoKHR; + +typedef struct VkVideoSessionMemoryRequirementsKHR { + VkStructureType sType; + void* pNext; + uint32_t memoryBindIndex; + VkMemoryRequirements memoryRequirements; +} VkVideoSessionMemoryRequirementsKHR; + +typedef struct VkBindVideoSessionMemoryInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t memoryBindIndex; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkDeviceSize memorySize; +} VkBindVideoSessionMemoryInfoKHR; + +typedef struct VkVideoSessionCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t queueFamilyIndex; + VkVideoSessionCreateFlagsKHR flags; + const VkVideoProfileInfoKHR* pVideoProfile; + VkFormat pictureFormat; + VkExtent2D maxCodedExtent; + VkFormat referencePictureFormat; + uint32_t maxDpbSlots; + uint32_t maxActiveReferencePictures; + const VkExtensionProperties* pStdHeaderVersion; +} VkVideoSessionCreateInfoKHR; + +typedef struct VkVideoSessionParametersCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoSessionParametersCreateFlagsKHR flags; + VkVideoSessionParametersKHR videoSessionParametersTemplate; + VkVideoSessionKHR videoSession; +} VkVideoSessionParametersCreateInfoKHR; + +typedef struct VkVideoSessionParametersUpdateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t updateSequenceCount; +} VkVideoSessionParametersUpdateInfoKHR; + +typedef struct VkVideoBeginCodingInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoBeginCodingFlagsKHR flags; + VkVideoSessionKHR videoSession; + VkVideoSessionParametersKHR videoSessionParameters; + uint32_t referenceSlotCount; + const VkVideoReferenceSlotInfoKHR* pReferenceSlots; +} VkVideoBeginCodingInfoKHR; + +typedef struct VkVideoEndCodingInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEndCodingFlagsKHR flags; +} VkVideoEndCodingInfoKHR; + +typedef struct VkVideoCodingControlInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoCodingControlFlagsKHR flags; +} VkVideoCodingControlInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceVideoCapabilitiesKHR)(VkPhysicalDevice physicalDevice, const VkVideoProfileInfoKHR* pVideoProfile, VkVideoCapabilitiesKHR* pCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceVideoFormatPropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceVideoFormatInfoKHR* pVideoFormatInfo, uint32_t* pVideoFormatPropertyCount, VkVideoFormatPropertiesKHR* pVideoFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkCreateVideoSessionKHR)(VkDevice device, const VkVideoSessionCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkVideoSessionKHR* pVideoSession); +typedef void (VKAPI_PTR *PFN_vkDestroyVideoSessionKHR)(VkDevice device, VkVideoSessionKHR videoSession, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetVideoSessionMemoryRequirementsKHR)(VkDevice device, VkVideoSessionKHR videoSession, uint32_t* pMemoryRequirementsCount, VkVideoSessionMemoryRequirementsKHR* pMemoryRequirements); +typedef VkResult (VKAPI_PTR *PFN_vkBindVideoSessionMemoryKHR)(VkDevice device, VkVideoSessionKHR videoSession, uint32_t bindSessionMemoryInfoCount, const VkBindVideoSessionMemoryInfoKHR* pBindSessionMemoryInfos); +typedef VkResult (VKAPI_PTR *PFN_vkCreateVideoSessionParametersKHR)(VkDevice device, const VkVideoSessionParametersCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkVideoSessionParametersKHR* pVideoSessionParameters); +typedef VkResult (VKAPI_PTR *PFN_vkUpdateVideoSessionParametersKHR)(VkDevice device, VkVideoSessionParametersKHR videoSessionParameters, const VkVideoSessionParametersUpdateInfoKHR* pUpdateInfo); +typedef void (VKAPI_PTR *PFN_vkDestroyVideoSessionParametersKHR)(VkDevice device, VkVideoSessionParametersKHR videoSessionParameters, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkCmdBeginVideoCodingKHR)(VkCommandBuffer commandBuffer, const VkVideoBeginCodingInfoKHR* pBeginInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndVideoCodingKHR)(VkCommandBuffer commandBuffer, const VkVideoEndCodingInfoKHR* pEndCodingInfo); +typedef void (VKAPI_PTR *PFN_vkCmdControlVideoCodingKHR)(VkCommandBuffer commandBuffer, const VkVideoCodingControlInfoKHR* pCodingControlInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceVideoCapabilitiesKHR( + VkPhysicalDevice physicalDevice, + const VkVideoProfileInfoKHR* pVideoProfile, + VkVideoCapabilitiesKHR* pCapabilities); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceVideoFormatPropertiesKHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceVideoFormatInfoKHR* pVideoFormatInfo, + uint32_t* pVideoFormatPropertyCount, + VkVideoFormatPropertiesKHR* pVideoFormatProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateVideoSessionKHR( + VkDevice device, + const VkVideoSessionCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkVideoSessionKHR* pVideoSession); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyVideoSessionKHR( + VkDevice device, + VkVideoSessionKHR videoSession, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetVideoSessionMemoryRequirementsKHR( + VkDevice device, + VkVideoSessionKHR videoSession, + uint32_t* pMemoryRequirementsCount, + VkVideoSessionMemoryRequirementsKHR* pMemoryRequirements); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkBindVideoSessionMemoryKHR( + VkDevice device, + VkVideoSessionKHR videoSession, + uint32_t bindSessionMemoryInfoCount, + const VkBindVideoSessionMemoryInfoKHR* pBindSessionMemoryInfos); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateVideoSessionParametersKHR( + VkDevice device, + const VkVideoSessionParametersCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkVideoSessionParametersKHR* pVideoSessionParameters); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkUpdateVideoSessionParametersKHR( + VkDevice device, + VkVideoSessionParametersKHR videoSessionParameters, + const VkVideoSessionParametersUpdateInfoKHR* pUpdateInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyVideoSessionParametersKHR( + VkDevice device, + VkVideoSessionParametersKHR videoSessionParameters, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginVideoCodingKHR( + VkCommandBuffer commandBuffer, + const VkVideoBeginCodingInfoKHR* pBeginInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdEndVideoCodingKHR( + VkCommandBuffer commandBuffer, + const VkVideoEndCodingInfoKHR* pEndCodingInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdControlVideoCodingKHR( + VkCommandBuffer commandBuffer, + const VkVideoCodingControlInfoKHR* pCodingControlInfo); +#endif +#endif + + +// VK_KHR_video_decode_queue is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_decode_queue 1 +#define VK_KHR_VIDEO_DECODE_QUEUE_SPEC_VERSION 8 +#define VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME "VK_KHR_video_decode_queue" + +typedef enum VkVideoDecodeCapabilityFlagBitsKHR { + VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR = 0x00000001, + VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR = 0x00000002, + VK_VIDEO_DECODE_CAPABILITY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoDecodeCapabilityFlagBitsKHR; +typedef VkFlags VkVideoDecodeCapabilityFlagsKHR; + +typedef enum VkVideoDecodeUsageFlagBitsKHR { + VK_VIDEO_DECODE_USAGE_DEFAULT_KHR = 0, + VK_VIDEO_DECODE_USAGE_TRANSCODING_BIT_KHR = 0x00000001, + VK_VIDEO_DECODE_USAGE_OFFLINE_BIT_KHR = 0x00000002, + VK_VIDEO_DECODE_USAGE_STREAMING_BIT_KHR = 0x00000004, + VK_VIDEO_DECODE_USAGE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoDecodeUsageFlagBitsKHR; +typedef VkFlags VkVideoDecodeUsageFlagsKHR; +typedef VkFlags VkVideoDecodeFlagsKHR; +typedef struct VkVideoDecodeCapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkVideoDecodeCapabilityFlagsKHR flags; +} VkVideoDecodeCapabilitiesKHR; + +typedef struct VkVideoDecodeUsageInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoDecodeUsageFlagsKHR videoUsageHints; +} VkVideoDecodeUsageInfoKHR; + +typedef struct VkVideoDecodeInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoDecodeFlagsKHR flags; + VkBuffer srcBuffer; + VkDeviceSize srcBufferOffset; + VkDeviceSize srcBufferRange; + VkVideoPictureResourceInfoKHR dstPictureResource; + const VkVideoReferenceSlotInfoKHR* pSetupReferenceSlot; + uint32_t referenceSlotCount; + const VkVideoReferenceSlotInfoKHR* pReferenceSlots; +} VkVideoDecodeInfoKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdDecodeVideoKHR)(VkCommandBuffer commandBuffer, const VkVideoDecodeInfoKHR* pDecodeInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDecodeVideoKHR( + VkCommandBuffer commandBuffer, + const VkVideoDecodeInfoKHR* pDecodeInfo); +#endif +#endif + + +// VK_KHR_video_encode_h264 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_encode_h264 1 +#include "vk_video/vulkan_video_codec_h264std.h" +#include "vk_video/vulkan_video_codec_h264std_encode.h" +#define VK_KHR_VIDEO_ENCODE_H264_SPEC_VERSION 14 +#define VK_KHR_VIDEO_ENCODE_H264_EXTENSION_NAME "VK_KHR_video_encode_h264" + +typedef enum VkVideoEncodeH264CapabilityFlagBitsKHR { + VK_VIDEO_ENCODE_H264_CAPABILITY_HRD_COMPLIANCE_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_H264_CAPABILITY_PREDICTION_WEIGHT_TABLE_GENERATED_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_H264_CAPABILITY_ROW_UNALIGNED_SLICE_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_H264_CAPABILITY_DIFFERENT_SLICE_TYPE_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_H264_CAPABILITY_B_FRAME_IN_L0_LIST_BIT_KHR = 0x00000010, + VK_VIDEO_ENCODE_H264_CAPABILITY_B_FRAME_IN_L1_LIST_BIT_KHR = 0x00000020, + VK_VIDEO_ENCODE_H264_CAPABILITY_PER_PICTURE_TYPE_MIN_MAX_QP_BIT_KHR = 0x00000040, + VK_VIDEO_ENCODE_H264_CAPABILITY_PER_SLICE_CONSTANT_QP_BIT_KHR = 0x00000080, + VK_VIDEO_ENCODE_H264_CAPABILITY_GENERATE_PREFIX_NALU_BIT_KHR = 0x00000100, + VK_VIDEO_ENCODE_H264_CAPABILITY_B_PICTURE_INTRA_REFRESH_BIT_KHR = 0x00000400, + VK_VIDEO_ENCODE_H264_CAPABILITY_MB_QP_DIFF_WRAPAROUND_BIT_KHR = 0x00000200, + VK_VIDEO_ENCODE_H264_CAPABILITY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeH264CapabilityFlagBitsKHR; +typedef VkFlags VkVideoEncodeH264CapabilityFlagsKHR; + +typedef enum VkVideoEncodeH264StdFlagBitsKHR { + VK_VIDEO_ENCODE_H264_STD_SEPARATE_COLOR_PLANE_FLAG_SET_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_H264_STD_QPPRIME_Y_ZERO_TRANSFORM_BYPASS_FLAG_SET_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_H264_STD_SCALING_MATRIX_PRESENT_FLAG_SET_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_H264_STD_CHROMA_QP_INDEX_OFFSET_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_H264_STD_SECOND_CHROMA_QP_INDEX_OFFSET_BIT_KHR = 0x00000010, + VK_VIDEO_ENCODE_H264_STD_PIC_INIT_QP_MINUS26_BIT_KHR = 0x00000020, + VK_VIDEO_ENCODE_H264_STD_WEIGHTED_PRED_FLAG_SET_BIT_KHR = 0x00000040, + VK_VIDEO_ENCODE_H264_STD_WEIGHTED_BIPRED_IDC_EXPLICIT_BIT_KHR = 0x00000080, + VK_VIDEO_ENCODE_H264_STD_WEIGHTED_BIPRED_IDC_IMPLICIT_BIT_KHR = 0x00000100, + VK_VIDEO_ENCODE_H264_STD_TRANSFORM_8X8_MODE_FLAG_SET_BIT_KHR = 0x00000200, + VK_VIDEO_ENCODE_H264_STD_DIRECT_SPATIAL_MV_PRED_FLAG_UNSET_BIT_KHR = 0x00000400, + VK_VIDEO_ENCODE_H264_STD_ENTROPY_CODING_MODE_FLAG_UNSET_BIT_KHR = 0x00000800, + VK_VIDEO_ENCODE_H264_STD_ENTROPY_CODING_MODE_FLAG_SET_BIT_KHR = 0x00001000, + VK_VIDEO_ENCODE_H264_STD_DIRECT_8X8_INFERENCE_FLAG_UNSET_BIT_KHR = 0x00002000, + VK_VIDEO_ENCODE_H264_STD_CONSTRAINED_INTRA_PRED_FLAG_SET_BIT_KHR = 0x00004000, + VK_VIDEO_ENCODE_H264_STD_DEBLOCKING_FILTER_DISABLED_BIT_KHR = 0x00008000, + VK_VIDEO_ENCODE_H264_STD_DEBLOCKING_FILTER_ENABLED_BIT_KHR = 0x00010000, + VK_VIDEO_ENCODE_H264_STD_DEBLOCKING_FILTER_PARTIAL_BIT_KHR = 0x00020000, + VK_VIDEO_ENCODE_H264_STD_SLICE_QP_DELTA_BIT_KHR = 0x00080000, + VK_VIDEO_ENCODE_H264_STD_DIFFERENT_SLICE_QP_DELTA_BIT_KHR = 0x00100000, + VK_VIDEO_ENCODE_H264_STD_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeH264StdFlagBitsKHR; +typedef VkFlags VkVideoEncodeH264StdFlagsKHR; + +typedef enum VkVideoEncodeH264RateControlFlagBitsKHR { + VK_VIDEO_ENCODE_H264_RATE_CONTROL_ATTEMPT_HRD_COMPLIANCE_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_H264_RATE_CONTROL_REGULAR_GOP_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_H264_RATE_CONTROL_REFERENCE_PATTERN_FLAT_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_H264_RATE_CONTROL_REFERENCE_PATTERN_DYADIC_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_H264_RATE_CONTROL_TEMPORAL_LAYER_PATTERN_DYADIC_BIT_KHR = 0x00000010, + VK_VIDEO_ENCODE_H264_RATE_CONTROL_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeH264RateControlFlagBitsKHR; +typedef VkFlags VkVideoEncodeH264RateControlFlagsKHR; +typedef struct VkVideoEncodeH264CapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeH264CapabilityFlagsKHR flags; + StdVideoH264LevelIdc maxLevelIdc; + uint32_t maxSliceCount; + uint32_t maxPPictureL0ReferenceCount; + uint32_t maxBPictureL0ReferenceCount; + uint32_t maxL1ReferenceCount; + uint32_t maxTemporalLayerCount; + VkBool32 expectDyadicTemporalLayerPattern; + int32_t minQp; + int32_t maxQp; + VkBool32 prefersGopRemainingFrames; + VkBool32 requiresGopRemainingFrames; + VkVideoEncodeH264StdFlagsKHR stdSyntaxFlags; +} VkVideoEncodeH264CapabilitiesKHR; + +typedef struct VkVideoEncodeH264QpKHR { + int32_t qpI; + int32_t qpP; + int32_t qpB; +} VkVideoEncodeH264QpKHR; + +typedef struct VkVideoEncodeH264QualityLevelPropertiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeH264RateControlFlagsKHR preferredRateControlFlags; + uint32_t preferredGopFrameCount; + uint32_t preferredIdrPeriod; + uint32_t preferredConsecutiveBFrameCount; + uint32_t preferredTemporalLayerCount; + VkVideoEncodeH264QpKHR preferredConstantQp; + uint32_t preferredMaxL0ReferenceCount; + uint32_t preferredMaxL1ReferenceCount; + VkBool32 preferredStdEntropyCodingModeFlag; +} VkVideoEncodeH264QualityLevelPropertiesKHR; + +typedef struct VkVideoEncodeH264SessionCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 useMaxLevelIdc; + StdVideoH264LevelIdc maxLevelIdc; +} VkVideoEncodeH264SessionCreateInfoKHR; + +typedef struct VkVideoEncodeH264SessionParametersAddInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t stdSPSCount; + const StdVideoH264SequenceParameterSet* pStdSPSs; + uint32_t stdPPSCount; + const StdVideoH264PictureParameterSet* pStdPPSs; +} VkVideoEncodeH264SessionParametersAddInfoKHR; + +typedef struct VkVideoEncodeH264SessionParametersCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t maxStdSPSCount; + uint32_t maxStdPPSCount; + const VkVideoEncodeH264SessionParametersAddInfoKHR* pParametersAddInfo; +} VkVideoEncodeH264SessionParametersCreateInfoKHR; + +typedef struct VkVideoEncodeH264SessionParametersGetInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 writeStdSPS; + VkBool32 writeStdPPS; + uint32_t stdSPSId; + uint32_t stdPPSId; +} VkVideoEncodeH264SessionParametersGetInfoKHR; + +typedef struct VkVideoEncodeH264SessionParametersFeedbackInfoKHR { + VkStructureType sType; + void* pNext; + VkBool32 hasStdSPSOverrides; + VkBool32 hasStdPPSOverrides; +} VkVideoEncodeH264SessionParametersFeedbackInfoKHR; + +typedef struct VkVideoEncodeH264NaluSliceInfoKHR { + VkStructureType sType; + const void* pNext; + int32_t constantQp; + const StdVideoEncodeH264SliceHeader* pStdSliceHeader; +} VkVideoEncodeH264NaluSliceInfoKHR; + +typedef struct VkVideoEncodeH264PictureInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t naluSliceEntryCount; + const VkVideoEncodeH264NaluSliceInfoKHR* pNaluSliceEntries; + const StdVideoEncodeH264PictureInfo* pStdPictureInfo; + VkBool32 generatePrefixNalu; +} VkVideoEncodeH264PictureInfoKHR; + +typedef struct VkVideoEncodeH264DpbSlotInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoEncodeH264ReferenceInfo* pStdReferenceInfo; +} VkVideoEncodeH264DpbSlotInfoKHR; + +typedef struct VkVideoEncodeH264ProfileInfoKHR { + VkStructureType sType; + const void* pNext; + StdVideoH264ProfileIdc stdProfileIdc; +} VkVideoEncodeH264ProfileInfoKHR; + +typedef struct VkVideoEncodeH264RateControlInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeH264RateControlFlagsKHR flags; + uint32_t gopFrameCount; + uint32_t idrPeriod; + uint32_t consecutiveBFrameCount; + uint32_t temporalLayerCount; +} VkVideoEncodeH264RateControlInfoKHR; + +typedef struct VkVideoEncodeH264FrameSizeKHR { + uint32_t frameISize; + uint32_t framePSize; + uint32_t frameBSize; +} VkVideoEncodeH264FrameSizeKHR; + +typedef struct VkVideoEncodeH264RateControlLayerInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 useMinQp; + VkVideoEncodeH264QpKHR minQp; + VkBool32 useMaxQp; + VkVideoEncodeH264QpKHR maxQp; + VkBool32 useMaxFrameSize; + VkVideoEncodeH264FrameSizeKHR maxFrameSize; +} VkVideoEncodeH264RateControlLayerInfoKHR; + +typedef struct VkVideoEncodeH264GopRemainingFrameInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 useGopRemainingFrames; + uint32_t gopRemainingI; + uint32_t gopRemainingP; + uint32_t gopRemainingB; +} VkVideoEncodeH264GopRemainingFrameInfoKHR; + + + +// VK_KHR_video_encode_h265 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_encode_h265 1 +#include "vk_video/vulkan_video_codec_h265std.h" +#include "vk_video/vulkan_video_codec_h265std_encode.h" +#define VK_KHR_VIDEO_ENCODE_H265_SPEC_VERSION 14 +#define VK_KHR_VIDEO_ENCODE_H265_EXTENSION_NAME "VK_KHR_video_encode_h265" + +typedef enum VkVideoEncodeH265CapabilityFlagBitsKHR { + VK_VIDEO_ENCODE_H265_CAPABILITY_HRD_COMPLIANCE_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_H265_CAPABILITY_PREDICTION_WEIGHT_TABLE_GENERATED_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_H265_CAPABILITY_ROW_UNALIGNED_SLICE_SEGMENT_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_H265_CAPABILITY_DIFFERENT_SLICE_SEGMENT_TYPE_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_H265_CAPABILITY_B_FRAME_IN_L0_LIST_BIT_KHR = 0x00000010, + VK_VIDEO_ENCODE_H265_CAPABILITY_B_FRAME_IN_L1_LIST_BIT_KHR = 0x00000020, + VK_VIDEO_ENCODE_H265_CAPABILITY_PER_PICTURE_TYPE_MIN_MAX_QP_BIT_KHR = 0x00000040, + VK_VIDEO_ENCODE_H265_CAPABILITY_PER_SLICE_SEGMENT_CONSTANT_QP_BIT_KHR = 0x00000080, + VK_VIDEO_ENCODE_H265_CAPABILITY_MULTIPLE_TILES_PER_SLICE_SEGMENT_BIT_KHR = 0x00000100, + VK_VIDEO_ENCODE_H265_CAPABILITY_MULTIPLE_SLICE_SEGMENTS_PER_TILE_BIT_KHR = 0x00000200, + VK_VIDEO_ENCODE_H265_CAPABILITY_B_PICTURE_INTRA_REFRESH_BIT_KHR = 0x00000800, + VK_VIDEO_ENCODE_H265_CAPABILITY_CU_QP_DIFF_WRAPAROUND_BIT_KHR = 0x00000400, + VK_VIDEO_ENCODE_H265_CAPABILITY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeH265CapabilityFlagBitsKHR; +typedef VkFlags VkVideoEncodeH265CapabilityFlagsKHR; + +typedef enum VkVideoEncodeH265StdFlagBitsKHR { + VK_VIDEO_ENCODE_H265_STD_SEPARATE_COLOR_PLANE_FLAG_SET_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_H265_STD_SAMPLE_ADAPTIVE_OFFSET_ENABLED_FLAG_SET_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_H265_STD_SCALING_LIST_DATA_PRESENT_FLAG_SET_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_H265_STD_PCM_ENABLED_FLAG_SET_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_H265_STD_SPS_TEMPORAL_MVP_ENABLED_FLAG_SET_BIT_KHR = 0x00000010, + VK_VIDEO_ENCODE_H265_STD_INIT_QP_MINUS26_BIT_KHR = 0x00000020, + VK_VIDEO_ENCODE_H265_STD_WEIGHTED_PRED_FLAG_SET_BIT_KHR = 0x00000040, + VK_VIDEO_ENCODE_H265_STD_WEIGHTED_BIPRED_FLAG_SET_BIT_KHR = 0x00000080, + VK_VIDEO_ENCODE_H265_STD_LOG2_PARALLEL_MERGE_LEVEL_MINUS2_BIT_KHR = 0x00000100, + VK_VIDEO_ENCODE_H265_STD_SIGN_DATA_HIDING_ENABLED_FLAG_SET_BIT_KHR = 0x00000200, + VK_VIDEO_ENCODE_H265_STD_TRANSFORM_SKIP_ENABLED_FLAG_SET_BIT_KHR = 0x00000400, + VK_VIDEO_ENCODE_H265_STD_TRANSFORM_SKIP_ENABLED_FLAG_UNSET_BIT_KHR = 0x00000800, + VK_VIDEO_ENCODE_H265_STD_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT_FLAG_SET_BIT_KHR = 0x00001000, + VK_VIDEO_ENCODE_H265_STD_TRANSQUANT_BYPASS_ENABLED_FLAG_SET_BIT_KHR = 0x00002000, + VK_VIDEO_ENCODE_H265_STD_CONSTRAINED_INTRA_PRED_FLAG_SET_BIT_KHR = 0x00004000, + VK_VIDEO_ENCODE_H265_STD_ENTROPY_CODING_SYNC_ENABLED_FLAG_SET_BIT_KHR = 0x00008000, + VK_VIDEO_ENCODE_H265_STD_DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG_SET_BIT_KHR = 0x00010000, + VK_VIDEO_ENCODE_H265_STD_DEPENDENT_SLICE_SEGMENTS_ENABLED_FLAG_SET_BIT_KHR = 0x00020000, + VK_VIDEO_ENCODE_H265_STD_DEPENDENT_SLICE_SEGMENT_FLAG_SET_BIT_KHR = 0x00040000, + VK_VIDEO_ENCODE_H265_STD_SLICE_QP_DELTA_BIT_KHR = 0x00080000, + VK_VIDEO_ENCODE_H265_STD_DIFFERENT_SLICE_QP_DELTA_BIT_KHR = 0x00100000, + VK_VIDEO_ENCODE_H265_STD_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeH265StdFlagBitsKHR; +typedef VkFlags VkVideoEncodeH265StdFlagsKHR; + +typedef enum VkVideoEncodeH265CtbSizeFlagBitsKHR { + VK_VIDEO_ENCODE_H265_CTB_SIZE_16_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_H265_CTB_SIZE_32_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_H265_CTB_SIZE_64_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_H265_CTB_SIZE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeH265CtbSizeFlagBitsKHR; +typedef VkFlags VkVideoEncodeH265CtbSizeFlagsKHR; + +typedef enum VkVideoEncodeH265TransformBlockSizeFlagBitsKHR { + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_4_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_8_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_16_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_32_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeH265TransformBlockSizeFlagBitsKHR; +typedef VkFlags VkVideoEncodeH265TransformBlockSizeFlagsKHR; + +typedef enum VkVideoEncodeH265RateControlFlagBitsKHR { + VK_VIDEO_ENCODE_H265_RATE_CONTROL_ATTEMPT_HRD_COMPLIANCE_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_H265_RATE_CONTROL_REGULAR_GOP_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_H265_RATE_CONTROL_REFERENCE_PATTERN_FLAT_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_H265_RATE_CONTROL_REFERENCE_PATTERN_DYADIC_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_H265_RATE_CONTROL_TEMPORAL_SUB_LAYER_PATTERN_DYADIC_BIT_KHR = 0x00000010, + VK_VIDEO_ENCODE_H265_RATE_CONTROL_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeH265RateControlFlagBitsKHR; +typedef VkFlags VkVideoEncodeH265RateControlFlagsKHR; +typedef struct VkVideoEncodeH265CapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeH265CapabilityFlagsKHR flags; + StdVideoH265LevelIdc maxLevelIdc; + uint32_t maxSliceSegmentCount; + VkExtent2D maxTiles; + VkVideoEncodeH265CtbSizeFlagsKHR ctbSizes; + VkVideoEncodeH265TransformBlockSizeFlagsKHR transformBlockSizes; + uint32_t maxPPictureL0ReferenceCount; + uint32_t maxBPictureL0ReferenceCount; + uint32_t maxL1ReferenceCount; + uint32_t maxSubLayerCount; + VkBool32 expectDyadicTemporalSubLayerPattern; + int32_t minQp; + int32_t maxQp; + VkBool32 prefersGopRemainingFrames; + VkBool32 requiresGopRemainingFrames; + VkVideoEncodeH265StdFlagsKHR stdSyntaxFlags; +} VkVideoEncodeH265CapabilitiesKHR; + +typedef struct VkVideoEncodeH265SessionCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 useMaxLevelIdc; + StdVideoH265LevelIdc maxLevelIdc; +} VkVideoEncodeH265SessionCreateInfoKHR; + +typedef struct VkVideoEncodeH265QpKHR { + int32_t qpI; + int32_t qpP; + int32_t qpB; +} VkVideoEncodeH265QpKHR; + +typedef struct VkVideoEncodeH265QualityLevelPropertiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeH265RateControlFlagsKHR preferredRateControlFlags; + uint32_t preferredGopFrameCount; + uint32_t preferredIdrPeriod; + uint32_t preferredConsecutiveBFrameCount; + uint32_t preferredSubLayerCount; + VkVideoEncodeH265QpKHR preferredConstantQp; + uint32_t preferredMaxL0ReferenceCount; + uint32_t preferredMaxL1ReferenceCount; +} VkVideoEncodeH265QualityLevelPropertiesKHR; + +typedef struct VkVideoEncodeH265SessionParametersAddInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t stdVPSCount; + const StdVideoH265VideoParameterSet* pStdVPSs; + uint32_t stdSPSCount; + const StdVideoH265SequenceParameterSet* pStdSPSs; + uint32_t stdPPSCount; + const StdVideoH265PictureParameterSet* pStdPPSs; +} VkVideoEncodeH265SessionParametersAddInfoKHR; + +typedef struct VkVideoEncodeH265SessionParametersCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t maxStdVPSCount; + uint32_t maxStdSPSCount; + uint32_t maxStdPPSCount; + const VkVideoEncodeH265SessionParametersAddInfoKHR* pParametersAddInfo; +} VkVideoEncodeH265SessionParametersCreateInfoKHR; + +typedef struct VkVideoEncodeH265SessionParametersGetInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 writeStdVPS; + VkBool32 writeStdSPS; + VkBool32 writeStdPPS; + uint32_t stdVPSId; + uint32_t stdSPSId; + uint32_t stdPPSId; +} VkVideoEncodeH265SessionParametersGetInfoKHR; + +typedef struct VkVideoEncodeH265SessionParametersFeedbackInfoKHR { + VkStructureType sType; + void* pNext; + VkBool32 hasStdVPSOverrides; + VkBool32 hasStdSPSOverrides; + VkBool32 hasStdPPSOverrides; +} VkVideoEncodeH265SessionParametersFeedbackInfoKHR; + +typedef struct VkVideoEncodeH265NaluSliceSegmentInfoKHR { + VkStructureType sType; + const void* pNext; + int32_t constantQp; + const StdVideoEncodeH265SliceSegmentHeader* pStdSliceSegmentHeader; +} VkVideoEncodeH265NaluSliceSegmentInfoKHR; + +typedef struct VkVideoEncodeH265PictureInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t naluSliceSegmentEntryCount; + const VkVideoEncodeH265NaluSliceSegmentInfoKHR* pNaluSliceSegmentEntries; + const StdVideoEncodeH265PictureInfo* pStdPictureInfo; +} VkVideoEncodeH265PictureInfoKHR; + +typedef struct VkVideoEncodeH265DpbSlotInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoEncodeH265ReferenceInfo* pStdReferenceInfo; +} VkVideoEncodeH265DpbSlotInfoKHR; + +typedef struct VkVideoEncodeH265ProfileInfoKHR { + VkStructureType sType; + const void* pNext; + StdVideoH265ProfileIdc stdProfileIdc; +} VkVideoEncodeH265ProfileInfoKHR; + +typedef struct VkVideoEncodeH265RateControlInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeH265RateControlFlagsKHR flags; + uint32_t gopFrameCount; + uint32_t idrPeriod; + uint32_t consecutiveBFrameCount; + uint32_t subLayerCount; +} VkVideoEncodeH265RateControlInfoKHR; + +typedef struct VkVideoEncodeH265FrameSizeKHR { + uint32_t frameISize; + uint32_t framePSize; + uint32_t frameBSize; +} VkVideoEncodeH265FrameSizeKHR; + +typedef struct VkVideoEncodeH265RateControlLayerInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 useMinQp; + VkVideoEncodeH265QpKHR minQp; + VkBool32 useMaxQp; + VkVideoEncodeH265QpKHR maxQp; + VkBool32 useMaxFrameSize; + VkVideoEncodeH265FrameSizeKHR maxFrameSize; +} VkVideoEncodeH265RateControlLayerInfoKHR; + +typedef struct VkVideoEncodeH265GopRemainingFrameInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 useGopRemainingFrames; + uint32_t gopRemainingI; + uint32_t gopRemainingP; + uint32_t gopRemainingB; +} VkVideoEncodeH265GopRemainingFrameInfoKHR; + + + +// VK_KHR_video_decode_h264 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_decode_h264 1 +#include "vk_video/vulkan_video_codec_h264std_decode.h" +#define VK_KHR_VIDEO_DECODE_H264_SPEC_VERSION 9 +#define VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME "VK_KHR_video_decode_h264" + +typedef enum VkVideoDecodeH264PictureLayoutFlagBitsKHR { + VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_PROGRESSIVE_KHR = 0, + VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_INTERLACED_INTERLEAVED_LINES_BIT_KHR = 0x00000001, + VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_INTERLACED_SEPARATE_PLANES_BIT_KHR = 0x00000002, + VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoDecodeH264PictureLayoutFlagBitsKHR; +typedef VkFlags VkVideoDecodeH264PictureLayoutFlagsKHR; +typedef struct VkVideoDecodeH264ProfileInfoKHR { + VkStructureType sType; + const void* pNext; + StdVideoH264ProfileIdc stdProfileIdc; + VkVideoDecodeH264PictureLayoutFlagBitsKHR pictureLayout; +} VkVideoDecodeH264ProfileInfoKHR; + +typedef struct VkVideoDecodeH264CapabilitiesKHR { + VkStructureType sType; + void* pNext; + StdVideoH264LevelIdc maxLevelIdc; + VkOffset2D fieldOffsetGranularity; +} VkVideoDecodeH264CapabilitiesKHR; + +typedef struct VkVideoDecodeH264SessionParametersAddInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t stdSPSCount; + const StdVideoH264SequenceParameterSet* pStdSPSs; + uint32_t stdPPSCount; + const StdVideoH264PictureParameterSet* pStdPPSs; +} VkVideoDecodeH264SessionParametersAddInfoKHR; + +typedef struct VkVideoDecodeH264SessionParametersCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t maxStdSPSCount; + uint32_t maxStdPPSCount; + const VkVideoDecodeH264SessionParametersAddInfoKHR* pParametersAddInfo; +} VkVideoDecodeH264SessionParametersCreateInfoKHR; + +typedef struct VkVideoDecodeH264PictureInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoDecodeH264PictureInfo* pStdPictureInfo; + uint32_t sliceCount; + const uint32_t* pSliceOffsets; +} VkVideoDecodeH264PictureInfoKHR; + +typedef struct VkVideoDecodeH264DpbSlotInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoDecodeH264ReferenceInfo* pStdReferenceInfo; +} VkVideoDecodeH264DpbSlotInfoKHR; + + + +// VK_KHR_dynamic_rendering is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_dynamic_rendering 1 +#define VK_KHR_DYNAMIC_RENDERING_SPEC_VERSION 1 +#define VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME "VK_KHR_dynamic_rendering" +typedef VkRenderingFlags VkRenderingFlagsKHR; + +typedef VkRenderingFlagBits VkRenderingFlagBitsKHR; + +typedef VkRenderingInfo VkRenderingInfoKHR; + +typedef VkRenderingAttachmentInfo VkRenderingAttachmentInfoKHR; + +typedef VkPipelineRenderingCreateInfo VkPipelineRenderingCreateInfoKHR; + +typedef VkPhysicalDeviceDynamicRenderingFeatures VkPhysicalDeviceDynamicRenderingFeaturesKHR; + +typedef VkCommandBufferInheritanceRenderingInfo VkCommandBufferInheritanceRenderingInfoKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderingKHR)(VkCommandBuffer commandBuffer, const VkRenderingInfo* pRenderingInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderingKHR)(VkCommandBuffer commandBuffer); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderingKHR( + VkCommandBuffer commandBuffer, + const VkRenderingInfo* pRenderingInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderingKHR( + VkCommandBuffer commandBuffer); +#endif +#endif + + +// VK_KHR_multiview is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_multiview 1 +#define VK_KHR_MULTIVIEW_SPEC_VERSION 1 +#define VK_KHR_MULTIVIEW_EXTENSION_NAME "VK_KHR_multiview" +typedef VkRenderPassMultiviewCreateInfo VkRenderPassMultiviewCreateInfoKHR; + +typedef VkPhysicalDeviceMultiviewFeatures VkPhysicalDeviceMultiviewFeaturesKHR; + +typedef VkPhysicalDeviceMultiviewProperties VkPhysicalDeviceMultiviewPropertiesKHR; + + + +// VK_KHR_get_physical_device_properties2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_get_physical_device_properties2 1 +#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 2 +#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2" +typedef VkPhysicalDeviceFeatures2 VkPhysicalDeviceFeatures2KHR; + +typedef VkPhysicalDeviceProperties2 VkPhysicalDeviceProperties2KHR; + +typedef VkFormatProperties2 VkFormatProperties2KHR; + +typedef VkImageFormatProperties2 VkImageFormatProperties2KHR; + +typedef VkPhysicalDeviceImageFormatInfo2 VkPhysicalDeviceImageFormatInfo2KHR; + +typedef VkQueueFamilyProperties2 VkQueueFamilyProperties2KHR; + +typedef VkPhysicalDeviceMemoryProperties2 VkPhysicalDeviceMemoryProperties2KHR; + +typedef VkSparseImageFormatProperties2 VkSparseImageFormatProperties2KHR; + +typedef VkPhysicalDeviceSparseImageFormatInfo2 VkPhysicalDeviceSparseImageFormatInfo2KHR; + +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures2* pFeatures); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties2* pProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties2* pFormatProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, + VkImageFormatProperties2* pImageFormatProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR( + VkPhysicalDevice physicalDevice, + uint32_t* pQueueFamilyPropertyCount, + VkQueueFamilyProperties2* pQueueFamilyProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties2* pMemoryProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, + uint32_t* pPropertyCount, + VkSparseImageFormatProperties2* pProperties); +#endif +#endif + + +// VK_KHR_device_group is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_device_group 1 +#define VK_KHR_DEVICE_GROUP_SPEC_VERSION 4 +#define VK_KHR_DEVICE_GROUP_EXTENSION_NAME "VK_KHR_device_group" +typedef VkPeerMemoryFeatureFlags VkPeerMemoryFeatureFlagsKHR; + +typedef VkPeerMemoryFeatureFlagBits VkPeerMemoryFeatureFlagBitsKHR; + +typedef VkMemoryAllocateFlags VkMemoryAllocateFlagsKHR; + +typedef VkMemoryAllocateFlagBits VkMemoryAllocateFlagBitsKHR; + +typedef VkMemoryAllocateFlagsInfo VkMemoryAllocateFlagsInfoKHR; + +typedef VkDeviceGroupRenderPassBeginInfo VkDeviceGroupRenderPassBeginInfoKHR; + +typedef VkDeviceGroupCommandBufferBeginInfo VkDeviceGroupCommandBufferBeginInfoKHR; + +typedef VkDeviceGroupSubmitInfo VkDeviceGroupSubmitInfoKHR; + +typedef VkDeviceGroupBindSparseInfo VkDeviceGroupBindSparseInfoKHR; + +typedef VkBindBufferMemoryDeviceGroupInfo VkBindBufferMemoryDeviceGroupInfoKHR; + +typedef VkBindImageMemoryDeviceGroupInfo VkBindImageMemoryDeviceGroupInfoKHR; + +typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); +typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMaskKHR)(VkCommandBuffer commandBuffer, uint32_t deviceMask); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchBaseKHR)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeaturesKHR( + VkDevice device, + uint32_t heapIndex, + uint32_t localDeviceIndex, + uint32_t remoteDeviceIndex, + VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMaskKHR( + VkCommandBuffer commandBuffer, + uint32_t deviceMask); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBaseKHR( + VkCommandBuffer commandBuffer, + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); +#endif +#endif + + +// VK_KHR_shader_draw_parameters is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_draw_parameters 1 +#define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1 +#define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters" + + +// VK_KHR_maintenance1 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance1 1 +#define VK_KHR_MAINTENANCE_1_SPEC_VERSION 2 +#define VK_KHR_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_maintenance1" +// VK_KHR_MAINTENANCE1_SPEC_VERSION is a legacy alias +#define VK_KHR_MAINTENANCE1_SPEC_VERSION VK_KHR_MAINTENANCE_1_SPEC_VERSION +// VK_KHR_MAINTENANCE1_EXTENSION_NAME is a legacy alias +#define VK_KHR_MAINTENANCE1_EXTENSION_NAME VK_KHR_MAINTENANCE_1_EXTENSION_NAME +typedef VkCommandPoolTrimFlags VkCommandPoolTrimFlagsKHR; + +typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkTrimCommandPoolKHR( + VkDevice device, + VkCommandPool commandPool, + VkCommandPoolTrimFlags flags); +#endif +#endif + + +// VK_KHR_device_group_creation is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_device_group_creation 1 +#define VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION 1 +#define VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHR_device_group_creation" +#define VK_MAX_DEVICE_GROUP_SIZE_KHR VK_MAX_DEVICE_GROUP_SIZE +typedef VkPhysicalDeviceGroupProperties VkPhysicalDeviceGroupPropertiesKHR; + +typedef VkDeviceGroupDeviceCreateInfo VkDeviceGroupDeviceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroupsKHR)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroupsKHR( + VkInstance instance, + uint32_t* pPhysicalDeviceGroupCount, + VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); +#endif +#endif + + +// VK_KHR_external_memory_capabilities is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_memory_capabilities 1 +#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_memory_capabilities" +#define VK_LUID_SIZE_KHR VK_LUID_SIZE +typedef VkExternalMemoryHandleTypeFlags VkExternalMemoryHandleTypeFlagsKHR; + +typedef VkExternalMemoryHandleTypeFlagBits VkExternalMemoryHandleTypeFlagBitsKHR; + +typedef VkExternalMemoryFeatureFlags VkExternalMemoryFeatureFlagsKHR; + +typedef VkExternalMemoryFeatureFlagBits VkExternalMemoryFeatureFlagBitsKHR; + +typedef VkExternalMemoryProperties VkExternalMemoryPropertiesKHR; + +typedef VkPhysicalDeviceExternalImageFormatInfo VkPhysicalDeviceExternalImageFormatInfoKHR; + +typedef VkExternalImageFormatProperties VkExternalImageFormatPropertiesKHR; + +typedef VkPhysicalDeviceExternalBufferInfo VkPhysicalDeviceExternalBufferInfoKHR; + +typedef VkExternalBufferProperties VkExternalBufferPropertiesKHR; + +typedef VkPhysicalDeviceIDProperties VkPhysicalDeviceIDPropertiesKHR; + +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferPropertiesKHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, + VkExternalBufferProperties* pExternalBufferProperties); +#endif +#endif + + +// VK_KHR_external_memory is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_memory 1 +#define VK_KHR_EXTERNAL_MEMORY_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHR_external_memory" +#define VK_QUEUE_FAMILY_EXTERNAL_KHR VK_QUEUE_FAMILY_EXTERNAL +typedef VkExternalMemoryImageCreateInfo VkExternalMemoryImageCreateInfoKHR; + +typedef VkExternalMemoryBufferCreateInfo VkExternalMemoryBufferCreateInfoKHR; + +typedef VkExportMemoryAllocateInfo VkExportMemoryAllocateInfoKHR; + + + +// VK_KHR_external_memory_fd is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_memory_fd 1 +#define VK_KHR_EXTERNAL_MEMORY_FD_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME "VK_KHR_external_memory_fd" +typedef struct VkImportMemoryFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + int fd; +} VkImportMemoryFdInfoKHR; + +typedef struct VkMemoryFdPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t memoryTypeBits; +} VkMemoryFdPropertiesKHR; + +typedef struct VkMemoryGetFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkMemoryGetFdInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdKHR)(VkDevice device, const VkMemoryGetFdInfoKHR* pGetFdInfo, int* pFd); +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdPropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, int fd, VkMemoryFdPropertiesKHR* pMemoryFdProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdKHR( + VkDevice device, + const VkMemoryGetFdInfoKHR* pGetFdInfo, + int* pFd); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdPropertiesKHR( + VkDevice device, + VkExternalMemoryHandleTypeFlagBits handleType, + int fd, + VkMemoryFdPropertiesKHR* pMemoryFdProperties); +#endif +#endif + + +// VK_KHR_external_semaphore_capabilities is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_semaphore_capabilities 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_semaphore_capabilities" +typedef VkExternalSemaphoreHandleTypeFlags VkExternalSemaphoreHandleTypeFlagsKHR; + +typedef VkExternalSemaphoreHandleTypeFlagBits VkExternalSemaphoreHandleTypeFlagBitsKHR; + +typedef VkExternalSemaphoreFeatureFlags VkExternalSemaphoreFeatureFlagsKHR; + +typedef VkExternalSemaphoreFeatureFlagBits VkExternalSemaphoreFeatureFlagBitsKHR; + +typedef VkPhysicalDeviceExternalSemaphoreInfo VkPhysicalDeviceExternalSemaphoreInfoKHR; + +typedef VkExternalSemaphoreProperties VkExternalSemaphorePropertiesKHR; + +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphorePropertiesKHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, + VkExternalSemaphoreProperties* pExternalSemaphoreProperties); +#endif +#endif + + +// VK_KHR_external_semaphore is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_semaphore 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHR_external_semaphore" +typedef VkSemaphoreImportFlags VkSemaphoreImportFlagsKHR; + +typedef VkSemaphoreImportFlagBits VkSemaphoreImportFlagBitsKHR; + +typedef VkExportSemaphoreCreateInfo VkExportSemaphoreCreateInfoKHR; + + + +// VK_KHR_external_semaphore_fd is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_semaphore_fd 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHR_external_semaphore_fd" +typedef struct VkImportSemaphoreFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkSemaphoreImportFlags flags; + VkExternalSemaphoreHandleTypeFlagBits handleType; + int fd; +} VkImportSemaphoreFdInfoKHR; + +typedef struct VkSemaphoreGetFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkExternalSemaphoreHandleTypeFlagBits handleType; +} VkSemaphoreGetFdInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreFdKHR)(VkDevice device, const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreFdKHR)(VkDevice device, const VkSemaphoreGetFdInfoKHR* pGetFdInfo, int* pFd); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreFdKHR( + VkDevice device, + const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreFdKHR( + VkDevice device, + const VkSemaphoreGetFdInfoKHR* pGetFdInfo, + int* pFd); +#endif +#endif + + +// VK_KHR_push_descriptor is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_push_descriptor 1 +#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2 +#define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor" +typedef VkPhysicalDevicePushDescriptorProperties VkPhysicalDevicePushDescriptorPropertiesKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetKHR)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites); +typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplate descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void* pData); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetKHR( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, + uint32_t set, + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet* pDescriptorWrites); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR( + VkCommandBuffer commandBuffer, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + VkPipelineLayout layout, + uint32_t set, + const void* pData); +#endif +#endif + + +// VK_KHR_shader_float16_int8 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_float16_int8 1 +#define VK_KHR_SHADER_FLOAT16_INT8_SPEC_VERSION 1 +#define VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME "VK_KHR_shader_float16_int8" +typedef VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceShaderFloat16Int8FeaturesKHR; + +typedef VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceFloat16Int8FeaturesKHR; + + + +// VK_KHR_16bit_storage is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_16bit_storage 1 +#define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1 +#define VK_KHR_16BIT_STORAGE_EXTENSION_NAME "VK_KHR_16bit_storage" +typedef VkPhysicalDevice16BitStorageFeatures VkPhysicalDevice16BitStorageFeaturesKHR; + + + +// VK_KHR_incremental_present is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_incremental_present 1 +#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 2 +#define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present" +typedef struct VkRectLayerKHR { + VkOffset2D offset; + VkExtent2D extent; + uint32_t layer; +} VkRectLayerKHR; + +typedef struct VkPresentRegionKHR { + uint32_t rectangleCount; + const VkRectLayerKHR* pRectangles; +} VkPresentRegionKHR; + +typedef struct VkPresentRegionsKHR { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const VkPresentRegionKHR* pRegions; +} VkPresentRegionsKHR; + + + +// VK_KHR_descriptor_update_template is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_descriptor_update_template 1 +typedef VkDescriptorUpdateTemplate VkDescriptorUpdateTemplateKHR; + +#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1 +#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template" +typedef VkDescriptorUpdateTemplateType VkDescriptorUpdateTemplateTypeKHR; + +typedef VkDescriptorUpdateTemplateCreateFlags VkDescriptorUpdateTemplateCreateFlagsKHR; + +typedef VkDescriptorUpdateTemplateEntry VkDescriptorUpdateTemplateEntryKHR; + +typedef VkDescriptorUpdateTemplateCreateInfo VkDescriptorUpdateTemplateCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplateKHR)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplateKHR( + VkDevice device, + const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplateKHR( + VkDevice device, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplateKHR( + VkDevice device, + VkDescriptorSet descriptorSet, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const void* pData); +#endif +#endif + + +// VK_KHR_imageless_framebuffer is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_imageless_framebuffer 1 +#define VK_KHR_IMAGELESS_FRAMEBUFFER_SPEC_VERSION 1 +#define VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME "VK_KHR_imageless_framebuffer" +typedef VkPhysicalDeviceImagelessFramebufferFeatures VkPhysicalDeviceImagelessFramebufferFeaturesKHR; + +typedef VkFramebufferAttachmentsCreateInfo VkFramebufferAttachmentsCreateInfoKHR; + +typedef VkFramebufferAttachmentImageInfo VkFramebufferAttachmentImageInfoKHR; + +typedef VkRenderPassAttachmentBeginInfo VkRenderPassAttachmentBeginInfoKHR; + + + +// VK_KHR_create_renderpass2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_create_renderpass2 1 +#define VK_KHR_CREATE_RENDERPASS_2_SPEC_VERSION 1 +#define VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME "VK_KHR_create_renderpass2" +typedef VkRenderPassCreateInfo2 VkRenderPassCreateInfo2KHR; + +typedef VkAttachmentDescription2 VkAttachmentDescription2KHR; + +typedef VkAttachmentReference2 VkAttachmentReference2KHR; + +typedef VkSubpassDescription2 VkSubpassDescription2KHR; + +typedef VkSubpassDependency2 VkSubpassDependency2KHR; + +typedef VkSubpassBeginInfo VkSubpassBeginInfoKHR; + +typedef VkSubpassEndInfo VkSubpassEndInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo); +typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass2KHR( + VkDevice device, + const VkRenderPassCreateInfo2* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkRenderPass* pRenderPass); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass2KHR( + VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo* pRenderPassBegin, + const VkSubpassBeginInfo* pSubpassBeginInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass2KHR( + VkCommandBuffer commandBuffer, + const VkSubpassBeginInfo* pSubpassBeginInfo, + const VkSubpassEndInfo* pSubpassEndInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass2KHR( + VkCommandBuffer commandBuffer, + const VkSubpassEndInfo* pSubpassEndInfo); +#endif +#endif + + +// VK_KHR_shared_presentable_image is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shared_presentable_image 1 +#define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1 +#define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image" +typedef struct VkSharedPresentSurfaceCapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkImageUsageFlags sharedPresentSupportedUsageFlags; +} VkSharedPresentSurfaceCapabilitiesKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainStatusKHR)(VkDevice device, VkSwapchainKHR swapchain); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainStatusKHR( + VkDevice device, + VkSwapchainKHR swapchain); +#endif +#endif + + +// VK_KHR_external_fence_capabilities is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_fence_capabilities 1 +#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_fence_capabilities" +typedef VkExternalFenceHandleTypeFlags VkExternalFenceHandleTypeFlagsKHR; + +typedef VkExternalFenceHandleTypeFlagBits VkExternalFenceHandleTypeFlagBitsKHR; + +typedef VkExternalFenceFeatureFlags VkExternalFenceFeatureFlagsKHR; + +typedef VkExternalFenceFeatureFlagBits VkExternalFenceFeatureFlagBitsKHR; + +typedef VkPhysicalDeviceExternalFenceInfo VkPhysicalDeviceExternalFenceInfoKHR; + +typedef VkExternalFenceProperties VkExternalFencePropertiesKHR; + +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFencePropertiesKHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, + VkExternalFenceProperties* pExternalFenceProperties); +#endif +#endif + + +// VK_KHR_external_fence is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_fence 1 +#define VK_KHR_EXTERNAL_FENCE_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME "VK_KHR_external_fence" +typedef VkFenceImportFlags VkFenceImportFlagsKHR; + +typedef VkFenceImportFlagBits VkFenceImportFlagBitsKHR; + +typedef VkExportFenceCreateInfo VkExportFenceCreateInfoKHR; + + + +// VK_KHR_external_fence_fd is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_fence_fd 1 +#define VK_KHR_EXTERNAL_FENCE_FD_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME "VK_KHR_external_fence_fd" +typedef struct VkImportFenceFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkFence fence; + VkFenceImportFlags flags; + VkExternalFenceHandleTypeFlagBits handleType; + int fd; +} VkImportFenceFdInfoKHR; + +typedef struct VkFenceGetFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkFence fence; + VkExternalFenceHandleTypeFlagBits handleType; +} VkFenceGetFdInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkImportFenceFdKHR)(VkDevice device, const VkImportFenceFdInfoKHR* pImportFenceFdInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetFenceFdKHR)(VkDevice device, const VkFenceGetFdInfoKHR* pGetFdInfo, int* pFd); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkImportFenceFdKHR( + VkDevice device, + const VkImportFenceFdInfoKHR* pImportFenceFdInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceFdKHR( + VkDevice device, + const VkFenceGetFdInfoKHR* pGetFdInfo, + int* pFd); +#endif +#endif + + +// VK_KHR_performance_query is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_performance_query 1 +#define VK_KHR_PERFORMANCE_QUERY_SPEC_VERSION 1 +#define VK_KHR_PERFORMANCE_QUERY_EXTENSION_NAME "VK_KHR_performance_query" + +typedef enum VkPerformanceCounterUnitKHR { + VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR = 0, + VK_PERFORMANCE_COUNTER_UNIT_PERCENTAGE_KHR = 1, + VK_PERFORMANCE_COUNTER_UNIT_NANOSECONDS_KHR = 2, + VK_PERFORMANCE_COUNTER_UNIT_BYTES_KHR = 3, + VK_PERFORMANCE_COUNTER_UNIT_BYTES_PER_SECOND_KHR = 4, + VK_PERFORMANCE_COUNTER_UNIT_KELVIN_KHR = 5, + VK_PERFORMANCE_COUNTER_UNIT_WATTS_KHR = 6, + VK_PERFORMANCE_COUNTER_UNIT_VOLTS_KHR = 7, + VK_PERFORMANCE_COUNTER_UNIT_AMPS_KHR = 8, + VK_PERFORMANCE_COUNTER_UNIT_HERTZ_KHR = 9, + VK_PERFORMANCE_COUNTER_UNIT_CYCLES_KHR = 10, + VK_PERFORMANCE_COUNTER_UNIT_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPerformanceCounterUnitKHR; + +typedef enum VkPerformanceCounterScopeKHR { + VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR = 0, + VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR = 1, + VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR = 2, + // VK_QUERY_SCOPE_COMMAND_BUFFER_KHR is a legacy alias + VK_QUERY_SCOPE_COMMAND_BUFFER_KHR = VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR, + // VK_QUERY_SCOPE_RENDER_PASS_KHR is a legacy alias + VK_QUERY_SCOPE_RENDER_PASS_KHR = VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR, + // VK_QUERY_SCOPE_COMMAND_KHR is a legacy alias + VK_QUERY_SCOPE_COMMAND_KHR = VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR, + VK_PERFORMANCE_COUNTER_SCOPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPerformanceCounterScopeKHR; + +typedef enum VkPerformanceCounterStorageKHR { + VK_PERFORMANCE_COUNTER_STORAGE_INT32_KHR = 0, + VK_PERFORMANCE_COUNTER_STORAGE_INT64_KHR = 1, + VK_PERFORMANCE_COUNTER_STORAGE_UINT32_KHR = 2, + VK_PERFORMANCE_COUNTER_STORAGE_UINT64_KHR = 3, + VK_PERFORMANCE_COUNTER_STORAGE_FLOAT32_KHR = 4, + VK_PERFORMANCE_COUNTER_STORAGE_FLOAT64_KHR = 5, + VK_PERFORMANCE_COUNTER_STORAGE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPerformanceCounterStorageKHR; + +typedef enum VkPerformanceCounterDescriptionFlagBitsKHR { + VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_BIT_KHR = 0x00000001, + VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_BIT_KHR = 0x00000002, + // VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_KHR is a legacy alias + VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_KHR = VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_BIT_KHR, + // VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_KHR is a legacy alias + VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_KHR = VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_BIT_KHR, + VK_PERFORMANCE_COUNTER_DESCRIPTION_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPerformanceCounterDescriptionFlagBitsKHR; +typedef VkFlags VkPerformanceCounterDescriptionFlagsKHR; + +typedef enum VkAcquireProfilingLockFlagBitsKHR { + VK_ACQUIRE_PROFILING_LOCK_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAcquireProfilingLockFlagBitsKHR; +typedef VkFlags VkAcquireProfilingLockFlagsKHR; +typedef struct VkPhysicalDevicePerformanceQueryFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 performanceCounterQueryPools; + VkBool32 performanceCounterMultipleQueryPools; +} VkPhysicalDevicePerformanceQueryFeaturesKHR; + +typedef struct VkPhysicalDevicePerformanceQueryPropertiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 allowCommandBufferQueryCopies; +} VkPhysicalDevicePerformanceQueryPropertiesKHR; + +typedef struct VkPerformanceCounterKHR { + VkStructureType sType; + void* pNext; + VkPerformanceCounterUnitKHR unit; + VkPerformanceCounterScopeKHR scope; + VkPerformanceCounterStorageKHR storage; + uint8_t uuid[VK_UUID_SIZE]; +} VkPerformanceCounterKHR; + +typedef struct VkPerformanceCounterDescriptionKHR { + VkStructureType sType; + void* pNext; + VkPerformanceCounterDescriptionFlagsKHR flags; + char name[VK_MAX_DESCRIPTION_SIZE]; + char category[VK_MAX_DESCRIPTION_SIZE]; + char description[VK_MAX_DESCRIPTION_SIZE]; +} VkPerformanceCounterDescriptionKHR; + +typedef struct VkQueryPoolPerformanceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t queueFamilyIndex; + uint32_t counterIndexCount; + const uint32_t* pCounterIndices; +} VkQueryPoolPerformanceCreateInfoKHR; + +typedef union VkPerformanceCounterResultKHR { + int32_t int32; + int64_t int64; + uint32_t uint32; + uint64_t uint64; + float float32; + double float64; +} VkPerformanceCounterResultKHR; + +typedef struct VkAcquireProfilingLockInfoKHR { + VkStructureType sType; + const void* pNext; + VkAcquireProfilingLockFlagsKHR flags; + uint64_t timeout; +} VkAcquireProfilingLockInfoKHR; + +typedef struct VkPerformanceQuerySubmitInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t counterPassIndex; +} VkPerformanceQuerySubmitInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, uint32_t* pCounterCount, VkPerformanceCounterKHR* pCounters, VkPerformanceCounterDescriptionKHR* pCounterDescriptions); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR)(VkPhysicalDevice physicalDevice, const VkQueryPoolPerformanceCreateInfoKHR* pPerformanceQueryCreateInfo, uint32_t* pNumPasses); +typedef VkResult (VKAPI_PTR *PFN_vkAcquireProfilingLockKHR)(VkDevice device, const VkAcquireProfilingLockInfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkReleaseProfilingLockKHR)(VkDevice device); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + uint32_t* pCounterCount, + VkPerformanceCounterKHR* pCounters, + VkPerformanceCounterDescriptionKHR* pCounterDescriptions); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR( + VkPhysicalDevice physicalDevice, + const VkQueryPoolPerformanceCreateInfoKHR* pPerformanceQueryCreateInfo, + uint32_t* pNumPasses); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireProfilingLockKHR( + VkDevice device, + const VkAcquireProfilingLockInfoKHR* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkReleaseProfilingLockKHR( + VkDevice device); +#endif +#endif + + +// VK_KHR_maintenance2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance2 1 +#define VK_KHR_MAINTENANCE_2_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_2_EXTENSION_NAME "VK_KHR_maintenance2" +// VK_KHR_MAINTENANCE2_SPEC_VERSION is a legacy alias +#define VK_KHR_MAINTENANCE2_SPEC_VERSION VK_KHR_MAINTENANCE_2_SPEC_VERSION +// VK_KHR_MAINTENANCE2_EXTENSION_NAME is a legacy alias +#define VK_KHR_MAINTENANCE2_EXTENSION_NAME VK_KHR_MAINTENANCE_2_EXTENSION_NAME +typedef VkPointClippingBehavior VkPointClippingBehaviorKHR; + +typedef VkTessellationDomainOrigin VkTessellationDomainOriginKHR; + +typedef VkPhysicalDevicePointClippingProperties VkPhysicalDevicePointClippingPropertiesKHR; + +typedef VkRenderPassInputAttachmentAspectCreateInfo VkRenderPassInputAttachmentAspectCreateInfoKHR; + +typedef VkInputAttachmentAspectReference VkInputAttachmentAspectReferenceKHR; + +typedef VkImageViewUsageCreateInfo VkImageViewUsageCreateInfoKHR; + +typedef VkPipelineTessellationDomainOriginStateCreateInfo VkPipelineTessellationDomainOriginStateCreateInfoKHR; + + + +// VK_KHR_get_surface_capabilities2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_get_surface_capabilities2 1 +#define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1 +#define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2" +typedef struct VkPhysicalDeviceSurfaceInfo2KHR { + VkStructureType sType; + const void* pNext; + VkSurfaceKHR surface; +} VkPhysicalDeviceSurfaceInfo2KHR; + +typedef struct VkSurfaceCapabilities2KHR { + VkStructureType sType; + void* pNext; + VkSurfaceCapabilitiesKHR surfaceCapabilities; +} VkSurfaceCapabilities2KHR; + +typedef struct VkSurfaceFormat2KHR { + VkStructureType sType; + void* pNext; + VkSurfaceFormatKHR surfaceFormat; +} VkSurfaceFormat2KHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkSurfaceCapabilities2KHR* pSurfaceCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2KHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, + VkSurfaceCapabilities2KHR* pSurfaceCapabilities); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormats2KHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, + uint32_t* pSurfaceFormatCount, + VkSurfaceFormat2KHR* pSurfaceFormats); +#endif +#endif + + +// VK_KHR_variable_pointers is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_variable_pointers 1 +#define VK_KHR_VARIABLE_POINTERS_SPEC_VERSION 1 +#define VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME "VK_KHR_variable_pointers" +typedef VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeaturesKHR; + +typedef VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointersFeaturesKHR; + + + +// VK_KHR_get_display_properties2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_get_display_properties2 1 +#define VK_KHR_GET_DISPLAY_PROPERTIES_2_SPEC_VERSION 1 +#define VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_display_properties2" +typedef struct VkDisplayProperties2KHR { + VkStructureType sType; + void* pNext; + VkDisplayPropertiesKHR displayProperties; +} VkDisplayProperties2KHR; + +typedef struct VkDisplayPlaneProperties2KHR { + VkStructureType sType; + void* pNext; + VkDisplayPlanePropertiesKHR displayPlaneProperties; +} VkDisplayPlaneProperties2KHR; + +typedef struct VkDisplayModeProperties2KHR { + VkStructureType sType; + void* pNext; + VkDisplayModePropertiesKHR displayModeProperties; +} VkDisplayModeProperties2KHR; + +typedef struct VkDisplayPlaneInfo2KHR { + VkStructureType sType; + const void* pNext; + VkDisplayModeKHR mode; + uint32_t planeIndex; +} VkDisplayPlaneInfo2KHR; + +typedef struct VkDisplayPlaneCapabilities2KHR { + VkStructureType sType; + void* pNext; + VkDisplayPlaneCapabilitiesKHR capabilities; +} VkDisplayPlaneCapabilities2KHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayProperties2KHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlaneProperties2KHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModeProperties2KHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModeProperties2KHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkDisplayPlaneInfo2KHR* pDisplayPlaneInfo, VkDisplayPlaneCapabilities2KHR* pCapabilities); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayProperties2KHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayProperties2KHR* pProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlaneProperties2KHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayPlaneProperties2KHR* pProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModeProperties2KHR( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + uint32_t* pPropertyCount, + VkDisplayModeProperties2KHR* pProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilities2KHR( + VkPhysicalDevice physicalDevice, + const VkDisplayPlaneInfo2KHR* pDisplayPlaneInfo, + VkDisplayPlaneCapabilities2KHR* pCapabilities); +#endif +#endif + + +// VK_KHR_dedicated_allocation is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_dedicated_allocation 1 +#define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 3 +#define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation" +typedef VkMemoryDedicatedRequirements VkMemoryDedicatedRequirementsKHR; + +typedef VkMemoryDedicatedAllocateInfo VkMemoryDedicatedAllocateInfoKHR; + + + +// VK_KHR_storage_buffer_storage_class is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_storage_buffer_storage_class 1 +#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_SPEC_VERSION 1 +#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME "VK_KHR_storage_buffer_storage_class" + + +// VK_KHR_shader_bfloat16 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_bfloat16 1 +#define VK_KHR_SHADER_BFLOAT16_SPEC_VERSION 1 +#define VK_KHR_SHADER_BFLOAT16_EXTENSION_NAME "VK_KHR_shader_bfloat16" +typedef struct VkPhysicalDeviceShaderBfloat16FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderBFloat16Type; + VkBool32 shaderBFloat16DotProduct; + VkBool32 shaderBFloat16CooperativeMatrix; +} VkPhysicalDeviceShaderBfloat16FeaturesKHR; + + + +// VK_KHR_relaxed_block_layout is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_relaxed_block_layout 1 +#define VK_KHR_RELAXED_BLOCK_LAYOUT_SPEC_VERSION 1 +#define VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME "VK_KHR_relaxed_block_layout" + + +// VK_KHR_get_memory_requirements2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_get_memory_requirements2 1 +#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_SPEC_VERSION 1 +#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME "VK_KHR_get_memory_requirements2" +typedef VkBufferMemoryRequirementsInfo2 VkBufferMemoryRequirementsInfo2KHR; + +typedef VkImageMemoryRequirementsInfo2 VkImageMemoryRequirementsInfo2KHR; + +typedef VkImageSparseMemoryRequirementsInfo2 VkImageSparseMemoryRequirementsInfo2KHR; + +typedef VkMemoryRequirements2 VkMemoryRequirements2KHR; + +typedef VkSparseImageMemoryRequirements2 VkSparseImageMemoryRequirements2KHR; + +typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2KHR)(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2KHR)(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2KHR)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2KHR( + VkDevice device, + const VkImageMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2KHR( + VkDevice device, + const VkBufferMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2KHR( + VkDevice device, + const VkImageSparseMemoryRequirementsInfo2* pInfo, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +#endif +#endif + + +// VK_KHR_image_format_list is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_image_format_list 1 +#define VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION 1 +#define VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME "VK_KHR_image_format_list" +typedef VkImageFormatListCreateInfo VkImageFormatListCreateInfoKHR; + + + +// VK_KHR_sampler_ycbcr_conversion is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_sampler_ycbcr_conversion 1 +typedef VkSamplerYcbcrConversion VkSamplerYcbcrConversionKHR; + +#define VK_KHR_SAMPLER_YCBCR_CONVERSION_SPEC_VERSION 14 +#define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME "VK_KHR_sampler_ycbcr_conversion" +typedef VkSamplerYcbcrModelConversion VkSamplerYcbcrModelConversionKHR; + +typedef VkSamplerYcbcrRange VkSamplerYcbcrRangeKHR; + +typedef VkChromaLocation VkChromaLocationKHR; + +typedef VkSamplerYcbcrConversionCreateInfo VkSamplerYcbcrConversionCreateInfoKHR; + +typedef VkSamplerYcbcrConversionInfo VkSamplerYcbcrConversionInfoKHR; + +typedef VkBindImagePlaneMemoryInfo VkBindImagePlaneMemoryInfoKHR; + +typedef VkImagePlaneMemoryRequirementsInfo VkImagePlaneMemoryRequirementsInfoKHR; + +typedef VkPhysicalDeviceSamplerYcbcrConversionFeatures VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR; + +typedef VkSamplerYcbcrConversionImageFormatProperties VkSamplerYcbcrConversionImageFormatPropertiesKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversionKHR)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); +typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversionKHR)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversionKHR( + VkDevice device, + const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSamplerYcbcrConversion* pYcbcrConversion); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroySamplerYcbcrConversionKHR( + VkDevice device, + VkSamplerYcbcrConversion ycbcrConversion, + const VkAllocationCallbacks* pAllocator); +#endif +#endif + + +// VK_KHR_bind_memory2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_bind_memory2 1 +#define VK_KHR_BIND_MEMORY_2_SPEC_VERSION 1 +#define VK_KHR_BIND_MEMORY_2_EXTENSION_NAME "VK_KHR_bind_memory2" +typedef VkBindBufferMemoryInfo VkBindBufferMemoryInfoKHR; + +typedef VkBindImageMemoryInfo VkBindImageMemoryInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); +typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2KHR( + VkDevice device, + uint32_t bindInfoCount, + const VkBindBufferMemoryInfo* pBindInfos); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2KHR( + VkDevice device, + uint32_t bindInfoCount, + const VkBindImageMemoryInfo* pBindInfos); +#endif +#endif + + +// VK_KHR_maintenance3 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance3 1 +#define VK_KHR_MAINTENANCE_3_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_3_EXTENSION_NAME "VK_KHR_maintenance3" +// VK_KHR_MAINTENANCE3_SPEC_VERSION is a legacy alias +#define VK_KHR_MAINTENANCE3_SPEC_VERSION VK_KHR_MAINTENANCE_3_SPEC_VERSION +// VK_KHR_MAINTENANCE3_EXTENSION_NAME is a legacy alias +#define VK_KHR_MAINTENANCE3_EXTENSION_NAME VK_KHR_MAINTENANCE_3_EXTENSION_NAME +typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; + +typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; + +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupportKHR( + VkDevice device, + const VkDescriptorSetLayoutCreateInfo* pCreateInfo, + VkDescriptorSetLayoutSupport* pSupport); +#endif +#endif + + +// VK_KHR_draw_indirect_count is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_draw_indirect_count 1 +#define VK_KHR_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 +#define VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_KHR_draw_indirect_count" +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountKHR)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountKHR)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountKHR( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountKHR( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); +#endif +#endif + + +// VK_KHR_shader_subgroup_extended_types is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_subgroup_extended_types 1 +#define VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_SPEC_VERSION 1 +#define VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_EXTENSION_NAME "VK_KHR_shader_subgroup_extended_types" +typedef VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR; + + + +// VK_KHR_8bit_storage is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_8bit_storage 1 +#define VK_KHR_8BIT_STORAGE_SPEC_VERSION 1 +#define VK_KHR_8BIT_STORAGE_EXTENSION_NAME "VK_KHR_8bit_storage" +typedef VkPhysicalDevice8BitStorageFeatures VkPhysicalDevice8BitStorageFeaturesKHR; + + + +// VK_KHR_shader_atomic_int64 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_atomic_int64 1 +#define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1 +#define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64" +typedef VkPhysicalDeviceShaderAtomicInt64Features VkPhysicalDeviceShaderAtomicInt64FeaturesKHR; + + + +// VK_KHR_shader_clock is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_clock 1 +#define VK_KHR_SHADER_CLOCK_SPEC_VERSION 1 +#define VK_KHR_SHADER_CLOCK_EXTENSION_NAME "VK_KHR_shader_clock" +typedef struct VkPhysicalDeviceShaderClockFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderSubgroupClock; + VkBool32 shaderDeviceClock; +} VkPhysicalDeviceShaderClockFeaturesKHR; + + + +// VK_KHR_video_decode_h265 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_decode_h265 1 +#include "vk_video/vulkan_video_codec_h265std_decode.h" +#define VK_KHR_VIDEO_DECODE_H265_SPEC_VERSION 8 +#define VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME "VK_KHR_video_decode_h265" +typedef struct VkVideoDecodeH265ProfileInfoKHR { + VkStructureType sType; + const void* pNext; + StdVideoH265ProfileIdc stdProfileIdc; +} VkVideoDecodeH265ProfileInfoKHR; + +typedef struct VkVideoDecodeH265CapabilitiesKHR { + VkStructureType sType; + void* pNext; + StdVideoH265LevelIdc maxLevelIdc; +} VkVideoDecodeH265CapabilitiesKHR; + +typedef struct VkVideoDecodeH265SessionParametersAddInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t stdVPSCount; + const StdVideoH265VideoParameterSet* pStdVPSs; + uint32_t stdSPSCount; + const StdVideoH265SequenceParameterSet* pStdSPSs; + uint32_t stdPPSCount; + const StdVideoH265PictureParameterSet* pStdPPSs; +} VkVideoDecodeH265SessionParametersAddInfoKHR; + +typedef struct VkVideoDecodeH265SessionParametersCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t maxStdVPSCount; + uint32_t maxStdSPSCount; + uint32_t maxStdPPSCount; + const VkVideoDecodeH265SessionParametersAddInfoKHR* pParametersAddInfo; +} VkVideoDecodeH265SessionParametersCreateInfoKHR; + +typedef struct VkVideoDecodeH265PictureInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoDecodeH265PictureInfo* pStdPictureInfo; + uint32_t sliceSegmentCount; + const uint32_t* pSliceSegmentOffsets; +} VkVideoDecodeH265PictureInfoKHR; + +typedef struct VkVideoDecodeH265DpbSlotInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoDecodeH265ReferenceInfo* pStdReferenceInfo; +} VkVideoDecodeH265DpbSlotInfoKHR; + + + +// VK_KHR_global_priority is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_global_priority 1 +#define VK_KHR_GLOBAL_PRIORITY_SPEC_VERSION 1 +#define VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME "VK_KHR_global_priority" +#define VK_MAX_GLOBAL_PRIORITY_SIZE_KHR VK_MAX_GLOBAL_PRIORITY_SIZE +typedef VkQueueGlobalPriority VkQueueGlobalPriorityKHR; + +typedef VkDeviceQueueGlobalPriorityCreateInfo VkDeviceQueueGlobalPriorityCreateInfoKHR; + +typedef VkPhysicalDeviceGlobalPriorityQueryFeatures VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR; + +typedef VkQueueFamilyGlobalPriorityProperties VkQueueFamilyGlobalPriorityPropertiesKHR; + + + +// VK_KHR_driver_properties is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_driver_properties 1 +#define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1 +#define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties" +#define VK_MAX_DRIVER_NAME_SIZE_KHR VK_MAX_DRIVER_NAME_SIZE +#define VK_MAX_DRIVER_INFO_SIZE_KHR VK_MAX_DRIVER_INFO_SIZE +typedef VkDriverId VkDriverIdKHR; + +typedef VkConformanceVersion VkConformanceVersionKHR; + +typedef VkPhysicalDeviceDriverProperties VkPhysicalDeviceDriverPropertiesKHR; + + + +// VK_KHR_shader_float_controls is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_float_controls 1 +#define VK_KHR_SHADER_FLOAT_CONTROLS_SPEC_VERSION 4 +#define VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME "VK_KHR_shader_float_controls" +typedef VkShaderFloatControlsIndependence VkShaderFloatControlsIndependenceKHR; + +typedef VkPhysicalDeviceFloatControlsProperties VkPhysicalDeviceFloatControlsPropertiesKHR; + + + +// VK_KHR_depth_stencil_resolve is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_depth_stencil_resolve 1 +#define VK_KHR_DEPTH_STENCIL_RESOLVE_SPEC_VERSION 1 +#define VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME "VK_KHR_depth_stencil_resolve" +typedef VkResolveModeFlagBits VkResolveModeFlagBitsKHR; + +typedef VkResolveModeFlags VkResolveModeFlagsKHR; + +typedef VkSubpassDescriptionDepthStencilResolve VkSubpassDescriptionDepthStencilResolveKHR; + +typedef VkPhysicalDeviceDepthStencilResolveProperties VkPhysicalDeviceDepthStencilResolvePropertiesKHR; + + + +// VK_KHR_swapchain_mutable_format is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_swapchain_mutable_format 1 +#define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_SPEC_VERSION 1 +#define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME "VK_KHR_swapchain_mutable_format" + + +// VK_KHR_timeline_semaphore is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_timeline_semaphore 1 +#define VK_KHR_TIMELINE_SEMAPHORE_SPEC_VERSION 2 +#define VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME "VK_KHR_timeline_semaphore" +typedef VkSemaphoreType VkSemaphoreTypeKHR; + +typedef VkSemaphoreWaitFlagBits VkSemaphoreWaitFlagBitsKHR; + +typedef VkSemaphoreWaitFlags VkSemaphoreWaitFlagsKHR; + +typedef VkPhysicalDeviceTimelineSemaphoreFeatures VkPhysicalDeviceTimelineSemaphoreFeaturesKHR; + +typedef VkPhysicalDeviceTimelineSemaphoreProperties VkPhysicalDeviceTimelineSemaphorePropertiesKHR; + +typedef VkSemaphoreTypeCreateInfo VkSemaphoreTypeCreateInfoKHR; + +typedef VkTimelineSemaphoreSubmitInfo VkTimelineSemaphoreSubmitInfoKHR; + +typedef VkSemaphoreWaitInfo VkSemaphoreWaitInfoKHR; + +typedef VkSemaphoreSignalInfo VkSemaphoreSignalInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreCounterValueKHR)(VkDevice device, VkSemaphore semaphore, uint64_t* pValue); +typedef VkResult (VKAPI_PTR *PFN_vkWaitSemaphoresKHR)(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout); +typedef VkResult (VKAPI_PTR *PFN_vkSignalSemaphoreKHR)(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreCounterValueKHR( + VkDevice device, + VkSemaphore semaphore, + uint64_t* pValue); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkWaitSemaphoresKHR( + VkDevice device, + const VkSemaphoreWaitInfo* pWaitInfo, + uint64_t timeout); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkSignalSemaphoreKHR( + VkDevice device, + const VkSemaphoreSignalInfo* pSignalInfo); +#endif +#endif + + +// VK_KHR_vulkan_memory_model is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_vulkan_memory_model 1 +#define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 3 +#define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model" +typedef VkPhysicalDeviceVulkanMemoryModelFeatures VkPhysicalDeviceVulkanMemoryModelFeaturesKHR; + + + +// VK_KHR_shader_terminate_invocation is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_terminate_invocation 1 +#define VK_KHR_SHADER_TERMINATE_INVOCATION_SPEC_VERSION 1 +#define VK_KHR_SHADER_TERMINATE_INVOCATION_EXTENSION_NAME "VK_KHR_shader_terminate_invocation" +typedef VkPhysicalDeviceShaderTerminateInvocationFeatures VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR; + + + +// VK_KHR_fragment_shading_rate is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_fragment_shading_rate 1 +#define VK_KHR_FRAGMENT_SHADING_RATE_SPEC_VERSION 2 +#define VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME "VK_KHR_fragment_shading_rate" + +typedef enum VkFragmentShadingRateCombinerOpKHR { + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR = 0, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR = 1, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR = 2, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR = 3, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR = 4, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_ENUM_KHR = 0x7FFFFFFF +} VkFragmentShadingRateCombinerOpKHR; +typedef struct VkFragmentShadingRateAttachmentInfoKHR { + VkStructureType sType; + const void* pNext; + const VkAttachmentReference2* pFragmentShadingRateAttachment; + VkExtent2D shadingRateAttachmentTexelSize; +} VkFragmentShadingRateAttachmentInfoKHR; + +typedef struct VkPipelineFragmentShadingRateStateCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkExtent2D fragmentSize; + VkFragmentShadingRateCombinerOpKHR combinerOps[2]; +} VkPipelineFragmentShadingRateStateCreateInfoKHR; + +typedef struct VkPhysicalDeviceFragmentShadingRateFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 pipelineFragmentShadingRate; + VkBool32 primitiveFragmentShadingRate; + VkBool32 attachmentFragmentShadingRate; +} VkPhysicalDeviceFragmentShadingRateFeaturesKHR; + +typedef struct VkPhysicalDeviceFragmentShadingRatePropertiesKHR { + VkStructureType sType; + void* pNext; + VkExtent2D minFragmentShadingRateAttachmentTexelSize; + VkExtent2D maxFragmentShadingRateAttachmentTexelSize; + uint32_t maxFragmentShadingRateAttachmentTexelSizeAspectRatio; + VkBool32 primitiveFragmentShadingRateWithMultipleViewports; + VkBool32 layeredShadingRateAttachments; + VkBool32 fragmentShadingRateNonTrivialCombinerOps; + VkExtent2D maxFragmentSize; + uint32_t maxFragmentSizeAspectRatio; + uint32_t maxFragmentShadingRateCoverageSamples; + VkSampleCountFlagBits maxFragmentShadingRateRasterizationSamples; + VkBool32 fragmentShadingRateWithShaderDepthStencilWrites; + VkBool32 fragmentShadingRateWithSampleMask; + VkBool32 fragmentShadingRateWithShaderSampleMask; + VkBool32 fragmentShadingRateWithConservativeRasterization; + VkBool32 fragmentShadingRateWithFragmentShaderInterlock; + VkBool32 fragmentShadingRateWithCustomSampleLocations; + VkBool32 fragmentShadingRateStrictMultiplyCombiner; +} VkPhysicalDeviceFragmentShadingRatePropertiesKHR; + +typedef struct VkPhysicalDeviceFragmentShadingRateKHR { + VkStructureType sType; + void* pNext; + VkSampleCountFlags sampleCounts; + VkExtent2D fragmentSize; +} VkPhysicalDeviceFragmentShadingRateKHR; + +typedef struct VkRenderingFragmentShadingRateAttachmentInfoKHR { + VkStructureType sType; + const void* pNext; + VkImageView imageView; + VkImageLayout imageLayout; + VkExtent2D shadingRateAttachmentTexelSize; +} VkRenderingFragmentShadingRateAttachmentInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pFragmentShadingRateCount, VkPhysicalDeviceFragmentShadingRateKHR* pFragmentShadingRates); +typedef void (VKAPI_PTR *PFN_vkCmdSetFragmentShadingRateKHR)(VkCommandBuffer commandBuffer, const VkExtent2D* pFragmentSize, const VkFragmentShadingRateCombinerOpKHR combinerOps[2]); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceFragmentShadingRatesKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pFragmentShadingRateCount, + VkPhysicalDeviceFragmentShadingRateKHR* pFragmentShadingRates); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetFragmentShadingRateKHR( + VkCommandBuffer commandBuffer, + const VkExtent2D* pFragmentSize, + const VkFragmentShadingRateCombinerOpKHR combinerOps[2]); +#endif +#endif + + +// VK_KHR_shader_constant_data is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_constant_data 1 +#define VK_KHR_SHADER_CONSTANT_DATA_SPEC_VERSION 1 +#define VK_KHR_SHADER_CONSTANT_DATA_EXTENSION_NAME "VK_KHR_shader_constant_data" +typedef struct VkPhysicalDeviceShaderConstantDataFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderConstantData; +} VkPhysicalDeviceShaderConstantDataFeaturesKHR; + + + +// VK_KHR_dynamic_rendering_local_read is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_dynamic_rendering_local_read 1 +#define VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_SPEC_VERSION 1 +#define VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_EXTENSION_NAME "VK_KHR_dynamic_rendering_local_read" +typedef VkPhysicalDeviceDynamicRenderingLocalReadFeatures VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR; + +typedef VkRenderingAttachmentLocationInfo VkRenderingAttachmentLocationInfoKHR; + +typedef VkRenderingInputAttachmentIndexInfo VkRenderingInputAttachmentIndexInfoKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdSetRenderingAttachmentLocationsKHR)(VkCommandBuffer commandBuffer, const VkRenderingAttachmentLocationInfo* pLocationInfo); +typedef void (VKAPI_PTR *PFN_vkCmdSetRenderingInputAttachmentIndicesKHR)(VkCommandBuffer commandBuffer, const VkRenderingInputAttachmentIndexInfo* pInputAttachmentIndexInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetRenderingAttachmentLocationsKHR( + VkCommandBuffer commandBuffer, + const VkRenderingAttachmentLocationInfo* pLocationInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetRenderingInputAttachmentIndicesKHR( + VkCommandBuffer commandBuffer, + const VkRenderingInputAttachmentIndexInfo* pInputAttachmentIndexInfo); +#endif +#endif + + +// VK_KHR_shader_abort is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_abort 1 +#define VK_KHR_SHADER_ABORT_SPEC_VERSION 1 +#define VK_KHR_SHADER_ABORT_EXTENSION_NAME "VK_KHR_shader_abort" +typedef struct VkPhysicalDeviceShaderAbortFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderAbort; +} VkPhysicalDeviceShaderAbortFeaturesKHR; + +typedef struct VkDeviceFaultShaderAbortMessageInfoKHR { + VkStructureType sType; + void* pNext; + uint64_t messageDataSize; + void* pMessageData; +} VkDeviceFaultShaderAbortMessageInfoKHR; + +typedef struct VkPhysicalDeviceShaderAbortPropertiesKHR { + VkStructureType sType; + void* pNext; + uint64_t maxShaderAbortMessageSize; +} VkPhysicalDeviceShaderAbortPropertiesKHR; + + + +// VK_KHR_shader_quad_control is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_quad_control 1 +#define VK_KHR_SHADER_QUAD_CONTROL_SPEC_VERSION 1 +#define VK_KHR_SHADER_QUAD_CONTROL_EXTENSION_NAME "VK_KHR_shader_quad_control" +typedef struct VkPhysicalDeviceShaderQuadControlFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderQuadControl; +} VkPhysicalDeviceShaderQuadControlFeaturesKHR; + + + +// VK_KHR_spirv_1_4 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_spirv_1_4 1 +#define VK_KHR_SPIRV_1_4_SPEC_VERSION 1 +#define VK_KHR_SPIRV_1_4_EXTENSION_NAME "VK_KHR_spirv_1_4" + + +// VK_KHR_surface_protected_capabilities is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_surface_protected_capabilities 1 +#define VK_KHR_SURFACE_PROTECTED_CAPABILITIES_SPEC_VERSION 1 +#define VK_KHR_SURFACE_PROTECTED_CAPABILITIES_EXTENSION_NAME "VK_KHR_surface_protected_capabilities" +typedef struct VkSurfaceProtectedCapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 supportsProtected; +} VkSurfaceProtectedCapabilitiesKHR; + + + +// VK_KHR_separate_depth_stencil_layouts is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_separate_depth_stencil_layouts 1 +#define VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_SPEC_VERSION 1 +#define VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_EXTENSION_NAME "VK_KHR_separate_depth_stencil_layouts" +typedef VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR; + +typedef VkAttachmentReferenceStencilLayout VkAttachmentReferenceStencilLayoutKHR; + +typedef VkAttachmentDescriptionStencilLayout VkAttachmentDescriptionStencilLayoutKHR; + + + +// VK_KHR_present_wait is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_present_wait 1 +#define VK_KHR_PRESENT_WAIT_SPEC_VERSION 1 +#define VK_KHR_PRESENT_WAIT_EXTENSION_NAME "VK_KHR_present_wait" +typedef struct VkPhysicalDevicePresentWaitFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 presentWait; +} VkPhysicalDevicePresentWaitFeaturesKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkWaitForPresentKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t presentId, uint64_t timeout); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkWaitForPresentKHR( + VkDevice device, + VkSwapchainKHR swapchain, + uint64_t presentId, + uint64_t timeout); +#endif +#endif + + +// VK_KHR_uniform_buffer_standard_layout is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_uniform_buffer_standard_layout 1 +#define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_SPEC_VERSION 1 +#define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME "VK_KHR_uniform_buffer_standard_layout" +typedef VkPhysicalDeviceUniformBufferStandardLayoutFeatures VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR; + + + +// VK_KHR_buffer_device_address is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_buffer_device_address 1 +#define VK_KHR_BUFFER_DEVICE_ADDRESS_SPEC_VERSION 1 +#define VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME "VK_KHR_buffer_device_address" +typedef VkPhysicalDeviceBufferDeviceAddressFeatures VkPhysicalDeviceBufferDeviceAddressFeaturesKHR; + +typedef VkBufferDeviceAddressInfo VkBufferDeviceAddressInfoKHR; + +typedef VkBufferOpaqueCaptureAddressCreateInfo VkBufferOpaqueCaptureAddressCreateInfoKHR; + +typedef VkMemoryOpaqueCaptureAddressAllocateInfo VkMemoryOpaqueCaptureAddressAllocateInfoKHR; + +typedef VkDeviceMemoryOpaqueCaptureAddressInfo VkDeviceMemoryOpaqueCaptureAddressInfoKHR; + +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetBufferOpaqueCaptureAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddressKHR( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR uint64_t VKAPI_CALL vkGetBufferOpaqueCaptureAddressKHR( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR uint64_t VKAPI_CALL vkGetDeviceMemoryOpaqueCaptureAddressKHR( + VkDevice device, + const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo); +#endif +#endif + + +// VK_KHR_deferred_host_operations is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_deferred_host_operations 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeferredOperationKHR) +#define VK_KHR_DEFERRED_HOST_OPERATIONS_SPEC_VERSION 4 +#define VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME "VK_KHR_deferred_host_operations" +typedef VkResult (VKAPI_PTR *PFN_vkCreateDeferredOperationKHR)(VkDevice device, const VkAllocationCallbacks* pAllocator, VkDeferredOperationKHR* pDeferredOperation); +typedef void (VKAPI_PTR *PFN_vkDestroyDeferredOperationKHR)(VkDevice device, VkDeferredOperationKHR operation, const VkAllocationCallbacks* pAllocator); +typedef uint32_t (VKAPI_PTR *PFN_vkGetDeferredOperationMaxConcurrencyKHR)(VkDevice device, VkDeferredOperationKHR operation); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeferredOperationResultKHR)(VkDevice device, VkDeferredOperationKHR operation); +typedef VkResult (VKAPI_PTR *PFN_vkDeferredOperationJoinKHR)(VkDevice device, VkDeferredOperationKHR operation); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDeferredOperationKHR( + VkDevice device, + const VkAllocationCallbacks* pAllocator, + VkDeferredOperationKHR* pDeferredOperation); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyDeferredOperationKHR( + VkDevice device, + VkDeferredOperationKHR operation, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR uint32_t VKAPI_CALL vkGetDeferredOperationMaxConcurrencyKHR( + VkDevice device, + VkDeferredOperationKHR operation); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeferredOperationResultKHR( + VkDevice device, + VkDeferredOperationKHR operation); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkDeferredOperationJoinKHR( + VkDevice device, + VkDeferredOperationKHR operation); +#endif +#endif + + +// VK_KHR_pipeline_executable_properties is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_pipeline_executable_properties 1 +#define VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_SPEC_VERSION 1 +#define VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME "VK_KHR_pipeline_executable_properties" + +typedef enum VkPipelineExecutableStatisticFormatKHR { + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR = 0, + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR = 1, + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR = 2, + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR = 3, + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPipelineExecutableStatisticFormatKHR; +typedef struct VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 pipelineExecutableInfo; +} VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR; + +typedef struct VkPipelineInfoKHR { + VkStructureType sType; + const void* pNext; + VkPipeline pipeline; +} VkPipelineInfoKHR; + +typedef struct VkPipelineExecutablePropertiesKHR { + VkStructureType sType; + void* pNext; + VkShaderStageFlags stages; + char name[VK_MAX_DESCRIPTION_SIZE]; + char description[VK_MAX_DESCRIPTION_SIZE]; + uint32_t subgroupSize; +} VkPipelineExecutablePropertiesKHR; + +typedef struct VkPipelineExecutableInfoKHR { + VkStructureType sType; + const void* pNext; + VkPipeline pipeline; + uint32_t executableIndex; +} VkPipelineExecutableInfoKHR; + +typedef union VkPipelineExecutableStatisticValueKHR { + VkBool32 b32; + int64_t i64; + uint64_t u64; + double f64; +} VkPipelineExecutableStatisticValueKHR; + +typedef struct VkPipelineExecutableStatisticKHR { + VkStructureType sType; + void* pNext; + char name[VK_MAX_DESCRIPTION_SIZE]; + char description[VK_MAX_DESCRIPTION_SIZE]; + VkPipelineExecutableStatisticFormatKHR format; + VkPipelineExecutableStatisticValueKHR value; +} VkPipelineExecutableStatisticKHR; + +typedef struct VkPipelineExecutableInternalRepresentationKHR { + VkStructureType sType; + void* pNext; + char name[VK_MAX_DESCRIPTION_SIZE]; + char description[VK_MAX_DESCRIPTION_SIZE]; + VkBool32 isText; + size_t dataSize; + void* pData; +} VkPipelineExecutableInternalRepresentationKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineExecutablePropertiesKHR)(VkDevice device, const VkPipelineInfoKHR* pPipelineInfo, uint32_t* pExecutableCount, VkPipelineExecutablePropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineExecutableStatisticsKHR)(VkDevice device, const VkPipelineExecutableInfoKHR* pExecutableInfo, uint32_t* pStatisticCount, VkPipelineExecutableStatisticKHR* pStatistics); +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineExecutableInternalRepresentationsKHR)(VkDevice device, const VkPipelineExecutableInfoKHR* pExecutableInfo, uint32_t* pInternalRepresentationCount, VkPipelineExecutableInternalRepresentationKHR* pInternalRepresentations); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineExecutablePropertiesKHR( + VkDevice device, + const VkPipelineInfoKHR* pPipelineInfo, + uint32_t* pExecutableCount, + VkPipelineExecutablePropertiesKHR* pProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineExecutableStatisticsKHR( + VkDevice device, + const VkPipelineExecutableInfoKHR* pExecutableInfo, + uint32_t* pStatisticCount, + VkPipelineExecutableStatisticKHR* pStatistics); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineExecutableInternalRepresentationsKHR( + VkDevice device, + const VkPipelineExecutableInfoKHR* pExecutableInfo, + uint32_t* pInternalRepresentationCount, + VkPipelineExecutableInternalRepresentationKHR* pInternalRepresentations); +#endif +#endif + + +// VK_KHR_map_memory2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_map_memory2 1 +#define VK_KHR_MAP_MEMORY_2_SPEC_VERSION 1 +#define VK_KHR_MAP_MEMORY_2_EXTENSION_NAME "VK_KHR_map_memory2" +typedef VkMemoryUnmapFlagBits VkMemoryUnmapFlagBitsKHR; + +typedef VkMemoryUnmapFlags VkMemoryUnmapFlagsKHR; + +typedef VkMemoryMapInfo VkMemoryMapInfoKHR; + +typedef VkMemoryUnmapInfo VkMemoryUnmapInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkMapMemory2KHR)(VkDevice device, const VkMemoryMapInfo* pMemoryMapInfo, void** ppData); +typedef VkResult (VKAPI_PTR *PFN_vkUnmapMemory2KHR)(VkDevice device, const VkMemoryUnmapInfo* pMemoryUnmapInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory2KHR( + VkDevice device, + const VkMemoryMapInfo* pMemoryMapInfo, + void** ppData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkUnmapMemory2KHR( + VkDevice device, + const VkMemoryUnmapInfo* pMemoryUnmapInfo); +#endif +#endif + + +// VK_KHR_shader_integer_dot_product is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_integer_dot_product 1 +#define VK_KHR_SHADER_INTEGER_DOT_PRODUCT_SPEC_VERSION 1 +#define VK_KHR_SHADER_INTEGER_DOT_PRODUCT_EXTENSION_NAME "VK_KHR_shader_integer_dot_product" +typedef VkPhysicalDeviceShaderIntegerDotProductFeatures VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR; + +typedef VkPhysicalDeviceShaderIntegerDotProductProperties VkPhysicalDeviceShaderIntegerDotProductPropertiesKHR; + + + +// VK_KHR_pipeline_library is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_pipeline_library 1 +#define VK_KHR_PIPELINE_LIBRARY_SPEC_VERSION 1 +#define VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME "VK_KHR_pipeline_library" +typedef struct VkPipelineLibraryCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t libraryCount; + const VkPipeline* pLibraries; +} VkPipelineLibraryCreateInfoKHR; + + + +// VK_KHR_shader_non_semantic_info is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_non_semantic_info 1 +#define VK_KHR_SHADER_NON_SEMANTIC_INFO_SPEC_VERSION 1 +#define VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME "VK_KHR_shader_non_semantic_info" + + +// VK_KHR_present_id is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_present_id 1 +#define VK_KHR_PRESENT_ID_SPEC_VERSION 1 +#define VK_KHR_PRESENT_ID_EXTENSION_NAME "VK_KHR_present_id" +typedef struct VkPresentIdKHR { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const uint64_t* pPresentIds; +} VkPresentIdKHR; + +typedef struct VkPhysicalDevicePresentIdFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 presentId; +} VkPhysicalDevicePresentIdFeaturesKHR; + + + +// VK_KHR_video_encode_queue is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_encode_queue 1 +#define VK_KHR_VIDEO_ENCODE_QUEUE_SPEC_VERSION 12 +#define VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME "VK_KHR_video_encode_queue" + +typedef enum VkVideoEncodeTuningModeKHR { + VK_VIDEO_ENCODE_TUNING_MODE_DEFAULT_KHR = 0, + VK_VIDEO_ENCODE_TUNING_MODE_HIGH_QUALITY_KHR = 1, + VK_VIDEO_ENCODE_TUNING_MODE_LOW_LATENCY_KHR = 2, + VK_VIDEO_ENCODE_TUNING_MODE_ULTRA_LOW_LATENCY_KHR = 3, + VK_VIDEO_ENCODE_TUNING_MODE_LOSSLESS_KHR = 4, + VK_VIDEO_ENCODE_TUNING_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeTuningModeKHR; + +typedef enum VkVideoEncodeFlagBitsKHR { + VK_VIDEO_ENCODE_INTRA_REFRESH_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_WITH_QUANTIZATION_DELTA_MAP_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_WITH_EMPHASIS_MAP_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeFlagBitsKHR; +typedef VkFlags VkVideoEncodeFlagsKHR; + +typedef enum VkVideoEncodeCapabilityFlagBitsKHR { + VK_VIDEO_ENCODE_CAPABILITY_PRECEDING_EXTERNALLY_ENCODED_BYTES_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_CAPABILITY_INSUFFICIENT_BITSTREAM_BUFFER_RANGE_DETECTION_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_CAPABILITY_QUANTIZATION_DELTA_MAP_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_CAPABILITY_EMPHASIS_MAP_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_CAPABILITY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeCapabilityFlagBitsKHR; +typedef VkFlags VkVideoEncodeCapabilityFlagsKHR; + +typedef enum VkVideoEncodeRateControlModeFlagBitsKHR { + VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DEFAULT_KHR = 0, + VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_RATE_CONTROL_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeRateControlModeFlagBitsKHR; +typedef VkFlags VkVideoEncodeRateControlModeFlagsKHR; + +typedef enum VkVideoEncodeFeedbackFlagBitsKHR { + VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BUFFER_OFFSET_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_BYTES_WRITTEN_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_FEEDBACK_BITSTREAM_HAS_OVERRIDES_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_FEEDBACK_AVERAGE_QUANTIZATION_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_FEEDBACK_MIN_QUANTIZATION_BIT_KHR = 0x00000010, + VK_VIDEO_ENCODE_FEEDBACK_MAX_QUANTIZATION_BIT_KHR = 0x00000020, + VK_VIDEO_ENCODE_FEEDBACK_INTRA_PIXELS_BIT_KHR = 0x00000040, + VK_VIDEO_ENCODE_FEEDBACK_INTER_PIXELS_BIT_KHR = 0x00000080, + VK_VIDEO_ENCODE_FEEDBACK_SKIPPED_PIXELS_BIT_KHR = 0x00000100, + VK_VIDEO_ENCODE_FEEDBACK_PICTURE_PARTITION_COUNT_BIT_KHR = 0x00000200, + VK_VIDEO_ENCODE_FEEDBACK_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeFeedbackFlagBitsKHR; +typedef VkFlags VkVideoEncodeFeedbackFlagsKHR; + +typedef enum VkVideoEncodeUsageFlagBitsKHR { + VK_VIDEO_ENCODE_USAGE_DEFAULT_KHR = 0, + VK_VIDEO_ENCODE_USAGE_TRANSCODING_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_USAGE_STREAMING_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_USAGE_RECORDING_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_USAGE_CONFERENCING_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_USAGE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeUsageFlagBitsKHR; +typedef VkFlags VkVideoEncodeUsageFlagsKHR; + +typedef enum VkVideoEncodeContentFlagBitsKHR { + VK_VIDEO_ENCODE_CONTENT_DEFAULT_KHR = 0, + VK_VIDEO_ENCODE_CONTENT_CAMERA_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_CONTENT_DESKTOP_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_CONTENT_RENDERED_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_CONTENT_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeContentFlagBitsKHR; +typedef VkFlags VkVideoEncodeContentFlagsKHR; +typedef VkFlags VkVideoEncodeRateControlFlagsKHR; +typedef struct VkVideoEncodeInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeFlagsKHR flags; + VkBuffer dstBuffer; + VkDeviceSize dstBufferOffset; + VkDeviceSize dstBufferRange; + VkVideoPictureResourceInfoKHR srcPictureResource; + const VkVideoReferenceSlotInfoKHR* pSetupReferenceSlot; + uint32_t referenceSlotCount; + const VkVideoReferenceSlotInfoKHR* pReferenceSlots; + uint32_t precedingExternallyEncodedBytes; +} VkVideoEncodeInfoKHR; + +typedef struct VkVideoEncodeCapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeCapabilityFlagsKHR flags; + VkVideoEncodeRateControlModeFlagsKHR rateControlModes; + uint32_t maxRateControlLayers; + uint64_t maxBitrate; + uint32_t maxQualityLevels; + VkExtent2D encodeInputPictureGranularity; + VkVideoEncodeFeedbackFlagsKHR supportedEncodeFeedbackFlags; +} VkVideoEncodeCapabilitiesKHR; + +typedef struct VkQueryPoolVideoEncodeFeedbackCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeFeedbackFlagsKHR encodeFeedbackFlags; +} VkQueryPoolVideoEncodeFeedbackCreateInfoKHR; + +typedef struct VkVideoEncodeUsageInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeUsageFlagsKHR videoUsageHints; + VkVideoEncodeContentFlagsKHR videoContentHints; + VkVideoEncodeTuningModeKHR tuningMode; +} VkVideoEncodeUsageInfoKHR; + +typedef struct VkVideoEncodeRateControlLayerInfoKHR { + VkStructureType sType; + const void* pNext; + uint64_t averageBitrate; + uint64_t maxBitrate; + uint32_t frameRateNumerator; + uint32_t frameRateDenominator; +} VkVideoEncodeRateControlLayerInfoKHR; + +typedef struct VkVideoEncodeRateControlInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeRateControlFlagsKHR flags; + VkVideoEncodeRateControlModeFlagBitsKHR rateControlMode; + uint32_t layerCount; + const VkVideoEncodeRateControlLayerInfoKHR* pLayers; + uint32_t virtualBufferSizeInMs; + uint32_t initialVirtualBufferSizeInMs; +} VkVideoEncodeRateControlInfoKHR; + +typedef struct VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR { + VkStructureType sType; + const void* pNext; + const VkVideoProfileInfoKHR* pVideoProfile; + uint32_t qualityLevel; +} VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR; + +typedef struct VkVideoEncodeQualityLevelPropertiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeRateControlModeFlagBitsKHR preferredRateControlMode; + uint32_t preferredRateControlLayerCount; +} VkVideoEncodeQualityLevelPropertiesKHR; + +typedef struct VkVideoEncodeQualityLevelInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t qualityLevel; +} VkVideoEncodeQualityLevelInfoKHR; + +typedef struct VkVideoEncodeSessionParametersGetInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoSessionParametersKHR videoSessionParameters; +} VkVideoEncodeSessionParametersGetInfoKHR; + +typedef struct VkVideoEncodeSessionParametersFeedbackInfoKHR { + VkStructureType sType; + void* pNext; + VkBool32 hasOverrides; +} VkVideoEncodeSessionParametersFeedbackInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR* pQualityLevelInfo, VkVideoEncodeQualityLevelPropertiesKHR* pQualityLevelProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetEncodedVideoSessionParametersKHR)(VkDevice device, const VkVideoEncodeSessionParametersGetInfoKHR* pVideoSessionParametersInfo, VkVideoEncodeSessionParametersFeedbackInfoKHR* pFeedbackInfo, size_t* pDataSize, void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdEncodeVideoKHR)(VkCommandBuffer commandBuffer, const VkVideoEncodeInfoKHR* pEncodeInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR* pQualityLevelInfo, + VkVideoEncodeQualityLevelPropertiesKHR* pQualityLevelProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetEncodedVideoSessionParametersKHR( + VkDevice device, + const VkVideoEncodeSessionParametersGetInfoKHR* pVideoSessionParametersInfo, + VkVideoEncodeSessionParametersFeedbackInfoKHR* pFeedbackInfo, + size_t* pDataSize, + void* pData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdEncodeVideoKHR( + VkCommandBuffer commandBuffer, + const VkVideoEncodeInfoKHR* pEncodeInfo); +#endif +#endif + + +// VK_KHR_synchronization2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_synchronization2 1 +#define VK_KHR_SYNCHRONIZATION_2_SPEC_VERSION 1 +#define VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME "VK_KHR_synchronization2" +typedef VkPipelineStageFlags2 VkPipelineStageFlags2KHR; + +typedef VkPipelineStageFlagBits2 VkPipelineStageFlagBits2KHR; + +typedef VkAccessFlags2 VkAccessFlags2KHR; + +typedef VkAccessFlagBits2 VkAccessFlagBits2KHR; + +typedef VkSubmitFlagBits VkSubmitFlagBitsKHR; + +typedef VkSubmitFlags VkSubmitFlagsKHR; + +typedef VkMemoryBarrier2 VkMemoryBarrier2KHR; + +typedef VkBufferMemoryBarrier2 VkBufferMemoryBarrier2KHR; + +typedef VkImageMemoryBarrier2 VkImageMemoryBarrier2KHR; + +typedef VkDependencyInfo VkDependencyInfoKHR; + +typedef VkSubmitInfo2 VkSubmitInfo2KHR; + +typedef VkSemaphoreSubmitInfo VkSemaphoreSubmitInfoKHR; + +typedef VkCommandBufferSubmitInfo VkCommandBufferSubmitInfoKHR; + +typedef VkPhysicalDeviceSynchronization2Features VkPhysicalDeviceSynchronization2FeaturesKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdSetEvent2KHR)(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfo* pDependencyInfo); +typedef void (VKAPI_PTR *PFN_vkCmdResetEvent2KHR)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2 stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents2KHR)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, const VkDependencyInfo* pDependencyInfos); +typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier2KHR)(VkCommandBuffer commandBuffer, const VkDependencyInfo* pDependencyInfo); +typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp2KHR)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkQueryPool queryPool, uint32_t query); +typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit2KHR)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2* pSubmits, VkFence fence); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent2KHR( + VkCommandBuffer commandBuffer, + VkEvent event, + const VkDependencyInfo* pDependencyInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent2KHR( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags2 stageMask); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents2KHR( + VkCommandBuffer commandBuffer, + uint32_t eventCount, + const VkEvent* pEvents, + const VkDependencyInfo* pDependencyInfos); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier2KHR( + VkCommandBuffer commandBuffer, + const VkDependencyInfo* pDependencyInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp2KHR( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags2 stage, + VkQueryPool queryPool, + uint32_t query); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit2KHR( + VkQueue queue, + uint32_t submitCount, + const VkSubmitInfo2* pSubmits, + VkFence fence); +#endif +#endif + + +// VK_KHR_device_address_commands is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_device_address_commands 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureKHR) +#define VK_KHR_DEVICE_ADDRESS_COMMANDS_SPEC_VERSION 1 +#define VK_KHR_DEVICE_ADDRESS_COMMANDS_EXTENSION_NAME "VK_KHR_device_address_commands" + +typedef enum VkAccelerationStructureTypeKHR { + VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR = 0, + VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR = 1, + VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR = 2, + VK_ACCELERATION_STRUCTURE_TYPE_OPACITY_MICROMAP_KHR = 1000623000, + VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, + VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, + VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureTypeKHR; + +typedef enum VkAddressCommandFlagBitsKHR { + VK_ADDRESS_COMMAND_PROTECTED_BIT_KHR = 0x00000001, + VK_ADDRESS_COMMAND_FULLY_BOUND_BIT_KHR = 0x00000002, + VK_ADDRESS_COMMAND_STORAGE_BUFFER_USAGE_BIT_KHR = 0x00000004, + VK_ADDRESS_COMMAND_UNKNOWN_STORAGE_BUFFER_USAGE_BIT_KHR = 0x00000008, + VK_ADDRESS_COMMAND_TRANSFORM_FEEDBACK_BUFFER_USAGE_BIT_KHR = 0x00000010, + VK_ADDRESS_COMMAND_UNKNOWN_TRANSFORM_FEEDBACK_BUFFER_USAGE_BIT_KHR = 0x00000020, + VK_ADDRESS_COMMAND_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAddressCommandFlagBitsKHR; +typedef VkFlags VkAddressCommandFlagsKHR; + +typedef enum VkConditionalRenderingFlagBitsEXT { + VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT = 0x00000001, + VK_CONDITIONAL_RENDERING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkConditionalRenderingFlagBitsEXT; +typedef VkFlags VkConditionalRenderingFlagsEXT; + +typedef enum VkAccelerationStructureCreateFlagBitsKHR { + VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = 0x00000001, + VK_ACCELERATION_STRUCTURE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 0x00000008, + VK_ACCELERATION_STRUCTURE_CREATE_MOTION_BIT_NV = 0x00000004, + VK_ACCELERATION_STRUCTURE_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureCreateFlagBitsKHR; +typedef VkFlags VkAccelerationStructureCreateFlagsKHR; +typedef struct VkDeviceAddressRangeKHR { + VkDeviceAddress address; + VkDeviceSize size; +} VkDeviceAddressRangeKHR; + +typedef struct VkStridedDeviceAddressRangeKHR { + VkDeviceAddress address; + VkDeviceSize size; + VkDeviceSize stride; +} VkStridedDeviceAddressRangeKHR; + +typedef struct VkDeviceMemoryCopyKHR { + VkStructureType sType; + const void* pNext; + VkDeviceAddressRangeKHR srcRange; + VkAddressCommandFlagsKHR srcFlags; + VkDeviceAddressRangeKHR dstRange; + VkAddressCommandFlagsKHR dstFlags; +} VkDeviceMemoryCopyKHR; + +typedef struct VkCopyDeviceMemoryInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t regionCount; + const VkDeviceMemoryCopyKHR* pRegions; +} VkCopyDeviceMemoryInfoKHR; + +typedef struct VkDeviceMemoryImageCopyKHR { + VkStructureType sType; + const void* pNext; + VkDeviceAddressRangeKHR addressRange; + VkAddressCommandFlagsKHR addressFlags; + uint32_t addressRowLength; + uint32_t addressImageHeight; + VkImageSubresourceLayers imageSubresource; + VkImageLayout imageLayout; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkDeviceMemoryImageCopyKHR; + +typedef struct VkCopyDeviceMemoryImageInfoKHR { + VkStructureType sType; + const void* pNext; + VkImage image; + uint32_t regionCount; + const VkDeviceMemoryImageCopyKHR* pRegions; +} VkCopyDeviceMemoryImageInfoKHR; + +typedef struct VkMemoryRangeBarrierKHR { + VkStructureType sType; + const void* pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkDeviceAddressRangeKHR addressRange; + VkAddressCommandFlagsKHR addressFlags; +} VkMemoryRangeBarrierKHR; + +typedef struct VkMemoryRangeBarriersInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t memoryRangeBarrierCount; + const VkMemoryRangeBarrierKHR* pMemoryRangeBarriers; +} VkMemoryRangeBarriersInfoKHR; + +typedef struct VkPhysicalDeviceDeviceAddressCommandsFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 deviceAddressCommands; +} VkPhysicalDeviceDeviceAddressCommandsFeaturesKHR; + +typedef struct VkBindIndexBuffer3InfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceAddressRangeKHR addressRange; + VkAddressCommandFlagsKHR addressFlags; + VkIndexType indexType; +} VkBindIndexBuffer3InfoKHR; + +typedef struct VkBindVertexBuffer3InfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 setStride; + VkStridedDeviceAddressRangeKHR addressRange; + VkAddressCommandFlagsKHR addressFlags; +} VkBindVertexBuffer3InfoKHR; + +typedef struct VkDrawIndirect2InfoKHR { + VkStructureType sType; + const void* pNext; + VkStridedDeviceAddressRangeKHR addressRange; + VkAddressCommandFlagsKHR addressFlags; + uint32_t drawCount; +} VkDrawIndirect2InfoKHR; + +typedef struct VkDrawIndirectCount2InfoKHR { + VkStructureType sType; + const void* pNext; + VkStridedDeviceAddressRangeKHR addressRange; + VkAddressCommandFlagsKHR addressFlags; + VkDeviceAddressRangeKHR countAddressRange; + VkAddressCommandFlagsKHR countAddressFlags; + uint32_t maxDrawCount; +} VkDrawIndirectCount2InfoKHR; + +typedef struct VkDispatchIndirect2InfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceAddressRangeKHR addressRange; + VkAddressCommandFlagsKHR addressFlags; +} VkDispatchIndirect2InfoKHR; + +typedef struct VkConditionalRenderingBeginInfo2EXT { + VkStructureType sType; + const void* pNext; + VkDeviceAddressRangeKHR addressRange; + VkAddressCommandFlagsKHR addressFlags; + VkConditionalRenderingFlagsEXT flags; +} VkConditionalRenderingBeginInfo2EXT; + +typedef struct VkBindTransformFeedbackBuffer2InfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceAddressRangeKHR addressRange; + VkAddressCommandFlagsKHR addressFlags; +} VkBindTransformFeedbackBuffer2InfoEXT; + +typedef struct VkMemoryMarkerInfoAMD { + VkStructureType sType; + const void* pNext; + VkPipelineStageFlags2KHR stage; + VkDeviceAddressRangeKHR dstRange; + VkAddressCommandFlagsKHR dstFlags; + uint32_t marker; +} VkMemoryMarkerInfoAMD; + +typedef struct VkAccelerationStructureCreateInfo2KHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureCreateFlagsKHR createFlags; + VkDeviceAddressRangeKHR addressRange; + VkAddressCommandFlagsKHR addressFlags; + VkAccelerationStructureTypeKHR type; +} VkAccelerationStructureCreateInfo2KHR; + +typedef void (VKAPI_PTR *PFN_vkCmdBindIndexBuffer3KHR)(VkCommandBuffer commandBuffer, const VkBindIndexBuffer3InfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers3KHR)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBindVertexBuffer3InfoKHR* pBindingInfos); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirect2KHR)(VkCommandBuffer commandBuffer, const VkDrawIndirect2InfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirect2KHR)(VkCommandBuffer commandBuffer, const VkDrawIndirect2InfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchIndirect2KHR)(VkCommandBuffer commandBuffer, const VkDispatchIndirect2InfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryKHR)(VkCommandBuffer commandBuffer, const VkCopyDeviceMemoryInfoKHR* pCopyMemoryInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryToImageKHR)(VkCommandBuffer commandBuffer, const VkCopyDeviceMemoryImageInfoKHR* pCopyMemoryInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToMemoryKHR)(VkCommandBuffer commandBuffer, const VkCopyDeviceMemoryImageInfoKHR* pCopyMemoryInfo); +typedef void (VKAPI_PTR *PFN_vkCmdUpdateMemoryKHR)(VkCommandBuffer commandBuffer, const VkDeviceAddressRangeKHR* pDstRange, VkAddressCommandFlagsKHR dstFlags, VkDeviceSize dataSize, const void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdFillMemoryKHR)(VkCommandBuffer commandBuffer, const VkDeviceAddressRangeKHR* pDstRange, VkAddressCommandFlagsKHR dstFlags, uint32_t data); +typedef void (VKAPI_PTR *PFN_vkCmdCopyQueryPoolResultsToMemoryKHR)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, const VkStridedDeviceAddressRangeKHR* pDstRange, VkAddressCommandFlagsKHR dstFlags, VkQueryResultFlags queryResultFlags); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCount2KHR)(VkCommandBuffer commandBuffer, const VkDrawIndirectCount2InfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCount2KHR)(VkCommandBuffer commandBuffer, const VkDrawIndirectCount2InfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBeginConditionalRendering2EXT)(VkCommandBuffer commandBuffer, const VkConditionalRenderingBeginInfo2EXT* pConditionalRenderingBegin); +typedef void (VKAPI_PTR *PFN_vkCmdBindTransformFeedbackBuffers2EXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBindTransformFeedbackBuffer2InfoEXT* pBindingInfos); +typedef void (VKAPI_PTR *PFN_vkCmdBeginTransformFeedback2EXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterRange, uint32_t counterRangeCount, const VkBindTransformFeedbackBuffer2InfoEXT* pCounterInfos); +typedef void (VKAPI_PTR *PFN_vkCmdEndTransformFeedback2EXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterRange, uint32_t counterRangeCount, const VkBindTransformFeedbackBuffer2InfoEXT* pCounterInfos); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectByteCount2EXT)(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, const VkBindTransformFeedbackBuffer2InfoEXT* pCounterInfo, uint32_t counterOffset, uint32_t vertexStride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirect2EXT)(VkCommandBuffer commandBuffer, const VkDrawIndirect2InfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectCount2EXT)(VkCommandBuffer commandBuffer, const VkDrawIndirectCount2InfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdWriteMarkerToMemoryAMD)(VkCommandBuffer commandBuffer, const VkMemoryMarkerInfoAMD* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructure2KHR)(VkDevice device, const VkAccelerationStructureCreateInfo2KHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureKHR* pAccelerationStructure); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer3KHR( + VkCommandBuffer commandBuffer, + const VkBindIndexBuffer3InfoKHR* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers3KHR( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBindVertexBuffer3InfoKHR* pBindingInfos); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirect2KHR( + VkCommandBuffer commandBuffer, + const VkDrawIndirect2InfoKHR* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirect2KHR( + VkCommandBuffer commandBuffer, + const VkDrawIndirect2InfoKHR* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchIndirect2KHR( + VkCommandBuffer commandBuffer, + const VkDispatchIndirect2InfoKHR* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMemoryKHR( + VkCommandBuffer commandBuffer, + const VkCopyDeviceMemoryInfoKHR* pCopyMemoryInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMemoryToImageKHR( + VkCommandBuffer commandBuffer, + const VkCopyDeviceMemoryImageInfoKHR* pCopyMemoryInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToMemoryKHR( + VkCommandBuffer commandBuffer, + const VkCopyDeviceMemoryImageInfoKHR* pCopyMemoryInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdUpdateMemoryKHR( + VkCommandBuffer commandBuffer, + const VkDeviceAddressRangeKHR* pDstRange, + VkAddressCommandFlagsKHR dstFlags, + VkDeviceSize dataSize, + const void* pData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdFillMemoryKHR( + VkCommandBuffer commandBuffer, + const VkDeviceAddressRangeKHR* pDstRange, + VkAddressCommandFlagsKHR dstFlags, + uint32_t data); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyQueryPoolResultsToMemoryKHR( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount, + const VkStridedDeviceAddressRangeKHR* pDstRange, + VkAddressCommandFlagsKHR dstFlags, + VkQueryResultFlags queryResultFlags); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCount2KHR( + VkCommandBuffer commandBuffer, + const VkDrawIndirectCount2InfoKHR* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCount2KHR( + VkCommandBuffer commandBuffer, + const VkDrawIndirectCount2InfoKHR* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginConditionalRendering2EXT( + VkCommandBuffer commandBuffer, + const VkConditionalRenderingBeginInfo2EXT* pConditionalRenderingBegin); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindTransformFeedbackBuffers2EXT( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBindTransformFeedbackBuffer2InfoEXT* pBindingInfos); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginTransformFeedback2EXT( + VkCommandBuffer commandBuffer, + uint32_t firstCounterRange, + uint32_t counterRangeCount, + const VkBindTransformFeedbackBuffer2InfoEXT* pCounterInfos); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdEndTransformFeedback2EXT( + VkCommandBuffer commandBuffer, + uint32_t firstCounterRange, + uint32_t counterRangeCount, + const VkBindTransformFeedbackBuffer2InfoEXT* pCounterInfos); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectByteCount2EXT( + VkCommandBuffer commandBuffer, + uint32_t instanceCount, + uint32_t firstInstance, + const VkBindTransformFeedbackBuffer2InfoEXT* pCounterInfo, + uint32_t counterOffset, + uint32_t vertexStride); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirect2EXT( + VkCommandBuffer commandBuffer, + const VkDrawIndirect2InfoKHR* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectCount2EXT( + VkCommandBuffer commandBuffer, + const VkDrawIndirectCount2InfoKHR* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdWriteMarkerToMemoryAMD( + VkCommandBuffer commandBuffer, + const VkMemoryMarkerInfoAMD* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructure2KHR( + VkDevice device, + const VkAccelerationStructureCreateInfo2KHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkAccelerationStructureKHR* pAccelerationStructure); +#endif +#endif + + +// VK_KHR_fragment_shader_barycentric is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_fragment_shader_barycentric 1 +#define VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1 +#define VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_KHR_fragment_shader_barycentric" +typedef struct VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 fragmentShaderBarycentric; +} VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR; + +typedef struct VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 triStripVertexOrderIndependentOfProvokingVertex; +} VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR; + + + +// VK_KHR_shader_subgroup_uniform_control_flow is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_subgroup_uniform_control_flow 1 +#define VK_KHR_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_SPEC_VERSION 1 +#define VK_KHR_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_EXTENSION_NAME "VK_KHR_shader_subgroup_uniform_control_flow" +typedef struct VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderSubgroupUniformControlFlow; +} VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR; + + + +// VK_KHR_zero_initialize_workgroup_memory is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_zero_initialize_workgroup_memory 1 +#define VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_SPEC_VERSION 1 +#define VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_EXTENSION_NAME "VK_KHR_zero_initialize_workgroup_memory" +typedef VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR; + + + +// VK_KHR_workgroup_memory_explicit_layout is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_workgroup_memory_explicit_layout 1 +#define VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_SPEC_VERSION 1 +#define VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME "VK_KHR_workgroup_memory_explicit_layout" +typedef struct VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 workgroupMemoryExplicitLayout; + VkBool32 workgroupMemoryExplicitLayoutScalarBlockLayout; + VkBool32 workgroupMemoryExplicitLayout8BitAccess; + VkBool32 workgroupMemoryExplicitLayout16BitAccess; +} VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR; + + + +// VK_KHR_copy_commands2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_copy_commands2 1 +#define VK_KHR_COPY_COMMANDS_2_SPEC_VERSION 1 +#define VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME "VK_KHR_copy_commands2" +typedef VkCopyBufferInfo2 VkCopyBufferInfo2KHR; + +typedef VkCopyImageInfo2 VkCopyImageInfo2KHR; + +typedef VkCopyBufferToImageInfo2 VkCopyBufferToImageInfo2KHR; + +typedef VkCopyImageToBufferInfo2 VkCopyImageToBufferInfo2KHR; + +typedef VkBlitImageInfo2 VkBlitImageInfo2KHR; + +typedef VkResolveImageInfo2 VkResolveImageInfo2KHR; + +typedef VkBufferCopy2 VkBufferCopy2KHR; + +typedef VkImageCopy2 VkImageCopy2KHR; + +typedef VkImageBlit2 VkImageBlit2KHR; + +typedef VkBufferImageCopy2 VkBufferImageCopy2KHR; + +typedef VkImageResolve2 VkImageResolve2KHR; + +typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer2KHR)(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2* pCopyBufferInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImage2KHR)(VkCommandBuffer commandBuffer, const VkCopyImageInfo2* pCopyImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage2KHR)(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2* pCopyBufferToImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer2KHR)(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2* pCopyImageToBufferInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBlitImage2KHR)(VkCommandBuffer commandBuffer, const VkBlitImageInfo2* pBlitImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdResolveImage2KHR)(VkCommandBuffer commandBuffer, const VkResolveImageInfo2* pResolveImageInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer2KHR( + VkCommandBuffer commandBuffer, + const VkCopyBufferInfo2* pCopyBufferInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage2KHR( + VkCommandBuffer commandBuffer, + const VkCopyImageInfo2* pCopyImageInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage2KHR( + VkCommandBuffer commandBuffer, + const VkCopyBufferToImageInfo2* pCopyBufferToImageInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer2KHR( + VkCommandBuffer commandBuffer, + const VkCopyImageToBufferInfo2* pCopyImageToBufferInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage2KHR( + VkCommandBuffer commandBuffer, + const VkBlitImageInfo2* pBlitImageInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage2KHR( + VkCommandBuffer commandBuffer, + const VkResolveImageInfo2* pResolveImageInfo); +#endif +#endif + + +// VK_KHR_format_feature_flags2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_format_feature_flags2 1 +#define VK_KHR_FORMAT_FEATURE_FLAGS_2_SPEC_VERSION 2 +#define VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME "VK_KHR_format_feature_flags2" +typedef VkFormatFeatureFlags2 VkFormatFeatureFlags2KHR; + +typedef VkFormatFeatureFlagBits2 VkFormatFeatureFlagBits2KHR; + +typedef VkFormatProperties3 VkFormatProperties3KHR; + + + +// VK_KHR_ray_tracing_maintenance1 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_ray_tracing_maintenance1 1 +#define VK_KHR_RAY_TRACING_MAINTENANCE_1_SPEC_VERSION 1 +#define VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_ray_tracing_maintenance1" +typedef struct VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 rayTracingMaintenance1; + VkBool32 rayTracingPipelineTraceRaysIndirect2; +} VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR; + +typedef struct VkTraceRaysIndirectCommand2KHR { + VkDeviceAddress raygenShaderRecordAddress; + VkDeviceSize raygenShaderRecordSize; + VkDeviceAddress missShaderBindingTableAddress; + VkDeviceSize missShaderBindingTableSize; + VkDeviceSize missShaderBindingTableStride; + VkDeviceAddress hitShaderBindingTableAddress; + VkDeviceSize hitShaderBindingTableSize; + VkDeviceSize hitShaderBindingTableStride; + VkDeviceAddress callableShaderBindingTableAddress; + VkDeviceSize callableShaderBindingTableSize; + VkDeviceSize callableShaderBindingTableStride; + uint32_t width; + uint32_t height; + uint32_t depth; +} VkTraceRaysIndirectCommand2KHR; + +typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysIndirect2KHR)(VkCommandBuffer commandBuffer, VkDeviceAddress indirectDeviceAddress); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysIndirect2KHR( + VkCommandBuffer commandBuffer, + VkDeviceAddress indirectDeviceAddress); +#endif +#endif + + +// VK_KHR_shader_untyped_pointers is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_untyped_pointers 1 +#define VK_KHR_SHADER_UNTYPED_POINTERS_SPEC_VERSION 1 +#define VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME "VK_KHR_shader_untyped_pointers" +typedef struct VkPhysicalDeviceShaderUntypedPointersFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderUntypedPointers; +} VkPhysicalDeviceShaderUntypedPointersFeaturesKHR; + + + +// VK_KHR_portability_enumeration is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_portability_enumeration 1 +#define VK_KHR_PORTABILITY_ENUMERATION_SPEC_VERSION 1 +#define VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME "VK_KHR_portability_enumeration" + + +// VK_KHR_maintenance4 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance4 1 +#define VK_KHR_MAINTENANCE_4_SPEC_VERSION 2 +#define VK_KHR_MAINTENANCE_4_EXTENSION_NAME "VK_KHR_maintenance4" +typedef VkPhysicalDeviceMaintenance4Features VkPhysicalDeviceMaintenance4FeaturesKHR; + +typedef VkPhysicalDeviceMaintenance4Properties VkPhysicalDeviceMaintenance4PropertiesKHR; + +typedef VkDeviceBufferMemoryRequirements VkDeviceBufferMemoryRequirementsKHR; + +typedef VkDeviceImageMemoryRequirements VkDeviceImageMemoryRequirementsKHR; + +typedef void (VKAPI_PTR *PFN_vkGetDeviceBufferMemoryRequirementsKHR)(VkDevice device, const VkDeviceBufferMemoryRequirements* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetDeviceImageMemoryRequirementsKHR)(VkDevice device, const VkDeviceImageMemoryRequirements* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetDeviceImageSparseMemoryRequirementsKHR)(VkDevice device, const VkDeviceImageMemoryRequirements* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDeviceBufferMemoryRequirementsKHR( + VkDevice device, + const VkDeviceBufferMemoryRequirements* pInfo, + VkMemoryRequirements2* pMemoryRequirements); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDeviceImageMemoryRequirementsKHR( + VkDevice device, + const VkDeviceImageMemoryRequirements* pInfo, + VkMemoryRequirements2* pMemoryRequirements); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDeviceImageSparseMemoryRequirementsKHR( + VkDevice device, + const VkDeviceImageMemoryRequirements* pInfo, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +#endif +#endif + + +// VK_KHR_shader_subgroup_rotate is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_subgroup_rotate 1 +#define VK_KHR_SHADER_SUBGROUP_ROTATE_SPEC_VERSION 2 +#define VK_KHR_SHADER_SUBGROUP_ROTATE_EXTENSION_NAME "VK_KHR_shader_subgroup_rotate" +typedef VkPhysicalDeviceShaderSubgroupRotateFeatures VkPhysicalDeviceShaderSubgroupRotateFeaturesKHR; + + + +// VK_KHR_shader_maximal_reconvergence is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_maximal_reconvergence 1 +#define VK_KHR_SHADER_MAXIMAL_RECONVERGENCE_SPEC_VERSION 1 +#define VK_KHR_SHADER_MAXIMAL_RECONVERGENCE_EXTENSION_NAME "VK_KHR_shader_maximal_reconvergence" +typedef struct VkPhysicalDeviceShaderMaximalReconvergenceFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderMaximalReconvergence; +} VkPhysicalDeviceShaderMaximalReconvergenceFeaturesKHR; + + + +// VK_KHR_maintenance5 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance5 1 +#define VK_KHR_MAINTENANCE_5_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_5_EXTENSION_NAME "VK_KHR_maintenance5" +typedef VkPipelineCreateFlags2 VkPipelineCreateFlags2KHR; + +typedef VkPipelineCreateFlagBits2 VkPipelineCreateFlagBits2KHR; + +typedef VkBufferUsageFlags2 VkBufferUsageFlags2KHR; + +typedef VkBufferUsageFlagBits2 VkBufferUsageFlagBits2KHR; + +typedef VkPhysicalDeviceMaintenance5Features VkPhysicalDeviceMaintenance5FeaturesKHR; + +typedef VkPhysicalDeviceMaintenance5Properties VkPhysicalDeviceMaintenance5PropertiesKHR; + +typedef VkRenderingAreaInfo VkRenderingAreaInfoKHR; + +typedef VkDeviceImageSubresourceInfo VkDeviceImageSubresourceInfoKHR; + +typedef VkImageSubresource2 VkImageSubresource2KHR; + +typedef VkSubresourceLayout2 VkSubresourceLayout2KHR; + +typedef VkPipelineCreateFlags2CreateInfo VkPipelineCreateFlags2CreateInfoKHR; + +typedef VkBufferUsageFlags2CreateInfo VkBufferUsageFlags2CreateInfoKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdBindIndexBuffer2KHR)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size, VkIndexType indexType); +typedef void (VKAPI_PTR *PFN_vkGetRenderingAreaGranularityKHR)(VkDevice device, const VkRenderingAreaInfo* pRenderingAreaInfo, VkExtent2D* pGranularity); +typedef void (VKAPI_PTR *PFN_vkGetDeviceImageSubresourceLayoutKHR)(VkDevice device, const VkDeviceImageSubresourceInfo* pInfo, VkSubresourceLayout2* pLayout); +typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout2KHR)(VkDevice device, VkImage image, const VkImageSubresource2* pSubresource, VkSubresourceLayout2* pLayout); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer2KHR( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkDeviceSize size, + VkIndexType indexType); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetRenderingAreaGranularityKHR( + VkDevice device, + const VkRenderingAreaInfo* pRenderingAreaInfo, + VkExtent2D* pGranularity); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDeviceImageSubresourceLayoutKHR( + VkDevice device, + const VkDeviceImageSubresourceInfo* pInfo, + VkSubresourceLayout2* pLayout); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout2KHR( + VkDevice device, + VkImage image, + const VkImageSubresource2* pSubresource, + VkSubresourceLayout2* pLayout); +#endif +#endif + + +// VK_KHR_present_id2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_present_id2 1 +#define VK_KHR_PRESENT_ID_2_SPEC_VERSION 1 +#define VK_KHR_PRESENT_ID_2_EXTENSION_NAME "VK_KHR_present_id2" +typedef struct VkSurfaceCapabilitiesPresentId2KHR { + VkStructureType sType; + void* pNext; + VkBool32 presentId2Supported; +} VkSurfaceCapabilitiesPresentId2KHR; + +typedef struct VkPresentId2KHR { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const uint64_t* pPresentIds; +} VkPresentId2KHR; + +typedef struct VkPhysicalDevicePresentId2FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 presentId2; +} VkPhysicalDevicePresentId2FeaturesKHR; + + + +// VK_KHR_present_wait2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_present_wait2 1 +#define VK_KHR_PRESENT_WAIT_2_SPEC_VERSION 1 +#define VK_KHR_PRESENT_WAIT_2_EXTENSION_NAME "VK_KHR_present_wait2" +typedef struct VkSurfaceCapabilitiesPresentWait2KHR { + VkStructureType sType; + void* pNext; + VkBool32 presentWait2Supported; +} VkSurfaceCapabilitiesPresentWait2KHR; + +typedef struct VkPhysicalDevicePresentWait2FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 presentWait2; +} VkPhysicalDevicePresentWait2FeaturesKHR; + +typedef struct VkPresentWait2InfoKHR { + VkStructureType sType; + const void* pNext; + uint64_t presentId; + uint64_t timeout; +} VkPresentWait2InfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkWaitForPresent2KHR)(VkDevice device, VkSwapchainKHR swapchain, const VkPresentWait2InfoKHR* pPresentWait2Info); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkWaitForPresent2KHR( + VkDevice device, + VkSwapchainKHR swapchain, + const VkPresentWait2InfoKHR* pPresentWait2Info); +#endif +#endif + + +// VK_KHR_ray_tracing_position_fetch is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_ray_tracing_position_fetch 1 +#define VK_KHR_RAY_TRACING_POSITION_FETCH_SPEC_VERSION 1 +#define VK_KHR_RAY_TRACING_POSITION_FETCH_EXTENSION_NAME "VK_KHR_ray_tracing_position_fetch" +typedef struct VkPhysicalDeviceRayTracingPositionFetchFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 rayTracingPositionFetch; +} VkPhysicalDeviceRayTracingPositionFetchFeaturesKHR; + + + +// VK_KHR_pipeline_binary is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_pipeline_binary 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineBinaryKHR) +#define VK_MAX_PIPELINE_BINARY_KEY_SIZE_KHR 32U +#define VK_KHR_PIPELINE_BINARY_SPEC_VERSION 1 +#define VK_KHR_PIPELINE_BINARY_EXTENSION_NAME "VK_KHR_pipeline_binary" +typedef struct VkPhysicalDevicePipelineBinaryFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 pipelineBinaries; +} VkPhysicalDevicePipelineBinaryFeaturesKHR; + +typedef struct VkPhysicalDevicePipelineBinaryPropertiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 pipelineBinaryInternalCache; + VkBool32 pipelineBinaryInternalCacheControl; + VkBool32 pipelineBinaryPrefersInternalCache; + VkBool32 pipelineBinaryPrecompiledInternalCache; + VkBool32 pipelineBinaryCompressedData; +} VkPhysicalDevicePipelineBinaryPropertiesKHR; + +typedef struct VkDevicePipelineBinaryInternalCacheControlKHR { + VkStructureType sType; + const void* pNext; + VkBool32 disableInternalCache; +} VkDevicePipelineBinaryInternalCacheControlKHR; + +typedef struct VkPipelineBinaryKeyKHR { + VkStructureType sType; + void* pNext; + uint32_t keySize; + uint8_t key[VK_MAX_PIPELINE_BINARY_KEY_SIZE_KHR]; +} VkPipelineBinaryKeyKHR; + +typedef struct VkPipelineBinaryDataKHR { + size_t dataSize; + void* pData; +} VkPipelineBinaryDataKHR; + +typedef struct VkPipelineBinaryKeysAndDataKHR { + uint32_t binaryCount; + const VkPipelineBinaryKeyKHR* pPipelineBinaryKeys; + const VkPipelineBinaryDataKHR* pPipelineBinaryData; +} VkPipelineBinaryKeysAndDataKHR; + +typedef struct VkPipelineCreateInfoKHR { + VkStructureType sType; + void* pNext; +} VkPipelineCreateInfoKHR; + +typedef struct VkPipelineBinaryCreateInfoKHR { + VkStructureType sType; + const void* pNext; + const VkPipelineBinaryKeysAndDataKHR* pKeysAndDataInfo; + VkPipeline pipeline; + const VkPipelineCreateInfoKHR* pPipelineCreateInfo; +} VkPipelineBinaryCreateInfoKHR; + +typedef struct VkPipelineBinaryInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t binaryCount; + const VkPipelineBinaryKHR* pPipelineBinaries; +} VkPipelineBinaryInfoKHR; + +typedef struct VkReleaseCapturedPipelineDataInfoKHR { + VkStructureType sType; + void* pNext; + VkPipeline pipeline; +} VkReleaseCapturedPipelineDataInfoKHR; + +typedef struct VkPipelineBinaryDataInfoKHR { + VkStructureType sType; + void* pNext; + VkPipelineBinaryKHR pipelineBinary; +} VkPipelineBinaryDataInfoKHR; + +typedef struct VkPipelineBinaryHandlesInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t pipelineBinaryCount; + VkPipelineBinaryKHR* pPipelineBinaries; +} VkPipelineBinaryHandlesInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineBinariesKHR)(VkDevice device, const VkPipelineBinaryCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineBinaryHandlesInfoKHR* pBinaries); +typedef void (VKAPI_PTR *PFN_vkDestroyPipelineBinaryKHR)(VkDevice device, VkPipelineBinaryKHR pipelineBinary, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineKeyKHR)(VkDevice device, const VkPipelineCreateInfoKHR* pPipelineCreateInfo, VkPipelineBinaryKeyKHR* pPipelineKey); +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineBinaryDataKHR)(VkDevice device, const VkPipelineBinaryDataInfoKHR* pInfo, VkPipelineBinaryKeyKHR* pPipelineBinaryKey, size_t* pPipelineBinaryDataSize, void* pPipelineBinaryData); +typedef VkResult (VKAPI_PTR *PFN_vkReleaseCapturedPipelineDataKHR)(VkDevice device, const VkReleaseCapturedPipelineDataInfoKHR* pInfo, const VkAllocationCallbacks* pAllocator); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineBinariesKHR( + VkDevice device, + const VkPipelineBinaryCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPipelineBinaryHandlesInfoKHR* pBinaries); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineBinaryKHR( + VkDevice device, + VkPipelineBinaryKHR pipelineBinary, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineKeyKHR( + VkDevice device, + const VkPipelineCreateInfoKHR* pPipelineCreateInfo, + VkPipelineBinaryKeyKHR* pPipelineKey); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineBinaryDataKHR( + VkDevice device, + const VkPipelineBinaryDataInfoKHR* pInfo, + VkPipelineBinaryKeyKHR* pPipelineBinaryKey, + size_t* pPipelineBinaryDataSize, + void* pPipelineBinaryData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkReleaseCapturedPipelineDataKHR( + VkDevice device, + const VkReleaseCapturedPipelineDataInfoKHR* pInfo, + const VkAllocationCallbacks* pAllocator); +#endif +#endif + + +// VK_KHR_surface_maintenance1 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_surface_maintenance1 1 +#define VK_KHR_SURFACE_MAINTENANCE_1_SPEC_VERSION 1 +#define VK_KHR_SURFACE_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_surface_maintenance1" + +typedef enum VkPresentScalingFlagBitsKHR { + VK_PRESENT_SCALING_ONE_TO_ONE_BIT_KHR = 0x00000001, + VK_PRESENT_SCALING_ASPECT_RATIO_STRETCH_BIT_KHR = 0x00000002, + VK_PRESENT_SCALING_STRETCH_BIT_KHR = 0x00000004, + VK_PRESENT_SCALING_ONE_TO_ONE_BIT_EXT = VK_PRESENT_SCALING_ONE_TO_ONE_BIT_KHR, + VK_PRESENT_SCALING_ASPECT_RATIO_STRETCH_BIT_EXT = VK_PRESENT_SCALING_ASPECT_RATIO_STRETCH_BIT_KHR, + VK_PRESENT_SCALING_STRETCH_BIT_EXT = VK_PRESENT_SCALING_STRETCH_BIT_KHR, + VK_PRESENT_SCALING_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPresentScalingFlagBitsKHR; +typedef VkFlags VkPresentScalingFlagsKHR; + +typedef enum VkPresentGravityFlagBitsKHR { + VK_PRESENT_GRAVITY_MIN_BIT_KHR = 0x00000001, + VK_PRESENT_GRAVITY_MAX_BIT_KHR = 0x00000002, + VK_PRESENT_GRAVITY_CENTERED_BIT_KHR = 0x00000004, + VK_PRESENT_GRAVITY_MIN_BIT_EXT = VK_PRESENT_GRAVITY_MIN_BIT_KHR, + VK_PRESENT_GRAVITY_MAX_BIT_EXT = VK_PRESENT_GRAVITY_MAX_BIT_KHR, + VK_PRESENT_GRAVITY_CENTERED_BIT_EXT = VK_PRESENT_GRAVITY_CENTERED_BIT_KHR, + VK_PRESENT_GRAVITY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPresentGravityFlagBitsKHR; +typedef VkFlags VkPresentGravityFlagsKHR; +typedef struct VkSurfacePresentModeKHR { + VkStructureType sType; + void* pNext; + VkPresentModeKHR presentMode; +} VkSurfacePresentModeKHR; + +typedef struct VkSurfacePresentScalingCapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkPresentScalingFlagsKHR supportedPresentScaling; + VkPresentGravityFlagsKHR supportedPresentGravityX; + VkPresentGravityFlagsKHR supportedPresentGravityY; + VkExtent2D minScaledImageExtent; + VkExtent2D maxScaledImageExtent; +} VkSurfacePresentScalingCapabilitiesKHR; + +typedef struct VkSurfacePresentModeCompatibilityKHR { + VkStructureType sType; + void* pNext; + uint32_t presentModeCount; + VkPresentModeKHR* pPresentModes; +} VkSurfacePresentModeCompatibilityKHR; + + + +// VK_KHR_swapchain_maintenance1 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_swapchain_maintenance1 1 +#define VK_KHR_SWAPCHAIN_MAINTENANCE_1_SPEC_VERSION 1 +#define VK_KHR_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_swapchain_maintenance1" +typedef struct VkPhysicalDeviceSwapchainMaintenance1FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 swapchainMaintenance1; +} VkPhysicalDeviceSwapchainMaintenance1FeaturesKHR; + +typedef struct VkSwapchainPresentFenceInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const VkFence* pFences; +} VkSwapchainPresentFenceInfoKHR; + +typedef struct VkSwapchainPresentModesCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t presentModeCount; + const VkPresentModeKHR* pPresentModes; +} VkSwapchainPresentModesCreateInfoKHR; + +typedef struct VkSwapchainPresentModeInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const VkPresentModeKHR* pPresentModes; +} VkSwapchainPresentModeInfoKHR; + +typedef struct VkSwapchainPresentScalingCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkPresentScalingFlagsKHR scalingBehavior; + VkPresentGravityFlagsKHR presentGravityX; + VkPresentGravityFlagsKHR presentGravityY; +} VkSwapchainPresentScalingCreateInfoKHR; + +typedef struct VkReleaseSwapchainImagesInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; + uint32_t imageIndexCount; + const uint32_t* pImageIndices; +} VkReleaseSwapchainImagesInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkReleaseSwapchainImagesKHR)(VkDevice device, const VkReleaseSwapchainImagesInfoKHR* pReleaseInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkReleaseSwapchainImagesKHR( + VkDevice device, + const VkReleaseSwapchainImagesInfoKHR* pReleaseInfo); +#endif +#endif + + +// VK_KHR_internally_synchronized_queues is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_internally_synchronized_queues 1 +#define VK_KHR_INTERNALLY_SYNCHRONIZED_QUEUES_SPEC_VERSION 1 +#define VK_KHR_INTERNALLY_SYNCHRONIZED_QUEUES_EXTENSION_NAME "VK_KHR_internally_synchronized_queues" +typedef struct VkPhysicalDeviceInternallySynchronizedQueuesFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 internallySynchronizedQueues; +} VkPhysicalDeviceInternallySynchronizedQueuesFeaturesKHR; + + + +// VK_KHR_cooperative_matrix is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_cooperative_matrix 1 +#define VK_KHR_COOPERATIVE_MATRIX_SPEC_VERSION 2 +#define VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME "VK_KHR_cooperative_matrix" + +typedef enum VkComponentTypeKHR { + VK_COMPONENT_TYPE_FLOAT16_KHR = 0, + VK_COMPONENT_TYPE_FLOAT32_KHR = 1, + VK_COMPONENT_TYPE_FLOAT64_KHR = 2, + VK_COMPONENT_TYPE_SINT8_KHR = 3, + VK_COMPONENT_TYPE_SINT16_KHR = 4, + VK_COMPONENT_TYPE_SINT32_KHR = 5, + VK_COMPONENT_TYPE_SINT64_KHR = 6, + VK_COMPONENT_TYPE_UINT8_KHR = 7, + VK_COMPONENT_TYPE_UINT16_KHR = 8, + VK_COMPONENT_TYPE_UINT32_KHR = 9, + VK_COMPONENT_TYPE_UINT64_KHR = 10, + VK_COMPONENT_TYPE_BFLOAT16_KHR = 1000141000, + VK_COMPONENT_TYPE_SINT8_PACKED_NV = 1000491000, + VK_COMPONENT_TYPE_UINT8_PACKED_NV = 1000491001, + VK_COMPONENT_TYPE_FLOAT8_E4M3_EXT = 1000491002, + VK_COMPONENT_TYPE_FLOAT8_E5M2_EXT = 1000491003, + VK_COMPONENT_TYPE_FLOAT6_E2M3_EXT = 1000672000, + VK_COMPONENT_TYPE_FLOAT6_E3M2_EXT = 1000672001, + VK_COMPONENT_TYPE_FLOAT4_E2M1_EXT = 1000672002, + VK_COMPONENT_TYPE_FLOAT8_UNSIGNED_E8M0_EXT = 1000672003, + VK_COMPONENT_TYPE_MXINT8_EXT = 1000672004, + VK_COMPONENT_TYPE_FLOAT16_NV = VK_COMPONENT_TYPE_FLOAT16_KHR, + VK_COMPONENT_TYPE_FLOAT32_NV = VK_COMPONENT_TYPE_FLOAT32_KHR, + VK_COMPONENT_TYPE_FLOAT64_NV = VK_COMPONENT_TYPE_FLOAT64_KHR, + VK_COMPONENT_TYPE_SINT8_NV = VK_COMPONENT_TYPE_SINT8_KHR, + VK_COMPONENT_TYPE_SINT16_NV = VK_COMPONENT_TYPE_SINT16_KHR, + VK_COMPONENT_TYPE_SINT32_NV = VK_COMPONENT_TYPE_SINT32_KHR, + VK_COMPONENT_TYPE_SINT64_NV = VK_COMPONENT_TYPE_SINT64_KHR, + VK_COMPONENT_TYPE_UINT8_NV = VK_COMPONENT_TYPE_UINT8_KHR, + VK_COMPONENT_TYPE_UINT16_NV = VK_COMPONENT_TYPE_UINT16_KHR, + VK_COMPONENT_TYPE_UINT32_NV = VK_COMPONENT_TYPE_UINT32_KHR, + VK_COMPONENT_TYPE_UINT64_NV = VK_COMPONENT_TYPE_UINT64_KHR, + VK_COMPONENT_TYPE_FLOAT_E4M3_NV = VK_COMPONENT_TYPE_FLOAT8_E4M3_EXT, + VK_COMPONENT_TYPE_FLOAT_E5M2_NV = VK_COMPONENT_TYPE_FLOAT8_E5M2_EXT, + VK_COMPONENT_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkComponentTypeKHR; + +typedef enum VkScopeKHR { + VK_SCOPE_DEVICE_KHR = 1, + VK_SCOPE_WORKGROUP_KHR = 2, + VK_SCOPE_SUBGROUP_KHR = 3, + VK_SCOPE_QUEUE_FAMILY_KHR = 5, + VK_SCOPE_DEVICE_NV = VK_SCOPE_DEVICE_KHR, + VK_SCOPE_WORKGROUP_NV = VK_SCOPE_WORKGROUP_KHR, + VK_SCOPE_SUBGROUP_NV = VK_SCOPE_SUBGROUP_KHR, + VK_SCOPE_QUEUE_FAMILY_NV = VK_SCOPE_QUEUE_FAMILY_KHR, + VK_SCOPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkScopeKHR; +typedef struct VkCooperativeMatrixPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeKHR AType; + VkComponentTypeKHR BType; + VkComponentTypeKHR CType; + VkComponentTypeKHR ResultType; + VkBool32 saturatingAccumulation; + VkScopeKHR scope; +} VkCooperativeMatrixPropertiesKHR; + +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesKHR; + +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesKHR { + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesKHR* pProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkCooperativeMatrixPropertiesKHR* pProperties); +#endif +#endif + + +// VK_KHR_compute_shader_derivatives is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_compute_shader_derivatives 1 +#define VK_KHR_COMPUTE_SHADER_DERIVATIVES_SPEC_VERSION 1 +#define VK_KHR_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME "VK_KHR_compute_shader_derivatives" +typedef struct VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 computeDerivativeGroupQuads; + VkBool32 computeDerivativeGroupLinear; +} VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR; + +typedef struct VkPhysicalDeviceComputeShaderDerivativesPropertiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 meshAndTaskShaderDerivatives; +} VkPhysicalDeviceComputeShaderDerivativesPropertiesKHR; + + + +// VK_KHR_video_decode_av1 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_decode_av1 1 +#include "vk_video/vulkan_video_codec_av1std.h" +#include "vk_video/vulkan_video_codec_av1std_decode.h" +#define VK_MAX_VIDEO_AV1_REFERENCES_PER_FRAME_KHR 7U +#define VK_KHR_VIDEO_DECODE_AV1_SPEC_VERSION 1 +#define VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME "VK_KHR_video_decode_av1" +typedef struct VkVideoDecodeAV1ProfileInfoKHR { + VkStructureType sType; + const void* pNext; + StdVideoAV1Profile stdProfile; + VkBool32 filmGrainSupport; +} VkVideoDecodeAV1ProfileInfoKHR; + +typedef struct VkVideoDecodeAV1CapabilitiesKHR { + VkStructureType sType; + void* pNext; + StdVideoAV1Level maxLevel; +} VkVideoDecodeAV1CapabilitiesKHR; + +typedef struct VkVideoDecodeAV1SessionParametersCreateInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoAV1SequenceHeader* pStdSequenceHeader; +} VkVideoDecodeAV1SessionParametersCreateInfoKHR; + +typedef struct VkVideoDecodeAV1PictureInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoDecodeAV1PictureInfo* pStdPictureInfo; + int32_t referenceNameSlotIndices[VK_MAX_VIDEO_AV1_REFERENCES_PER_FRAME_KHR]; + uint32_t frameHeaderOffset; + uint32_t tileCount; + const uint32_t* pTileOffsets; + const uint32_t* pTileSizes; +} VkVideoDecodeAV1PictureInfoKHR; + +typedef struct VkVideoDecodeAV1DpbSlotInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoDecodeAV1ReferenceInfo* pStdReferenceInfo; +} VkVideoDecodeAV1DpbSlotInfoKHR; + + + +// VK_KHR_video_encode_av1 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_encode_av1 1 +#include "vk_video/vulkan_video_codec_av1std_encode.h" +#define VK_KHR_VIDEO_ENCODE_AV1_SPEC_VERSION 1 +#define VK_KHR_VIDEO_ENCODE_AV1_EXTENSION_NAME "VK_KHR_video_encode_av1" + +typedef enum VkVideoEncodeAV1PredictionModeKHR { + VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_INTRA_ONLY_KHR = 0, + VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_SINGLE_REFERENCE_KHR = 1, + VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_UNIDIRECTIONAL_COMPOUND_KHR = 2, + VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_BIDIRECTIONAL_COMPOUND_KHR = 3, + VK_VIDEO_ENCODE_AV1_PREDICTION_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeAV1PredictionModeKHR; + +typedef enum VkVideoEncodeAV1RateControlGroupKHR { + VK_VIDEO_ENCODE_AV1_RATE_CONTROL_GROUP_INTRA_KHR = 0, + VK_VIDEO_ENCODE_AV1_RATE_CONTROL_GROUP_PREDICTIVE_KHR = 1, + VK_VIDEO_ENCODE_AV1_RATE_CONTROL_GROUP_BIPREDICTIVE_KHR = 2, + VK_VIDEO_ENCODE_AV1_RATE_CONTROL_GROUP_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeAV1RateControlGroupKHR; + +typedef enum VkVideoEncodeAV1CapabilityFlagBitsKHR { + VK_VIDEO_ENCODE_AV1_CAPABILITY_PER_RATE_CONTROL_GROUP_MIN_MAX_Q_INDEX_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_AV1_CAPABILITY_GENERATE_OBU_EXTENSION_HEADER_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_AV1_CAPABILITY_PRIMARY_REFERENCE_CDF_ONLY_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_AV1_CAPABILITY_FRAME_SIZE_OVERRIDE_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_AV1_CAPABILITY_MOTION_VECTOR_SCALING_BIT_KHR = 0x00000010, + VK_VIDEO_ENCODE_AV1_CAPABILITY_COMPOUND_PREDICTION_INTRA_REFRESH_BIT_KHR = 0x00000020, + VK_VIDEO_ENCODE_AV1_CAPABILITY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeAV1CapabilityFlagBitsKHR; +typedef VkFlags VkVideoEncodeAV1CapabilityFlagsKHR; + +typedef enum VkVideoEncodeAV1StdFlagBitsKHR { + VK_VIDEO_ENCODE_AV1_STD_UNIFORM_TILE_SPACING_FLAG_SET_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_AV1_STD_SKIP_MODE_PRESENT_UNSET_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_AV1_STD_PRIMARY_REF_FRAME_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_AV1_STD_DELTA_Q_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_AV1_STD_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeAV1StdFlagBitsKHR; +typedef VkFlags VkVideoEncodeAV1StdFlagsKHR; + +typedef enum VkVideoEncodeAV1SuperblockSizeFlagBitsKHR { + VK_VIDEO_ENCODE_AV1_SUPERBLOCK_SIZE_64_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_AV1_SUPERBLOCK_SIZE_128_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_AV1_SUPERBLOCK_SIZE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeAV1SuperblockSizeFlagBitsKHR; +typedef VkFlags VkVideoEncodeAV1SuperblockSizeFlagsKHR; + +typedef enum VkVideoEncodeAV1RateControlFlagBitsKHR { + VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REGULAR_GOP_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_AV1_RATE_CONTROL_TEMPORAL_LAYER_PATTERN_DYADIC_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REFERENCE_PATTERN_FLAT_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_AV1_RATE_CONTROL_REFERENCE_PATTERN_DYADIC_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_AV1_RATE_CONTROL_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeAV1RateControlFlagBitsKHR; +typedef VkFlags VkVideoEncodeAV1RateControlFlagsKHR; +typedef struct VkPhysicalDeviceVideoEncodeAV1FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 videoEncodeAV1; +} VkPhysicalDeviceVideoEncodeAV1FeaturesKHR; + +typedef struct VkVideoEncodeAV1CapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeAV1CapabilityFlagsKHR flags; + StdVideoAV1Level maxLevel; + VkExtent2D codedPictureAlignment; + VkExtent2D maxTiles; + VkExtent2D minTileSize; + VkExtent2D maxTileSize; + VkVideoEncodeAV1SuperblockSizeFlagsKHR superblockSizes; + uint32_t maxSingleReferenceCount; + uint32_t singleReferenceNameMask; + uint32_t maxUnidirectionalCompoundReferenceCount; + uint32_t maxUnidirectionalCompoundGroup1ReferenceCount; + uint32_t unidirectionalCompoundReferenceNameMask; + uint32_t maxBidirectionalCompoundReferenceCount; + uint32_t maxBidirectionalCompoundGroup1ReferenceCount; + uint32_t maxBidirectionalCompoundGroup2ReferenceCount; + uint32_t bidirectionalCompoundReferenceNameMask; + uint32_t maxTemporalLayerCount; + uint32_t maxSpatialLayerCount; + uint32_t maxOperatingPoints; + uint32_t minQIndex; + uint32_t maxQIndex; + VkBool32 prefersGopRemainingFrames; + VkBool32 requiresGopRemainingFrames; + VkVideoEncodeAV1StdFlagsKHR stdSyntaxFlags; +} VkVideoEncodeAV1CapabilitiesKHR; + +typedef struct VkVideoEncodeAV1QIndexKHR { + uint32_t intraQIndex; + uint32_t predictiveQIndex; + uint32_t bipredictiveQIndex; +} VkVideoEncodeAV1QIndexKHR; + +typedef struct VkVideoEncodeAV1QualityLevelPropertiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeAV1RateControlFlagsKHR preferredRateControlFlags; + uint32_t preferredGopFrameCount; + uint32_t preferredKeyFramePeriod; + uint32_t preferredConsecutiveBipredictiveFrameCount; + uint32_t preferredTemporalLayerCount; + VkVideoEncodeAV1QIndexKHR preferredConstantQIndex; + uint32_t preferredMaxSingleReferenceCount; + uint32_t preferredSingleReferenceNameMask; + uint32_t preferredMaxUnidirectionalCompoundReferenceCount; + uint32_t preferredMaxUnidirectionalCompoundGroup1ReferenceCount; + uint32_t preferredUnidirectionalCompoundReferenceNameMask; + uint32_t preferredMaxBidirectionalCompoundReferenceCount; + uint32_t preferredMaxBidirectionalCompoundGroup1ReferenceCount; + uint32_t preferredMaxBidirectionalCompoundGroup2ReferenceCount; + uint32_t preferredBidirectionalCompoundReferenceNameMask; +} VkVideoEncodeAV1QualityLevelPropertiesKHR; + +typedef struct VkVideoEncodeAV1SessionCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 useMaxLevel; + StdVideoAV1Level maxLevel; +} VkVideoEncodeAV1SessionCreateInfoKHR; + +typedef struct VkVideoEncodeAV1SessionParametersCreateInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoAV1SequenceHeader* pStdSequenceHeader; + const StdVideoEncodeAV1DecoderModelInfo* pStdDecoderModelInfo; + uint32_t stdOperatingPointCount; + const StdVideoEncodeAV1OperatingPointInfo* pStdOperatingPoints; +} VkVideoEncodeAV1SessionParametersCreateInfoKHR; + +typedef struct VkVideoEncodeAV1PictureInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeAV1PredictionModeKHR predictionMode; + VkVideoEncodeAV1RateControlGroupKHR rateControlGroup; + uint32_t constantQIndex; + const StdVideoEncodeAV1PictureInfo* pStdPictureInfo; + int32_t referenceNameSlotIndices[VK_MAX_VIDEO_AV1_REFERENCES_PER_FRAME_KHR]; + VkBool32 primaryReferenceCdfOnly; + VkBool32 generateObuExtensionHeader; +} VkVideoEncodeAV1PictureInfoKHR; + +typedef struct VkVideoEncodeAV1DpbSlotInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoEncodeAV1ReferenceInfo* pStdReferenceInfo; +} VkVideoEncodeAV1DpbSlotInfoKHR; + +typedef struct VkVideoEncodeAV1ProfileInfoKHR { + VkStructureType sType; + const void* pNext; + StdVideoAV1Profile stdProfile; +} VkVideoEncodeAV1ProfileInfoKHR; + +typedef struct VkVideoEncodeAV1FrameSizeKHR { + uint32_t intraFrameSize; + uint32_t predictiveFrameSize; + uint32_t bipredictiveFrameSize; +} VkVideoEncodeAV1FrameSizeKHR; + +typedef struct VkVideoEncodeAV1GopRemainingFrameInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 useGopRemainingFrames; + uint32_t gopRemainingIntra; + uint32_t gopRemainingPredictive; + uint32_t gopRemainingBipredictive; +} VkVideoEncodeAV1GopRemainingFrameInfoKHR; + +typedef struct VkVideoEncodeAV1RateControlInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeAV1RateControlFlagsKHR flags; + uint32_t gopFrameCount; + uint32_t keyFramePeriod; + uint32_t consecutiveBipredictiveFrameCount; + uint32_t temporalLayerCount; +} VkVideoEncodeAV1RateControlInfoKHR; + +typedef struct VkVideoEncodeAV1RateControlLayerInfoKHR { + VkStructureType sType; + const void* pNext; + VkBool32 useMinQIndex; + VkVideoEncodeAV1QIndexKHR minQIndex; + VkBool32 useMaxQIndex; + VkVideoEncodeAV1QIndexKHR maxQIndex; + VkBool32 useMaxFrameSize; + VkVideoEncodeAV1FrameSizeKHR maxFrameSize; +} VkVideoEncodeAV1RateControlLayerInfoKHR; + + + +// VK_KHR_video_decode_vp9 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_decode_vp9 1 +#include "vk_video/vulkan_video_codec_vp9std.h" +#include "vk_video/vulkan_video_codec_vp9std_decode.h" +#define VK_MAX_VIDEO_VP9_REFERENCES_PER_FRAME_KHR 3U +#define VK_KHR_VIDEO_DECODE_VP9_SPEC_VERSION 1 +#define VK_KHR_VIDEO_DECODE_VP9_EXTENSION_NAME "VK_KHR_video_decode_vp9" +typedef struct VkPhysicalDeviceVideoDecodeVP9FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 videoDecodeVP9; +} VkPhysicalDeviceVideoDecodeVP9FeaturesKHR; + +typedef struct VkVideoDecodeVP9ProfileInfoKHR { + VkStructureType sType; + const void* pNext; + StdVideoVP9Profile stdProfile; +} VkVideoDecodeVP9ProfileInfoKHR; + +typedef struct VkVideoDecodeVP9CapabilitiesKHR { + VkStructureType sType; + void* pNext; + StdVideoVP9Level maxLevel; +} VkVideoDecodeVP9CapabilitiesKHR; + +typedef struct VkVideoDecodeVP9PictureInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoDecodeVP9PictureInfo* pStdPictureInfo; + int32_t referenceNameSlotIndices[VK_MAX_VIDEO_VP9_REFERENCES_PER_FRAME_KHR]; + uint32_t uncompressedHeaderOffset; + uint32_t compressedHeaderOffset; + uint32_t tilesOffset; +} VkVideoDecodeVP9PictureInfoKHR; + + + +// VK_KHR_video_maintenance1 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_maintenance1 1 +#define VK_KHR_VIDEO_MAINTENANCE_1_SPEC_VERSION 1 +#define VK_KHR_VIDEO_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_video_maintenance1" +typedef struct VkPhysicalDeviceVideoMaintenance1FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 videoMaintenance1; +} VkPhysicalDeviceVideoMaintenance1FeaturesKHR; + +typedef struct VkVideoInlineQueryInfoKHR { + VkStructureType sType; + const void* pNext; + VkQueryPool queryPool; + uint32_t firstQuery; + uint32_t queryCount; +} VkVideoInlineQueryInfoKHR; + + + +// VK_KHR_vertex_attribute_divisor is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_vertex_attribute_divisor 1 +#define VK_KHR_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 1 +#define VK_KHR_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_KHR_vertex_attribute_divisor" +typedef VkPhysicalDeviceVertexAttributeDivisorProperties VkPhysicalDeviceVertexAttributeDivisorPropertiesKHR; + +typedef VkVertexInputBindingDivisorDescription VkVertexInputBindingDivisorDescriptionKHR; + +typedef VkPipelineVertexInputDivisorStateCreateInfo VkPipelineVertexInputDivisorStateCreateInfoKHR; + +typedef VkPhysicalDeviceVertexAttributeDivisorFeatures VkPhysicalDeviceVertexAttributeDivisorFeaturesKHR; + + + +// VK_KHR_load_store_op_none is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_load_store_op_none 1 +#define VK_KHR_LOAD_STORE_OP_NONE_SPEC_VERSION 1 +#define VK_KHR_LOAD_STORE_OP_NONE_EXTENSION_NAME "VK_KHR_load_store_op_none" + + +// VK_KHR_unified_image_layouts is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_unified_image_layouts 1 +#define VK_KHR_UNIFIED_IMAGE_LAYOUTS_SPEC_VERSION 1 +#define VK_KHR_UNIFIED_IMAGE_LAYOUTS_EXTENSION_NAME "VK_KHR_unified_image_layouts" +typedef struct VkPhysicalDeviceUnifiedImageLayoutsFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 unifiedImageLayouts; + VkBool32 unifiedImageLayoutsVideo; +} VkPhysicalDeviceUnifiedImageLayoutsFeaturesKHR; + +typedef struct VkAttachmentFeedbackLoopInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 feedbackLoopEnable; +} VkAttachmentFeedbackLoopInfoEXT; + + + +// VK_KHR_shader_float_controls2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_float_controls2 1 +#define VK_KHR_SHADER_FLOAT_CONTROLS_2_SPEC_VERSION 1 +#define VK_KHR_SHADER_FLOAT_CONTROLS_2_EXTENSION_NAME "VK_KHR_shader_float_controls2" +typedef VkPhysicalDeviceShaderFloatControls2Features VkPhysicalDeviceShaderFloatControls2FeaturesKHR; + + + +// VK_KHR_index_type_uint8 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_index_type_uint8 1 +#define VK_KHR_INDEX_TYPE_UINT8_SPEC_VERSION 1 +#define VK_KHR_INDEX_TYPE_UINT8_EXTENSION_NAME "VK_KHR_index_type_uint8" +typedef VkPhysicalDeviceIndexTypeUint8Features VkPhysicalDeviceIndexTypeUint8FeaturesKHR; + + + +// VK_KHR_line_rasterization is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_line_rasterization 1 +#define VK_KHR_LINE_RASTERIZATION_SPEC_VERSION 1 +#define VK_KHR_LINE_RASTERIZATION_EXTENSION_NAME "VK_KHR_line_rasterization" +typedef VkLineRasterizationMode VkLineRasterizationModeKHR; + +typedef VkPhysicalDeviceLineRasterizationFeatures VkPhysicalDeviceLineRasterizationFeaturesKHR; + +typedef VkPhysicalDeviceLineRasterizationProperties VkPhysicalDeviceLineRasterizationPropertiesKHR; + +typedef VkPipelineRasterizationLineStateCreateInfo VkPipelineRasterizationLineStateCreateInfoKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdSetLineStippleKHR)(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetLineStippleKHR( + VkCommandBuffer commandBuffer, + uint32_t lineStippleFactor, + uint16_t lineStipplePattern); +#endif +#endif + + +// VK_KHR_calibrated_timestamps is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_calibrated_timestamps 1 +#define VK_KHR_CALIBRATED_TIMESTAMPS_SPEC_VERSION 1 +#define VK_KHR_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_KHR_calibrated_timestamps" + +typedef enum VkTimeDomainKHR { + VK_TIME_DOMAIN_DEVICE_KHR = 0, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR = 1, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR = 2, + VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_KHR = 3, + VK_TIME_DOMAIN_PRESENT_STAGE_LOCAL_EXT = 1000208000, + VK_TIME_DOMAIN_SWAPCHAIN_LOCAL_EXT = 1000208001, + VK_TIME_DOMAIN_DEVICE_EXT = VK_TIME_DOMAIN_DEVICE_KHR, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR, + VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_KHR, + VK_TIME_DOMAIN_MAX_ENUM_KHR = 0x7FFFFFFF +} VkTimeDomainKHR; +typedef struct VkCalibratedTimestampInfoKHR { + VkStructureType sType; + const void* pNext; + VkTimeDomainKHR timeDomain; +} VkCalibratedTimestampInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR)(VkPhysicalDevice physicalDevice, uint32_t* pTimeDomainCount, VkTimeDomainKHR* pTimeDomains); +typedef VkResult (VKAPI_PTR *PFN_vkGetCalibratedTimestampsKHR)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoKHR* pTimestampInfos, uint64_t* pTimestamps, uint64_t* pMaxDeviation); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCalibrateableTimeDomainsKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pTimeDomainCount, + VkTimeDomainKHR* pTimeDomains); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetCalibratedTimestampsKHR( + VkDevice device, + uint32_t timestampCount, + const VkCalibratedTimestampInfoKHR* pTimestampInfos, + uint64_t* pTimestamps, + uint64_t* pMaxDeviation); +#endif +#endif + + +// VK_KHR_shader_expect_assume is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_expect_assume 1 +#define VK_KHR_SHADER_EXPECT_ASSUME_SPEC_VERSION 1 +#define VK_KHR_SHADER_EXPECT_ASSUME_EXTENSION_NAME "VK_KHR_shader_expect_assume" +typedef VkPhysicalDeviceShaderExpectAssumeFeatures VkPhysicalDeviceShaderExpectAssumeFeaturesKHR; + + + +// VK_KHR_maintenance6 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance6 1 +#define VK_KHR_MAINTENANCE_6_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_6_EXTENSION_NAME "VK_KHR_maintenance6" +typedef VkPhysicalDeviceMaintenance6Features VkPhysicalDeviceMaintenance6FeaturesKHR; + +typedef VkPhysicalDeviceMaintenance6Properties VkPhysicalDeviceMaintenance6PropertiesKHR; + +typedef VkBindMemoryStatus VkBindMemoryStatusKHR; + +typedef VkBindDescriptorSetsInfo VkBindDescriptorSetsInfoKHR; + +typedef VkPushConstantsInfo VkPushConstantsInfoKHR; + +typedef VkPushDescriptorSetInfo VkPushDescriptorSetInfoKHR; + +typedef VkPushDescriptorSetWithTemplateInfo VkPushDescriptorSetWithTemplateInfoKHR; + +typedef struct VkSetDescriptorBufferOffsetsInfoEXT { + VkStructureType sType; + const void* pNext; + VkShaderStageFlags stageFlags; + VkPipelineLayout layout; + uint32_t firstSet; + uint32_t setCount; + const uint32_t* pBufferIndices; + const VkDeviceSize* pOffsets; +} VkSetDescriptorBufferOffsetsInfoEXT; + +typedef struct VkBindDescriptorBufferEmbeddedSamplersInfoEXT { + VkStructureType sType; + const void* pNext; + VkShaderStageFlags stageFlags; + VkPipelineLayout layout; + uint32_t set; +} VkBindDescriptorBufferEmbeddedSamplersInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorSets2KHR)(VkCommandBuffer commandBuffer, const VkBindDescriptorSetsInfo* pBindDescriptorSetsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdPushConstants2KHR)(VkCommandBuffer commandBuffer, const VkPushConstantsInfo* pPushConstantsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSet2KHR)(VkCommandBuffer commandBuffer, const VkPushDescriptorSetInfo* pPushDescriptorSetInfo); +typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplate2KHR)(VkCommandBuffer commandBuffer, const VkPushDescriptorSetWithTemplateInfo* pPushDescriptorSetWithTemplateInfo); +typedef void (VKAPI_PTR *PFN_vkCmdSetDescriptorBufferOffsets2EXT)(VkCommandBuffer commandBuffer, const VkSetDescriptorBufferOffsetsInfoEXT* pSetDescriptorBufferOffsetsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT)(VkCommandBuffer commandBuffer, const VkBindDescriptorBufferEmbeddedSamplersInfoEXT* pBindDescriptorBufferEmbeddedSamplersInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorSets2KHR( + VkCommandBuffer commandBuffer, + const VkBindDescriptorSetsInfo* pBindDescriptorSetsInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants2KHR( + VkCommandBuffer commandBuffer, + const VkPushConstantsInfo* pPushConstantsInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSet2KHR( + VkCommandBuffer commandBuffer, + const VkPushDescriptorSetInfo* pPushDescriptorSetInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplate2KHR( + VkCommandBuffer commandBuffer, + const VkPushDescriptorSetWithTemplateInfo* pPushDescriptorSetWithTemplateInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDescriptorBufferOffsets2EXT( + VkCommandBuffer commandBuffer, + const VkSetDescriptorBufferOffsetsInfoEXT* pSetDescriptorBufferOffsetsInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorBufferEmbeddedSamplers2EXT( + VkCommandBuffer commandBuffer, + const VkBindDescriptorBufferEmbeddedSamplersInfoEXT* pBindDescriptorBufferEmbeddedSamplersInfo); +#endif +#endif + + +// VK_KHR_copy_memory_indirect is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_copy_memory_indirect 1 +#define VK_KHR_COPY_MEMORY_INDIRECT_SPEC_VERSION 1 +#define VK_KHR_COPY_MEMORY_INDIRECT_EXTENSION_NAME "VK_KHR_copy_memory_indirect" + +typedef enum VkAddressCopyFlagBitsKHR { + VK_ADDRESS_COPY_DEVICE_LOCAL_BIT_KHR = 0x00000001, + VK_ADDRESS_COPY_SPARSE_BIT_KHR = 0x00000002, + VK_ADDRESS_COPY_PROTECTED_BIT_KHR = 0x00000004, + VK_ADDRESS_COPY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAddressCopyFlagBitsKHR; +typedef VkFlags VkAddressCopyFlagsKHR; +typedef struct VkCopyMemoryIndirectCommandKHR { + VkDeviceAddress srcAddress; + VkDeviceAddress dstAddress; + VkDeviceSize size; +} VkCopyMemoryIndirectCommandKHR; + +typedef struct VkCopyMemoryIndirectInfoKHR { + VkStructureType sType; + const void* pNext; + VkAddressCopyFlagsKHR srcCopyFlags; + VkAddressCopyFlagsKHR dstCopyFlags; + uint32_t copyCount; + VkStridedDeviceAddressRangeKHR copyAddressRange; +} VkCopyMemoryIndirectInfoKHR; + +typedef struct VkCopyMemoryToImageIndirectCommandKHR { + VkDeviceAddress srcAddress; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkCopyMemoryToImageIndirectCommandKHR; + +typedef struct VkCopyMemoryToImageIndirectInfoKHR { + VkStructureType sType; + const void* pNext; + VkAddressCopyFlagsKHR srcCopyFlags; + uint32_t copyCount; + VkStridedDeviceAddressRangeKHR copyAddressRange; + VkImage dstImage; + VkImageLayout dstImageLayout; + const VkImageSubresourceLayers* pImageSubresources; +} VkCopyMemoryToImageIndirectInfoKHR; + +typedef struct VkPhysicalDeviceCopyMemoryIndirectFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 indirectMemoryCopy; + VkBool32 indirectMemoryToImageCopy; +} VkPhysicalDeviceCopyMemoryIndirectFeaturesKHR; + +typedef struct VkPhysicalDeviceCopyMemoryIndirectPropertiesKHR { + VkStructureType sType; + void* pNext; + VkQueueFlags supportedQueues; +} VkPhysicalDeviceCopyMemoryIndirectPropertiesKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryIndirectKHR)(VkCommandBuffer commandBuffer, const VkCopyMemoryIndirectInfoKHR* pCopyMemoryIndirectInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryToImageIndirectKHR)(VkCommandBuffer commandBuffer, const VkCopyMemoryToImageIndirectInfoKHR* pCopyMemoryToImageIndirectInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMemoryIndirectKHR( + VkCommandBuffer commandBuffer, + const VkCopyMemoryIndirectInfoKHR* pCopyMemoryIndirectInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMemoryToImageIndirectKHR( + VkCommandBuffer commandBuffer, + const VkCopyMemoryToImageIndirectInfoKHR* pCopyMemoryToImageIndirectInfo); +#endif +#endif + + +// VK_KHR_video_encode_intra_refresh is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_encode_intra_refresh 1 +#define VK_KHR_VIDEO_ENCODE_INTRA_REFRESH_SPEC_VERSION 1 +#define VK_KHR_VIDEO_ENCODE_INTRA_REFRESH_EXTENSION_NAME "VK_KHR_video_encode_intra_refresh" + +typedef enum VkVideoEncodeIntraRefreshModeFlagBitsKHR { + VK_VIDEO_ENCODE_INTRA_REFRESH_MODE_NONE_KHR = 0, + VK_VIDEO_ENCODE_INTRA_REFRESH_MODE_PER_PICTURE_PARTITION_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_INTRA_REFRESH_MODE_BLOCK_BASED_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_INTRA_REFRESH_MODE_BLOCK_ROW_BASED_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_INTRA_REFRESH_MODE_BLOCK_COLUMN_BASED_BIT_KHR = 0x00000008, + VK_VIDEO_ENCODE_INTRA_REFRESH_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodeIntraRefreshModeFlagBitsKHR; +typedef VkFlags VkVideoEncodeIntraRefreshModeFlagsKHR; +typedef struct VkVideoEncodeIntraRefreshCapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeIntraRefreshModeFlagsKHR intraRefreshModes; + uint32_t maxIntraRefreshCycleDuration; + uint32_t maxIntraRefreshActiveReferencePictures; + VkBool32 partitionIndependentIntraRefreshRegions; + VkBool32 nonRectangularIntraRefreshRegions; +} VkVideoEncodeIntraRefreshCapabilitiesKHR; + +typedef struct VkVideoEncodeSessionIntraRefreshCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkVideoEncodeIntraRefreshModeFlagBitsKHR intraRefreshMode; +} VkVideoEncodeSessionIntraRefreshCreateInfoKHR; + +typedef struct VkVideoEncodeIntraRefreshInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t intraRefreshCycleDuration; + uint32_t intraRefreshIndex; +} VkVideoEncodeIntraRefreshInfoKHR; + +typedef struct VkVideoReferenceIntraRefreshInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t dirtyIntraRefreshRegions; +} VkVideoReferenceIntraRefreshInfoKHR; + +typedef struct VkPhysicalDeviceVideoEncodeIntraRefreshFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 videoEncodeIntraRefresh; +} VkPhysicalDeviceVideoEncodeIntraRefreshFeaturesKHR; + + + +// VK_KHR_video_encode_quantization_map is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_encode_quantization_map 1 +#define VK_KHR_VIDEO_ENCODE_QUANTIZATION_MAP_SPEC_VERSION 2 +#define VK_KHR_VIDEO_ENCODE_QUANTIZATION_MAP_EXTENSION_NAME "VK_KHR_video_encode_quantization_map" +typedef struct VkVideoEncodeQuantizationMapCapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkExtent2D maxQuantizationMapExtent; +} VkVideoEncodeQuantizationMapCapabilitiesKHR; + +typedef struct VkVideoFormatQuantizationMapPropertiesKHR { + VkStructureType sType; + void* pNext; + VkExtent2D quantizationMapTexelSize; +} VkVideoFormatQuantizationMapPropertiesKHR; + +typedef struct VkVideoEncodeQuantizationMapInfoKHR { + VkStructureType sType; + const void* pNext; + VkImageView quantizationMap; + VkExtent2D quantizationMapExtent; +} VkVideoEncodeQuantizationMapInfoKHR; + +typedef struct VkVideoEncodeQuantizationMapSessionParametersCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkExtent2D quantizationMapTexelSize; +} VkVideoEncodeQuantizationMapSessionParametersCreateInfoKHR; + +typedef struct VkPhysicalDeviceVideoEncodeQuantizationMapFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 videoEncodeQuantizationMap; +} VkPhysicalDeviceVideoEncodeQuantizationMapFeaturesKHR; + +typedef struct VkVideoEncodeH264QuantizationMapCapabilitiesKHR { + VkStructureType sType; + void* pNext; + int32_t minQpDelta; + int32_t maxQpDelta; +} VkVideoEncodeH264QuantizationMapCapabilitiesKHR; + +typedef struct VkVideoEncodeH265QuantizationMapCapabilitiesKHR { + VkStructureType sType; + void* pNext; + int32_t minQpDelta; + int32_t maxQpDelta; +} VkVideoEncodeH265QuantizationMapCapabilitiesKHR; + +typedef struct VkVideoFormatH265QuantizationMapPropertiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeH265CtbSizeFlagsKHR compatibleCtbSizes; +} VkVideoFormatH265QuantizationMapPropertiesKHR; + +typedef struct VkVideoEncodeAV1QuantizationMapCapabilitiesKHR { + VkStructureType sType; + void* pNext; + int32_t minQIndexDelta; + int32_t maxQIndexDelta; +} VkVideoEncodeAV1QuantizationMapCapabilitiesKHR; + +typedef struct VkVideoFormatAV1QuantizationMapPropertiesKHR { + VkStructureType sType; + void* pNext; + VkVideoEncodeAV1SuperblockSizeFlagsKHR compatibleSuperblockSizes; +} VkVideoFormatAV1QuantizationMapPropertiesKHR; + + + +// VK_KHR_shader_relaxed_extended_instruction is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_relaxed_extended_instruction 1 +#define VK_KHR_SHADER_RELAXED_EXTENDED_INSTRUCTION_SPEC_VERSION 1 +#define VK_KHR_SHADER_RELAXED_EXTENDED_INSTRUCTION_EXTENSION_NAME "VK_KHR_shader_relaxed_extended_instruction" +typedef struct VkPhysicalDeviceShaderRelaxedExtendedInstructionFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderRelaxedExtendedInstruction; +} VkPhysicalDeviceShaderRelaxedExtendedInstructionFeaturesKHR; + + + +// VK_KHR_maintenance7 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance7 1 +#define VK_KHR_MAINTENANCE_7_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_7_EXTENSION_NAME "VK_KHR_maintenance7" + +typedef enum VkPhysicalDeviceLayeredApiKHR { + VK_PHYSICAL_DEVICE_LAYERED_API_VULKAN_KHR = 0, + VK_PHYSICAL_DEVICE_LAYERED_API_D3D12_KHR = 1, + VK_PHYSICAL_DEVICE_LAYERED_API_METAL_KHR = 2, + VK_PHYSICAL_DEVICE_LAYERED_API_OPENGL_KHR = 3, + VK_PHYSICAL_DEVICE_LAYERED_API_OPENGLES_KHR = 4, + VK_PHYSICAL_DEVICE_LAYERED_API_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPhysicalDeviceLayeredApiKHR; +typedef struct VkPhysicalDeviceMaintenance7FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 maintenance7; +} VkPhysicalDeviceMaintenance7FeaturesKHR; + +typedef struct VkPhysicalDeviceMaintenance7PropertiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 robustFragmentShadingRateAttachmentAccess; + VkBool32 separateDepthStencilAttachmentAccess; + uint32_t maxDescriptorSetTotalUniformBuffersDynamic; + uint32_t maxDescriptorSetTotalStorageBuffersDynamic; + uint32_t maxDescriptorSetTotalBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindTotalUniformBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindTotalStorageBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindTotalBuffersDynamic; +} VkPhysicalDeviceMaintenance7PropertiesKHR; + +typedef struct VkPhysicalDeviceLayeredApiPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t vendorID; + uint32_t deviceID; + VkPhysicalDeviceLayeredApiKHR layeredAPI; + char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]; +} VkPhysicalDeviceLayeredApiPropertiesKHR; + +typedef struct VkPhysicalDeviceLayeredApiPropertiesListKHR { + VkStructureType sType; + void* pNext; + uint32_t layeredApiCount; + VkPhysicalDeviceLayeredApiPropertiesKHR* pLayeredApis; +} VkPhysicalDeviceLayeredApiPropertiesListKHR; + +typedef struct VkPhysicalDeviceLayeredApiVulkanPropertiesKHR { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceProperties2 properties; +} VkPhysicalDeviceLayeredApiVulkanPropertiesKHR; + + + +// VK_KHR_device_fault is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_device_fault 1 +#define VK_KHR_DEVICE_FAULT_SPEC_VERSION 1 +#define VK_KHR_DEVICE_FAULT_EXTENSION_NAME "VK_KHR_device_fault" + +typedef enum VkDeviceFaultAddressTypeKHR { + VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_KHR = 0, + VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_KHR = 1, + VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_KHR = 2, + VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_KHR = 3, + VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_KHR = 4, + VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_KHR = 5, + VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_KHR = 6, + VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT = VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_KHR, + VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT = VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_KHR, + VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT = VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_KHR, + VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT = VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_KHR, + VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT = VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_KHR, + VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT = VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_KHR, + VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT = VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_KHR, + VK_DEVICE_FAULT_ADDRESS_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkDeviceFaultAddressTypeKHR; + +typedef enum VkDeviceFaultVendorBinaryHeaderVersionKHR { + VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_KHR = 1, + VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_EXT = VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_KHR, + VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_MAX_ENUM_KHR = 0x7FFFFFFF +} VkDeviceFaultVendorBinaryHeaderVersionKHR; + +typedef enum VkDeviceFaultFlagBitsKHR { + VK_DEVICE_FAULT_FLAG_DEVICE_LOST_KHR = 0x00000001, + VK_DEVICE_FAULT_FLAG_MEMORY_ADDRESS_KHR = 0x00000002, + VK_DEVICE_FAULT_FLAG_INSTRUCTION_ADDRESS_KHR = 0x00000004, + VK_DEVICE_FAULT_FLAG_VENDOR_KHR = 0x00000008, + VK_DEVICE_FAULT_FLAG_WATCHDOG_TIMEOUT_KHR = 0x00000010, + VK_DEVICE_FAULT_FLAG_OVERFLOW_KHR = 0x00000020, + VK_DEVICE_FAULT_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkDeviceFaultFlagBitsKHR; +typedef VkFlags VkDeviceFaultFlagsKHR; +typedef struct VkPhysicalDeviceFaultFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 deviceFault; + VkBool32 deviceFaultVendorBinary; + VkBool32 deviceFaultReportMasked; + VkBool32 deviceFaultDeviceLostOnMasked; +} VkPhysicalDeviceFaultFeaturesKHR; + +typedef struct VkPhysicalDeviceFaultPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t maxDeviceFaultCount; +} VkPhysicalDeviceFaultPropertiesKHR; + +typedef struct VkDeviceFaultAddressInfoKHR { + VkDeviceFaultAddressTypeKHR addressType; + VkDeviceAddress reportedAddress; + VkDeviceSize addressPrecision; +} VkDeviceFaultAddressInfoKHR; + +typedef struct VkDeviceFaultVendorInfoKHR { + char description[VK_MAX_DESCRIPTION_SIZE]; + uint64_t vendorFaultCode; + uint64_t vendorFaultData; +} VkDeviceFaultVendorInfoKHR; + +typedef struct VkDeviceFaultInfoKHR { + VkStructureType sType; + void* pNext; + VkDeviceFaultFlagsKHR flags; + uint64_t groupId; + char description[VK_MAX_DESCRIPTION_SIZE]; + VkDeviceFaultAddressInfoKHR faultAddressInfo; + VkDeviceFaultAddressInfoKHR instructionAddressInfo; + VkDeviceFaultVendorInfoKHR vendorInfo; +} VkDeviceFaultInfoKHR; + +typedef struct VkDeviceFaultDebugInfoKHR { + VkStructureType sType; + void* pNext; + uint32_t vendorBinarySize; + void* pVendorBinaryData; +} VkDeviceFaultDebugInfoKHR; + +typedef struct VkDeviceFaultVendorBinaryHeaderVersionOneKHR { + uint32_t headerSize; + VkDeviceFaultVendorBinaryHeaderVersionKHR headerVersion; + uint32_t vendorID; + uint32_t deviceID; + uint32_t driverVersion; + uint8_t pipelineCacheUUID[VK_UUID_SIZE]; + uint32_t applicationNameOffset; + uint32_t applicationVersion; + uint32_t engineNameOffset; + uint32_t engineVersion; + uint32_t apiVersion; +} VkDeviceFaultVendorBinaryHeaderVersionOneKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceFaultReportsKHR)(VkDevice device, uint64_t timeout, uint32_t* pFaultCounts, VkDeviceFaultInfoKHR* pFaultInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceFaultDebugInfoKHR)(VkDevice device, VkDeviceFaultDebugInfoKHR* pDebugInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceFaultReportsKHR( + VkDevice device, + uint64_t timeout, + uint32_t* pFaultCounts, + VkDeviceFaultInfoKHR* pFaultInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceFaultDebugInfoKHR( + VkDevice device, + VkDeviceFaultDebugInfoKHR* pDebugInfo); +#endif +#endif + + +// VK_KHR_maintenance8 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance8 1 +#define VK_KHR_MAINTENANCE_8_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_8_EXTENSION_NAME "VK_KHR_maintenance8" +typedef VkFlags64 VkAccessFlags3KHR; + +// Flag bits for VkAccessFlagBits3KHR +typedef VkFlags64 VkAccessFlagBits3KHR; +static const VkAccessFlagBits3KHR VK_ACCESS_3_NONE_KHR = 0ULL; + +typedef struct VkMemoryBarrierAccessFlags3KHR { + VkStructureType sType; + const void* pNext; + VkAccessFlags3KHR srcAccessMask3; + VkAccessFlags3KHR dstAccessMask3; +} VkMemoryBarrierAccessFlags3KHR; + +typedef struct VkPhysicalDeviceMaintenance8FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 maintenance8; +} VkPhysicalDeviceMaintenance8FeaturesKHR; + + + +// VK_KHR_shader_fma is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_shader_fma 1 +#define VK_KHR_SHADER_FMA_SPEC_VERSION 1 +#define VK_KHR_SHADER_FMA_EXTENSION_NAME "VK_KHR_shader_fma" +typedef struct VkPhysicalDeviceShaderFmaFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderFmaFloat16; + VkBool32 shaderFmaFloat32; + VkBool32 shaderFmaFloat64; +} VkPhysicalDeviceShaderFmaFeaturesKHR; + + + +// VK_KHR_maintenance9 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance9 1 +#define VK_KHR_MAINTENANCE_9_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_9_EXTENSION_NAME "VK_KHR_maintenance9" + +typedef enum VkDefaultVertexAttributeValueKHR { + VK_DEFAULT_VERTEX_ATTRIBUTE_VALUE_ZERO_ZERO_ZERO_ZERO_KHR = 0, + VK_DEFAULT_VERTEX_ATTRIBUTE_VALUE_ZERO_ZERO_ZERO_ONE_KHR = 1, + VK_DEFAULT_VERTEX_ATTRIBUTE_VALUE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkDefaultVertexAttributeValueKHR; +typedef struct VkPhysicalDeviceMaintenance9FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 maintenance9; +} VkPhysicalDeviceMaintenance9FeaturesKHR; + +typedef struct VkPhysicalDeviceMaintenance9PropertiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 image2DViewOf3DSparse; + VkDefaultVertexAttributeValueKHR defaultVertexAttributeValue; +} VkPhysicalDeviceMaintenance9PropertiesKHR; + +typedef struct VkQueueFamilyOwnershipTransferPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t optimalImageTransferToQueueFamilies; +} VkQueueFamilyOwnershipTransferPropertiesKHR; + + + +// VK_KHR_video_maintenance2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_maintenance2 1 +#define VK_KHR_VIDEO_MAINTENANCE_2_SPEC_VERSION 1 +#define VK_KHR_VIDEO_MAINTENANCE_2_EXTENSION_NAME "VK_KHR_video_maintenance2" +typedef struct VkPhysicalDeviceVideoMaintenance2FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 videoMaintenance2; +} VkPhysicalDeviceVideoMaintenance2FeaturesKHR; + +typedef struct VkVideoDecodeH264InlineSessionParametersInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoH264SequenceParameterSet* pStdSPS; + const StdVideoH264PictureParameterSet* pStdPPS; +} VkVideoDecodeH264InlineSessionParametersInfoKHR; + +typedef struct VkVideoDecodeH265InlineSessionParametersInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoH265VideoParameterSet* pStdVPS; + const StdVideoH265SequenceParameterSet* pStdSPS; + const StdVideoH265PictureParameterSet* pStdPPS; +} VkVideoDecodeH265InlineSessionParametersInfoKHR; + +typedef struct VkVideoDecodeAV1InlineSessionParametersInfoKHR { + VkStructureType sType; + const void* pNext; + const StdVideoAV1SequenceHeader* pStdSequenceHeader; +} VkVideoDecodeAV1InlineSessionParametersInfoKHR; + + + +// VK_KHR_video_encode_feedback2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_video_encode_feedback2 1 +#define VK_KHR_VIDEO_ENCODE_FEEDBACK_2_SPEC_VERSION 1 +#define VK_KHR_VIDEO_ENCODE_FEEDBACK_2_EXTENSION_NAME "VK_KHR_video_encode_feedback2" + +typedef enum VkVideoEncodePerPartitionFeedbackFlagBitsKHR { + VK_VIDEO_ENCODE_PER_PARTITION_FEEDBACK_STATUS_BIT_KHR = 0x00000001, + VK_VIDEO_ENCODE_PER_PARTITION_FEEDBACK_BITSTREAM_BUFFER_OFFSET_BIT_KHR = 0x00000002, + VK_VIDEO_ENCODE_PER_PARTITION_FEEDBACK_BITSTREAM_BYTES_WRITTEN_BIT_KHR = 0x00000004, + VK_VIDEO_ENCODE_PER_PARTITION_FEEDBACK_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkVideoEncodePerPartitionFeedbackFlagBitsKHR; +typedef VkFlags VkVideoEncodePerPartitionFeedbackFlagsKHR; +typedef struct VkPhysicalDeviceVideoEncodeFeedback2FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 videoEncodeFeedback2; +} VkPhysicalDeviceVideoEncodeFeedback2FeaturesKHR; + +typedef struct VkVideoEncodeFeedback2CapabilitiesKHR { + VkStructureType sType; + void* pNext; + uint32_t maxPerPartitionFeedbackEntries; + VkVideoEncodePerPartitionFeedbackFlagsKHR supportedPerPartitionEncodeFeedbackFlags; +} VkVideoEncodeFeedback2CapabilitiesKHR; + +typedef struct VkQueryPoolVideoEncodePerPartitionFeedbackCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t maxPerPartitionFeedbackEntries; + VkVideoEncodePerPartitionFeedbackFlagsKHR perPartitionEncodeFeedbackFlags; +} VkQueryPoolVideoEncodePerPartitionFeedbackCreateInfoKHR; + + + +// VK_KHR_depth_clamp_zero_one is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_depth_clamp_zero_one 1 +#define VK_KHR_DEPTH_CLAMP_ZERO_ONE_SPEC_VERSION 1 +#define VK_KHR_DEPTH_CLAMP_ZERO_ONE_EXTENSION_NAME "VK_KHR_depth_clamp_zero_one" +typedef struct VkPhysicalDeviceDepthClampZeroOneFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 depthClampZeroOne; +} VkPhysicalDeviceDepthClampZeroOneFeaturesKHR; + + + +// VK_KHR_robustness2 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_robustness2 1 +#define VK_KHR_ROBUSTNESS_2_SPEC_VERSION 1 +#define VK_KHR_ROBUSTNESS_2_EXTENSION_NAME "VK_KHR_robustness2" +typedef struct VkPhysicalDeviceRobustness2FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 robustBufferAccess2; + VkBool32 robustImageAccess2; + VkBool32 nullDescriptor; +} VkPhysicalDeviceRobustness2FeaturesKHR; + +typedef struct VkPhysicalDeviceRobustness2PropertiesKHR { + VkStructureType sType; + void* pNext; + VkDeviceSize robustStorageBufferAccessSizeAlignment; + VkDeviceSize robustUniformBufferAccessSizeAlignment; +} VkPhysicalDeviceRobustness2PropertiesKHR; + + + +// VK_KHR_present_mode_fifo_latest_ready is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_present_mode_fifo_latest_ready 1 +#define VK_KHR_PRESENT_MODE_FIFO_LATEST_READY_SPEC_VERSION 1 +#define VK_KHR_PRESENT_MODE_FIFO_LATEST_READY_EXTENSION_NAME "VK_KHR_present_mode_fifo_latest_ready" +typedef struct VkPhysicalDevicePresentModeFifoLatestReadyFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 presentModeFifoLatestReady; +} VkPhysicalDevicePresentModeFifoLatestReadyFeaturesKHR; + + + +// VK_KHR_opacity_micromap is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_opacity_micromap 1 +#define VK_KHR_OPACITY_MICROMAP_SPEC_VERSION 1 +#define VK_KHR_OPACITY_MICROMAP_EXTENSION_NAME "VK_KHR_opacity_micromap" + +typedef enum VkOpacityMicromapFormatKHR { + VK_OPACITY_MICROMAP_FORMAT_2_STATE_KHR = 1, + VK_OPACITY_MICROMAP_FORMAT_4_STATE_KHR = 2, + VK_OPACITY_MICROMAP_FORMAT_2_STATE_EXT = VK_OPACITY_MICROMAP_FORMAT_2_STATE_KHR, + VK_OPACITY_MICROMAP_FORMAT_4_STATE_EXT = VK_OPACITY_MICROMAP_FORMAT_4_STATE_KHR, + VK_OPACITY_MICROMAP_FORMAT_MAX_ENUM_KHR = 0x7FFFFFFF +} VkOpacityMicromapFormatKHR; + +typedef enum VkOpacityMicromapSpecialIndexKHR { + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_TRANSPARENT_KHR = -1, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_OPAQUE_KHR = -2, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_TRANSPARENT_KHR = -3, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_OPAQUE_KHR = -4, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_CLUSTER_GEOMETRY_DISABLE_OPACITY_MICROMAP_NV = -5, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_TRANSPARENT_EXT = VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_TRANSPARENT_KHR, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_OPAQUE_EXT = VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_OPAQUE_KHR, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_TRANSPARENT_EXT = VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_TRANSPARENT_KHR, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_OPAQUE_EXT = VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_OPAQUE_KHR, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_MAX_ENUM_KHR = 0x7FFFFFFF +} VkOpacityMicromapSpecialIndexKHR; + +typedef enum VkAccelerationStructureSerializedBlockTypeKHR { + VK_ACCELERATION_STRUCTURE_SERIALIZED_BLOCK_TYPE_OPACITY_MICROMAP_KHR = 0, + VK_ACCELERATION_STRUCTURE_SERIALIZED_BLOCK_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureSerializedBlockTypeKHR; +typedef struct VkMicromapUsageKHR { + uint32_t count; + uint32_t subdivisionLevel; + VkOpacityMicromapFormatKHR format; +} VkMicromapUsageKHR; + +typedef struct VkAccelerationStructureGeometryMicromapDataKHR { + VkStructureType sType; + const void* pNext; + uint32_t usageCountsCount; + const VkMicromapUsageKHR* pUsageCounts; + const VkMicromapUsageKHR* const* ppUsageCounts; + VkDeviceAddress data; + VkDeviceAddress triangleArray; + VkDeviceSize triangleArrayStride; +} VkAccelerationStructureGeometryMicromapDataKHR; + +typedef struct VkPhysicalDeviceOpacityMicromapFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 micromap; +} VkPhysicalDeviceOpacityMicromapFeaturesKHR; + +typedef struct VkPhysicalDeviceOpacityMicromapPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t maxOpacity2StateSubdivisionLevel; + uint32_t maxOpacity4StateSubdivisionLevel; + uint32_t maxOpacityLossy4StateSubdivisionLevel; + uint64_t maxMicromapTriangles; +} VkPhysicalDeviceOpacityMicromapPropertiesKHR; + +typedef struct VkMicromapTriangleKHR { + uint32_t dataOffset; + uint16_t subdivisionLevel; + uint16_t format; +} VkMicromapTriangleKHR; + +typedef struct VkAccelerationStructureTrianglesOpacityMicromapKHR { + VkStructureType sType; + void* pNext; + VkIndexType indexType; + VkDeviceAddress indexBuffer; + VkDeviceSize indexStride; + uint32_t baseTriangle; + VkAccelerationStructureKHR micromap; +} VkAccelerationStructureTrianglesOpacityMicromapKHR; + + + +// VK_KHR_maintenance10 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance10 1 +#define VK_KHR_MAINTENANCE_10_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_10_EXTENSION_NAME "VK_KHR_maintenance10" + +typedef enum VkRenderingAttachmentFlagBitsKHR { + VK_RENDERING_ATTACHMENT_INPUT_ATTACHMENT_FEEDBACK_BIT_KHR = 0x00000001, + VK_RENDERING_ATTACHMENT_RESOLVE_SKIP_TRANSFER_FUNCTION_BIT_KHR = 0x00000002, + VK_RENDERING_ATTACHMENT_RESOLVE_ENABLE_TRANSFER_FUNCTION_BIT_KHR = 0x00000004, + VK_RENDERING_ATTACHMENT_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkRenderingAttachmentFlagBitsKHR; +typedef VkFlags VkRenderingAttachmentFlagsKHR; + +typedef enum VkResolveImageFlagBitsKHR { + VK_RESOLVE_IMAGE_SKIP_TRANSFER_FUNCTION_BIT_KHR = 0x00000001, + VK_RESOLVE_IMAGE_ENABLE_TRANSFER_FUNCTION_BIT_KHR = 0x00000002, + VK_RESOLVE_IMAGE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkResolveImageFlagBitsKHR; +typedef VkFlags VkResolveImageFlagsKHR; +typedef struct VkPhysicalDeviceMaintenance10FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 maintenance10; +} VkPhysicalDeviceMaintenance10FeaturesKHR; + +typedef struct VkPhysicalDeviceMaintenance10PropertiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 rgba4OpaqueBlackSwizzled; + VkBool32 resolveSrgbFormatAppliesTransferFunction; + VkBool32 resolveSrgbFormatSupportsTransferFunctionControl; +} VkPhysicalDeviceMaintenance10PropertiesKHR; + +typedef struct VkRenderingEndInfoKHR { + VkStructureType sType; + const void* pNext; +} VkRenderingEndInfoKHR; + +typedef struct VkRenderingAttachmentFlagsInfoKHR { + VkStructureType sType; + const void* pNext; + VkRenderingAttachmentFlagsKHR flags; +} VkRenderingAttachmentFlagsInfoKHR; + +typedef struct VkResolveImageModeInfoKHR { + VkStructureType sType; + const void* pNext; + VkResolveImageFlagsKHR flags; + VkResolveModeFlagBits resolveMode; + VkResolveModeFlagBits stencilResolveMode; +} VkResolveImageModeInfoKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdEndRendering2KHR)(VkCommandBuffer commandBuffer, const VkRenderingEndInfoKHR* pRenderingEndInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdEndRendering2KHR( + VkCommandBuffer commandBuffer, + const VkRenderingEndInfoKHR* pRenderingEndInfo); +#endif +#endif + + +// VK_KHR_maintenance11 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_maintenance11 1 +#define VK_KHR_MAINTENANCE_11_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_11_EXTENSION_NAME "VK_KHR_maintenance11" +typedef struct VkPhysicalDeviceMaintenance11FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 maintenance11; +} VkPhysicalDeviceMaintenance11FeaturesKHR; + +typedef struct VkQueueFamilyOptimalImageTransferGranularityPropertiesKHR { + VkStructureType sType; + void* pNext; + VkExtent3D optimalImageTransferGranularity; +} VkQueueFamilyOptimalImageTransferGranularityPropertiesKHR; + + + +// VK_KHR_extended_flags is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_extended_flags 1 +#define VK_KHR_EXTENDED_FLAGS_SPEC_VERSION 1 +#define VK_KHR_EXTENDED_FLAGS_EXTENSION_NAME "VK_KHR_extended_flags" +typedef VkFlags64 VkFormatFeatureFlags4KHR; + +// Flag bits for VkFormatFeatureFlagBits4KHR +typedef VkFlags64 VkFormatFeatureFlagBits4KHR; + +typedef VkFlags64 VkImageUsageFlags2KHR; + +// Flag bits for VkImageUsageFlagBits2KHR +typedef VkFlags64 VkImageUsageFlagBits2KHR; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_TRANSFER_SRC_BIT_KHR = 0x00000001ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_TRANSFER_DST_BIT_KHR = 0x00000002ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_SAMPLED_BIT_KHR = 0x00000004ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_STORAGE_BIT_KHR = 0x00000008ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_COLOR_ATTACHMENT_BIT_KHR = 0x00000010ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_DEPTH_STENCIL_ATTACHMENT_BIT_KHR = 0x00000020ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_TRANSIENT_ATTACHMENT_BIT_KHR = 0x00000040ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_INPUT_ATTACHMENT_BIT_KHR = 0x00000080ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00000100ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x00000200ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_VIDEO_DECODE_DST_BIT_KHR = 0x00000400ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_VIDEO_DECODE_SRC_BIT_KHR = 0x00000800ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_VIDEO_DECODE_DPB_BIT_KHR = 0x00001000ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_VIDEO_ENCODE_DST_BIT_KHR = 0x00002000ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_VIDEO_ENCODE_SRC_BIT_KHR = 0x00004000ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_VIDEO_ENCODE_DPB_BIT_KHR = 0x00008000ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_INVOCATION_MASK_BIT_HUAWEI = 0x00040000ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x00080000ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_SAMPLE_WEIGHT_BIT_QCOM = 0x00100000ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_SAMPLE_BLOCK_MATCH_BIT_QCOM = 0x00200000ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_HOST_TRANSFER_BIT_KHR = 0x00400000ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_TENSOR_ALIASING_BIT_ARM = 0x00800000ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_VIDEO_ENCODE_QUANTIZATION_DELTA_MAP_BIT_KHR = 0x02000000ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_VIDEO_ENCODE_EMPHASIS_MAP_BIT_KHR = 0x04000000ULL; +static const VkImageUsageFlagBits2KHR VK_IMAGE_USAGE_2_TILE_MEMORY_BIT_QCOM = 0x08000000ULL; + +typedef VkFlags64 VkImageCreateFlags2KHR; + +// Flag bits for VkImageCreateFlagBits2KHR +typedef VkFlags64 VkImageCreateFlagBits2KHR; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_SPARSE_BINDING_BIT_KHR = 0x00000001ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_SPARSE_RESIDENCY_BIT_KHR = 0x00000002ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_SPARSE_ALIASED_BIT_KHR = 0x00000004ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_MUTABLE_FORMAT_BIT_KHR = 0x00000008ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_CUBE_COMPATIBLE_BIT_KHR = 0x00000010ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_ALIAS_SINGLE_LAYER_DESCRIPTOR_BIT_KHR = 0x00400000ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_2D_ARRAY_COMPATIBLE_BIT_KHR = 0x00000020ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = 0x00000040ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR = 0x00000080ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_EXTENDED_USAGE_BIT_KHR = 0x00000100ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_DISJOINT_BIT_KHR = 0x00000200ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_ALIAS_BIT_KHR = 0x00000400ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_PROTECTED_BIT_KHR = 0x00000800ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_CORNER_SAMPLED_BIT_NV = 0x00002000ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_SUBSAMPLED_BIT_EXT = 0x00004000ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_FRAGMENT_DENSITY_MAP_OFFSET_BIT_EXT = 0x00008000ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 0x00010000ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_2D_VIEW_COMPATIBLE_BIT_EXT = 0x00020000ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT = 0x00040000ULL; +static const VkImageCreateFlagBits2KHR VK_IMAGE_CREATE_2_VIDEO_PROFILE_INDEPENDENT_BIT_KHR = 0x00100000ULL; + +typedef struct VkFormatProperties4KHR { + VkStructureType sType; + void* pNext; + VkFormatFeatureFlags4KHR linearTilingFeatures; + VkFormatFeatureFlags4KHR optimalTilingFeatures; + VkFormatFeatureFlags4KHR bufferFeatures; +} VkFormatProperties4KHR; + +typedef struct VkImageUsageFlags2CreateInfoKHR { + VkStructureType sType; + void* pNext; + VkImageUsageFlags2KHR usage; +} VkImageUsageFlags2CreateInfoKHR; + +typedef struct VkImageCreateFlags2CreateInfoKHR { + VkStructureType sType; + void* pNext; + VkImageCreateFlags2KHR flags; +} VkImageCreateFlags2CreateInfoKHR; + +typedef struct VkImageViewUsage2CreateInfoKHR { + VkStructureType sType; + void* pNext; + VkImageUsageFlags2KHR usage; +} VkImageViewUsage2CreateInfoKHR; + +typedef struct VkPhysicalDeviceExtendedFlagsFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 extendedFlags; +} VkPhysicalDeviceExtendedFlagsFeaturesKHR; + +typedef struct VkImageStencilUsage2CreateInfoKHR { + VkStructureType sType; + void* pNext; + VkImageUsageFlags2KHR stencilUsage; +} VkImageStencilUsage2CreateInfoKHR; + +typedef struct VkSharedPresentSurfaceCapabilities2KHR { + VkStructureType sType; + void* pNext; + VkImageUsageFlags2KHR sharedPresentSupportedUsageFlags; +} VkSharedPresentSurfaceCapabilities2KHR; + + + +// VK_EXT_debug_report is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_debug_report 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) +#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 10 +#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" + +typedef enum VkDebugReportObjectTypeEXT { + VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0, + VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1, + VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2, + VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3, + VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4, + VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5, + VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6, + VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7, + VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9, + VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10, + VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11, + VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13, + VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14, + VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17, + VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20, + VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23, + VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24, + VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25, + VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26, + VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27, + VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT = 28, + VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29, + VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30, + VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33, + VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000, + VK_DEBUG_REPORT_OBJECT_TYPE_CU_MODULE_NVX_EXT = 1000029000, + VK_DEBUG_REPORT_OBJECT_TYPE_CU_FUNCTION_NVX_EXT = 1000029001, + VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT = 1000150000, + VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000, + VK_DEBUG_REPORT_OBJECT_TYPE_CUDA_MODULE_NV_EXT = 1000307000, + VK_DEBUG_REPORT_OBJECT_TYPE_CUDA_FUNCTION_NV_EXT = 1000307001, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA_EXT = 1000366000, + // VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT is a legacy alias + VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT, + // VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT is a legacy alias + VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugReportObjectTypeEXT; + +typedef enum VkDebugReportFlagBitsEXT { + VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001, + VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002, + VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004, + VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008, + VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010, + VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugReportFlagBitsEXT; +typedef VkFlags VkDebugReportFlagsEXT; +typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)( + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage, + void* pUserData); + +typedef struct VkDebugReportCallbackCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDebugReportFlagsEXT flags; + PFN_vkDebugReportCallbackEXT pfnCallback; + void* pUserData; +} VkDebugReportCallbackCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback); +typedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT( + VkInstance instance, + const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDebugReportCallbackEXT* pCallback); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT( + VkInstance instance, + VkDebugReportCallbackEXT callback, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT( + VkInstance instance, + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage); +#endif +#endif + + +// VK_NV_glsl_shader is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_glsl_shader 1 +#define VK_NV_GLSL_SHADER_SPEC_VERSION 1 +#define VK_NV_GLSL_SHADER_EXTENSION_NAME "VK_NV_glsl_shader" + + +// VK_EXT_depth_range_unrestricted is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_depth_range_unrestricted 1 +#define VK_EXT_DEPTH_RANGE_UNRESTRICTED_SPEC_VERSION 1 +#define VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME "VK_EXT_depth_range_unrestricted" + + +// VK_IMG_filter_cubic is a preprocessor guard. Do not pass it to API calls. +#define VK_IMG_filter_cubic 1 +#define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1 +#define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic" + + +// VK_AMD_rasterization_order is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_rasterization_order 1 +#define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1 +#define VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME "VK_AMD_rasterization_order" + +typedef enum VkRasterizationOrderAMD { + VK_RASTERIZATION_ORDER_STRICT_AMD = 0, + VK_RASTERIZATION_ORDER_RELAXED_AMD = 1, + VK_RASTERIZATION_ORDER_MAX_ENUM_AMD = 0x7FFFFFFF +} VkRasterizationOrderAMD; +typedef struct VkPipelineRasterizationStateRasterizationOrderAMD { + VkStructureType sType; + const void* pNext; + VkRasterizationOrderAMD rasterizationOrder; +} VkPipelineRasterizationStateRasterizationOrderAMD; + + + +// VK_AMD_shader_trinary_minmax is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_trinary_minmax 1 +#define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1 +#define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax" + + +// VK_AMD_shader_explicit_vertex_parameter is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_explicit_vertex_parameter 1 +#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1 +#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter" + + +// VK_EXT_debug_marker is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_debug_marker 1 +#define VK_EXT_DEBUG_MARKER_SPEC_VERSION 4 +#define VK_EXT_DEBUG_MARKER_EXTENSION_NAME "VK_EXT_debug_marker" +typedef struct VkDebugMarkerObjectNameInfoEXT { + VkStructureType sType; + const void* pNext; + VkDebugReportObjectTypeEXT objectType; + uint64_t object; + const char* pObjectName; +} VkDebugMarkerObjectNameInfoEXT; + +typedef struct VkDebugMarkerObjectTagInfoEXT { + VkStructureType sType; + const void* pNext; + VkDebugReportObjectTypeEXT objectType; + uint64_t object; + uint64_t tagName; + size_t tagSize; + const void* pTag; +} VkDebugMarkerObjectTagInfoEXT; + +typedef struct VkDebugMarkerMarkerInfoEXT { + VkStructureType sType; + const void* pNext; + const char* pMarkerName; + float color[4]; +} VkDebugMarkerMarkerInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectTagEXT)(VkDevice device, const VkDebugMarkerObjectTagInfoEXT* pTagInfo); +typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectNameEXT)(VkDevice device, const VkDebugMarkerObjectNameInfoEXT* pNameInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerEndEXT)(VkCommandBuffer commandBuffer); +typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectTagEXT( + VkDevice device, + const VkDebugMarkerObjectTagInfoEXT* pTagInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectNameEXT( + VkDevice device, + const VkDebugMarkerObjectNameInfoEXT* pNameInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerBeginEXT( + VkCommandBuffer commandBuffer, + const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerEndEXT( + VkCommandBuffer commandBuffer); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerInsertEXT( + VkCommandBuffer commandBuffer, + const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); +#endif +#endif + + +// VK_AMD_gcn_shader is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_gcn_shader 1 +#define VK_AMD_GCN_SHADER_SPEC_VERSION 1 +#define VK_AMD_GCN_SHADER_EXTENSION_NAME "VK_AMD_gcn_shader" + + +// VK_NV_dedicated_allocation is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_dedicated_allocation 1 +#define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1 +#define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation" +typedef struct VkDedicatedAllocationImageCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 dedicatedAllocation; +} VkDedicatedAllocationImageCreateInfoNV; + +typedef struct VkDedicatedAllocationBufferCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 dedicatedAllocation; +} VkDedicatedAllocationBufferCreateInfoNV; + +typedef struct VkDedicatedAllocationMemoryAllocateInfoNV { + VkStructureType sType; + const void* pNext; + VkImage image; + VkBuffer buffer; +} VkDedicatedAllocationMemoryAllocateInfoNV; + + + +// VK_EXT_transform_feedback is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_transform_feedback 1 +#define VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION 1 +#define VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME "VK_EXT_transform_feedback" +typedef VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT; +typedef struct VkPhysicalDeviceTransformFeedbackFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 transformFeedback; + VkBool32 geometryStreams; +} VkPhysicalDeviceTransformFeedbackFeaturesEXT; + +typedef struct VkPhysicalDeviceTransformFeedbackPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxTransformFeedbackStreams; + uint32_t maxTransformFeedbackBuffers; + VkDeviceSize maxTransformFeedbackBufferSize; + uint32_t maxTransformFeedbackStreamDataSize; + uint32_t maxTransformFeedbackBufferDataSize; + uint32_t maxTransformFeedbackBufferDataStride; + VkBool32 transformFeedbackQueries; + VkBool32 transformFeedbackStreamsLinesTriangles; + VkBool32 transformFeedbackRasterizationStreamSelect; + VkBool32 transformFeedbackDraw; +} VkPhysicalDeviceTransformFeedbackPropertiesEXT; + +typedef struct VkPipelineRasterizationStateStreamCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipelineRasterizationStateStreamCreateFlagsEXT flags; + uint32_t rasterizationStream; +} VkPipelineRasterizationStateStreamCreateInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdBindTransformFeedbackBuffersEXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets, const VkDeviceSize* pSizes); +typedef void (VKAPI_PTR *PFN_vkCmdBeginTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdEndTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdBeginQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags, uint32_t index); +typedef void (VKAPI_PTR *PFN_vkCmdEndQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, uint32_t index); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectByteCountEXT)(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, VkBuffer counterBuffer, VkDeviceSize counterBufferOffset, uint32_t counterOffset, uint32_t vertexStride); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindTransformFeedbackBuffersEXT( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets, + const VkDeviceSize* pSizes); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginTransformFeedbackEXT( + VkCommandBuffer commandBuffer, + uint32_t firstCounterBuffer, + uint32_t counterBufferCount, + const VkBuffer* pCounterBuffers, + const VkDeviceSize* pCounterBufferOffsets); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdEndTransformFeedbackEXT( + VkCommandBuffer commandBuffer, + uint32_t firstCounterBuffer, + uint32_t counterBufferCount, + const VkBuffer* pCounterBuffers, + const VkDeviceSize* pCounterBufferOffsets); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginQueryIndexedEXT( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + VkQueryControlFlags flags, + uint32_t index); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdEndQueryIndexedEXT( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + uint32_t index); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectByteCountEXT( + VkCommandBuffer commandBuffer, + uint32_t instanceCount, + uint32_t firstInstance, + VkBuffer counterBuffer, + VkDeviceSize counterBufferOffset, + uint32_t counterOffset, + uint32_t vertexStride); +#endif +#endif + + +// VK_NVX_binary_import is a preprocessor guard. Do not pass it to API calls. +#define VK_NVX_binary_import 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCuModuleNVX) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCuFunctionNVX) +#define VK_NVX_BINARY_IMPORT_SPEC_VERSION 2 +#define VK_NVX_BINARY_IMPORT_EXTENSION_NAME "VK_NVX_binary_import" +typedef struct VkCuModuleCreateInfoNVX { + VkStructureType sType; + const void* pNext; + size_t dataSize; + const void* pData; +} VkCuModuleCreateInfoNVX; + +typedef struct VkCuModuleTexturingModeCreateInfoNVX { + VkStructureType sType; + const void* pNext; + VkBool32 use64bitTexturing; +} VkCuModuleTexturingModeCreateInfoNVX; + +typedef struct VkCuFunctionCreateInfoNVX { + VkStructureType sType; + const void* pNext; + VkCuModuleNVX module; + const char* pName; +} VkCuFunctionCreateInfoNVX; + +typedef struct VkCuLaunchInfoNVX { + VkStructureType sType; + const void* pNext; + VkCuFunctionNVX function; + uint32_t gridDimX; + uint32_t gridDimY; + uint32_t gridDimZ; + uint32_t blockDimX; + uint32_t blockDimY; + uint32_t blockDimZ; + uint32_t sharedMemBytes; + size_t paramCount; + const void* const * pParams; + size_t extraCount; + const void* const * pExtras; +} VkCuLaunchInfoNVX; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateCuModuleNVX)(VkDevice device, const VkCuModuleCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCuModuleNVX* pModule); +typedef VkResult (VKAPI_PTR *PFN_vkCreateCuFunctionNVX)(VkDevice device, const VkCuFunctionCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCuFunctionNVX* pFunction); +typedef void (VKAPI_PTR *PFN_vkDestroyCuModuleNVX)(VkDevice device, VkCuModuleNVX module, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkDestroyCuFunctionNVX)(VkDevice device, VkCuFunctionNVX function, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkCmdCuLaunchKernelNVX)(VkCommandBuffer commandBuffer, const VkCuLaunchInfoNVX* pLaunchInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateCuModuleNVX( + VkDevice device, + const VkCuModuleCreateInfoNVX* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkCuModuleNVX* pModule); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateCuFunctionNVX( + VkDevice device, + const VkCuFunctionCreateInfoNVX* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkCuFunctionNVX* pFunction); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyCuModuleNVX( + VkDevice device, + VkCuModuleNVX module, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyCuFunctionNVX( + VkDevice device, + VkCuFunctionNVX function, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCuLaunchKernelNVX( + VkCommandBuffer commandBuffer, + const VkCuLaunchInfoNVX* pLaunchInfo); +#endif +#endif + + +// VK_NVX_image_view_handle is a preprocessor guard. Do not pass it to API calls. +#define VK_NVX_image_view_handle 1 +#define VK_NVX_IMAGE_VIEW_HANDLE_SPEC_VERSION 4 +#define VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME "VK_NVX_image_view_handle" +typedef struct VkImageViewHandleInfoNVX { + VkStructureType sType; + const void* pNext; + VkImageView imageView; + VkDescriptorType descriptorType; + VkSampler sampler; +} VkImageViewHandleInfoNVX; + +typedef struct VkImageViewAddressPropertiesNVX { + VkStructureType sType; + void* pNext; + VkDeviceAddress deviceAddress; + VkDeviceSize size; +} VkImageViewAddressPropertiesNVX; + +typedef uint32_t (VKAPI_PTR *PFN_vkGetImageViewHandleNVX)(VkDevice device, const VkImageViewHandleInfoNVX* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetImageViewHandle64NVX)(VkDevice device, const VkImageViewHandleInfoNVX* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetImageViewAddressNVX)(VkDevice device, VkImageView imageView, VkImageViewAddressPropertiesNVX* pProperties); +typedef uint64_t (VKAPI_PTR *PFN_vkGetDeviceCombinedImageSamplerIndexNVX)(VkDevice device, uint64_t imageViewIndex, uint64_t samplerIndex); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR uint32_t VKAPI_CALL vkGetImageViewHandleNVX( + VkDevice device, + const VkImageViewHandleInfoNVX* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR uint64_t VKAPI_CALL vkGetImageViewHandle64NVX( + VkDevice device, + const VkImageViewHandleInfoNVX* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetImageViewAddressNVX( + VkDevice device, + VkImageView imageView, + VkImageViewAddressPropertiesNVX* pProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR uint64_t VKAPI_CALL vkGetDeviceCombinedImageSamplerIndexNVX( + VkDevice device, + uint64_t imageViewIndex, + uint64_t samplerIndex); +#endif +#endif + + +// VK_AMD_draw_indirect_count is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_draw_indirect_count 1 +#define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 2 +#define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count" +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountAMD( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountAMD( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); +#endif +#endif + + +// VK_AMD_negative_viewport_height is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_negative_viewport_height 1 +#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1 +#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME "VK_AMD_negative_viewport_height" + + +// VK_AMD_gpu_shader_half_float is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_gpu_shader_half_float 1 +#define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 2 +#define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME "VK_AMD_gpu_shader_half_float" + + +// VK_AMD_shader_ballot is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_ballot 1 +#define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1 +#define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot" + + +// VK_AMD_texture_gather_bias_lod is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_texture_gather_bias_lod 1 +#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_SPEC_VERSION 1 +#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME "VK_AMD_texture_gather_bias_lod" +typedef struct VkTextureLODGatherFormatPropertiesAMD { + VkStructureType sType; + void* pNext; + VkBool32 supportsTextureGatherLODBiasAMD; +} VkTextureLODGatherFormatPropertiesAMD; + + + +// VK_AMD_shader_info is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_info 1 +#define VK_AMD_SHADER_INFO_SPEC_VERSION 1 +#define VK_AMD_SHADER_INFO_EXTENSION_NAME "VK_AMD_shader_info" + +typedef enum VkShaderInfoTypeAMD { + VK_SHADER_INFO_TYPE_STATISTICS_AMD = 0, + VK_SHADER_INFO_TYPE_BINARY_AMD = 1, + VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD = 2, + VK_SHADER_INFO_TYPE_MAX_ENUM_AMD = 0x7FFFFFFF +} VkShaderInfoTypeAMD; +typedef struct VkShaderResourceUsageAMD { + uint32_t numUsedVgprs; + uint32_t numUsedSgprs; + uint32_t ldsSizePerLocalWorkGroup; + size_t ldsUsageSizeInBytes; + size_t scratchMemUsageInBytes; +} VkShaderResourceUsageAMD; + +typedef struct VkShaderStatisticsInfoAMD { + VkShaderStageFlags shaderStageMask; + VkShaderResourceUsageAMD resourceUsage; + uint32_t numPhysicalVgprs; + uint32_t numPhysicalSgprs; + uint32_t numAvailableVgprs; + uint32_t numAvailableSgprs; + uint32_t computeWorkGroupSize[3]; +} VkShaderStatisticsInfoAMD; + +typedef VkResult (VKAPI_PTR *PFN_vkGetShaderInfoAMD)(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits shaderStage, VkShaderInfoTypeAMD infoType, size_t* pInfoSize, void* pInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetShaderInfoAMD( + VkDevice device, + VkPipeline pipeline, + VkShaderStageFlagBits shaderStage, + VkShaderInfoTypeAMD infoType, + size_t* pInfoSize, + void* pInfo); +#endif +#endif + + +// VK_AMD_shader_image_load_store_lod is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_image_load_store_lod 1 +#define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_SPEC_VERSION 1 +#define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME "VK_AMD_shader_image_load_store_lod" + + +// VK_NV_corner_sampled_image is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_corner_sampled_image 1 +#define VK_NV_CORNER_SAMPLED_IMAGE_SPEC_VERSION 2 +#define VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME "VK_NV_corner_sampled_image" +typedef struct VkPhysicalDeviceCornerSampledImageFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 cornerSampledImage; +} VkPhysicalDeviceCornerSampledImageFeaturesNV; + + + +// VK_IMG_format_pvrtc is a preprocessor guard. Do not pass it to API calls. +#define VK_IMG_format_pvrtc 1 +#define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1 +#define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc" + + +// VK_NV_external_memory_capabilities is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_external_memory_capabilities 1 +#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 +#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_NV_external_memory_capabilities" + +typedef enum VkExternalMemoryHandleTypeFlagBitsNV { + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkExternalMemoryHandleTypeFlagBitsNV; +typedef VkFlags VkExternalMemoryHandleTypeFlagsNV; + +typedef enum VkExternalMemoryFeatureFlagBitsNV { + VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 0x00000001, + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 0x00000002, + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004, + VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkExternalMemoryFeatureFlagBitsNV; +typedef VkFlags VkExternalMemoryFeatureFlagsNV; +typedef struct VkExternalImageFormatPropertiesNV { + VkImageFormatProperties imageFormatProperties; + VkExternalMemoryFeatureFlagsNV externalMemoryFeatures; + VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes; + VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes; +} VkExternalImageFormatPropertiesNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkExternalMemoryHandleTypeFlagsNV externalHandleType, VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceExternalImageFormatPropertiesNV( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags flags, + VkExternalMemoryHandleTypeFlagsNV externalHandleType, + VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties); +#endif +#endif + + +// VK_NV_external_memory is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_external_memory 1 +#define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1 +#define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME "VK_NV_external_memory" +typedef struct VkExternalMemoryImageCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagsNV handleTypes; +} VkExternalMemoryImageCreateInfoNV; + +typedef struct VkExportMemoryAllocateInfoNV { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagsNV handleTypes; +} VkExportMemoryAllocateInfoNV; + + + +// VK_EXT_validation_flags is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_validation_flags 1 +#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 3 +#define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags" + +typedef enum VkValidationCheckEXT { + VK_VALIDATION_CHECK_ALL_EXT = 0, + VK_VALIDATION_CHECK_SHADERS_EXT = 1, + VK_VALIDATION_CHECK_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationCheckEXT; +typedef struct VkValidationFlagsEXT { + VkStructureType sType; + const void* pNext; + uint32_t disabledValidationCheckCount; + const VkValidationCheckEXT* pDisabledValidationChecks; +} VkValidationFlagsEXT; + + + +// VK_EXT_shader_subgroup_ballot is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_subgroup_ballot 1 +#define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1 +#define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot" + + +// VK_EXT_shader_subgroup_vote is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_subgroup_vote 1 +#define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1 +#define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote" + + +// VK_EXT_texture_compression_astc_hdr is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_texture_compression_astc_hdr 1 +#define VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_SPEC_VERSION 1 +#define VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME "VK_EXT_texture_compression_astc_hdr" +typedef VkPhysicalDeviceTextureCompressionASTCHDRFeatures VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT; + + + +// VK_EXT_astc_decode_mode is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_astc_decode_mode 1 +#define VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION 1 +#define VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME "VK_EXT_astc_decode_mode" +typedef struct VkImageViewASTCDecodeModeEXT { + VkStructureType sType; + const void* pNext; + VkFormat decodeMode; +} VkImageViewASTCDecodeModeEXT; + +typedef struct VkPhysicalDeviceASTCDecodeFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 decodeModeSharedExponent; +} VkPhysicalDeviceASTCDecodeFeaturesEXT; + + + +// VK_EXT_pipeline_robustness is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_pipeline_robustness 1 +#define VK_EXT_PIPELINE_ROBUSTNESS_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_ROBUSTNESS_EXTENSION_NAME "VK_EXT_pipeline_robustness" +typedef VkPipelineRobustnessBufferBehavior VkPipelineRobustnessBufferBehaviorEXT; + +typedef VkPipelineRobustnessImageBehavior VkPipelineRobustnessImageBehaviorEXT; + +typedef VkPhysicalDevicePipelineRobustnessFeatures VkPhysicalDevicePipelineRobustnessFeaturesEXT; + +typedef VkPhysicalDevicePipelineRobustnessProperties VkPhysicalDevicePipelineRobustnessPropertiesEXT; + +typedef VkPipelineRobustnessCreateInfo VkPipelineRobustnessCreateInfoEXT; + + + +// VK_EXT_conditional_rendering is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_conditional_rendering 1 +#define VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION 2 +#define VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME "VK_EXT_conditional_rendering" +typedef struct VkConditionalRenderingBeginInfoEXT { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; + VkDeviceSize offset; + VkConditionalRenderingFlagsEXT flags; +} VkConditionalRenderingBeginInfoEXT; + +typedef struct VkPhysicalDeviceConditionalRenderingFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 conditionalRendering; + VkBool32 inheritedConditionalRendering; +} VkPhysicalDeviceConditionalRenderingFeaturesEXT; + +typedef struct VkCommandBufferInheritanceConditionalRenderingInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 conditionalRenderingEnable; +} VkCommandBufferInheritanceConditionalRenderingInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdBeginConditionalRenderingEXT)(VkCommandBuffer commandBuffer, const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin); +typedef void (VKAPI_PTR *PFN_vkCmdEndConditionalRenderingEXT)(VkCommandBuffer commandBuffer); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginConditionalRenderingEXT( + VkCommandBuffer commandBuffer, + const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdEndConditionalRenderingEXT( + VkCommandBuffer commandBuffer); +#endif +#endif + + +// VK_NV_clip_space_w_scaling is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_clip_space_w_scaling 1 +#define VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION 1 +#define VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME "VK_NV_clip_space_w_scaling" +typedef struct VkViewportWScalingNV { + float xcoeff; + float ycoeff; +} VkViewportWScalingNV; + +typedef struct VkPipelineViewportWScalingStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 viewportWScalingEnable; + uint32_t viewportCount; + const VkViewportWScalingNV* pViewportWScalings; +} VkPipelineViewportWScalingStateCreateInfoNV; + +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWScalingNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportWScalingNV* pViewportWScalings); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWScalingNV( + VkCommandBuffer commandBuffer, + uint32_t firstViewport, + uint32_t viewportCount, + const VkViewportWScalingNV* pViewportWScalings); +#endif +#endif + + +// VK_EXT_direct_mode_display is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_direct_mode_display 1 +#define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1 +#define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME "VK_EXT_direct_mode_display" +typedef VkResult (VKAPI_PTR *PFN_vkReleaseDisplayEXT)(VkPhysicalDevice physicalDevice, VkDisplayKHR display); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkReleaseDisplayEXT( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display); +#endif +#endif + + +// VK_EXT_display_surface_counter is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_display_surface_counter 1 +#define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1 +#define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter" + +typedef enum VkSurfaceCounterFlagBitsEXT { + VK_SURFACE_COUNTER_VBLANK_BIT_EXT = 0x00000001, + // VK_SURFACE_COUNTER_VBLANK_EXT is a legacy alias + VK_SURFACE_COUNTER_VBLANK_EXT = VK_SURFACE_COUNTER_VBLANK_BIT_EXT, + VK_SURFACE_COUNTER_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkSurfaceCounterFlagBitsEXT; +typedef VkFlags VkSurfaceCounterFlagsEXT; +typedef struct VkSurfaceCapabilities2EXT { + VkStructureType sType; + void* pNext; + uint32_t minImageCount; + uint32_t maxImageCount; + VkExtent2D currentExtent; + VkExtent2D minImageExtent; + VkExtent2D maxImageExtent; + uint32_t maxImageArrayLayers; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkSurfaceTransformFlagBitsKHR currentTransform; + VkCompositeAlphaFlagsKHR supportedCompositeAlpha; + VkImageUsageFlags supportedUsageFlags; + VkSurfaceCounterFlagsEXT supportedSurfaceCounters; +} VkSurfaceCapabilities2EXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilities2EXT* pSurfaceCapabilities); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2EXT( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + VkSurfaceCapabilities2EXT* pSurfaceCapabilities); +#endif +#endif + + +// VK_EXT_display_control is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_display_control 1 +#define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1 +#define VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME "VK_EXT_display_control" + +typedef enum VkDisplayPowerStateEXT { + VK_DISPLAY_POWER_STATE_OFF_EXT = 0, + VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1, + VK_DISPLAY_POWER_STATE_ON_EXT = 2, + VK_DISPLAY_POWER_STATE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDisplayPowerStateEXT; + +typedef enum VkDeviceEventTypeEXT { + VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0, + VK_DEVICE_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceEventTypeEXT; + +typedef enum VkDisplayEventTypeEXT { + VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0, + VK_DISPLAY_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDisplayEventTypeEXT; +typedef struct VkDisplayPowerInfoEXT { + VkStructureType sType; + const void* pNext; + VkDisplayPowerStateEXT powerState; +} VkDisplayPowerInfoEXT; + +typedef struct VkDeviceEventInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceEventTypeEXT deviceEvent; +} VkDeviceEventInfoEXT; + +typedef struct VkDisplayEventInfoEXT { + VkStructureType sType; + const void* pNext; + VkDisplayEventTypeEXT displayEvent; +} VkDisplayEventInfoEXT; + +typedef struct VkSwapchainCounterCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkSurfaceCounterFlagsEXT surfaceCounters; +} VkSwapchainCounterCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkDisplayPowerControlEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayPowerInfoEXT* pDisplayPowerInfo); +typedef VkResult (VKAPI_PTR *PFN_vkRegisterDeviceEventEXT)(VkDevice device, const VkDeviceEventInfoEXT* pDeviceEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); +typedef VkResult (VKAPI_PTR *PFN_vkRegisterDisplayEventEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayEventInfoEXT* pDisplayEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); +typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainCounterEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSurfaceCounterFlagBitsEXT counter, uint64_t* pCounterValue); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkDisplayPowerControlEXT( + VkDevice device, + VkDisplayKHR display, + const VkDisplayPowerInfoEXT* pDisplayPowerInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDeviceEventEXT( + VkDevice device, + const VkDeviceEventInfoEXT* pDeviceEventInfo, + const VkAllocationCallbacks* pAllocator, + VkFence* pFence); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDisplayEventEXT( + VkDevice device, + VkDisplayKHR display, + const VkDisplayEventInfoEXT* pDisplayEventInfo, + const VkAllocationCallbacks* pAllocator, + VkFence* pFence); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainCounterEXT( + VkDevice device, + VkSwapchainKHR swapchain, + VkSurfaceCounterFlagBitsEXT counter, + uint64_t* pCounterValue); +#endif +#endif + + +// VK_GOOGLE_display_timing is a preprocessor guard. Do not pass it to API calls. +#define VK_GOOGLE_display_timing 1 +#define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1 +#define VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME "VK_GOOGLE_display_timing" +typedef struct VkRefreshCycleDurationGOOGLE { + uint64_t refreshDuration; +} VkRefreshCycleDurationGOOGLE; + +typedef struct VkPastPresentationTimingGOOGLE { + uint32_t presentID; + uint64_t desiredPresentTime; + uint64_t actualPresentTime; + uint64_t earliestPresentTime; + uint64_t presentMargin; +} VkPastPresentationTimingGOOGLE; + +typedef struct VkPresentTimeGOOGLE { + uint32_t presentID; + uint64_t desiredPresentTime; +} VkPresentTimeGOOGLE; + +typedef struct VkPresentTimesInfoGOOGLE { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const VkPresentTimeGOOGLE* pTimes; +} VkPresentTimesInfoGOOGLE; + +typedef VkResult (VKAPI_PTR *PFN_vkGetRefreshCycleDurationGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPastPresentationTimingGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetRefreshCycleDurationGOOGLE( + VkDevice device, + VkSwapchainKHR swapchain, + VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPastPresentationTimingGOOGLE( + VkDevice device, + VkSwapchainKHR swapchain, + uint32_t* pPresentationTimingCount, + VkPastPresentationTimingGOOGLE* pPresentationTimings); +#endif +#endif + + +// VK_NV_sample_mask_override_coverage is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_sample_mask_override_coverage 1 +#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_SPEC_VERSION 1 +#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME "VK_NV_sample_mask_override_coverage" + + +// VK_NV_geometry_shader_passthrough is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_geometry_shader_passthrough 1 +#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION 1 +#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME "VK_NV_geometry_shader_passthrough" + + +// VK_NV_viewport_array2 is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_viewport_array2 1 +#define VK_NV_VIEWPORT_ARRAY_2_SPEC_VERSION 1 +#define VK_NV_VIEWPORT_ARRAY_2_EXTENSION_NAME "VK_NV_viewport_array2" +// VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION is a legacy alias +#define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION VK_NV_VIEWPORT_ARRAY_2_SPEC_VERSION +// VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME is a legacy alias +#define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME VK_NV_VIEWPORT_ARRAY_2_EXTENSION_NAME + + +// VK_NVX_multiview_per_view_attributes is a preprocessor guard. Do not pass it to API calls. +#define VK_NVX_multiview_per_view_attributes 1 +#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_SPEC_VERSION 1 +#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME "VK_NVX_multiview_per_view_attributes" +typedef struct VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX { + VkStructureType sType; + void* pNext; + VkBool32 perViewPositionAllComponents; +} VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX; + +typedef struct VkMultiviewPerViewAttributesInfoNVX { + VkStructureType sType; + const void* pNext; + VkBool32 perViewAttributes; + VkBool32 perViewAttributesPositionXOnly; +} VkMultiviewPerViewAttributesInfoNVX; + + + +// VK_NV_viewport_swizzle is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_viewport_swizzle 1 +#define VK_NV_VIEWPORT_SWIZZLE_SPEC_VERSION 1 +#define VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME "VK_NV_viewport_swizzle" + +typedef enum VkViewportCoordinateSwizzleNV { + VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV = 0, + VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV = 1, + VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV = 2, + VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV = 3, + VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4, + VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5, + VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6, + VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7, + VK_VIEWPORT_COORDINATE_SWIZZLE_MAX_ENUM_NV = 0x7FFFFFFF +} VkViewportCoordinateSwizzleNV; +typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV; +typedef struct VkViewportSwizzleNV { + VkViewportCoordinateSwizzleNV x; + VkViewportCoordinateSwizzleNV y; + VkViewportCoordinateSwizzleNV z; + VkViewportCoordinateSwizzleNV w; +} VkViewportSwizzleNV; + +typedef struct VkPipelineViewportSwizzleStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineViewportSwizzleStateCreateFlagsNV flags; + uint32_t viewportCount; + const VkViewportSwizzleNV* pViewportSwizzles; +} VkPipelineViewportSwizzleStateCreateInfoNV; + + + +// VK_EXT_discard_rectangles is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_discard_rectangles 1 +#define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 2 +#define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles" + +typedef enum VkDiscardRectangleModeEXT { + VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT = 0, + VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1, + VK_DISCARD_RECTANGLE_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDiscardRectangleModeEXT; +typedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT; +typedef struct VkPhysicalDeviceDiscardRectanglePropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxDiscardRectangles; +} VkPhysicalDeviceDiscardRectanglePropertiesEXT; + +typedef struct VkPipelineDiscardRectangleStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipelineDiscardRectangleStateCreateFlagsEXT flags; + VkDiscardRectangleModeEXT discardRectangleMode; + uint32_t discardRectangleCount; + const VkRect2D* pDiscardRectangles; +} VkPipelineDiscardRectangleStateCreateInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetDiscardRectangleEXT)(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, const VkRect2D* pDiscardRectangles); +typedef void (VKAPI_PTR *PFN_vkCmdSetDiscardRectangleEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 discardRectangleEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDiscardRectangleModeEXT)(VkCommandBuffer commandBuffer, VkDiscardRectangleModeEXT discardRectangleMode); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDiscardRectangleEXT( + VkCommandBuffer commandBuffer, + uint32_t firstDiscardRectangle, + uint32_t discardRectangleCount, + const VkRect2D* pDiscardRectangles); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDiscardRectangleEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 discardRectangleEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDiscardRectangleModeEXT( + VkCommandBuffer commandBuffer, + VkDiscardRectangleModeEXT discardRectangleMode); +#endif +#endif + + +// VK_EXT_conservative_rasterization is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_conservative_rasterization 1 +#define VK_EXT_CONSERVATIVE_RASTERIZATION_SPEC_VERSION 1 +#define VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME "VK_EXT_conservative_rasterization" + +typedef enum VkConservativeRasterizationModeEXT { + VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT = 0, + VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT = 1, + VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT = 2, + VK_CONSERVATIVE_RASTERIZATION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkConservativeRasterizationModeEXT; +typedef VkFlags VkPipelineRasterizationConservativeStateCreateFlagsEXT; +typedef struct VkPhysicalDeviceConservativeRasterizationPropertiesEXT { + VkStructureType sType; + void* pNext; + float primitiveOverestimationSize; + float maxExtraPrimitiveOverestimationSize; + float extraPrimitiveOverestimationSizeGranularity; + VkBool32 primitiveUnderestimation; + VkBool32 conservativePointAndLineRasterization; + VkBool32 degenerateTrianglesRasterized; + VkBool32 degenerateLinesRasterized; + VkBool32 fullyCoveredFragmentShaderInputVariable; + VkBool32 conservativeRasterizationPostDepthCoverage; +} VkPhysicalDeviceConservativeRasterizationPropertiesEXT; + +typedef struct VkPipelineRasterizationConservativeStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipelineRasterizationConservativeStateCreateFlagsEXT flags; + VkConservativeRasterizationModeEXT conservativeRasterizationMode; + float extraPrimitiveOverestimationSize; +} VkPipelineRasterizationConservativeStateCreateInfoEXT; + + + +// VK_EXT_depth_clip_enable is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_depth_clip_enable 1 +#define VK_EXT_DEPTH_CLIP_ENABLE_SPEC_VERSION 1 +#define VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME "VK_EXT_depth_clip_enable" +typedef VkFlags VkPipelineRasterizationDepthClipStateCreateFlagsEXT; +typedef struct VkPhysicalDeviceDepthClipEnableFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 depthClipEnable; +} VkPhysicalDeviceDepthClipEnableFeaturesEXT; + +typedef struct VkPipelineRasterizationDepthClipStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipelineRasterizationDepthClipStateCreateFlagsEXT flags; + VkBool32 depthClipEnable; +} VkPipelineRasterizationDepthClipStateCreateInfoEXT; + + + +// VK_EXT_swapchain_colorspace is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_swapchain_colorspace 1 +#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 5 +#define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace" + + +// VK_EXT_hdr_metadata is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_hdr_metadata 1 +#define VK_EXT_HDR_METADATA_SPEC_VERSION 3 +#define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata" +typedef struct VkXYColorEXT { + float x; + float y; +} VkXYColorEXT; + +typedef struct VkHdrMetadataEXT { + VkStructureType sType; + const void* pNext; + VkXYColorEXT displayPrimaryRed; + VkXYColorEXT displayPrimaryGreen; + VkXYColorEXT displayPrimaryBlue; + VkXYColorEXT whitePoint; + float maxLuminance; + float minLuminance; + float maxContentLightLevel; + float maxFrameAverageLightLevel; +} VkHdrMetadataEXT; + +typedef void (VKAPI_PTR *PFN_vkSetHdrMetadataEXT)(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR* pSwapchains, const VkHdrMetadataEXT* pMetadata); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkSetHdrMetadataEXT( + VkDevice device, + uint32_t swapchainCount, + const VkSwapchainKHR* pSwapchains, + const VkHdrMetadataEXT* pMetadata); +#endif +#endif + + +// VK_IMG_relaxed_line_rasterization is a preprocessor guard. Do not pass it to API calls. +#define VK_IMG_relaxed_line_rasterization 1 +#define VK_IMG_RELAXED_LINE_RASTERIZATION_SPEC_VERSION 1 +#define VK_IMG_RELAXED_LINE_RASTERIZATION_EXTENSION_NAME "VK_IMG_relaxed_line_rasterization" +typedef struct VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG { + VkStructureType sType; + void* pNext; + VkBool32 relaxedLineRasterization; +} VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG; + + + +// VK_EXT_external_memory_dma_buf is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_external_memory_dma_buf 1 +#define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_SPEC_VERSION 1 +#define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME "VK_EXT_external_memory_dma_buf" + + +// VK_EXT_queue_family_foreign is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_queue_family_foreign 1 +#define VK_EXT_QUEUE_FAMILY_FOREIGN_SPEC_VERSION 1 +#define VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME "VK_EXT_queue_family_foreign" +#define VK_QUEUE_FAMILY_FOREIGN_EXT (~2U) + + +// VK_EXT_debug_utils is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_debug_utils 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugUtilsMessengerEXT) +#define VK_EXT_DEBUG_UTILS_SPEC_VERSION 2 +#define VK_EXT_DEBUG_UTILS_EXTENSION_NAME "VK_EXT_debug_utils" +typedef VkFlags VkDebugUtilsMessengerCallbackDataFlagsEXT; + +typedef enum VkDebugUtilsMessageSeverityFlagBitsEXT { + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 0x00000001, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT = 0x00000010, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 0x00000100, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 0x00001000, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugUtilsMessageSeverityFlagBitsEXT; + +typedef enum VkDebugUtilsMessageTypeFlagBitsEXT { + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 0x00000001, + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 0x00000002, + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 0x00000004, + VK_DEBUG_UTILS_MESSAGE_TYPE_DEVICE_ADDRESS_BINDING_BIT_EXT = 0x00000008, + VK_DEBUG_UTILS_MESSAGE_TYPE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugUtilsMessageTypeFlagBitsEXT; +typedef VkFlags VkDebugUtilsMessageTypeFlagsEXT; +typedef VkFlags VkDebugUtilsMessageSeverityFlagsEXT; +typedef VkFlags VkDebugUtilsMessengerCreateFlagsEXT; +typedef struct VkDebugUtilsLabelEXT { + VkStructureType sType; + const void* pNext; + const char* pLabelName; + float color[4]; +} VkDebugUtilsLabelEXT; + +typedef struct VkDebugUtilsObjectNameInfoEXT { + VkStructureType sType; + const void* pNext; + VkObjectType objectType; + uint64_t objectHandle; + const char* pObjectName; +} VkDebugUtilsObjectNameInfoEXT; + +typedef struct VkDebugUtilsMessengerCallbackDataEXT { + VkStructureType sType; + const void* pNext; + VkDebugUtilsMessengerCallbackDataFlagsEXT flags; + const char* pMessageIdName; + int32_t messageIdNumber; + const char* pMessage; + uint32_t queueLabelCount; + const VkDebugUtilsLabelEXT* pQueueLabels; + uint32_t cmdBufLabelCount; + const VkDebugUtilsLabelEXT* pCmdBufLabels; + uint32_t objectCount; + const VkDebugUtilsObjectNameInfoEXT* pObjects; +} VkDebugUtilsMessengerCallbackDataEXT; + +typedef VkBool32 (VKAPI_PTR *PFN_vkDebugUtilsMessengerCallbackEXT)( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData); + +typedef struct VkDebugUtilsMessengerCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDebugUtilsMessengerCreateFlagsEXT flags; + VkDebugUtilsMessageSeverityFlagsEXT messageSeverity; + VkDebugUtilsMessageTypeFlagsEXT messageType; + PFN_vkDebugUtilsMessengerCallbackEXT pfnUserCallback; + void* pUserData; +} VkDebugUtilsMessengerCreateInfoEXT; + +typedef struct VkDebugUtilsObjectTagInfoEXT { + VkStructureType sType; + const void* pNext; + VkObjectType objectType; + uint64_t objectHandle; + uint64_t tagName; + size_t tagSize; + const void* pTag; +} VkDebugUtilsObjectTagInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkSetDebugUtilsObjectNameEXT)(VkDevice device, const VkDebugUtilsObjectNameInfoEXT* pNameInfo); +typedef VkResult (VKAPI_PTR *PFN_vkSetDebugUtilsObjectTagEXT)(VkDevice device, const VkDebugUtilsObjectTagInfoEXT* pTagInfo); +typedef void (VKAPI_PTR *PFN_vkQueueBeginDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo); +typedef void (VKAPI_PTR *PFN_vkQueueEndDebugUtilsLabelEXT)(VkQueue queue); +typedef void (VKAPI_PTR *PFN_vkQueueInsertDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBeginDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT* pLabelInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer); +typedef void (VKAPI_PTR *PFN_vkCmdInsertDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT* pLabelInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugUtilsMessengerEXT)(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pMessenger); +typedef void (VKAPI_PTR *PFN_vkDestroyDebugUtilsMessengerEXT)(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkSubmitDebugUtilsMessageEXT)(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkSetDebugUtilsObjectNameEXT( + VkDevice device, + const VkDebugUtilsObjectNameInfoEXT* pNameInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkSetDebugUtilsObjectTagEXT( + VkDevice device, + const VkDebugUtilsObjectTagInfoEXT* pTagInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkQueueBeginDebugUtilsLabelEXT( + VkQueue queue, + const VkDebugUtilsLabelEXT* pLabelInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkQueueEndDebugUtilsLabelEXT( + VkQueue queue); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkQueueInsertDebugUtilsLabelEXT( + VkQueue queue, + const VkDebugUtilsLabelEXT* pLabelInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginDebugUtilsLabelEXT( + VkCommandBuffer commandBuffer, + const VkDebugUtilsLabelEXT* pLabelInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdEndDebugUtilsLabelEXT( + VkCommandBuffer commandBuffer); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdInsertDebugUtilsLabelEXT( + VkCommandBuffer commandBuffer, + const VkDebugUtilsLabelEXT* pLabelInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT( + VkInstance instance, + const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDebugUtilsMessengerEXT* pMessenger); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT( + VkInstance instance, + VkDebugUtilsMessengerEXT messenger, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkSubmitDebugUtilsMessageEXT( + VkInstance instance, + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData); +#endif +#endif + + +// VK_EXT_sampler_filter_minmax is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_sampler_filter_minmax 1 +#define VK_EXT_SAMPLER_FILTER_MINMAX_SPEC_VERSION 2 +#define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME "VK_EXT_sampler_filter_minmax" +typedef VkSamplerReductionMode VkSamplerReductionModeEXT; + +typedef VkSamplerReductionModeCreateInfo VkSamplerReductionModeCreateInfoEXT; + +typedef VkPhysicalDeviceSamplerFilterMinmaxProperties VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT; + + + +// VK_AMD_gpu_shader_int16 is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_gpu_shader_int16 1 +#define VK_AMD_GPU_SHADER_INT16_SPEC_VERSION 2 +#define VK_AMD_GPU_SHADER_INT16_EXTENSION_NAME "VK_AMD_gpu_shader_int16" + + +// VK_AMD_gpa_interface is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_gpa_interface 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkGpaSessionAMD) +#define VK_AMD_GPA_INTERFACE_SPEC_VERSION 1 +#define VK_AMD_GPA_INTERFACE_EXTENSION_NAME "VK_AMD_gpa_interface" + +typedef enum VkGpaPerfBlockAMD { + VK_GPA_PERF_BLOCK_CPF_AMD = 0, + VK_GPA_PERF_BLOCK_IA_AMD = 1, + VK_GPA_PERF_BLOCK_VGT_AMD = 2, + VK_GPA_PERF_BLOCK_PA_AMD = 3, + VK_GPA_PERF_BLOCK_SC_AMD = 4, + VK_GPA_PERF_BLOCK_SPI_AMD = 5, + VK_GPA_PERF_BLOCK_SQ_AMD = 6, + VK_GPA_PERF_BLOCK_SX_AMD = 7, + VK_GPA_PERF_BLOCK_TA_AMD = 8, + VK_GPA_PERF_BLOCK_TD_AMD = 9, + VK_GPA_PERF_BLOCK_TCP_AMD = 10, + VK_GPA_PERF_BLOCK_TCC_AMD = 11, + VK_GPA_PERF_BLOCK_TCA_AMD = 12, + VK_GPA_PERF_BLOCK_DB_AMD = 13, + VK_GPA_PERF_BLOCK_CB_AMD = 14, + VK_GPA_PERF_BLOCK_GDS_AMD = 15, + VK_GPA_PERF_BLOCK_SRBM_AMD = 16, + VK_GPA_PERF_BLOCK_GRBM_AMD = 17, + VK_GPA_PERF_BLOCK_GRBM_SE_AMD = 18, + VK_GPA_PERF_BLOCK_RLC_AMD = 19, + VK_GPA_PERF_BLOCK_DMA_AMD = 20, + VK_GPA_PERF_BLOCK_MC_AMD = 21, + VK_GPA_PERF_BLOCK_CPG_AMD = 22, + VK_GPA_PERF_BLOCK_CPC_AMD = 23, + VK_GPA_PERF_BLOCK_WD_AMD = 24, + VK_GPA_PERF_BLOCK_TCS_AMD = 25, + VK_GPA_PERF_BLOCK_ATC_AMD = 26, + VK_GPA_PERF_BLOCK_ATC_L2_AMD = 27, + VK_GPA_PERF_BLOCK_MC_VM_L2_AMD = 28, + VK_GPA_PERF_BLOCK_EA_AMD = 29, + VK_GPA_PERF_BLOCK_RPB_AMD = 30, + VK_GPA_PERF_BLOCK_RMI_AMD = 31, + VK_GPA_PERF_BLOCK_UMCCH_AMD = 32, + VK_GPA_PERF_BLOCK_GE_AMD = 33, + VK_GPA_PERF_BLOCK_GL1A_AMD = 34, + VK_GPA_PERF_BLOCK_GL1C_AMD = 35, + VK_GPA_PERF_BLOCK_GL1CG_AMD = 36, + VK_GPA_PERF_BLOCK_GL2A_AMD = 37, + VK_GPA_PERF_BLOCK_GL2C_AMD = 38, + VK_GPA_PERF_BLOCK_CHA_AMD = 39, + VK_GPA_PERF_BLOCK_CHC_AMD = 40, + VK_GPA_PERF_BLOCK_CHCG_AMD = 41, + VK_GPA_PERF_BLOCK_GUS_AMD = 42, + VK_GPA_PERF_BLOCK_GCR_AMD = 43, + VK_GPA_PERF_BLOCK_PH_AMD = 44, + VK_GPA_PERF_BLOCK_UTCL1_AMD = 45, + VK_GPA_PERF_BLOCK_GE_DIST_AMD = 46, + VK_GPA_PERF_BLOCK_GE_SE_AMD = 47, + VK_GPA_PERF_BLOCK_DF_MALL_AMD = 48, + VK_GPA_PERF_BLOCK_SQ_WGP_AMD = 49, + VK_GPA_PERF_BLOCK_PC_AMD = 50, + VK_GPA_PERF_BLOCK_GL1XA_AMD = 51, + VK_GPA_PERF_BLOCK_GL1XC_AMD = 52, + VK_GPA_PERF_BLOCK_WGS_AMD = 53, + VK_GPA_PERF_BLOCK_EACPWD_AMD = 54, + VK_GPA_PERF_BLOCK_EASE_AMD = 55, + VK_GPA_PERF_BLOCK_RLCUSER_AMD = 56, + VK_GPA_PERF_BLOCK_GE1_AMD = VK_GPA_PERF_BLOCK_GE_AMD, + VK_GPA_PERF_BLOCK_RLCLOCAL_AMD = VK_GPA_PERF_BLOCK_RLCUSER_AMD, + VK_GPA_PERF_BLOCK_MAX_ENUM_AMD = 0x7FFFFFFF +} VkGpaPerfBlockAMD; + +typedef enum VkGpaSampleTypeAMD { + VK_GPA_SAMPLE_TYPE_CUMULATIVE_AMD = 0, + VK_GPA_SAMPLE_TYPE_TRACE_AMD = 1, + VK_GPA_SAMPLE_TYPE_TIMING_AMD = 2, + VK_GPA_SAMPLE_TYPE_MAX_ENUM_AMD = 0x7FFFFFFF +} VkGpaSampleTypeAMD; + +typedef enum VkGpaDeviceClockModeAMD { + VK_GPA_DEVICE_CLOCK_MODE_DEFAULT_AMD = 0, + VK_GPA_DEVICE_CLOCK_MODE_QUERY_AMD = 1, + VK_GPA_DEVICE_CLOCK_MODE_PROFILING_AMD = 2, + VK_GPA_DEVICE_CLOCK_MODE_MIN_MEMORY_AMD = 3, + VK_GPA_DEVICE_CLOCK_MODE_MIN_ENGINE_AMD = 4, + VK_GPA_DEVICE_CLOCK_MODE_PEAK_AMD = 5, + VK_GPA_DEVICE_CLOCK_MODE_MAX_ENUM_AMD = 0x7FFFFFFF +} VkGpaDeviceClockModeAMD; + +typedef enum VkGpaSqShaderStageFlagBitsAMD { + VK_GPA_SQ_SHADER_STAGE_PS_BIT_AMD = 0x00000001, + VK_GPA_SQ_SHADER_STAGE_VS_BIT_AMD = 0x00000002, + VK_GPA_SQ_SHADER_STAGE_GS_BIT_AMD = 0x00000004, + VK_GPA_SQ_SHADER_STAGE_ES_BIT_AMD = 0x00000008, + VK_GPA_SQ_SHADER_STAGE_HS_BIT_AMD = 0x00000010, + VK_GPA_SQ_SHADER_STAGE_LS_BIT_AMD = 0x00000020, + VK_GPA_SQ_SHADER_STAGE_CS_BIT_AMD = 0x00000040, + VK_GPA_SQ_SHADER_STAGE_FLAG_BITS_MAX_ENUM_AMD = 0x7FFFFFFF +} VkGpaSqShaderStageFlagBitsAMD; +typedef VkFlags VkGpaSqShaderStageFlagsAMD; +typedef VkFlags VkGpaPerfBlockPropertiesFlagsAMD; +typedef VkFlags VkPhysicalDeviceGpaPropertiesFlagsAMD; +typedef struct VkGpaPerfBlockPropertiesAMD { + VkGpaPerfBlockAMD blockType; + VkGpaPerfBlockPropertiesFlagsAMD flags; + uint32_t instanceCount; + uint32_t maxEventID; + uint32_t maxGlobalOnlyCounters; + uint32_t maxGlobalSharedCounters; + uint32_t maxStreamingCounters; +} VkGpaPerfBlockPropertiesAMD; + +typedef struct VkPhysicalDeviceGpaFeaturesAMD { + VkStructureType sType; + void* pNext; + VkBool32 perfCounters; + VkBool32 streamingPerfCounters; + VkBool32 sqThreadTracing; + VkBool32 clockModes; +} VkPhysicalDeviceGpaFeaturesAMD; + +typedef struct VkPhysicalDeviceGpaPropertiesAMD { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceGpaPropertiesFlagsAMD flags; + VkDeviceSize maxSqttSeBufferSize; + uint32_t shaderEngineCount; + uint32_t perfBlockCount; + VkGpaPerfBlockPropertiesAMD* pPerfBlocks; +} VkPhysicalDeviceGpaPropertiesAMD; + +typedef struct VkPhysicalDeviceGpaProperties2AMD { + VkStructureType sType; + void* pNext; + uint32_t revisionId; +} VkPhysicalDeviceGpaProperties2AMD; + +typedef struct VkGpaPerfCounterAMD { + VkGpaPerfBlockAMD blockType; + uint32_t blockInstance; + uint32_t eventID; +} VkGpaPerfCounterAMD; + +typedef struct VkGpaSampleBeginInfoAMD { + VkStructureType sType; + const void* pNext; + VkGpaSampleTypeAMD sampleType; + VkBool32 sampleInternalOperations; + VkBool32 cacheFlushOnCounterCollection; + VkBool32 sqShaderMaskEnable; + VkGpaSqShaderStageFlagsAMD sqShaderMask; + uint32_t perfCounterCount; + const VkGpaPerfCounterAMD* pPerfCounters; + uint32_t streamingPerfTraceSampleInterval; + VkDeviceSize perfCounterDeviceMemoryLimit; + VkBool32 sqThreadTraceEnable; + VkBool32 sqThreadTraceSuppressInstructionTokens; + VkDeviceSize sqThreadTraceDeviceMemoryLimit; + VkPipelineStageFlags timingPreSample; + VkPipelineStageFlags timingPostSample; +} VkGpaSampleBeginInfoAMD; + +typedef struct VkGpaDeviceClockModeInfoAMD { + VkStructureType sType; + const void* pNext; + VkGpaDeviceClockModeAMD clockMode; + float memoryClockRatioToPeak; + float engineClockRatioToPeak; +} VkGpaDeviceClockModeInfoAMD; + +typedef struct VkGpaDeviceGetClockInfoAMD { + VkStructureType sType; + void* pNext; + float memoryClockRatioToPeak; + float engineClockRatioToPeak; + uint32_t memoryClockFrequency; + uint32_t engineClockFrequency; +} VkGpaDeviceGetClockInfoAMD; + +typedef struct VkGpaSessionCreateInfoAMD { + VkStructureType sType; + const void* pNext; + VkGpaSessionAMD secondaryCopySource; +} VkGpaSessionCreateInfoAMD; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateGpaSessionAMD)(VkDevice device, const VkGpaSessionCreateInfoAMD* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkGpaSessionAMD* pGpaSession); +typedef void (VKAPI_PTR *PFN_vkDestroyGpaSessionAMD)(VkDevice device, VkGpaSessionAMD gpaSession, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkSetGpaDeviceClockModeAMD)(VkDevice device, VkGpaDeviceClockModeInfoAMD* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetGpaDeviceClockInfoAMD)(VkDevice device, VkGpaDeviceGetClockInfoAMD* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCmdBeginGpaSessionAMD)(VkCommandBuffer commandBuffer, VkGpaSessionAMD gpaSession); +typedef VkResult (VKAPI_PTR *PFN_vkCmdEndGpaSessionAMD)(VkCommandBuffer commandBuffer, VkGpaSessionAMD gpaSession); +typedef VkResult (VKAPI_PTR *PFN_vkCmdBeginGpaSampleAMD)(VkCommandBuffer commandBuffer, VkGpaSessionAMD gpaSession, const VkGpaSampleBeginInfoAMD* pGpaSampleBeginInfo, uint32_t* pSampleID); +typedef void (VKAPI_PTR *PFN_vkCmdEndGpaSampleAMD)(VkCommandBuffer commandBuffer, VkGpaSessionAMD gpaSession, uint32_t sampleID); +typedef VkResult (VKAPI_PTR *PFN_vkGetGpaSessionStatusAMD)(VkDevice device, VkGpaSessionAMD gpaSession); +typedef VkResult (VKAPI_PTR *PFN_vkGetGpaSessionResultsAMD)(VkDevice device, VkGpaSessionAMD gpaSession, uint32_t sampleID, size_t* pSizeInBytes, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkResetGpaSessionAMD)(VkDevice device, VkGpaSessionAMD gpaSession); +typedef void (VKAPI_PTR *PFN_vkCmdCopyGpaSessionResultsAMD)(VkCommandBuffer commandBuffer, VkGpaSessionAMD gpaSession); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateGpaSessionAMD( + VkDevice device, + const VkGpaSessionCreateInfoAMD* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkGpaSessionAMD* pGpaSession); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyGpaSessionAMD( + VkDevice device, + VkGpaSessionAMD gpaSession, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkSetGpaDeviceClockModeAMD( + VkDevice device, + VkGpaDeviceClockModeInfoAMD* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetGpaDeviceClockInfoAMD( + VkDevice device, + VkGpaDeviceGetClockInfoAMD* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCmdBeginGpaSessionAMD( + VkCommandBuffer commandBuffer, + VkGpaSessionAMD gpaSession); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCmdEndGpaSessionAMD( + VkCommandBuffer commandBuffer, + VkGpaSessionAMD gpaSession); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCmdBeginGpaSampleAMD( + VkCommandBuffer commandBuffer, + VkGpaSessionAMD gpaSession, + const VkGpaSampleBeginInfoAMD* pGpaSampleBeginInfo, + uint32_t* pSampleID); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdEndGpaSampleAMD( + VkCommandBuffer commandBuffer, + VkGpaSessionAMD gpaSession, + uint32_t sampleID); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetGpaSessionStatusAMD( + VkDevice device, + VkGpaSessionAMD gpaSession); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetGpaSessionResultsAMD( + VkDevice device, + VkGpaSessionAMD gpaSession, + uint32_t sampleID, + size_t* pSizeInBytes, + void* pData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkResetGpaSessionAMD( + VkDevice device, + VkGpaSessionAMD gpaSession); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyGpaSessionResultsAMD( + VkCommandBuffer commandBuffer, + VkGpaSessionAMD gpaSession); +#endif +#endif + + +// VK_EXT_descriptor_heap is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_descriptor_heap 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkTensorARM) +#define VK_EXT_DESCRIPTOR_HEAP_SPEC_VERSION 1 +#define VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME "VK_EXT_descriptor_heap" + +typedef enum VkDescriptorMappingSourceEXT { + VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT = 0, + VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_PUSH_INDEX_EXT = 1, + VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_EXT = 2, + VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_ARRAY_EXT = 3, + VK_DESCRIPTOR_MAPPING_SOURCE_RESOURCE_HEAP_DATA_EXT = 4, + VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_DATA_EXT = 5, + VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT = 6, + VK_DESCRIPTOR_MAPPING_SOURCE_INDIRECT_ADDRESS_EXT = 7, + VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_SHADER_RECORD_INDEX_EXT = 8, + VK_DESCRIPTOR_MAPPING_SOURCE_SHADER_RECORD_DATA_EXT = 9, + VK_DESCRIPTOR_MAPPING_SOURCE_SHADER_RECORD_ADDRESS_EXT = 10, + VK_DESCRIPTOR_MAPPING_SOURCE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDescriptorMappingSourceEXT; +typedef VkFlags64 VkTensorViewCreateFlagsARM; + +// Flag bits for VkTensorViewCreateFlagBitsARM +typedef VkFlags64 VkTensorViewCreateFlagBitsARM; +static const VkTensorViewCreateFlagBitsARM VK_TENSOR_VIEW_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_ARM = 0x00000001ULL; + + +typedef enum VkSpirvResourceTypeFlagBitsEXT { + VK_SPIRV_RESOURCE_TYPE_ALL_EXT = 0x7FFFFFFF, + VK_SPIRV_RESOURCE_TYPE_SAMPLER_BIT_EXT = 0x00000001, + VK_SPIRV_RESOURCE_TYPE_SAMPLED_IMAGE_BIT_EXT = 0x00000002, + VK_SPIRV_RESOURCE_TYPE_READ_ONLY_IMAGE_BIT_EXT = 0x00000004, + VK_SPIRV_RESOURCE_TYPE_READ_WRITE_IMAGE_BIT_EXT = 0x00000008, + VK_SPIRV_RESOURCE_TYPE_COMBINED_SAMPLED_IMAGE_BIT_EXT = 0x00000010, + VK_SPIRV_RESOURCE_TYPE_UNIFORM_BUFFER_BIT_EXT = 0x00000020, + VK_SPIRV_RESOURCE_TYPE_READ_ONLY_STORAGE_BUFFER_BIT_EXT = 0x00000040, + VK_SPIRV_RESOURCE_TYPE_READ_WRITE_STORAGE_BUFFER_BIT_EXT = 0x00000080, + VK_SPIRV_RESOURCE_TYPE_ACCELERATION_STRUCTURE_BIT_EXT = 0x00000100, + VK_SPIRV_RESOURCE_TYPE_TENSOR_BIT_ARM = 0x00000200, + VK_SPIRV_RESOURCE_TYPE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkSpirvResourceTypeFlagBitsEXT; +typedef VkFlags VkSpirvResourceTypeFlagsEXT; +typedef struct VkHostAddressRangeEXT { + void* address; + size_t size; +} VkHostAddressRangeEXT; + +typedef struct VkHostAddressRangeConstEXT { + const void* address; + size_t size; +} VkHostAddressRangeConstEXT; + +typedef VkDeviceAddressRangeKHR VkDeviceAddressRangeEXT; + +typedef struct VkTexelBufferDescriptorInfoEXT { + VkStructureType sType; + const void* pNext; + VkFormat format; + VkDeviceAddressRangeEXT addressRange; +} VkTexelBufferDescriptorInfoEXT; + +typedef struct VkImageDescriptorInfoEXT { + VkStructureType sType; + const void* pNext; + const VkImageViewCreateInfo* pView; + VkImageLayout layout; +} VkImageDescriptorInfoEXT; + +typedef struct VkTensorViewCreateInfoARM { + VkStructureType sType; + const void* pNext; + VkTensorViewCreateFlagsARM flags; + VkTensorARM tensor; + VkFormat format; +} VkTensorViewCreateInfoARM; + +typedef union VkResourceDescriptorDataEXT { + const VkImageDescriptorInfoEXT* pImage; + const VkTexelBufferDescriptorInfoEXT* pTexelBuffer; + const VkDeviceAddressRangeEXT* pAddressRange; + const VkTensorViewCreateInfoARM* pTensorARM; +} VkResourceDescriptorDataEXT; + +typedef struct VkResourceDescriptorInfoEXT { + VkStructureType sType; + const void* pNext; + VkDescriptorType type; + VkResourceDescriptorDataEXT data; +} VkResourceDescriptorInfoEXT; + +typedef struct VkBindHeapInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceAddressRangeEXT heapRange; + VkDeviceSize reservedRangeOffset; + VkDeviceSize reservedRangeSize; +} VkBindHeapInfoEXT; + +typedef struct VkPushDataInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t offset; + VkHostAddressRangeConstEXT data; +} VkPushDataInfoEXT; + +typedef struct VkDescriptorMappingSourceConstantOffsetEXT { + uint32_t heapOffset; + uint32_t heapArrayStride; + const VkSamplerCreateInfo* pEmbeddedSampler; + uint32_t samplerHeapOffset; + uint32_t samplerHeapArrayStride; +} VkDescriptorMappingSourceConstantOffsetEXT; + +typedef struct VkDescriptorMappingSourcePushIndexEXT { + uint32_t heapOffset; + uint32_t pushOffset; + uint32_t heapIndexStride; + uint32_t heapArrayStride; + const VkSamplerCreateInfo* pEmbeddedSampler; + VkBool32 useCombinedImageSamplerIndex; + uint32_t samplerHeapOffset; + uint32_t samplerPushOffset; + uint32_t samplerHeapIndexStride; + uint32_t samplerHeapArrayStride; +} VkDescriptorMappingSourcePushIndexEXT; + +typedef struct VkDescriptorMappingSourceIndirectIndexEXT { + uint32_t heapOffset; + uint32_t pushOffset; + uint32_t addressOffset; + uint32_t heapIndexStride; + uint32_t heapArrayStride; + const VkSamplerCreateInfo* pEmbeddedSampler; + VkBool32 useCombinedImageSamplerIndex; + uint32_t samplerHeapOffset; + uint32_t samplerPushOffset; + uint32_t samplerAddressOffset; + uint32_t samplerHeapIndexStride; + uint32_t samplerHeapArrayStride; +} VkDescriptorMappingSourceIndirectIndexEXT; + +typedef struct VkDescriptorMappingSourceHeapDataEXT { + uint32_t heapOffset; + uint32_t pushOffset; +} VkDescriptorMappingSourceHeapDataEXT; + +typedef struct VkDescriptorMappingSourceIndirectAddressEXT { + uint32_t pushOffset; + uint32_t addressOffset; +} VkDescriptorMappingSourceIndirectAddressEXT; + +typedef struct VkDescriptorMappingSourceShaderRecordIndexEXT { + uint32_t heapOffset; + uint32_t shaderRecordOffset; + uint32_t heapIndexStride; + uint32_t heapArrayStride; + const VkSamplerCreateInfo* pEmbeddedSampler; + VkBool32 useCombinedImageSamplerIndex; + uint32_t samplerHeapOffset; + uint32_t samplerShaderRecordOffset; + uint32_t samplerHeapIndexStride; + uint32_t samplerHeapArrayStride; +} VkDescriptorMappingSourceShaderRecordIndexEXT; + +typedef struct VkDescriptorMappingSourceIndirectIndexArrayEXT { + uint32_t heapOffset; + uint32_t pushOffset; + uint32_t addressOffset; + uint32_t heapIndexStride; + const VkSamplerCreateInfo* pEmbeddedSampler; + VkBool32 useCombinedImageSamplerIndex; + uint32_t samplerHeapOffset; + uint32_t samplerPushOffset; + uint32_t samplerAddressOffset; + uint32_t samplerHeapIndexStride; +} VkDescriptorMappingSourceIndirectIndexArrayEXT; + +typedef union VkDescriptorMappingSourceDataEXT { + VkDescriptorMappingSourceConstantOffsetEXT constantOffset; + VkDescriptorMappingSourcePushIndexEXT pushIndex; + VkDescriptorMappingSourceIndirectIndexEXT indirectIndex; + VkDescriptorMappingSourceIndirectIndexArrayEXT indirectIndexArray; + VkDescriptorMappingSourceHeapDataEXT heapData; + uint32_t pushDataOffset; + uint32_t pushAddressOffset; + VkDescriptorMappingSourceIndirectAddressEXT indirectAddress; + VkDescriptorMappingSourceShaderRecordIndexEXT shaderRecordIndex; + uint32_t shaderRecordDataOffset; + uint32_t shaderRecordAddressOffset; +} VkDescriptorMappingSourceDataEXT; + +typedef struct VkDescriptorSetAndBindingMappingEXT { + VkStructureType sType; + const void* pNext; + uint32_t descriptorSet; + uint32_t firstBinding; + uint32_t bindingCount; + VkSpirvResourceTypeFlagsEXT resourceMask; + VkDescriptorMappingSourceEXT source; + VkDescriptorMappingSourceDataEXT sourceData; +} VkDescriptorSetAndBindingMappingEXT; + +typedef struct VkShaderDescriptorSetAndBindingMappingInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t mappingCount; + const VkDescriptorSetAndBindingMappingEXT* pMappings; +} VkShaderDescriptorSetAndBindingMappingInfoEXT; + +typedef struct VkOpaqueCaptureDataCreateInfoEXT { + VkStructureType sType; + const void* pNext; + const VkHostAddressRangeConstEXT* pData; +} VkOpaqueCaptureDataCreateInfoEXT; + +typedef struct VkPhysicalDeviceDescriptorHeapFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 descriptorHeap; + VkBool32 descriptorHeapCaptureReplay; +} VkPhysicalDeviceDescriptorHeapFeaturesEXT; + +typedef struct VkPhysicalDeviceDescriptorHeapPropertiesEXT { + VkStructureType sType; + void* pNext; + VkDeviceSize samplerHeapAlignment; + VkDeviceSize resourceHeapAlignment; + VkDeviceSize maxSamplerHeapSize; + VkDeviceSize maxResourceHeapSize; + VkDeviceSize minSamplerHeapReservedRange; + VkDeviceSize minSamplerHeapReservedRangeWithEmbedded; + VkDeviceSize minResourceHeapReservedRange; + VkDeviceSize samplerDescriptorSize; + VkDeviceSize imageDescriptorSize; + VkDeviceSize bufferDescriptorSize; + VkDeviceSize samplerDescriptorAlignment; + VkDeviceSize imageDescriptorAlignment; + VkDeviceSize bufferDescriptorAlignment; + VkDeviceSize maxPushDataSize; + size_t imageCaptureReplayOpaqueDataSize; + uint32_t maxDescriptorHeapEmbeddedSamplers; + uint32_t samplerYcbcrConversionCount; + VkBool32 sparseDescriptorHeaps; + VkBool32 protectedDescriptorHeaps; +} VkPhysicalDeviceDescriptorHeapPropertiesEXT; + +typedef struct VkCommandBufferInheritanceDescriptorHeapInfoEXT { + VkStructureType sType; + const void* pNext; + const VkBindHeapInfoEXT* pSamplerHeapBindInfo; + const VkBindHeapInfoEXT* pResourceHeapBindInfo; +} VkCommandBufferInheritanceDescriptorHeapInfoEXT; + +typedef struct VkSamplerCustomBorderColorIndexCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t index; +} VkSamplerCustomBorderColorIndexCreateInfoEXT; + +typedef struct VkSamplerCustomBorderColorCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkClearColorValue customBorderColor; + VkFormat format; +} VkSamplerCustomBorderColorCreateInfoEXT; + +typedef struct VkIndirectCommandsLayoutPushDataTokenNV { + VkStructureType sType; + const void* pNext; + uint32_t pushDataOffset; + uint32_t pushDataSize; +} VkIndirectCommandsLayoutPushDataTokenNV; + +typedef struct VkSubsampledImageFormatPropertiesEXT { + VkStructureType sType; + const void* pNext; + uint32_t subsampledImageDescriptorCount; +} VkSubsampledImageFormatPropertiesEXT; + +typedef struct VkPhysicalDeviceDescriptorHeapTensorPropertiesARM { + VkStructureType sType; + void* pNext; + VkDeviceSize tensorDescriptorSize; + VkDeviceSize tensorDescriptorAlignment; + size_t tensorCaptureReplayOpaqueDataSize; +} VkPhysicalDeviceDescriptorHeapTensorPropertiesARM; + +typedef VkResult (VKAPI_PTR *PFN_vkWriteSamplerDescriptorsEXT)(VkDevice device, uint32_t samplerCount, const VkSamplerCreateInfo* pSamplers, const VkHostAddressRangeEXT* pDescriptors); +typedef VkResult (VKAPI_PTR *PFN_vkWriteResourceDescriptorsEXT)(VkDevice device, uint32_t resourceCount, const VkResourceDescriptorInfoEXT* pResources, const VkHostAddressRangeEXT* pDescriptors); +typedef void (VKAPI_PTR *PFN_vkCmdBindSamplerHeapEXT)(VkCommandBuffer commandBuffer, const VkBindHeapInfoEXT* pBindInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBindResourceHeapEXT)(VkCommandBuffer commandBuffer, const VkBindHeapInfoEXT* pBindInfo); +typedef void (VKAPI_PTR *PFN_vkCmdPushDataEXT)(VkCommandBuffer commandBuffer, const VkPushDataInfoEXT* pPushDataInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetImageOpaqueCaptureDataEXT)(VkDevice device, uint32_t imageCount, const VkImage* pImages, VkHostAddressRangeEXT* pDatas); +typedef VkDeviceSize (VKAPI_PTR *PFN_vkGetPhysicalDeviceDescriptorSizeEXT)(VkPhysicalDevice physicalDevice, VkDescriptorType descriptorType); +typedef VkResult (VKAPI_PTR *PFN_vkRegisterCustomBorderColorEXT)(VkDevice device, const VkSamplerCustomBorderColorCreateInfoEXT* pBorderColor, VkBool32 requestIndex, uint32_t* pIndex); +typedef void (VKAPI_PTR *PFN_vkUnregisterCustomBorderColorEXT)(VkDevice device, uint32_t index); +typedef VkResult (VKAPI_PTR *PFN_vkGetTensorOpaqueCaptureDataARM)(VkDevice device, uint32_t tensorCount, const VkTensorARM* pTensors, VkHostAddressRangeEXT* pDatas); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkWriteSamplerDescriptorsEXT( + VkDevice device, + uint32_t samplerCount, + const VkSamplerCreateInfo* pSamplers, + const VkHostAddressRangeEXT* pDescriptors); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkWriteResourceDescriptorsEXT( + VkDevice device, + uint32_t resourceCount, + const VkResourceDescriptorInfoEXT* pResources, + const VkHostAddressRangeEXT* pDescriptors); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindSamplerHeapEXT( + VkCommandBuffer commandBuffer, + const VkBindHeapInfoEXT* pBindInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindResourceHeapEXT( + VkCommandBuffer commandBuffer, + const VkBindHeapInfoEXT* pBindInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdPushDataEXT( + VkCommandBuffer commandBuffer, + const VkPushDataInfoEXT* pPushDataInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetImageOpaqueCaptureDataEXT( + VkDevice device, + uint32_t imageCount, + const VkImage* pImages, + VkHostAddressRangeEXT* pDatas); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkDeviceSize VKAPI_CALL vkGetPhysicalDeviceDescriptorSizeEXT( + VkPhysicalDevice physicalDevice, + VkDescriptorType descriptorType); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkRegisterCustomBorderColorEXT( + VkDevice device, + const VkSamplerCustomBorderColorCreateInfoEXT* pBorderColor, + VkBool32 requestIndex, + uint32_t* pIndex); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkUnregisterCustomBorderColorEXT( + VkDevice device, + uint32_t index); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetTensorOpaqueCaptureDataARM( + VkDevice device, + uint32_t tensorCount, + const VkTensorARM* pTensors, + VkHostAddressRangeEXT* pDatas); +#endif +#endif + + +// VK_AMD_mixed_attachment_samples is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_mixed_attachment_samples 1 +#define VK_AMD_MIXED_ATTACHMENT_SAMPLES_SPEC_VERSION 1 +#define VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME "VK_AMD_mixed_attachment_samples" +typedef struct VkAttachmentSampleCountInfoAMD { + VkStructureType sType; + const void* pNext; + uint32_t colorAttachmentCount; + const VkSampleCountFlagBits* pColorAttachmentSamples; + VkSampleCountFlagBits depthStencilAttachmentSamples; +} VkAttachmentSampleCountInfoAMD; + + + +// VK_AMD_shader_fragment_mask is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_fragment_mask 1 +#define VK_AMD_SHADER_FRAGMENT_MASK_SPEC_VERSION 1 +#define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask" + + +// VK_EXT_inline_uniform_block is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_inline_uniform_block 1 +#define VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION 1 +#define VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME "VK_EXT_inline_uniform_block" +typedef VkPhysicalDeviceInlineUniformBlockFeatures VkPhysicalDeviceInlineUniformBlockFeaturesEXT; + +typedef VkPhysicalDeviceInlineUniformBlockProperties VkPhysicalDeviceInlineUniformBlockPropertiesEXT; + +typedef VkWriteDescriptorSetInlineUniformBlock VkWriteDescriptorSetInlineUniformBlockEXT; + +typedef VkDescriptorPoolInlineUniformBlockCreateInfo VkDescriptorPoolInlineUniformBlockCreateInfoEXT; + + + +// VK_EXT_shader_stencil_export is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_stencil_export 1 +#define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1 +#define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export" + + +// VK_EXT_sample_locations is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_sample_locations 1 +#define VK_EXT_SAMPLE_LOCATIONS_SPEC_VERSION 1 +#define VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME "VK_EXT_sample_locations" +typedef struct VkSampleLocationEXT { + float x; + float y; +} VkSampleLocationEXT; + +typedef struct VkSampleLocationsInfoEXT { + VkStructureType sType; + const void* pNext; + VkSampleCountFlagBits sampleLocationsPerPixel; + VkExtent2D sampleLocationGridSize; + uint32_t sampleLocationsCount; + const VkSampleLocationEXT* pSampleLocations; +} VkSampleLocationsInfoEXT; + +typedef struct VkAttachmentSampleLocationsEXT { + uint32_t attachmentIndex; + VkSampleLocationsInfoEXT sampleLocationsInfo; +} VkAttachmentSampleLocationsEXT; + +typedef struct VkSubpassSampleLocationsEXT { + uint32_t subpassIndex; + VkSampleLocationsInfoEXT sampleLocationsInfo; +} VkSubpassSampleLocationsEXT; + +typedef struct VkRenderPassSampleLocationsBeginInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t attachmentInitialSampleLocationsCount; + const VkAttachmentSampleLocationsEXT* pAttachmentInitialSampleLocations; + uint32_t postSubpassSampleLocationsCount; + const VkSubpassSampleLocationsEXT* pPostSubpassSampleLocations; +} VkRenderPassSampleLocationsBeginInfoEXT; + +typedef struct VkPipelineSampleLocationsStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 sampleLocationsEnable; + VkSampleLocationsInfoEXT sampleLocationsInfo; +} VkPipelineSampleLocationsStateCreateInfoEXT; + +typedef struct VkPhysicalDeviceSampleLocationsPropertiesEXT { + VkStructureType sType; + void* pNext; + VkSampleCountFlags sampleLocationSampleCounts; + VkExtent2D maxSampleLocationGridSize; + float sampleLocationCoordinateRange[2]; + uint32_t sampleLocationSubPixelBits; + VkBool32 variableSampleLocations; +} VkPhysicalDeviceSampleLocationsPropertiesEXT; + +typedef struct VkMultisamplePropertiesEXT { + VkStructureType sType; + void* pNext; + VkExtent2D maxSampleLocationGridSize; +} VkMultisamplePropertiesEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetSampleLocationsEXT)(VkCommandBuffer commandBuffer, const VkSampleLocationsInfoEXT* pSampleLocationsInfo); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT)(VkPhysicalDevice physicalDevice, VkSampleCountFlagBits samples, VkMultisamplePropertiesEXT* pMultisampleProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetSampleLocationsEXT( + VkCommandBuffer commandBuffer, + const VkSampleLocationsInfoEXT* pSampleLocationsInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMultisamplePropertiesEXT( + VkPhysicalDevice physicalDevice, + VkSampleCountFlagBits samples, + VkMultisamplePropertiesEXT* pMultisampleProperties); +#endif +#endif + + +// VK_EXT_blend_operation_advanced is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_blend_operation_advanced 1 +#define VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION 2 +#define VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME "VK_EXT_blend_operation_advanced" + +typedef enum VkBlendOverlapEXT { + VK_BLEND_OVERLAP_UNCORRELATED_EXT = 0, + VK_BLEND_OVERLAP_DISJOINT_EXT = 1, + VK_BLEND_OVERLAP_CONJOINT_EXT = 2, + VK_BLEND_OVERLAP_MAX_ENUM_EXT = 0x7FFFFFFF +} VkBlendOverlapEXT; +typedef struct VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 advancedBlendCoherentOperations; +} VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT; + +typedef struct VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t advancedBlendMaxColorAttachments; + VkBool32 advancedBlendIndependentBlend; + VkBool32 advancedBlendNonPremultipliedSrcColor; + VkBool32 advancedBlendNonPremultipliedDstColor; + VkBool32 advancedBlendCorrelatedOverlap; + VkBool32 advancedBlendAllOperations; +} VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT; + +typedef struct VkPipelineColorBlendAdvancedStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 srcPremultiplied; + VkBool32 dstPremultiplied; + VkBlendOverlapEXT blendOverlap; +} VkPipelineColorBlendAdvancedStateCreateInfoEXT; + + + +// VK_NV_fragment_coverage_to_color is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_fragment_coverage_to_color 1 +#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_SPEC_VERSION 1 +#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME "VK_NV_fragment_coverage_to_color" +typedef VkFlags VkPipelineCoverageToColorStateCreateFlagsNV; +typedef struct VkPipelineCoverageToColorStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineCoverageToColorStateCreateFlagsNV flags; + VkBool32 coverageToColorEnable; + uint32_t coverageToColorLocation; +} VkPipelineCoverageToColorStateCreateInfoNV; + + + +// VK_NV_framebuffer_mixed_samples is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_framebuffer_mixed_samples 1 +#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_SPEC_VERSION 1 +#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME "VK_NV_framebuffer_mixed_samples" + +typedef enum VkCoverageModulationModeNV { + VK_COVERAGE_MODULATION_MODE_NONE_NV = 0, + VK_COVERAGE_MODULATION_MODE_RGB_NV = 1, + VK_COVERAGE_MODULATION_MODE_ALPHA_NV = 2, + VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3, + VK_COVERAGE_MODULATION_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkCoverageModulationModeNV; +typedef VkFlags VkPipelineCoverageModulationStateCreateFlagsNV; +typedef struct VkPipelineCoverageModulationStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineCoverageModulationStateCreateFlagsNV flags; + VkCoverageModulationModeNV coverageModulationMode; + VkBool32 coverageModulationTableEnable; + uint32_t coverageModulationTableCount; + const float* pCoverageModulationTable; +} VkPipelineCoverageModulationStateCreateInfoNV; + +typedef VkAttachmentSampleCountInfoAMD VkAttachmentSampleCountInfoNV; + + + +// VK_NV_fill_rectangle is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_fill_rectangle 1 +#define VK_NV_FILL_RECTANGLE_SPEC_VERSION 1 +#define VK_NV_FILL_RECTANGLE_EXTENSION_NAME "VK_NV_fill_rectangle" + + +// VK_NV_shader_sm_builtins is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_shader_sm_builtins 1 +#define VK_NV_SHADER_SM_BUILTINS_SPEC_VERSION 1 +#define VK_NV_SHADER_SM_BUILTINS_EXTENSION_NAME "VK_NV_shader_sm_builtins" +typedef struct VkPhysicalDeviceShaderSMBuiltinsPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t shaderSMCount; + uint32_t shaderWarpsPerSM; +} VkPhysicalDeviceShaderSMBuiltinsPropertiesNV; + +typedef struct VkPhysicalDeviceShaderSMBuiltinsFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 shaderSMBuiltins; +} VkPhysicalDeviceShaderSMBuiltinsFeaturesNV; + + + +// VK_EXT_post_depth_coverage is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_post_depth_coverage 1 +#define VK_EXT_POST_DEPTH_COVERAGE_SPEC_VERSION 1 +#define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage" + + +// VK_EXT_image_drm_format_modifier is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_image_drm_format_modifier 1 +#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 2 +#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier" +typedef struct VkDrmFormatModifierPropertiesEXT { + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + VkFormatFeatureFlags drmFormatModifierTilingFeatures; +} VkDrmFormatModifierPropertiesEXT; + +typedef struct VkDrmFormatModifierPropertiesListEXT { + VkStructureType sType; + void* pNext; + uint32_t drmFormatModifierCount; + VkDrmFormatModifierPropertiesEXT* pDrmFormatModifierProperties; +} VkDrmFormatModifierPropertiesListEXT; + +typedef struct VkPhysicalDeviceImageDrmFormatModifierInfoEXT { + VkStructureType sType; + const void* pNext; + uint64_t drmFormatModifier; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; +} VkPhysicalDeviceImageDrmFormatModifierInfoEXT; + +typedef struct VkImageDrmFormatModifierListCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t drmFormatModifierCount; + const uint64_t* pDrmFormatModifiers; +} VkImageDrmFormatModifierListCreateInfoEXT; + +typedef struct VkImageDrmFormatModifierExplicitCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + const VkSubresourceLayout* pPlaneLayouts; +} VkImageDrmFormatModifierExplicitCreateInfoEXT; + +typedef struct VkImageDrmFormatModifierPropertiesEXT { + VkStructureType sType; + void* pNext; + uint64_t drmFormatModifier; +} VkImageDrmFormatModifierPropertiesEXT; + +typedef struct VkDrmFormatModifierProperties2EXT { + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + VkFormatFeatureFlags2 drmFormatModifierTilingFeatures; +} VkDrmFormatModifierProperties2EXT; + +typedef struct VkDrmFormatModifierPropertiesList2EXT { + VkStructureType sType; + void* pNext; + uint32_t drmFormatModifierCount; + VkDrmFormatModifierProperties2EXT* pDrmFormatModifierProperties; +} VkDrmFormatModifierPropertiesList2EXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetImageDrmFormatModifierPropertiesEXT)(VkDevice device, VkImage image, VkImageDrmFormatModifierPropertiesEXT* pProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetImageDrmFormatModifierPropertiesEXT( + VkDevice device, + VkImage image, + VkImageDrmFormatModifierPropertiesEXT* pProperties); +#endif +#endif + + +// VK_EXT_validation_cache is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_validation_cache 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT) +#define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1 +#define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache" + +typedef enum VkValidationCacheHeaderVersionEXT { + VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT = 1, + VK_VALIDATION_CACHE_HEADER_VERSION_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationCacheHeaderVersionEXT; +typedef VkFlags VkValidationCacheCreateFlagsEXT; +typedef struct VkValidationCacheCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkValidationCacheCreateFlagsEXT flags; + size_t initialDataSize; + const void* pInitialData; +} VkValidationCacheCreateInfoEXT; + +typedef struct VkShaderModuleValidationCacheCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkValidationCacheEXT validationCache; +} VkShaderModuleValidationCacheCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateValidationCacheEXT)(VkDevice device, const VkValidationCacheCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkValidationCacheEXT* pValidationCache); +typedef void (VKAPI_PTR *PFN_vkDestroyValidationCacheEXT)(VkDevice device, VkValidationCacheEXT validationCache, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkMergeValidationCachesEXT)(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount, const VkValidationCacheEXT* pSrcCaches); +typedef VkResult (VKAPI_PTR *PFN_vkGetValidationCacheDataEXT)(VkDevice device, VkValidationCacheEXT validationCache, size_t* pDataSize, void* pData); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateValidationCacheEXT( + VkDevice device, + const VkValidationCacheCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkValidationCacheEXT* pValidationCache); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyValidationCacheEXT( + VkDevice device, + VkValidationCacheEXT validationCache, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkMergeValidationCachesEXT( + VkDevice device, + VkValidationCacheEXT dstCache, + uint32_t srcCacheCount, + const VkValidationCacheEXT* pSrcCaches); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetValidationCacheDataEXT( + VkDevice device, + VkValidationCacheEXT validationCache, + size_t* pDataSize, + void* pData); +#endif +#endif + + +// VK_EXT_descriptor_indexing is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_descriptor_indexing 1 +#define VK_EXT_DESCRIPTOR_INDEXING_SPEC_VERSION 2 +#define VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME "VK_EXT_descriptor_indexing" +typedef VkDescriptorBindingFlagBits VkDescriptorBindingFlagBitsEXT; + +typedef VkDescriptorBindingFlags VkDescriptorBindingFlagsEXT; + +typedef VkDescriptorSetLayoutBindingFlagsCreateInfo VkDescriptorSetLayoutBindingFlagsCreateInfoEXT; + +typedef VkPhysicalDeviceDescriptorIndexingFeatures VkPhysicalDeviceDescriptorIndexingFeaturesEXT; + +typedef VkPhysicalDeviceDescriptorIndexingProperties VkPhysicalDeviceDescriptorIndexingPropertiesEXT; + +typedef VkDescriptorSetVariableDescriptorCountAllocateInfo VkDescriptorSetVariableDescriptorCountAllocateInfoEXT; + +typedef VkDescriptorSetVariableDescriptorCountLayoutSupport VkDescriptorSetVariableDescriptorCountLayoutSupportEXT; + + + +// VK_EXT_shader_viewport_index_layer is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_viewport_index_layer 1 +#define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION 1 +#define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME "VK_EXT_shader_viewport_index_layer" + + +// VK_NV_shading_rate_image is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_shading_rate_image 1 +#define VK_NV_SHADING_RATE_IMAGE_SPEC_VERSION 3 +#define VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME "VK_NV_shading_rate_image" + +typedef enum VkShadingRatePaletteEntryNV { + VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV = 0, + VK_SHADING_RATE_PALETTE_ENTRY_16_INVOCATIONS_PER_PIXEL_NV = 1, + VK_SHADING_RATE_PALETTE_ENTRY_8_INVOCATIONS_PER_PIXEL_NV = 2, + VK_SHADING_RATE_PALETTE_ENTRY_4_INVOCATIONS_PER_PIXEL_NV = 3, + VK_SHADING_RATE_PALETTE_ENTRY_2_INVOCATIONS_PER_PIXEL_NV = 4, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV = 5, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X1_PIXELS_NV = 6, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV = 7, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV = 8, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X2_PIXELS_NV = 9, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X4_PIXELS_NV = 10, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV = 11, + VK_SHADING_RATE_PALETTE_ENTRY_MAX_ENUM_NV = 0x7FFFFFFF +} VkShadingRatePaletteEntryNV; + +typedef enum VkCoarseSampleOrderTypeNV { + VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV = 0, + VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV = 1, + VK_COARSE_SAMPLE_ORDER_TYPE_PIXEL_MAJOR_NV = 2, + VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV = 3, + VK_COARSE_SAMPLE_ORDER_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkCoarseSampleOrderTypeNV; +typedef struct VkShadingRatePaletteNV { + uint32_t shadingRatePaletteEntryCount; + const VkShadingRatePaletteEntryNV* pShadingRatePaletteEntries; +} VkShadingRatePaletteNV; + +typedef struct VkPipelineViewportShadingRateImageStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 shadingRateImageEnable; + uint32_t viewportCount; + const VkShadingRatePaletteNV* pShadingRatePalettes; +} VkPipelineViewportShadingRateImageStateCreateInfoNV; + +typedef struct VkPhysicalDeviceShadingRateImageFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 shadingRateImage; + VkBool32 shadingRateCoarseSampleOrder; +} VkPhysicalDeviceShadingRateImageFeaturesNV; + +typedef struct VkPhysicalDeviceShadingRateImagePropertiesNV { + VkStructureType sType; + void* pNext; + VkExtent2D shadingRateTexelSize; + uint32_t shadingRatePaletteSize; + uint32_t shadingRateMaxCoarseSamples; +} VkPhysicalDeviceShadingRateImagePropertiesNV; + +typedef struct VkCoarseSampleLocationNV { + uint32_t pixelX; + uint32_t pixelY; + uint32_t sample; +} VkCoarseSampleLocationNV; + +typedef struct VkCoarseSampleOrderCustomNV { + VkShadingRatePaletteEntryNV shadingRate; + uint32_t sampleCount; + uint32_t sampleLocationCount; + const VkCoarseSampleLocationNV* pSampleLocations; +} VkCoarseSampleOrderCustomNV; + +typedef struct VkPipelineViewportCoarseSampleOrderStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkCoarseSampleOrderTypeNV sampleOrderType; + uint32_t customSampleOrderCount; + const VkCoarseSampleOrderCustomNV* pCustomSampleOrders; +} VkPipelineViewportCoarseSampleOrderStateCreateInfoNV; + +typedef void (VKAPI_PTR *PFN_vkCmdBindShadingRateImageNV)(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportShadingRatePaletteNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkShadingRatePaletteNV* pShadingRatePalettes); +typedef void (VKAPI_PTR *PFN_vkCmdSetCoarseSampleOrderNV)(VkCommandBuffer commandBuffer, VkCoarseSampleOrderTypeNV sampleOrderType, uint32_t customSampleOrderCount, const VkCoarseSampleOrderCustomNV* pCustomSampleOrders); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindShadingRateImageNV( + VkCommandBuffer commandBuffer, + VkImageView imageView, + VkImageLayout imageLayout); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportShadingRatePaletteNV( + VkCommandBuffer commandBuffer, + uint32_t firstViewport, + uint32_t viewportCount, + const VkShadingRatePaletteNV* pShadingRatePalettes); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetCoarseSampleOrderNV( + VkCommandBuffer commandBuffer, + VkCoarseSampleOrderTypeNV sampleOrderType, + uint32_t customSampleOrderCount, + const VkCoarseSampleOrderCustomNV* pCustomSampleOrders); +#endif +#endif + + +// VK_NV_ray_tracing is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_ray_tracing 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNV) +#define VK_NV_RAY_TRACING_SPEC_VERSION 3 +#define VK_NV_RAY_TRACING_EXTENSION_NAME "VK_NV_ray_tracing" +#define VK_SHADER_UNUSED_KHR (~0U) +#define VK_SHADER_UNUSED_NV VK_SHADER_UNUSED_KHR + +typedef enum VkRayTracingShaderGroupTypeKHR { + VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR = 0, + VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR = 1, + VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR = 2, + VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR, + VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR, + VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR, + VK_RAY_TRACING_SHADER_GROUP_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkRayTracingShaderGroupTypeKHR; +typedef VkRayTracingShaderGroupTypeKHR VkRayTracingShaderGroupTypeNV; + + +typedef enum VkGeometryTypeKHR { + VK_GEOMETRY_TYPE_TRIANGLES_KHR = 0, + VK_GEOMETRY_TYPE_AABBS_KHR = 1, + VK_GEOMETRY_TYPE_INSTANCES_KHR = 2, + VK_GEOMETRY_TYPE_SPHERES_NV = 1000429004, + VK_GEOMETRY_TYPE_LINEAR_SWEPT_SPHERES_NV = 1000429005, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_GEOMETRY_TYPE_DENSE_GEOMETRY_FORMAT_TRIANGLES_AMDX = 1000478000, +#endif + VK_GEOMETRY_TYPE_MICROMAP_KHR = 1000623000, + VK_GEOMETRY_TYPE_TRIANGLES_NV = VK_GEOMETRY_TYPE_TRIANGLES_KHR, + VK_GEOMETRY_TYPE_AABBS_NV = VK_GEOMETRY_TYPE_AABBS_KHR, + VK_GEOMETRY_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkGeometryTypeKHR; +typedef VkGeometryTypeKHR VkGeometryTypeNV; + +typedef VkAccelerationStructureTypeKHR VkAccelerationStructureTypeNV; + + +typedef enum VkCopyAccelerationStructureModeKHR { + VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR = 0, + VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR = 1, + VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR = 2, + VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR = 3, + VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR, + VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR, + VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkCopyAccelerationStructureModeKHR; +typedef VkCopyAccelerationStructureModeKHR VkCopyAccelerationStructureModeNV; + + +typedef enum VkAccelerationStructureMemoryRequirementsTypeNV { + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkAccelerationStructureMemoryRequirementsTypeNV; + +typedef enum VkGeometryFlagBitsKHR { + VK_GEOMETRY_OPAQUE_BIT_KHR = 0x00000001, + VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR = 0x00000002, + VK_GEOMETRY_OPAQUE_BIT_NV = VK_GEOMETRY_OPAQUE_BIT_KHR, + VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR, + VK_GEOMETRY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkGeometryFlagBitsKHR; +typedef VkFlags VkGeometryFlagsKHR; +typedef VkGeometryFlagsKHR VkGeometryFlagsNV; + +typedef VkGeometryFlagBitsKHR VkGeometryFlagBitsNV; + + +typedef enum VkGeometryInstanceFlagBitsKHR { + VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR = 0x00000001, + VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR = 0x00000002, + VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR = 0x00000004, + VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR = 0x00000008, + VK_GEOMETRY_INSTANCE_FORCE_OPACITY_MICROMAP_2_STATE_BIT_KHR = 0x00000010, + VK_GEOMETRY_INSTANCE_DISABLE_OPACITY_MICROMAPS_BIT_KHR = 0x00000020, + VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR = VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR, + VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR, + VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR, + VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR, + VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR, + VK_GEOMETRY_INSTANCE_FORCE_OPACITY_MICROMAP_2_STATE_BIT_EXT = VK_GEOMETRY_INSTANCE_FORCE_OPACITY_MICROMAP_2_STATE_BIT_KHR, + // VK_GEOMETRY_INSTANCE_FORCE_OPACITY_MICROMAP_2_STATE_EXT is a legacy alias + VK_GEOMETRY_INSTANCE_FORCE_OPACITY_MICROMAP_2_STATE_EXT = VK_GEOMETRY_INSTANCE_FORCE_OPACITY_MICROMAP_2_STATE_BIT_EXT, + VK_GEOMETRY_INSTANCE_DISABLE_OPACITY_MICROMAPS_BIT_EXT = VK_GEOMETRY_INSTANCE_DISABLE_OPACITY_MICROMAPS_BIT_KHR, + // VK_GEOMETRY_INSTANCE_DISABLE_OPACITY_MICROMAPS_EXT is a legacy alias + VK_GEOMETRY_INSTANCE_DISABLE_OPACITY_MICROMAPS_EXT = VK_GEOMETRY_INSTANCE_DISABLE_OPACITY_MICROMAPS_BIT_EXT, + VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkGeometryInstanceFlagBitsKHR; +typedef VkFlags VkGeometryInstanceFlagsKHR; +typedef VkGeometryInstanceFlagsKHR VkGeometryInstanceFlagsNV; + +typedef VkGeometryInstanceFlagBitsKHR VkGeometryInstanceFlagBitsNV; + + +typedef enum VkBuildAccelerationStructureFlagBitsKHR { + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR = 0x00000001, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR = 0x00000002, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR = 0x00000004, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR = 0x00000008, + VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR = 0x00000010, + VK_BUILD_ACCELERATION_STRUCTURE_MOTION_BIT_NV = 0x00000020, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_DATA_UPDATE_BIT_EXT = 0x00000100, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISPLACEMENT_MICROMAP_UPDATE_BIT_NV = 0x00000200, +#endif + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DATA_ACCESS_BIT_KHR = 0x00000800, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_CLUSTER_OPACITY_MICROMAPS_BIT_NV = 0x00001000, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_UPDATE_BIT_KHR = 0x00000040, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISABLE_OPACITY_MICROMAPS_BIT_KHR = 0x00000080, + VK_BUILD_ACCELERATION_STRUCTURE_MICROMAP_LOSSY_BIT_KHR = 0x00000400, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_UPDATE_BIT_EXT = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_UPDATE_BIT_KHR, + // VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_UPDATE_EXT is a legacy alias + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_UPDATE_EXT = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_UPDATE_BIT_EXT, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISABLE_OPACITY_MICROMAPS_BIT_EXT = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISABLE_OPACITY_MICROMAPS_BIT_KHR, + // VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISABLE_OPACITY_MICROMAPS_EXT is a legacy alias + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISABLE_OPACITY_MICROMAPS_EXT = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISABLE_OPACITY_MICROMAPS_BIT_EXT, + // VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_DATA_UPDATE_EXT is a legacy alias + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_DATA_UPDATE_EXT = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_DATA_UPDATE_BIT_EXT, +#ifdef VK_ENABLE_BETA_EXTENSIONS + // VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISPLACEMENT_MICROMAP_UPDATE_NV is a legacy alias + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISPLACEMENT_MICROMAP_UPDATE_NV = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISPLACEMENT_MICROMAP_UPDATE_BIT_NV, +#endif + // VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DATA_ACCESS_KHR is a legacy alias + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DATA_ACCESS_KHR = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DATA_ACCESS_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkBuildAccelerationStructureFlagBitsKHR; +typedef VkFlags VkBuildAccelerationStructureFlagsKHR; +typedef VkBuildAccelerationStructureFlagBitsKHR VkBuildAccelerationStructureFlagBitsNV; + +typedef VkBuildAccelerationStructureFlagsKHR VkBuildAccelerationStructureFlagsNV; + +typedef struct VkRayTracingShaderGroupCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkRayTracingShaderGroupTypeKHR type; + uint32_t generalShader; + uint32_t closestHitShader; + uint32_t anyHitShader; + uint32_t intersectionShader; +} VkRayTracingShaderGroupCreateInfoNV; + +typedef struct VkRayTracingPipelineCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + uint32_t groupCount; + const VkRayTracingShaderGroupCreateInfoNV* pGroups; + uint32_t maxRecursionDepth; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkRayTracingPipelineCreateInfoNV; + +typedef struct VkGeometryTrianglesNV { + VkStructureType sType; + const void* pNext; + VkBuffer vertexData; + VkDeviceSize vertexOffset; + uint32_t vertexCount; + VkDeviceSize vertexStride; + VkFormat vertexFormat; + VkBuffer indexData; + VkDeviceSize indexOffset; + uint32_t indexCount; + VkIndexType indexType; + VkBuffer transformData; + VkDeviceSize transformOffset; +} VkGeometryTrianglesNV; + +typedef struct VkGeometryAABBNV { + VkStructureType sType; + const void* pNext; + VkBuffer aabbData; + uint32_t numAABBs; + uint32_t stride; + VkDeviceSize offset; +} VkGeometryAABBNV; + +typedef struct VkGeometryDataNV { + VkGeometryTrianglesNV triangles; + VkGeometryAABBNV aabbs; +} VkGeometryDataNV; + +typedef struct VkGeometryNV { + VkStructureType sType; + const void* pNext; + VkGeometryTypeKHR geometryType; + VkGeometryDataNV geometry; + VkGeometryFlagsKHR flags; +} VkGeometryNV; + +typedef struct VkAccelerationStructureInfoNV { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureTypeNV type; + VkBuildAccelerationStructureFlagsKHR flags; + uint32_t instanceCount; + uint32_t geometryCount; + const VkGeometryNV* pGeometries; +} VkAccelerationStructureInfoNV; + +typedef struct VkAccelerationStructureCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkDeviceSize compactedSize; + VkAccelerationStructureInfoNV info; +} VkAccelerationStructureCreateInfoNV; + +typedef struct VkBindAccelerationStructureMemoryInfoNV { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureNV accelerationStructure; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + uint32_t deviceIndexCount; + const uint32_t* pDeviceIndices; +} VkBindAccelerationStructureMemoryInfoNV; + +typedef struct VkWriteDescriptorSetAccelerationStructureNV { + VkStructureType sType; + const void* pNext; + uint32_t accelerationStructureCount; + const VkAccelerationStructureNV* pAccelerationStructures; +} VkWriteDescriptorSetAccelerationStructureNV; + +typedef struct VkAccelerationStructureMemoryRequirementsInfoNV { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureMemoryRequirementsTypeNV type; + VkAccelerationStructureNV accelerationStructure; +} VkAccelerationStructureMemoryRequirementsInfoNV; + +typedef struct VkPhysicalDeviceRayTracingPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t shaderGroupHandleSize; + uint32_t maxRecursionDepth; + uint32_t maxShaderGroupStride; + uint32_t shaderGroupBaseAlignment; + uint64_t maxGeometryCount; + uint64_t maxInstanceCount; + uint64_t maxTriangleCount; + uint32_t maxDescriptorSetAccelerationStructures; +} VkPhysicalDeviceRayTracingPropertiesNV; + +typedef struct VkTransformMatrixKHR { + float matrix[3][4]; +} VkTransformMatrixKHR; + +typedef VkTransformMatrixKHR VkTransformMatrixNV; + +typedef struct VkAabbPositionsKHR { + float minX; + float minY; + float minZ; + float maxX; + float maxY; + float maxZ; +} VkAabbPositionsKHR; + +typedef VkAabbPositionsKHR VkAabbPositionsNV; + +typedef struct VkAccelerationStructureInstanceKHR { + VkTransformMatrixKHR transform; + uint32_t instanceCustomIndex:24; + uint32_t mask:8; + uint32_t instanceShaderBindingTableRecordOffset:24; + VkGeometryInstanceFlagsKHR flags:8; + uint64_t accelerationStructureReference; +} VkAccelerationStructureInstanceKHR; + +typedef VkAccelerationStructureInstanceKHR VkAccelerationStructureInstanceNV; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureNV)(VkDevice device, const VkAccelerationStructureCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureNV* pAccelerationStructure); +typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNV)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNV)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNV* pBindInfos); +typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV* pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset); +typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkCopyAccelerationStructureModeKHR mode); +typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNV)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, uint32_t width, uint32_t height, uint32_t depth); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRayTracingPipelinesNV)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupHandlesKHR)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupHandlesNV)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, size_t dataSize, void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureNV* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); +typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNV)(VkDevice device, VkPipeline pipeline, uint32_t shader); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureNV( + VkDevice device, + const VkAccelerationStructureCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkAccelerationStructureNV* pAccelerationStructure); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureNV( + VkDevice device, + VkAccelerationStructureNV accelerationStructure, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsNV( + VkDevice device, + const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, + VkMemoryRequirements2* pMemoryRequirements); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkBindAccelerationStructureMemoryNV( + VkDevice device, + uint32_t bindInfoCount, + const VkBindAccelerationStructureMemoryInfoNV* pBindInfos); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNV( + VkCommandBuffer commandBuffer, + const VkAccelerationStructureInfoNV* pInfo, + VkBuffer instanceData, + VkDeviceSize instanceOffset, + VkBool32 update, + VkAccelerationStructureNV dst, + VkAccelerationStructureNV src, + VkBuffer scratch, + VkDeviceSize scratchOffset); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNV( + VkCommandBuffer commandBuffer, + VkAccelerationStructureNV dst, + VkAccelerationStructureNV src, + VkCopyAccelerationStructureModeKHR mode); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNV( + VkCommandBuffer commandBuffer, + VkBuffer raygenShaderBindingTableBuffer, + VkDeviceSize raygenShaderBindingOffset, + VkBuffer missShaderBindingTableBuffer, + VkDeviceSize missShaderBindingOffset, + VkDeviceSize missShaderBindingStride, + VkBuffer hitShaderBindingTableBuffer, + VkDeviceSize hitShaderBindingOffset, + VkDeviceSize hitShaderBindingStride, + VkBuffer callableShaderBindingTableBuffer, + VkDeviceSize callableShaderBindingOffset, + VkDeviceSize callableShaderBindingStride, + uint32_t width, + uint32_t height, + uint32_t depth); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRayTracingPipelinesNV( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkRayTracingPipelineCreateInfoNV* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesKHR( + VkDevice device, + VkPipeline pipeline, + uint32_t firstGroup, + uint32_t groupCount, + size_t dataSize, + void* pData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesNV( + VkDevice device, + VkPipeline pipeline, + uint32_t firstGroup, + uint32_t groupCount, + size_t dataSize, + void* pData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetAccelerationStructureHandleNV( + VkDevice device, + VkAccelerationStructureNV accelerationStructure, + size_t dataSize, + void* pData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructuresPropertiesNV( + VkCommandBuffer commandBuffer, + uint32_t accelerationStructureCount, + const VkAccelerationStructureNV* pAccelerationStructures, + VkQueryType queryType, + VkQueryPool queryPool, + uint32_t firstQuery); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCompileDeferredNV( + VkDevice device, + VkPipeline pipeline, + uint32_t shader); +#endif +#endif + + +// VK_NV_representative_fragment_test is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_representative_fragment_test 1 +#define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION 2 +#define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_EXTENSION_NAME "VK_NV_representative_fragment_test" +typedef struct VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 representativeFragmentTest; +} VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV; + +typedef struct VkPipelineRepresentativeFragmentTestStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 representativeFragmentTestEnable; +} VkPipelineRepresentativeFragmentTestStateCreateInfoNV; + + + +// VK_EXT_filter_cubic is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_filter_cubic 1 +#define VK_EXT_FILTER_CUBIC_SPEC_VERSION 3 +#define VK_EXT_FILTER_CUBIC_EXTENSION_NAME "VK_EXT_filter_cubic" +typedef struct VkPhysicalDeviceImageViewImageFormatInfoEXT { + VkStructureType sType; + void* pNext; + VkImageViewType imageViewType; +} VkPhysicalDeviceImageViewImageFormatInfoEXT; + +typedef struct VkFilterCubicImageViewImageFormatPropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 filterCubic; + VkBool32 filterCubicMinmax; +} VkFilterCubicImageViewImageFormatPropertiesEXT; + + + +// VK_QCOM_render_pass_shader_resolve is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_render_pass_shader_resolve 1 +#define VK_QCOM_RENDER_PASS_SHADER_RESOLVE_SPEC_VERSION 4 +#define VK_QCOM_RENDER_PASS_SHADER_RESOLVE_EXTENSION_NAME "VK_QCOM_render_pass_shader_resolve" + + +// VK_QCOM_cooperative_matrix_conversion is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_cooperative_matrix_conversion 1 +#define VK_QCOM_COOPERATIVE_MATRIX_CONVERSION_SPEC_VERSION 1 +#define VK_QCOM_COOPERATIVE_MATRIX_CONVERSION_EXTENSION_NAME "VK_QCOM_cooperative_matrix_conversion" +typedef struct VkPhysicalDeviceCooperativeMatrixConversionFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrixConversion; +} VkPhysicalDeviceCooperativeMatrixConversionFeaturesQCOM; + + + +// VK_QCOM_elapsed_timer_query is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_elapsed_timer_query 1 +#define VK_QCOM_ELAPSED_TIMER_QUERY_SPEC_VERSION 1 +#define VK_QCOM_ELAPSED_TIMER_QUERY_EXTENSION_NAME "VK_QCOM_elapsed_timer_query" +typedef struct VkPhysicalDeviceElapsedTimerQueryFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 elapsedTimerQuery; +} VkPhysicalDeviceElapsedTimerQueryFeaturesQCOM; + + + +// VK_EXT_global_priority is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_global_priority 1 +#define VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION 2 +#define VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME "VK_EXT_global_priority" +typedef VkQueueGlobalPriority VkQueueGlobalPriorityEXT; + +typedef VkDeviceQueueGlobalPriorityCreateInfo VkDeviceQueueGlobalPriorityCreateInfoEXT; + + + +// VK_EXT_external_memory_host is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_external_memory_host 1 +#define VK_EXT_EXTERNAL_MEMORY_HOST_SPEC_VERSION 1 +#define VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME "VK_EXT_external_memory_host" +typedef struct VkImportMemoryHostPointerInfoEXT { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + void* pHostPointer; +} VkImportMemoryHostPointerInfoEXT; + +typedef struct VkMemoryHostPointerPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t memoryTypeBits; +} VkMemoryHostPointerPropertiesEXT; + +typedef struct VkPhysicalDeviceExternalMemoryHostPropertiesEXT { + VkStructureType sType; + void* pNext; + VkDeviceSize minImportedHostPointerAlignment; +} VkPhysicalDeviceExternalMemoryHostPropertiesEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryHostPointerPropertiesEXT)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, const void* pHostPointer, VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryHostPointerPropertiesEXT( + VkDevice device, + VkExternalMemoryHandleTypeFlagBits handleType, + const void* pHostPointer, + VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties); +#endif +#endif + + +// VK_AMD_buffer_marker is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_buffer_marker 1 +#define VK_AMD_BUFFER_MARKER_SPEC_VERSION 1 +#define VK_AMD_BUFFER_MARKER_EXTENSION_NAME "VK_AMD_buffer_marker" +typedef void (VKAPI_PTR *PFN_vkCmdWriteBufferMarkerAMD)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); +typedef void (VKAPI_PTR *PFN_vkCmdWriteBufferMarker2AMD)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdWriteBufferMarkerAMD( + VkCommandBuffer commandBuffer, + VkPipelineStageFlagBits pipelineStage, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + uint32_t marker); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdWriteBufferMarker2AMD( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags2 stage, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + uint32_t marker); +#endif +#endif + + +// VK_AMD_pipeline_compiler_control is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_pipeline_compiler_control 1 +#define VK_AMD_PIPELINE_COMPILER_CONTROL_SPEC_VERSION 1 +#define VK_AMD_PIPELINE_COMPILER_CONTROL_EXTENSION_NAME "VK_AMD_pipeline_compiler_control" + +typedef enum VkPipelineCompilerControlFlagBitsAMD { + VK_PIPELINE_COMPILER_CONTROL_FLAG_BITS_MAX_ENUM_AMD = 0x7FFFFFFF +} VkPipelineCompilerControlFlagBitsAMD; +typedef VkFlags VkPipelineCompilerControlFlagsAMD; +typedef struct VkPipelineCompilerControlCreateInfoAMD { + VkStructureType sType; + const void* pNext; + VkPipelineCompilerControlFlagsAMD compilerControlFlags; +} VkPipelineCompilerControlCreateInfoAMD; + + + +// VK_EXT_calibrated_timestamps is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_calibrated_timestamps 1 +#define VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION 2 +#define VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_EXT_calibrated_timestamps" +typedef VkTimeDomainKHR VkTimeDomainEXT; + +typedef VkCalibratedTimestampInfoKHR VkCalibratedTimestampInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice physicalDevice, uint32_t* pTimeDomainCount, VkTimeDomainKHR* pTimeDomains); +typedef VkResult (VKAPI_PTR *PFN_vkGetCalibratedTimestampsEXT)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoKHR* pTimestampInfos, uint64_t* pTimestamps, uint64_t* pMaxDeviation); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCalibrateableTimeDomainsEXT( + VkPhysicalDevice physicalDevice, + uint32_t* pTimeDomainCount, + VkTimeDomainKHR* pTimeDomains); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetCalibratedTimestampsEXT( + VkDevice device, + uint32_t timestampCount, + const VkCalibratedTimestampInfoKHR* pTimestampInfos, + uint64_t* pTimestamps, + uint64_t* pMaxDeviation); +#endif +#endif + + +// VK_AMD_shader_core_properties is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_core_properties 1 +#define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 2 +#define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties" +typedef struct VkPhysicalDeviceShaderCorePropertiesAMD { + VkStructureType sType; + void* pNext; + uint32_t shaderEngineCount; + uint32_t shaderArraysPerEngineCount; + uint32_t computeUnitsPerShaderArray; + uint32_t simdPerComputeUnit; + uint32_t wavefrontsPerSimd; + uint32_t wavefrontSize; + uint32_t sgprsPerSimd; + uint32_t minSgprAllocation; + uint32_t maxSgprAllocation; + uint32_t sgprAllocationGranularity; + uint32_t vgprsPerSimd; + uint32_t minVgprAllocation; + uint32_t maxVgprAllocation; + uint32_t vgprAllocationGranularity; +} VkPhysicalDeviceShaderCorePropertiesAMD; + + + +// VK_AMD_memory_overallocation_behavior is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_memory_overallocation_behavior 1 +#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION 1 +#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME "VK_AMD_memory_overallocation_behavior" + +typedef enum VkMemoryOverallocationBehaviorAMD { + VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_MAX_ENUM_AMD = 0x7FFFFFFF +} VkMemoryOverallocationBehaviorAMD; +typedef struct VkDeviceMemoryOverallocationCreateInfoAMD { + VkStructureType sType; + const void* pNext; + VkMemoryOverallocationBehaviorAMD overallocationBehavior; +} VkDeviceMemoryOverallocationCreateInfoAMD; + + + +// VK_EXT_vertex_attribute_divisor is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_vertex_attribute_divisor 1 +#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 3 +#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor" +typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxVertexAttribDivisor; +} VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT; + +typedef VkVertexInputBindingDivisorDescription VkVertexInputBindingDivisorDescriptionEXT; + +typedef VkPipelineVertexInputDivisorStateCreateInfo VkPipelineVertexInputDivisorStateCreateInfoEXT; + +typedef VkPhysicalDeviceVertexAttributeDivisorFeatures VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT; + + + +// VK_EXT_pipeline_creation_feedback is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_pipeline_creation_feedback 1 +#define VK_EXT_PIPELINE_CREATION_FEEDBACK_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME "VK_EXT_pipeline_creation_feedback" +typedef VkPipelineCreationFeedbackFlagBits VkPipelineCreationFeedbackFlagBitsEXT; + +typedef VkPipelineCreationFeedbackFlags VkPipelineCreationFeedbackFlagsEXT; + +typedef VkPipelineCreationFeedbackCreateInfo VkPipelineCreationFeedbackCreateInfoEXT; + +typedef VkPipelineCreationFeedback VkPipelineCreationFeedbackEXT; + + + +// VK_NV_shader_subgroup_partitioned is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_shader_subgroup_partitioned 1 +#define VK_NV_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION 1 +#define VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME "VK_NV_shader_subgroup_partitioned" + + +// VK_NV_compute_shader_derivatives is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_compute_shader_derivatives 1 +#define VK_NV_COMPUTE_SHADER_DERIVATIVES_SPEC_VERSION 1 +#define VK_NV_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME "VK_NV_compute_shader_derivatives" +typedef VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR VkPhysicalDeviceComputeShaderDerivativesFeaturesNV; + + + +// VK_NV_mesh_shader is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_mesh_shader 1 +#define VK_NV_MESH_SHADER_SPEC_VERSION 1 +#define VK_NV_MESH_SHADER_EXTENSION_NAME "VK_NV_mesh_shader" +typedef struct VkPhysicalDeviceMeshShaderFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 taskShader; + VkBool32 meshShader; +} VkPhysicalDeviceMeshShaderFeaturesNV; + +typedef struct VkPhysicalDeviceMeshShaderPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t maxDrawMeshTasksCount; + uint32_t maxTaskWorkGroupInvocations; + uint32_t maxTaskWorkGroupSize[3]; + uint32_t maxTaskTotalMemorySize; + uint32_t maxTaskOutputCount; + uint32_t maxMeshWorkGroupInvocations; + uint32_t maxMeshWorkGroupSize[3]; + uint32_t maxMeshTotalMemorySize; + uint32_t maxMeshOutputVertices; + uint32_t maxMeshOutputPrimitives; + uint32_t maxMeshMultiviewViewCount; + uint32_t meshOutputPerVertexGranularity; + uint32_t meshOutputPerPrimitiveGranularity; +} VkPhysicalDeviceMeshShaderPropertiesNV; + +typedef struct VkDrawMeshTasksIndirectCommandNV { + uint32_t taskCount; + uint32_t firstTask; +} VkDrawMeshTasksIndirectCommandNV; + +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksNV)(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask); +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectNV)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectCountNV)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksNV( + VkCommandBuffer commandBuffer, + uint32_t taskCount, + uint32_t firstTask); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectNV( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectCountNV( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); +#endif +#endif + + +// VK_NV_fragment_shader_barycentric is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_fragment_shader_barycentric 1 +#define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1 +#define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_NV_fragment_shader_barycentric" +typedef VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV; + + + +// VK_NV_shader_image_footprint is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_shader_image_footprint 1 +#define VK_NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION 2 +#define VK_NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME "VK_NV_shader_image_footprint" +typedef struct VkPhysicalDeviceShaderImageFootprintFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 imageFootprint; +} VkPhysicalDeviceShaderImageFootprintFeaturesNV; + + + +// VK_NV_scissor_exclusive is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_scissor_exclusive 1 +#define VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION 2 +#define VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME "VK_NV_scissor_exclusive" +typedef struct VkPipelineViewportExclusiveScissorStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t exclusiveScissorCount; + const VkRect2D* pExclusiveScissors; +} VkPipelineViewportExclusiveScissorStateCreateInfoNV; + +typedef struct VkPhysicalDeviceExclusiveScissorFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 exclusiveScissor; +} VkPhysicalDeviceExclusiveScissorFeaturesNV; + +typedef void (VKAPI_PTR *PFN_vkCmdSetExclusiveScissorEnableNV)(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor, uint32_t exclusiveScissorCount, const VkBool32* pExclusiveScissorEnables); +typedef void (VKAPI_PTR *PFN_vkCmdSetExclusiveScissorNV)(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor, uint32_t exclusiveScissorCount, const VkRect2D* pExclusiveScissors); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetExclusiveScissorEnableNV( + VkCommandBuffer commandBuffer, + uint32_t firstExclusiveScissor, + uint32_t exclusiveScissorCount, + const VkBool32* pExclusiveScissorEnables); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetExclusiveScissorNV( + VkCommandBuffer commandBuffer, + uint32_t firstExclusiveScissor, + uint32_t exclusiveScissorCount, + const VkRect2D* pExclusiveScissors); +#endif +#endif + + +// VK_NV_device_diagnostic_checkpoints is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_device_diagnostic_checkpoints 1 +#define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_SPEC_VERSION 2 +#define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME "VK_NV_device_diagnostic_checkpoints" +typedef struct VkQueueFamilyCheckpointPropertiesNV { + VkStructureType sType; + void* pNext; + VkPipelineStageFlags checkpointExecutionStageMask; +} VkQueueFamilyCheckpointPropertiesNV; + +typedef struct VkCheckpointDataNV { + VkStructureType sType; + void* pNext; + VkPipelineStageFlagBits stage; + void* pCheckpointMarker; +} VkCheckpointDataNV; + +typedef struct VkQueueFamilyCheckpointProperties2NV { + VkStructureType sType; + void* pNext; + VkPipelineStageFlags2 checkpointExecutionStageMask; +} VkQueueFamilyCheckpointProperties2NV; + +typedef struct VkCheckpointData2NV { + VkStructureType sType; + void* pNext; + VkPipelineStageFlags2 stage; + void* pCheckpointMarker; +} VkCheckpointData2NV; + +typedef void (VKAPI_PTR *PFN_vkCmdSetCheckpointNV)(VkCommandBuffer commandBuffer, const void* pCheckpointMarker); +typedef void (VKAPI_PTR *PFN_vkGetQueueCheckpointDataNV)(VkQueue queue, uint32_t* pCheckpointDataCount, VkCheckpointDataNV* pCheckpointData); +typedef void (VKAPI_PTR *PFN_vkGetQueueCheckpointData2NV)(VkQueue queue, uint32_t* pCheckpointDataCount, VkCheckpointData2NV* pCheckpointData); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetCheckpointNV( + VkCommandBuffer commandBuffer, + const void* pCheckpointMarker); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetQueueCheckpointDataNV( + VkQueue queue, + uint32_t* pCheckpointDataCount, + VkCheckpointDataNV* pCheckpointData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetQueueCheckpointData2NV( + VkQueue queue, + uint32_t* pCheckpointDataCount, + VkCheckpointData2NV* pCheckpointData); +#endif +#endif + + +// VK_EXT_present_timing is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_present_timing 1 +#define VK_EXT_PRESENT_TIMING_SPEC_VERSION 3 +#define VK_EXT_PRESENT_TIMING_EXTENSION_NAME "VK_EXT_present_timing" + +typedef enum VkPresentStageFlagBitsEXT { + VK_PRESENT_STAGE_QUEUE_OPERATIONS_END_BIT_EXT = 0x00000001, + VK_PRESENT_STAGE_REQUEST_DEQUEUED_BIT_EXT = 0x00000002, + VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_OUT_BIT_EXT = 0x00000004, + VK_PRESENT_STAGE_IMAGE_FIRST_PIXEL_VISIBLE_BIT_EXT = 0x00000008, + VK_PRESENT_STAGE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkPresentStageFlagBitsEXT; +typedef VkFlags VkPresentStageFlagsEXT; + +typedef enum VkPastPresentationTimingFlagBitsEXT { + VK_PAST_PRESENTATION_TIMING_ALLOW_PARTIAL_RESULTS_BIT_EXT = 0x00000001, + VK_PAST_PRESENTATION_TIMING_ALLOW_OUT_OF_ORDER_RESULTS_BIT_EXT = 0x00000002, + VK_PAST_PRESENTATION_TIMING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkPastPresentationTimingFlagBitsEXT; +typedef VkFlags VkPastPresentationTimingFlagsEXT; + +typedef enum VkPresentTimingInfoFlagBitsEXT { + VK_PRESENT_TIMING_INFO_PRESENT_AT_RELATIVE_TIME_BIT_EXT = 0x00000001, + VK_PRESENT_TIMING_INFO_PRESENT_AT_NEAREST_REFRESH_CYCLE_BIT_EXT = 0x00000002, + VK_PRESENT_TIMING_INFO_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkPresentTimingInfoFlagBitsEXT; +typedef VkFlags VkPresentTimingInfoFlagsEXT; +typedef struct VkPhysicalDevicePresentTimingFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 presentTiming; + VkBool32 presentAtAbsoluteTime; + VkBool32 presentAtRelativeTime; +} VkPhysicalDevicePresentTimingFeaturesEXT; + +typedef struct VkPresentTimingSurfaceCapabilitiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 presentTimingSupported; + VkBool32 presentAtAbsoluteTimeSupported; + VkBool32 presentAtRelativeTimeSupported; + VkPresentStageFlagsEXT presentStageQueries; +} VkPresentTimingSurfaceCapabilitiesEXT; + +typedef struct VkSwapchainCalibratedTimestampInfoEXT { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; + VkPresentStageFlagsEXT presentStage; + uint64_t timeDomainId; +} VkSwapchainCalibratedTimestampInfoEXT; + +typedef struct VkSwapchainTimingPropertiesEXT { + VkStructureType sType; + void* pNext; + uint64_t refreshDuration; + uint64_t refreshInterval; +} VkSwapchainTimingPropertiesEXT; + +typedef struct VkSwapchainTimeDomainPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t timeDomainCount; + VkTimeDomainKHR* pTimeDomains; + uint64_t* pTimeDomainIds; +} VkSwapchainTimeDomainPropertiesEXT; + +typedef struct VkPastPresentationTimingInfoEXT { + VkStructureType sType; + const void* pNext; + VkPastPresentationTimingFlagsEXT flags; + VkSwapchainKHR swapchain; +} VkPastPresentationTimingInfoEXT; + +typedef struct VkPresentStageTimeEXT { + VkPresentStageFlagsEXT stage; + uint64_t time; +} VkPresentStageTimeEXT; + +typedef struct VkPastPresentationTimingEXT { + VkStructureType sType; + void* pNext; + uint64_t presentId; + uint64_t targetTime; + uint32_t presentStageCount; + VkPresentStageTimeEXT* pPresentStages; + VkTimeDomainKHR timeDomain; + uint64_t timeDomainId; + VkBool32 reportComplete; +} VkPastPresentationTimingEXT; + +typedef struct VkPastPresentationTimingPropertiesEXT { + VkStructureType sType; + void* pNext; + uint64_t timingPropertiesCounter; + uint64_t timeDomainsCounter; + uint32_t presentationTimingCount; + VkPastPresentationTimingEXT* pPresentationTimings; +} VkPastPresentationTimingPropertiesEXT; + +typedef struct VkPresentTimingInfoEXT { + VkStructureType sType; + const void* pNext; + VkPresentTimingInfoFlagsEXT flags; + uint64_t targetTime; + uint64_t timeDomainId; + VkPresentStageFlagsEXT presentStageQueries; + VkPresentStageFlagsEXT targetTimeDomainPresentStage; +} VkPresentTimingInfoEXT; + +typedef struct VkPresentTimingsInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const VkPresentTimingInfoEXT* pTimingInfos; +} VkPresentTimingsInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkSetSwapchainPresentTimingQueueSizeEXT)(VkDevice device, VkSwapchainKHR swapchain, uint32_t size); +typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainTimingPropertiesEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSwapchainTimingPropertiesEXT* pSwapchainTimingProperties, uint64_t* pSwapchainTimingPropertiesCounter); +typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainTimeDomainPropertiesEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSwapchainTimeDomainPropertiesEXT* pSwapchainTimeDomainProperties, uint64_t* pTimeDomainsCounter); +typedef VkResult (VKAPI_PTR *PFN_vkGetPastPresentationTimingEXT)(VkDevice device, const VkPastPresentationTimingInfoEXT* pPastPresentationTimingInfo, VkPastPresentationTimingPropertiesEXT* pPastPresentationTimingProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkSetSwapchainPresentTimingQueueSizeEXT( + VkDevice device, + VkSwapchainKHR swapchain, + uint32_t size); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainTimingPropertiesEXT( + VkDevice device, + VkSwapchainKHR swapchain, + VkSwapchainTimingPropertiesEXT* pSwapchainTimingProperties, + uint64_t* pSwapchainTimingPropertiesCounter); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainTimeDomainPropertiesEXT( + VkDevice device, + VkSwapchainKHR swapchain, + VkSwapchainTimeDomainPropertiesEXT* pSwapchainTimeDomainProperties, + uint64_t* pTimeDomainsCounter); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPastPresentationTimingEXT( + VkDevice device, + const VkPastPresentationTimingInfoEXT* pPastPresentationTimingInfo, + VkPastPresentationTimingPropertiesEXT* pPastPresentationTimingProperties); +#endif +#endif + + +// VK_INTEL_shader_integer_functions2 is a preprocessor guard. Do not pass it to API calls. +#define VK_INTEL_shader_integer_functions2 1 +#define VK_INTEL_SHADER_INTEGER_FUNCTIONS_2_SPEC_VERSION 1 +#define VK_INTEL_SHADER_INTEGER_FUNCTIONS_2_EXTENSION_NAME "VK_INTEL_shader_integer_functions2" +typedef struct VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL { + VkStructureType sType; + void* pNext; + VkBool32 shaderIntegerFunctions2; +} VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL; + + + +// VK_INTEL_performance_query is a preprocessor guard. Do not pass it to API calls. +#define VK_INTEL_performance_query 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPerformanceConfigurationINTEL) +#define VK_INTEL_PERFORMANCE_QUERY_SPEC_VERSION 2 +#define VK_INTEL_PERFORMANCE_QUERY_EXTENSION_NAME "VK_INTEL_performance_query" + +typedef enum VkPerformanceConfigurationTypeINTEL { + VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL = 0, + VK_PERFORMANCE_CONFIGURATION_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF +} VkPerformanceConfigurationTypeINTEL; + +typedef enum VkQueryPoolSamplingModeINTEL { + VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL = 0, + VK_QUERY_POOL_SAMPLING_MODE_MAX_ENUM_INTEL = 0x7FFFFFFF +} VkQueryPoolSamplingModeINTEL; + +typedef enum VkPerformanceOverrideTypeINTEL { + VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL = 0, + VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL = 1, + VK_PERFORMANCE_OVERRIDE_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF +} VkPerformanceOverrideTypeINTEL; + +typedef enum VkPerformanceParameterTypeINTEL { + VK_PERFORMANCE_PARAMETER_TYPE_HW_COUNTERS_SUPPORTED_INTEL = 0, + VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL = 1, + VK_PERFORMANCE_PARAMETER_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF +} VkPerformanceParameterTypeINTEL; + +typedef enum VkPerformanceValueTypeINTEL { + VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL = 0, + VK_PERFORMANCE_VALUE_TYPE_UINT64_INTEL = 1, + VK_PERFORMANCE_VALUE_TYPE_FLOAT_INTEL = 2, + VK_PERFORMANCE_VALUE_TYPE_BOOL_INTEL = 3, + VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL = 4, + VK_PERFORMANCE_VALUE_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF +} VkPerformanceValueTypeINTEL; +typedef union VkPerformanceValueDataINTEL { + uint32_t value32; + uint64_t value64; + float valueFloat; + VkBool32 valueBool; + const char* valueString; +} VkPerformanceValueDataINTEL; + +typedef struct VkPerformanceValueINTEL { + VkPerformanceValueTypeINTEL type; + VkPerformanceValueDataINTEL data; +} VkPerformanceValueINTEL; + +typedef struct VkInitializePerformanceApiInfoINTEL { + VkStructureType sType; + const void* pNext; + void* pUserData; +} VkInitializePerformanceApiInfoINTEL; + +typedef struct VkQueryPoolPerformanceQueryCreateInfoINTEL { + VkStructureType sType; + const void* pNext; + VkQueryPoolSamplingModeINTEL performanceCountersSampling; +} VkQueryPoolPerformanceQueryCreateInfoINTEL; + +typedef VkQueryPoolPerformanceQueryCreateInfoINTEL VkQueryPoolCreateInfoINTEL; + +typedef struct VkPerformanceMarkerInfoINTEL { + VkStructureType sType; + const void* pNext; + uint64_t marker; +} VkPerformanceMarkerInfoINTEL; + +typedef struct VkPerformanceStreamMarkerInfoINTEL { + VkStructureType sType; + const void* pNext; + uint32_t marker; +} VkPerformanceStreamMarkerInfoINTEL; + +typedef struct VkPerformanceOverrideInfoINTEL { + VkStructureType sType; + const void* pNext; + VkPerformanceOverrideTypeINTEL type; + VkBool32 enable; + uint64_t parameter; +} VkPerformanceOverrideInfoINTEL; + +typedef struct VkPerformanceConfigurationAcquireInfoINTEL { + VkStructureType sType; + const void* pNext; + VkPerformanceConfigurationTypeINTEL type; +} VkPerformanceConfigurationAcquireInfoINTEL; + +typedef VkResult (VKAPI_PTR *PFN_vkInitializePerformanceApiINTEL)(VkDevice device, const VkInitializePerformanceApiInfoINTEL* pInitializeInfo); +typedef void (VKAPI_PTR *PFN_vkUninitializePerformanceApiINTEL)(VkDevice device); +typedef VkResult (VKAPI_PTR *PFN_vkCmdSetPerformanceMarkerINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceMarkerInfoINTEL* pMarkerInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCmdSetPerformanceStreamMarkerINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceStreamMarkerInfoINTEL* pMarkerInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCmdSetPerformanceOverrideINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceOverrideInfoINTEL* pOverrideInfo); +typedef VkResult (VKAPI_PTR *PFN_vkAcquirePerformanceConfigurationINTEL)(VkDevice device, const VkPerformanceConfigurationAcquireInfoINTEL* pAcquireInfo, VkPerformanceConfigurationINTEL* pConfiguration); +typedef VkResult (VKAPI_PTR *PFN_vkReleasePerformanceConfigurationINTEL)(VkDevice device, VkPerformanceConfigurationINTEL configuration); +typedef VkResult (VKAPI_PTR *PFN_vkQueueSetPerformanceConfigurationINTEL)(VkQueue queue, VkPerformanceConfigurationINTEL configuration); +typedef VkResult (VKAPI_PTR *PFN_vkGetPerformanceParameterINTEL)(VkDevice device, VkPerformanceParameterTypeINTEL parameter, VkPerformanceValueINTEL* pValue); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkInitializePerformanceApiINTEL( + VkDevice device, + const VkInitializePerformanceApiInfoINTEL* pInitializeInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkUninitializePerformanceApiINTEL( + VkDevice device); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCmdSetPerformanceMarkerINTEL( + VkCommandBuffer commandBuffer, + const VkPerformanceMarkerInfoINTEL* pMarkerInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCmdSetPerformanceStreamMarkerINTEL( + VkCommandBuffer commandBuffer, + const VkPerformanceStreamMarkerInfoINTEL* pMarkerInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCmdSetPerformanceOverrideINTEL( + VkCommandBuffer commandBuffer, + const VkPerformanceOverrideInfoINTEL* pOverrideInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkAcquirePerformanceConfigurationINTEL( + VkDevice device, + const VkPerformanceConfigurationAcquireInfoINTEL* pAcquireInfo, + VkPerformanceConfigurationINTEL* pConfiguration); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkReleasePerformanceConfigurationINTEL( + VkDevice device, + VkPerformanceConfigurationINTEL configuration); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkQueueSetPerformanceConfigurationINTEL( + VkQueue queue, + VkPerformanceConfigurationINTEL configuration); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPerformanceParameterINTEL( + VkDevice device, + VkPerformanceParameterTypeINTEL parameter, + VkPerformanceValueINTEL* pValue); +#endif +#endif + + +// VK_EXT_pci_bus_info is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_pci_bus_info 1 +#define VK_EXT_PCI_BUS_INFO_SPEC_VERSION 2 +#define VK_EXT_PCI_BUS_INFO_EXTENSION_NAME "VK_EXT_pci_bus_info" +typedef struct VkPhysicalDevicePCIBusInfoPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t pciDomain; + uint32_t pciBus; + uint32_t pciDevice; + uint32_t pciFunction; +} VkPhysicalDevicePCIBusInfoPropertiesEXT; + + + +// VK_AMD_display_native_hdr is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_display_native_hdr 1 +#define VK_AMD_DISPLAY_NATIVE_HDR_SPEC_VERSION 1 +#define VK_AMD_DISPLAY_NATIVE_HDR_EXTENSION_NAME "VK_AMD_display_native_hdr" +typedef struct VkDisplayNativeHdrSurfaceCapabilitiesAMD { + VkStructureType sType; + void* pNext; + VkBool32 localDimmingSupport; +} VkDisplayNativeHdrSurfaceCapabilitiesAMD; + +typedef struct VkSwapchainDisplayNativeHdrCreateInfoAMD { + VkStructureType sType; + const void* pNext; + VkBool32 localDimmingEnable; +} VkSwapchainDisplayNativeHdrCreateInfoAMD; + +typedef void (VKAPI_PTR *PFN_vkSetLocalDimmingAMD)(VkDevice device, VkSwapchainKHR swapChain, VkBool32 localDimmingEnable); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkSetLocalDimmingAMD( + VkDevice device, + VkSwapchainKHR swapChain, + VkBool32 localDimmingEnable); +#endif +#endif + + +// VK_EXT_fragment_density_map is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_fragment_density_map 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION 3 +#define VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME "VK_EXT_fragment_density_map" +typedef struct VkPhysicalDeviceFragmentDensityMapFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 fragmentDensityMap; + VkBool32 fragmentDensityMapDynamic; + VkBool32 fragmentDensityMapNonSubsampledImages; +} VkPhysicalDeviceFragmentDensityMapFeaturesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMapPropertiesEXT { + VkStructureType sType; + void* pNext; + VkExtent2D minFragmentDensityTexelSize; + VkExtent2D maxFragmentDensityTexelSize; + VkBool32 fragmentDensityInvocations; +} VkPhysicalDeviceFragmentDensityMapPropertiesEXT; + +typedef struct VkRenderPassFragmentDensityMapCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkAttachmentReference fragmentDensityMapAttachment; +} VkRenderPassFragmentDensityMapCreateInfoEXT; + +typedef struct VkRenderingFragmentDensityMapAttachmentInfoEXT { + VkStructureType sType; + const void* pNext; + VkImageView imageView; + VkImageLayout imageLayout; +} VkRenderingFragmentDensityMapAttachmentInfoEXT; + + + +// VK_EXT_scalar_block_layout is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_scalar_block_layout 1 +#define VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION 1 +#define VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME "VK_EXT_scalar_block_layout" +typedef VkPhysicalDeviceScalarBlockLayoutFeatures VkPhysicalDeviceScalarBlockLayoutFeaturesEXT; + + + +// VK_GOOGLE_hlsl_functionality1 is a preprocessor guard. Do not pass it to API calls. +#define VK_GOOGLE_hlsl_functionality1 1 +#define VK_GOOGLE_HLSL_FUNCTIONALITY_1_SPEC_VERSION 1 +#define VK_GOOGLE_HLSL_FUNCTIONALITY_1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1" +// VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION is a legacy alias +#define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION VK_GOOGLE_HLSL_FUNCTIONALITY_1_SPEC_VERSION +// VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME is a legacy alias +#define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME VK_GOOGLE_HLSL_FUNCTIONALITY_1_EXTENSION_NAME + + +// VK_GOOGLE_decorate_string is a preprocessor guard. Do not pass it to API calls. +#define VK_GOOGLE_decorate_string 1 +#define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 1 +#define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string" + + +// VK_EXT_subgroup_size_control is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_subgroup_size_control 1 +#define VK_EXT_SUBGROUP_SIZE_CONTROL_SPEC_VERSION 2 +#define VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME "VK_EXT_subgroup_size_control" +typedef VkPhysicalDeviceSubgroupSizeControlFeatures VkPhysicalDeviceSubgroupSizeControlFeaturesEXT; + +typedef VkPhysicalDeviceSubgroupSizeControlProperties VkPhysicalDeviceSubgroupSizeControlPropertiesEXT; + +typedef VkPipelineShaderStageRequiredSubgroupSizeCreateInfo VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT; + + + +// VK_AMD_shader_core_properties2 is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_core_properties2 1 +#define VK_AMD_SHADER_CORE_PROPERTIES_2_SPEC_VERSION 1 +#define VK_AMD_SHADER_CORE_PROPERTIES_2_EXTENSION_NAME "VK_AMD_shader_core_properties2" + +typedef enum VkShaderCorePropertiesFlagBitsAMD { + VK_SHADER_CORE_PROPERTIES_FLAG_BITS_MAX_ENUM_AMD = 0x7FFFFFFF +} VkShaderCorePropertiesFlagBitsAMD; +typedef VkFlags VkShaderCorePropertiesFlagsAMD; +typedef struct VkPhysicalDeviceShaderCoreProperties2AMD { + VkStructureType sType; + void* pNext; + VkShaderCorePropertiesFlagsAMD shaderCoreFeatures; + uint32_t activeComputeUnitCount; +} VkPhysicalDeviceShaderCoreProperties2AMD; + + + +// VK_AMD_device_coherent_memory is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_device_coherent_memory 1 +#define VK_AMD_DEVICE_COHERENT_MEMORY_SPEC_VERSION 1 +#define VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME "VK_AMD_device_coherent_memory" +typedef struct VkPhysicalDeviceCoherentMemoryFeaturesAMD { + VkStructureType sType; + void* pNext; + VkBool32 deviceCoherentMemory; +} VkPhysicalDeviceCoherentMemoryFeaturesAMD; + + + +// VK_EXT_shader_image_atomic_int64 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_image_atomic_int64 1 +#define VK_EXT_SHADER_IMAGE_ATOMIC_INT64_SPEC_VERSION 1 +#define VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME "VK_EXT_shader_image_atomic_int64" +typedef struct VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderImageInt64Atomics; + VkBool32 sparseImageInt64Atomics; +} VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT; + + + +// VK_EXT_memory_budget is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_memory_budget 1 +#define VK_EXT_MEMORY_BUDGET_SPEC_VERSION 1 +#define VK_EXT_MEMORY_BUDGET_EXTENSION_NAME "VK_EXT_memory_budget" +typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT { + VkStructureType sType; + void* pNext; + VkDeviceSize heapBudget[VK_MAX_MEMORY_HEAPS]; + VkDeviceSize heapUsage[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryBudgetPropertiesEXT; + + + +// VK_EXT_memory_priority is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_memory_priority 1 +#define VK_EXT_MEMORY_PRIORITY_SPEC_VERSION 1 +#define VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME "VK_EXT_memory_priority" +typedef struct VkPhysicalDeviceMemoryPriorityFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 memoryPriority; +} VkPhysicalDeviceMemoryPriorityFeaturesEXT; + +typedef struct VkMemoryPriorityAllocateInfoEXT { + VkStructureType sType; + const void* pNext; + float priority; +} VkMemoryPriorityAllocateInfoEXT; + + + +// VK_NV_dedicated_allocation_image_aliasing is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_dedicated_allocation_image_aliasing 1 +#define VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_SPEC_VERSION 1 +#define VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_EXTENSION_NAME "VK_NV_dedicated_allocation_image_aliasing" +typedef struct VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 dedicatedAllocationImageAliasing; +} VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV; + + + +// VK_EXT_buffer_device_address is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_buffer_device_address 1 +#define VK_EXT_BUFFER_DEVICE_ADDRESS_SPEC_VERSION 2 +#define VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME "VK_EXT_buffer_device_address" +typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferDeviceAddressFeaturesEXT; + +typedef VkPhysicalDeviceBufferDeviceAddressFeaturesEXT VkPhysicalDeviceBufferAddressFeaturesEXT; + +typedef VkBufferDeviceAddressInfo VkBufferDeviceAddressInfoEXT; + +typedef struct VkBufferDeviceAddressCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceAddress deviceAddress; +} VkBufferDeviceAddressCreateInfoEXT; + +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddressEXT)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddressEXT( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); +#endif +#endif + + +// VK_EXT_tooling_info is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_tooling_info 1 +#define VK_EXT_TOOLING_INFO_SPEC_VERSION 1 +#define VK_EXT_TOOLING_INFO_EXTENSION_NAME "VK_EXT_tooling_info" +typedef VkToolPurposeFlagBits VkToolPurposeFlagBitsEXT; + +typedef VkToolPurposeFlags VkToolPurposeFlagsEXT; + +typedef VkPhysicalDeviceToolProperties VkPhysicalDeviceToolPropertiesEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceToolPropertiesEXT)(VkPhysicalDevice physicalDevice, uint32_t* pToolCount, VkPhysicalDeviceToolProperties* pToolProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceToolPropertiesEXT( + VkPhysicalDevice physicalDevice, + uint32_t* pToolCount, + VkPhysicalDeviceToolProperties* pToolProperties); +#endif +#endif + + +// VK_EXT_separate_stencil_usage is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_separate_stencil_usage 1 +#define VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION 1 +#define VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME "VK_EXT_separate_stencil_usage" +typedef VkImageStencilUsageCreateInfo VkImageStencilUsageCreateInfoEXT; + + + +// VK_EXT_validation_features is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_validation_features 1 +#define VK_EXT_VALIDATION_FEATURES_SPEC_VERSION 6 +#define VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME "VK_EXT_validation_features" + +typedef enum VkValidationFeatureEnableEXT { + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT = 0, + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT = 1, + VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT = 2, + VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT = 3, + VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT = 4, + VK_VALIDATION_FEATURE_ENABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureEnableEXT; + +typedef enum VkValidationFeatureDisableEXT { + VK_VALIDATION_FEATURE_DISABLE_ALL_EXT = 0, + VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT = 1, + VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT = 2, + VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT = 3, + VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT = 4, + VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT = 5, + VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6, + VK_VALIDATION_FEATURE_DISABLE_SHADER_VALIDATION_CACHE_EXT = 7, + VK_VALIDATION_FEATURE_DISABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureDisableEXT; +typedef struct VkValidationFeaturesEXT { + VkStructureType sType; + const void* pNext; + uint32_t enabledValidationFeatureCount; + const VkValidationFeatureEnableEXT* pEnabledValidationFeatures; + uint32_t disabledValidationFeatureCount; + const VkValidationFeatureDisableEXT* pDisabledValidationFeatures; +} VkValidationFeaturesEXT; + + + +// VK_NV_cooperative_matrix is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_cooperative_matrix 1 +#define VK_NV_COOPERATIVE_MATRIX_SPEC_VERSION 1 +#define VK_NV_COOPERATIVE_MATRIX_EXTENSION_NAME "VK_NV_cooperative_matrix" +typedef VkComponentTypeKHR VkComponentTypeNV; + +typedef VkScopeKHR VkScopeNV; + +typedef struct VkCooperativeMatrixPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeNV AType; + VkComponentTypeNV BType; + VkComponentTypeNV CType; + VkComponentTypeNV DType; + VkScopeNV scope; +} VkCooperativeMatrixPropertiesNV; + +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesNV; + +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV { + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesNV* pProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCooperativeMatrixPropertiesNV( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkCooperativeMatrixPropertiesNV* pProperties); +#endif +#endif + + +// VK_NV_coverage_reduction_mode is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_coverage_reduction_mode 1 +#define VK_NV_COVERAGE_REDUCTION_MODE_SPEC_VERSION 1 +#define VK_NV_COVERAGE_REDUCTION_MODE_EXTENSION_NAME "VK_NV_coverage_reduction_mode" + +typedef enum VkCoverageReductionModeNV { + VK_COVERAGE_REDUCTION_MODE_MERGE_NV = 0, + VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV = 1, + VK_COVERAGE_REDUCTION_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkCoverageReductionModeNV; +typedef VkFlags VkPipelineCoverageReductionStateCreateFlagsNV; +typedef struct VkPhysicalDeviceCoverageReductionModeFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 coverageReductionMode; +} VkPhysicalDeviceCoverageReductionModeFeaturesNV; + +typedef struct VkPipelineCoverageReductionStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineCoverageReductionStateCreateFlagsNV flags; + VkCoverageReductionModeNV coverageReductionMode; +} VkPipelineCoverageReductionStateCreateInfoNV; + +typedef struct VkFramebufferMixedSamplesCombinationNV { + VkStructureType sType; + void* pNext; + VkCoverageReductionModeNV coverageReductionMode; + VkSampleCountFlagBits rasterizationSamples; + VkSampleCountFlags depthStencilSamples; + VkSampleCountFlags colorSamples; +} VkFramebufferMixedSamplesCombinationNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV)(VkPhysicalDevice physicalDevice, uint32_t* pCombinationCount, VkFramebufferMixedSamplesCombinationNV* pCombinations); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV( + VkPhysicalDevice physicalDevice, + uint32_t* pCombinationCount, + VkFramebufferMixedSamplesCombinationNV* pCombinations); +#endif +#endif + + +// VK_EXT_fragment_shader_interlock is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_fragment_shader_interlock 1 +#define VK_EXT_FRAGMENT_SHADER_INTERLOCK_SPEC_VERSION 1 +#define VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME "VK_EXT_fragment_shader_interlock" +typedef struct VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 fragmentShaderSampleInterlock; + VkBool32 fragmentShaderPixelInterlock; + VkBool32 fragmentShaderShadingRateInterlock; +} VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT; + + + +// VK_EXT_ycbcr_image_arrays is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_ycbcr_image_arrays 1 +#define VK_EXT_YCBCR_IMAGE_ARRAYS_SPEC_VERSION 1 +#define VK_EXT_YCBCR_IMAGE_ARRAYS_EXTENSION_NAME "VK_EXT_ycbcr_image_arrays" +typedef struct VkPhysicalDeviceYcbcrImageArraysFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 ycbcrImageArrays; +} VkPhysicalDeviceYcbcrImageArraysFeaturesEXT; + + + +// VK_EXT_provoking_vertex is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_provoking_vertex 1 +#define VK_EXT_PROVOKING_VERTEX_SPEC_VERSION 1 +#define VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME "VK_EXT_provoking_vertex" + +typedef enum VkProvokingVertexModeEXT { + VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT = 0, + VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT = 1, + VK_PROVOKING_VERTEX_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkProvokingVertexModeEXT; +typedef struct VkPhysicalDeviceProvokingVertexFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 provokingVertexLast; + VkBool32 transformFeedbackPreservesProvokingVertex; +} VkPhysicalDeviceProvokingVertexFeaturesEXT; + +typedef struct VkPhysicalDeviceProvokingVertexPropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 provokingVertexModePerPipeline; + VkBool32 transformFeedbackPreservesTriangleFanProvokingVertex; +} VkPhysicalDeviceProvokingVertexPropertiesEXT; + +typedef struct VkPipelineRasterizationProvokingVertexStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkProvokingVertexModeEXT provokingVertexMode; +} VkPipelineRasterizationProvokingVertexStateCreateInfoEXT; + + + +// VK_EXT_headless_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_headless_surface 1 +#define VK_EXT_HEADLESS_SURFACE_SPEC_VERSION 1 +#define VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME "VK_EXT_headless_surface" +typedef VkFlags VkHeadlessSurfaceCreateFlagsEXT; +typedef struct VkHeadlessSurfaceCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkHeadlessSurfaceCreateFlagsEXT flags; +} VkHeadlessSurfaceCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateHeadlessSurfaceEXT)(VkInstance instance, const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateHeadlessSurfaceEXT( + VkInstance instance, + const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif +#endif + + +// VK_EXT_line_rasterization is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_line_rasterization 1 +#define VK_EXT_LINE_RASTERIZATION_SPEC_VERSION 1 +#define VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME "VK_EXT_line_rasterization" +typedef VkLineRasterizationMode VkLineRasterizationModeEXT; + +typedef VkPhysicalDeviceLineRasterizationFeatures VkPhysicalDeviceLineRasterizationFeaturesEXT; + +typedef VkPhysicalDeviceLineRasterizationProperties VkPhysicalDeviceLineRasterizationPropertiesEXT; + +typedef VkPipelineRasterizationLineStateCreateInfo VkPipelineRasterizationLineStateCreateInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetLineStippleEXT)(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetLineStippleEXT( + VkCommandBuffer commandBuffer, + uint32_t lineStippleFactor, + uint16_t lineStipplePattern); +#endif +#endif + + +// VK_EXT_shader_atomic_float is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_atomic_float 1 +#define VK_EXT_SHADER_ATOMIC_FLOAT_SPEC_VERSION 1 +#define VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME "VK_EXT_shader_atomic_float" +typedef struct VkPhysicalDeviceShaderAtomicFloatFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderBufferFloat32Atomics; + VkBool32 shaderBufferFloat32AtomicAdd; + VkBool32 shaderBufferFloat64Atomics; + VkBool32 shaderBufferFloat64AtomicAdd; + VkBool32 shaderSharedFloat32Atomics; + VkBool32 shaderSharedFloat32AtomicAdd; + VkBool32 shaderSharedFloat64Atomics; + VkBool32 shaderSharedFloat64AtomicAdd; + VkBool32 shaderImageFloat32Atomics; + VkBool32 shaderImageFloat32AtomicAdd; + VkBool32 sparseImageFloat32Atomics; + VkBool32 sparseImageFloat32AtomicAdd; +} VkPhysicalDeviceShaderAtomicFloatFeaturesEXT; + + + +// VK_EXT_host_query_reset is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_host_query_reset 1 +#define VK_EXT_HOST_QUERY_RESET_SPEC_VERSION 1 +#define VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME "VK_EXT_host_query_reset" +typedef VkPhysicalDeviceHostQueryResetFeatures VkPhysicalDeviceHostQueryResetFeaturesEXT; + +typedef void (VKAPI_PTR *PFN_vkResetQueryPoolEXT)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkResetQueryPoolEXT( + VkDevice device, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount); +#endif +#endif + + +// VK_EXT_index_type_uint8 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_index_type_uint8 1 +#define VK_EXT_INDEX_TYPE_UINT8_SPEC_VERSION 1 +#define VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME "VK_EXT_index_type_uint8" +typedef VkPhysicalDeviceIndexTypeUint8Features VkPhysicalDeviceIndexTypeUint8FeaturesEXT; + + + +// VK_EXT_extended_dynamic_state is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_extended_dynamic_state 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_SPEC_VERSION 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME "VK_EXT_extended_dynamic_state" +typedef struct VkPhysicalDeviceExtendedDynamicStateFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 extendedDynamicState; +} VkPhysicalDeviceExtendedDynamicStateFeaturesEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetCullModeEXT)(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode); +typedef void (VKAPI_PTR *PFN_vkCmdSetFrontFaceEXT)(VkCommandBuffer commandBuffer, VkFrontFace frontFace); +typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveTopologyEXT)(VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWithCountEXT)(VkCommandBuffer commandBuffer, uint32_t viewportCount, const VkViewport* pViewports); +typedef void (VKAPI_PTR *PFN_vkCmdSetScissorWithCountEXT)(VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D* pScissors); +typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers2EXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets, const VkDeviceSize* pSizes, const VkDeviceSize* pStrides); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthTestEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthWriteEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthCompareOpEXT)(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBoundsTestEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilTestEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilOpEXT)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetCullModeEXT( + VkCommandBuffer commandBuffer, + VkCullModeFlags cullMode); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetFrontFaceEXT( + VkCommandBuffer commandBuffer, + VkFrontFace frontFace); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetPrimitiveTopologyEXT( + VkCommandBuffer commandBuffer, + VkPrimitiveTopology primitiveTopology); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWithCountEXT( + VkCommandBuffer commandBuffer, + uint32_t viewportCount, + const VkViewport* pViewports); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetScissorWithCountEXT( + VkCommandBuffer commandBuffer, + uint32_t scissorCount, + const VkRect2D* pScissors); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers2EXT( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets, + const VkDeviceSize* pSizes, + const VkDeviceSize* pStrides); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthTestEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthTestEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthWriteEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthWriteEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthCompareOpEXT( + VkCommandBuffer commandBuffer, + VkCompareOp depthCompareOp); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBoundsTestEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthBoundsTestEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilTestEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 stencilTestEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilOpEXT( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + VkStencilOp failOp, + VkStencilOp passOp, + VkStencilOp depthFailOp, + VkCompareOp compareOp); +#endif +#endif + + +// VK_EXT_host_image_copy is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_host_image_copy 1 +#define VK_EXT_HOST_IMAGE_COPY_SPEC_VERSION 1 +#define VK_EXT_HOST_IMAGE_COPY_EXTENSION_NAME "VK_EXT_host_image_copy" +typedef VkHostImageCopyFlagBits VkHostImageCopyFlagBitsEXT; + +typedef VkHostImageCopyFlags VkHostImageCopyFlagsEXT; + +typedef VkPhysicalDeviceHostImageCopyFeatures VkPhysicalDeviceHostImageCopyFeaturesEXT; + +typedef VkPhysicalDeviceHostImageCopyProperties VkPhysicalDeviceHostImageCopyPropertiesEXT; + +typedef VkMemoryToImageCopy VkMemoryToImageCopyEXT; + +typedef VkImageToMemoryCopy VkImageToMemoryCopyEXT; + +typedef VkCopyMemoryToImageInfo VkCopyMemoryToImageInfoEXT; + +typedef VkCopyImageToMemoryInfo VkCopyImageToMemoryInfoEXT; + +typedef VkCopyImageToImageInfo VkCopyImageToImageInfoEXT; + +typedef VkHostImageLayoutTransitionInfo VkHostImageLayoutTransitionInfoEXT; + +typedef VkSubresourceHostMemcpySize VkSubresourceHostMemcpySizeEXT; + +typedef VkHostImageCopyDevicePerformanceQuery VkHostImageCopyDevicePerformanceQueryEXT; + +typedef VkSubresourceLayout2 VkSubresourceLayout2EXT; + +typedef VkImageSubresource2 VkImageSubresource2EXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCopyMemoryToImageEXT)(VkDevice device, const VkCopyMemoryToImageInfo* pCopyMemoryToImageInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyImageToMemoryEXT)(VkDevice device, const VkCopyImageToMemoryInfo* pCopyImageToMemoryInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyImageToImageEXT)(VkDevice device, const VkCopyImageToImageInfo* pCopyImageToImageInfo); +typedef VkResult (VKAPI_PTR *PFN_vkTransitionImageLayoutEXT)(VkDevice device, uint32_t transitionCount, const VkHostImageLayoutTransitionInfo* pTransitions); +typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout2EXT)(VkDevice device, VkImage image, const VkImageSubresource2* pSubresource, VkSubresourceLayout2* pLayout); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCopyMemoryToImageEXT( + VkDevice device, + const VkCopyMemoryToImageInfo* pCopyMemoryToImageInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCopyImageToMemoryEXT( + VkDevice device, + const VkCopyImageToMemoryInfo* pCopyImageToMemoryInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCopyImageToImageEXT( + VkDevice device, + const VkCopyImageToImageInfo* pCopyImageToImageInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkTransitionImageLayoutEXT( + VkDevice device, + uint32_t transitionCount, + const VkHostImageLayoutTransitionInfo* pTransitions); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout2EXT( + VkDevice device, + VkImage image, + const VkImageSubresource2* pSubresource, + VkSubresourceLayout2* pLayout); +#endif +#endif + + +// VK_EXT_map_memory_placed is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_map_memory_placed 1 +#define VK_EXT_MAP_MEMORY_PLACED_SPEC_VERSION 1 +#define VK_EXT_MAP_MEMORY_PLACED_EXTENSION_NAME "VK_EXT_map_memory_placed" +typedef struct VkPhysicalDeviceMapMemoryPlacedFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 memoryMapPlaced; + VkBool32 memoryMapRangePlaced; + VkBool32 memoryUnmapReserve; +} VkPhysicalDeviceMapMemoryPlacedFeaturesEXT; + +typedef struct VkPhysicalDeviceMapMemoryPlacedPropertiesEXT { + VkStructureType sType; + void* pNext; + VkDeviceSize minPlacedMemoryMapAlignment; +} VkPhysicalDeviceMapMemoryPlacedPropertiesEXT; + +typedef struct VkMemoryMapPlacedInfoEXT { + VkStructureType sType; + const void* pNext; + void* pPlacedAddress; +} VkMemoryMapPlacedInfoEXT; + + + +// VK_EXT_shader_atomic_float2 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_atomic_float2 1 +#define VK_EXT_SHADER_ATOMIC_FLOAT_2_SPEC_VERSION 1 +#define VK_EXT_SHADER_ATOMIC_FLOAT_2_EXTENSION_NAME "VK_EXT_shader_atomic_float2" +typedef struct VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderBufferFloat16Atomics; + VkBool32 shaderBufferFloat16AtomicAdd; + VkBool32 shaderBufferFloat16AtomicMinMax; + VkBool32 shaderBufferFloat32AtomicMinMax; + VkBool32 shaderBufferFloat64AtomicMinMax; + VkBool32 shaderSharedFloat16Atomics; + VkBool32 shaderSharedFloat16AtomicAdd; + VkBool32 shaderSharedFloat16AtomicMinMax; + VkBool32 shaderSharedFloat32AtomicMinMax; + VkBool32 shaderSharedFloat64AtomicMinMax; + VkBool32 shaderImageFloat32AtomicMinMax; + VkBool32 sparseImageFloat32AtomicMinMax; +} VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT; + + + +// VK_EXT_surface_maintenance1 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_surface_maintenance1 1 +#define VK_EXT_SURFACE_MAINTENANCE_1_SPEC_VERSION 1 +#define VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME "VK_EXT_surface_maintenance1" +typedef VkPresentScalingFlagBitsKHR VkPresentScalingFlagBitsEXT; + +typedef VkPresentScalingFlagsKHR VkPresentScalingFlagsEXT; + +typedef VkPresentGravityFlagBitsKHR VkPresentGravityFlagBitsEXT; + +typedef VkPresentGravityFlagsKHR VkPresentGravityFlagsEXT; + +typedef VkSurfacePresentModeKHR VkSurfacePresentModeEXT; + +typedef VkSurfacePresentScalingCapabilitiesKHR VkSurfacePresentScalingCapabilitiesEXT; + +typedef VkSurfacePresentModeCompatibilityKHR VkSurfacePresentModeCompatibilityEXT; + + + +// VK_EXT_swapchain_maintenance1 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_swapchain_maintenance1 1 +#define VK_EXT_SWAPCHAIN_MAINTENANCE_1_SPEC_VERSION 1 +#define VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME "VK_EXT_swapchain_maintenance1" +typedef VkPhysicalDeviceSwapchainMaintenance1FeaturesKHR VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT; + +typedef VkSwapchainPresentFenceInfoKHR VkSwapchainPresentFenceInfoEXT; + +typedef VkSwapchainPresentModesCreateInfoKHR VkSwapchainPresentModesCreateInfoEXT; + +typedef VkSwapchainPresentModeInfoKHR VkSwapchainPresentModeInfoEXT; + +typedef VkSwapchainPresentScalingCreateInfoKHR VkSwapchainPresentScalingCreateInfoEXT; + +typedef VkReleaseSwapchainImagesInfoKHR VkReleaseSwapchainImagesInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkReleaseSwapchainImagesEXT)(VkDevice device, const VkReleaseSwapchainImagesInfoKHR* pReleaseInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkReleaseSwapchainImagesEXT( + VkDevice device, + const VkReleaseSwapchainImagesInfoKHR* pReleaseInfo); +#endif +#endif + + +// VK_EXT_shader_demote_to_helper_invocation is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_demote_to_helper_invocation 1 +#define VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_SPEC_VERSION 1 +#define VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME "VK_EXT_shader_demote_to_helper_invocation" +typedef VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT; + + + +// VK_NV_device_generated_commands is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_device_generated_commands 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNV) +#define VK_NV_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 3 +#define VK_NV_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NV_device_generated_commands" + +typedef enum VkIndirectCommandsTokenTypeNV { + VK_INDIRECT_COMMANDS_TOKEN_TYPE_SHADER_GROUP_NV = 0, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_STATE_FLAGS_NV = 1, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NV = 2, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NV = 3, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NV = 4, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NV = 5, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NV = 6, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_TASKS_NV = 7, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_DATA_NV = 1000135000, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV = 1000328000, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NV = 1000428003, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NV = 1000428004, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkIndirectCommandsTokenTypeNV; + +typedef enum VkIndirectStateFlagBitsNV { + VK_INDIRECT_STATE_FLAG_FRONTFACE_BIT_NV = 0x00000001, + VK_INDIRECT_STATE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkIndirectStateFlagBitsNV; +typedef VkFlags VkIndirectStateFlagsNV; + +typedef enum VkIndirectCommandsLayoutUsageFlagBitsNV { + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_NV = 0x00000001, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NV = 0x00000002, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NV = 0x00000004, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkIndirectCommandsLayoutUsageFlagBitsNV; +typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNV; +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t maxGraphicsShaderGroupCount; + uint32_t maxIndirectSequenceCount; + uint32_t maxIndirectCommandsTokenCount; + uint32_t maxIndirectCommandsStreamCount; + uint32_t maxIndirectCommandsTokenOffset; + uint32_t maxIndirectCommandsStreamStride; + uint32_t minSequencesCountBufferOffsetAlignment; + uint32_t minSequencesIndexBufferOffsetAlignment; + uint32_t minIndirectCommandsBufferOffsetAlignment; +} VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV; + +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 deviceGeneratedCommands; +} VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV; + +typedef struct VkGraphicsShaderGroupCreateInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + const VkPipelineVertexInputStateCreateInfo* pVertexInputState; + const VkPipelineTessellationStateCreateInfo* pTessellationState; +} VkGraphicsShaderGroupCreateInfoNV; + +typedef struct VkGraphicsPipelineShaderGroupsCreateInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t groupCount; + const VkGraphicsShaderGroupCreateInfoNV* pGroups; + uint32_t pipelineCount; + const VkPipeline* pPipelines; +} VkGraphicsPipelineShaderGroupsCreateInfoNV; + +typedef struct VkBindShaderGroupIndirectCommandNV { + uint32_t groupIndex; +} VkBindShaderGroupIndirectCommandNV; + +typedef struct VkBindIndexBufferIndirectCommandNV { + VkDeviceAddress bufferAddress; + uint32_t size; + VkIndexType indexType; +} VkBindIndexBufferIndirectCommandNV; + +typedef struct VkBindVertexBufferIndirectCommandNV { + VkDeviceAddress bufferAddress; + uint32_t size; + uint32_t stride; +} VkBindVertexBufferIndirectCommandNV; + +typedef struct VkSetStateFlagsIndirectCommandNV { + uint32_t data; +} VkSetStateFlagsIndirectCommandNV; + +typedef struct VkIndirectCommandsStreamNV { + VkBuffer buffer; + VkDeviceSize offset; +} VkIndirectCommandsStreamNV; + +typedef struct VkIndirectCommandsLayoutTokenNV { + VkStructureType sType; + const void* pNext; + VkIndirectCommandsTokenTypeNV tokenType; + uint32_t stream; + uint32_t offset; + uint32_t vertexBindingUnit; + VkBool32 vertexDynamicStride; + VkPipelineLayout pushconstantPipelineLayout; + VkShaderStageFlags pushconstantShaderStageFlags; + uint32_t pushconstantOffset; + uint32_t pushconstantSize; + VkIndirectStateFlagsNV indirectStateFlags; + uint32_t indexTypeCount; + const VkIndexType* pIndexTypes; + const uint32_t* pIndexTypeValues; +} VkIndirectCommandsLayoutTokenNV; + +typedef struct VkIndirectCommandsLayoutCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkIndirectCommandsLayoutUsageFlagsNV flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t tokenCount; + const VkIndirectCommandsLayoutTokenNV* pTokens; + uint32_t streamCount; + const uint32_t* pStreamStrides; +} VkIndirectCommandsLayoutCreateInfoNV; + +typedef struct VkGeneratedCommandsInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineBindPoint pipelineBindPoint; + VkPipeline pipeline; + VkIndirectCommandsLayoutNV indirectCommandsLayout; + uint32_t streamCount; + const VkIndirectCommandsStreamNV* pStreams; + uint32_t sequencesCount; + VkBuffer preprocessBuffer; + VkDeviceSize preprocessOffset; + VkDeviceSize preprocessSize; + VkBuffer sequencesCountBuffer; + VkDeviceSize sequencesCountOffset; + VkBuffer sequencesIndexBuffer; + VkDeviceSize sequencesIndexOffset; +} VkGeneratedCommandsInfoNV; + +typedef struct VkGeneratedCommandsMemoryRequirementsInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineBindPoint pipelineBindPoint; + VkPipeline pipeline; + VkIndirectCommandsLayoutNV indirectCommandsLayout; + uint32_t maxSequencesCount; +} VkGeneratedCommandsMemoryRequirementsInfoNV; + +typedef void (VKAPI_PTR *PFN_vkGetGeneratedCommandsMemoryRequirementsNV)(VkDevice device, const VkGeneratedCommandsMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkCmdPreprocessGeneratedCommandsNV)(VkCommandBuffer commandBuffer, const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdExecuteGeneratedCommandsNV)(VkCommandBuffer commandBuffer, VkBool32 isPreprocessed, const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBindPipelineShaderGroupNV)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline, uint32_t groupIndex); +typedef VkResult (VKAPI_PTR *PFN_vkCreateIndirectCommandsLayoutNV)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkIndirectCommandsLayoutNV* pIndirectCommandsLayout); +typedef void (VKAPI_PTR *PFN_vkDestroyIndirectCommandsLayoutNV)(VkDevice device, VkIndirectCommandsLayoutNV indirectCommandsLayout, const VkAllocationCallbacks* pAllocator); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetGeneratedCommandsMemoryRequirementsNV( + VkDevice device, + const VkGeneratedCommandsMemoryRequirementsInfoNV* pInfo, + VkMemoryRequirements2* pMemoryRequirements); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdPreprocessGeneratedCommandsNV( + VkCommandBuffer commandBuffer, + const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdExecuteGeneratedCommandsNV( + VkCommandBuffer commandBuffer, + VkBool32 isPreprocessed, + const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindPipelineShaderGroupNV( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipeline pipeline, + uint32_t groupIndex); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateIndirectCommandsLayoutNV( + VkDevice device, + const VkIndirectCommandsLayoutCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkIndirectCommandsLayoutNV* pIndirectCommandsLayout); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyIndirectCommandsLayoutNV( + VkDevice device, + VkIndirectCommandsLayoutNV indirectCommandsLayout, + const VkAllocationCallbacks* pAllocator); +#endif +#endif + + +// VK_NV_inherited_viewport_scissor is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_inherited_viewport_scissor 1 +#define VK_NV_INHERITED_VIEWPORT_SCISSOR_SPEC_VERSION 1 +#define VK_NV_INHERITED_VIEWPORT_SCISSOR_EXTENSION_NAME "VK_NV_inherited_viewport_scissor" +typedef struct VkPhysicalDeviceInheritedViewportScissorFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 inheritedViewportScissor2D; +} VkPhysicalDeviceInheritedViewportScissorFeaturesNV; + +typedef struct VkCommandBufferInheritanceViewportScissorInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 viewportScissor2D; + uint32_t viewportDepthCount; + const VkViewport* pViewportDepths; +} VkCommandBufferInheritanceViewportScissorInfoNV; + + + +// VK_EXT_texel_buffer_alignment is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_texel_buffer_alignment 1 +#define VK_EXT_TEXEL_BUFFER_ALIGNMENT_SPEC_VERSION 1 +#define VK_EXT_TEXEL_BUFFER_ALIGNMENT_EXTENSION_NAME "VK_EXT_texel_buffer_alignment" +typedef struct VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 texelBufferAlignment; +} VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT; + +typedef VkPhysicalDeviceTexelBufferAlignmentProperties VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT; + + + +// VK_QCOM_render_pass_transform is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_render_pass_transform 1 +#define VK_QCOM_RENDER_PASS_TRANSFORM_SPEC_VERSION 5 +#define VK_QCOM_RENDER_PASS_TRANSFORM_EXTENSION_NAME "VK_QCOM_render_pass_transform" +typedef struct VkRenderPassTransformBeginInfoQCOM { + VkStructureType sType; + const void* pNext; + VkSurfaceTransformFlagBitsKHR transform; +} VkRenderPassTransformBeginInfoQCOM; + +typedef struct VkCommandBufferInheritanceRenderPassTransformInfoQCOM { + VkStructureType sType; + const void* pNext; + VkSurfaceTransformFlagBitsKHR transform; + VkRect2D renderArea; +} VkCommandBufferInheritanceRenderPassTransformInfoQCOM; + + + +// VK_EXT_depth_bias_control is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_depth_bias_control 1 +#define VK_EXT_DEPTH_BIAS_CONTROL_SPEC_VERSION 1 +#define VK_EXT_DEPTH_BIAS_CONTROL_EXTENSION_NAME "VK_EXT_depth_bias_control" + +typedef enum VkDepthBiasRepresentationEXT { + VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT = 0, + VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT = 1, + VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT = 2, + VK_DEPTH_BIAS_REPRESENTATION_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDepthBiasRepresentationEXT; +typedef struct VkPhysicalDeviceDepthBiasControlFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 depthBiasControl; + VkBool32 leastRepresentableValueForceUnormRepresentation; + VkBool32 floatRepresentation; + VkBool32 depthBiasExact; +} VkPhysicalDeviceDepthBiasControlFeaturesEXT; + +typedef struct VkDepthBiasInfoEXT { + VkStructureType sType; + const void* pNext; + float depthBiasConstantFactor; + float depthBiasClamp; + float depthBiasSlopeFactor; +} VkDepthBiasInfoEXT; + +typedef struct VkDepthBiasRepresentationInfoEXT { + VkStructureType sType; + const void* pNext; + VkDepthBiasRepresentationEXT depthBiasRepresentation; + VkBool32 depthBiasExact; +} VkDepthBiasRepresentationInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBias2EXT)(VkCommandBuffer commandBuffer, const VkDepthBiasInfoEXT* pDepthBiasInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBias2EXT( + VkCommandBuffer commandBuffer, + const VkDepthBiasInfoEXT* pDepthBiasInfo); +#endif +#endif + + +// VK_EXT_device_memory_report is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_device_memory_report 1 +#define VK_EXT_DEVICE_MEMORY_REPORT_SPEC_VERSION 2 +#define VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME "VK_EXT_device_memory_report" + +typedef enum VkDeviceMemoryReportEventTypeEXT { + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATE_EXT = 0, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_FREE_EXT = 1, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_IMPORT_EXT = 2, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_UNIMPORT_EXT = 3, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATION_FAILED_EXT = 4, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceMemoryReportEventTypeEXT; +typedef VkFlags VkDeviceMemoryReportFlagsEXT; +typedef struct VkPhysicalDeviceDeviceMemoryReportFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 deviceMemoryReport; +} VkPhysicalDeviceDeviceMemoryReportFeaturesEXT; + +typedef struct VkDeviceMemoryReportCallbackDataEXT { + VkStructureType sType; + void* pNext; + VkDeviceMemoryReportFlagsEXT flags; + VkDeviceMemoryReportEventTypeEXT type; + uint64_t memoryObjectId; + VkDeviceSize size; + VkObjectType objectType; + uint64_t objectHandle; + uint32_t heapIndex; +} VkDeviceMemoryReportCallbackDataEXT; + +typedef void (VKAPI_PTR *PFN_vkDeviceMemoryReportCallbackEXT)( + const VkDeviceMemoryReportCallbackDataEXT* pCallbackData, + void* pUserData); + +typedef struct VkDeviceDeviceMemoryReportCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceMemoryReportFlagsEXT flags; + PFN_vkDeviceMemoryReportCallbackEXT pfnUserCallback; + void* pUserData; +} VkDeviceDeviceMemoryReportCreateInfoEXT; + + + +// VK_EXT_acquire_drm_display is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_acquire_drm_display 1 +#define VK_EXT_ACQUIRE_DRM_DISPLAY_SPEC_VERSION 1 +#define VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_drm_display" +typedef VkResult (VKAPI_PTR *PFN_vkAcquireDrmDisplayEXT)(VkPhysicalDevice physicalDevice, int32_t drmFd, VkDisplayKHR display); +typedef VkResult (VKAPI_PTR *PFN_vkGetDrmDisplayEXT)(VkPhysicalDevice physicalDevice, int32_t drmFd, uint32_t connectorId, VkDisplayKHR* display); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireDrmDisplayEXT( + VkPhysicalDevice physicalDevice, + int32_t drmFd, + VkDisplayKHR display); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDrmDisplayEXT( + VkPhysicalDevice physicalDevice, + int32_t drmFd, + uint32_t connectorId, + VkDisplayKHR* display); +#endif +#endif + + +// VK_EXT_robustness2 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_robustness2 1 +#define VK_EXT_ROBUSTNESS_2_SPEC_VERSION 1 +#define VK_EXT_ROBUSTNESS_2_EXTENSION_NAME "VK_EXT_robustness2" +typedef VkPhysicalDeviceRobustness2FeaturesKHR VkPhysicalDeviceRobustness2FeaturesEXT; + +typedef VkPhysicalDeviceRobustness2PropertiesKHR VkPhysicalDeviceRobustness2PropertiesEXT; + + + +// VK_EXT_custom_border_color is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_custom_border_color 1 +#define VK_EXT_CUSTOM_BORDER_COLOR_SPEC_VERSION 12 +#define VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME "VK_EXT_custom_border_color" +typedef struct VkPhysicalDeviceCustomBorderColorPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxCustomBorderColorSamplers; +} VkPhysicalDeviceCustomBorderColorPropertiesEXT; + +typedef struct VkPhysicalDeviceCustomBorderColorFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 customBorderColors; + VkBool32 customBorderColorWithoutFormat; +} VkPhysicalDeviceCustomBorderColorFeaturesEXT; + + + +// VK_EXT_texture_compression_astc_3d is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_texture_compression_astc_3d 1 +#define VK_EXT_TEXTURE_COMPRESSION_ASTC_3D_SPEC_VERSION 1 +#define VK_EXT_TEXTURE_COMPRESSION_ASTC_3D_EXTENSION_NAME "VK_EXT_texture_compression_astc_3d" +typedef struct VkPhysicalDeviceTextureCompressionASTC3DFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 textureCompressionASTC_3D; +} VkPhysicalDeviceTextureCompressionASTC3DFeaturesEXT; + + + +// VK_GOOGLE_user_type is a preprocessor guard. Do not pass it to API calls. +#define VK_GOOGLE_user_type 1 +#define VK_GOOGLE_USER_TYPE_SPEC_VERSION 1 +#define VK_GOOGLE_USER_TYPE_EXTENSION_NAME "VK_GOOGLE_user_type" + + +// VK_NV_present_barrier is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_present_barrier 1 +#define VK_NV_PRESENT_BARRIER_SPEC_VERSION 1 +#define VK_NV_PRESENT_BARRIER_EXTENSION_NAME "VK_NV_present_barrier" +typedef struct VkPhysicalDevicePresentBarrierFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 presentBarrier; +} VkPhysicalDevicePresentBarrierFeaturesNV; + +typedef struct VkSurfaceCapabilitiesPresentBarrierNV { + VkStructureType sType; + void* pNext; + VkBool32 presentBarrierSupported; +} VkSurfaceCapabilitiesPresentBarrierNV; + +typedef struct VkSwapchainPresentBarrierCreateInfoNV { + VkStructureType sType; + void* pNext; + VkBool32 presentBarrierEnable; +} VkSwapchainPresentBarrierCreateInfoNV; + + + +// VK_EXT_private_data is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_private_data 1 +typedef VkPrivateDataSlot VkPrivateDataSlotEXT; + +#define VK_EXT_PRIVATE_DATA_SPEC_VERSION 1 +#define VK_EXT_PRIVATE_DATA_EXTENSION_NAME "VK_EXT_private_data" +typedef VkPrivateDataSlotCreateFlags VkPrivateDataSlotCreateFlagsEXT; + +typedef VkPhysicalDevicePrivateDataFeatures VkPhysicalDevicePrivateDataFeaturesEXT; + +typedef VkDevicePrivateDataCreateInfo VkDevicePrivateDataCreateInfoEXT; + +typedef VkPrivateDataSlotCreateInfo VkPrivateDataSlotCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreatePrivateDataSlotEXT)(VkDevice device, const VkPrivateDataSlotCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPrivateDataSlot* pPrivateDataSlot); +typedef void (VKAPI_PTR *PFN_vkDestroyPrivateDataSlotEXT)(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkSetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data); +typedef void (VKAPI_PTR *PFN_vkGetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t* pData); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePrivateDataSlotEXT( + VkDevice device, + const VkPrivateDataSlotCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPrivateDataSlot* pPrivateDataSlot); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyPrivateDataSlotEXT( + VkDevice device, + VkPrivateDataSlot privateDataSlot, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkSetPrivateDataEXT( + VkDevice device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlot privateDataSlot, + uint64_t data); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPrivateDataEXT( + VkDevice device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlot privateDataSlot, + uint64_t* pData); +#endif +#endif + + +// VK_EXT_pipeline_creation_cache_control is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_pipeline_creation_cache_control 1 +#define VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_SPEC_VERSION 3 +#define VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME "VK_EXT_pipeline_creation_cache_control" +typedef VkPhysicalDevicePipelineCreationCacheControlFeatures VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT; + + + +// VK_NV_device_diagnostics_config is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_device_diagnostics_config 1 +#define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_SPEC_VERSION 2 +#define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME "VK_NV_device_diagnostics_config" + +typedef enum VkDeviceDiagnosticsConfigFlagBitsNV { + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV = 0x00000001, + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV = 0x00000002, + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV = 0x00000004, + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_ERROR_REPORTING_BIT_NV = 0x00000008, + VK_DEVICE_DIAGNOSTICS_CONFIG_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkDeviceDiagnosticsConfigFlagBitsNV; +typedef VkFlags VkDeviceDiagnosticsConfigFlagsNV; +typedef struct VkPhysicalDeviceDiagnosticsConfigFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 diagnosticsConfig; +} VkPhysicalDeviceDiagnosticsConfigFeaturesNV; + +typedef struct VkDeviceDiagnosticsConfigCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkDeviceDiagnosticsConfigFlagsNV flags; +} VkDeviceDiagnosticsConfigCreateInfoNV; + + + +// VK_QCOM_render_pass_store_ops is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_render_pass_store_ops 1 +#define VK_QCOM_RENDER_PASS_STORE_OPS_SPEC_VERSION 2 +#define VK_QCOM_RENDER_PASS_STORE_OPS_EXTENSION_NAME "VK_QCOM_render_pass_store_ops" + + +// VK_QCOM_queue_perf_hint is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_queue_perf_hint 1 +#define VK_QCOM_QUEUE_PERF_HINT_SPEC_VERSION 1 +#define VK_QCOM_QUEUE_PERF_HINT_EXTENSION_NAME "VK_QCOM_queue_perf_hint" + +typedef enum VkPerfHintTypeQCOM { + VK_PERF_HINT_TYPE_DEFAULT_QCOM = 0, + VK_PERF_HINT_TYPE_FREQUENCY_MIN_QCOM = 1, + VK_PERF_HINT_TYPE_FREQUENCY_MAX_QCOM = 2, + VK_PERF_HINT_TYPE_FREQUENCY_SCALED_QCOM = 3, + VK_PERF_HINT_TYPE_MAX_ENUM_QCOM = 0x7FFFFFFF +} VkPerfHintTypeQCOM; +typedef struct VkPerfHintInfoQCOM { + VkStructureType sType; + void* pNext; + VkPerfHintTypeQCOM type; + uint32_t scale; +} VkPerfHintInfoQCOM; + +typedef struct VkPhysicalDeviceQueuePerfHintFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 queuePerfHint; +} VkPhysicalDeviceQueuePerfHintFeaturesQCOM; + +typedef struct VkPhysicalDeviceQueuePerfHintPropertiesQCOM { + VkStructureType sType; + void* pNext; + VkQueueFlags supportedQueues; +} VkPhysicalDeviceQueuePerfHintPropertiesQCOM; + +typedef VkResult (VKAPI_PTR *PFN_vkQueueSetPerfHintQCOM)(VkQueue queue, const VkPerfHintInfoQCOM* pPerfHintInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkQueueSetPerfHintQCOM( + VkQueue queue, + const VkPerfHintInfoQCOM* pPerfHintInfo); +#endif +#endif + + +// VK_QCOM_image_processing3 is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_image_processing3 1 +#define VK_QCOM_IMAGE_PROCESSING_3_SPEC_VERSION 1 +#define VK_QCOM_IMAGE_PROCESSING_3_EXTENSION_NAME "VK_QCOM_image_processing3" +typedef struct VkPhysicalDeviceImageProcessing3FeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 imageGatherLinear; + VkBool32 imageGatherExtendedModes; + VkBool32 blockMatchExtendedClampToEdge; +} VkPhysicalDeviceImageProcessing3FeaturesQCOM; + + + +// VK_QCOM_shader_multiple_wait_queues is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_shader_multiple_wait_queues 1 +#define VK_QCOM_SHADER_MULTIPLE_WAIT_QUEUES_SPEC_VERSION 1 +#define VK_QCOM_SHADER_MULTIPLE_WAIT_QUEUES_EXTENSION_NAME "VK_QCOM_shader_multiple_wait_queues" +typedef struct VkPhysicalDeviceShaderMultipleWaitQueuesFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 shaderMultipleWaitQueues; +} VkPhysicalDeviceShaderMultipleWaitQueuesFeaturesQCOM; + +typedef struct VkPhysicalDeviceShaderMultipleWaitQueuesPropertiesQCOM { + VkStructureType sType; + void* pNext; + uint32_t maxShaderWaitQueues; +} VkPhysicalDeviceShaderMultipleWaitQueuesPropertiesQCOM; + + + +// VK_EXT_shader_split_barrier is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_split_barrier 1 +#define VK_EXT_SHADER_SPLIT_BARRIER_SPEC_VERSION 1 +#define VK_EXT_SHADER_SPLIT_BARRIER_EXTENSION_NAME "VK_EXT_shader_split_barrier" +typedef struct VkPhysicalDeviceShaderSplitBarrierFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderSplitBarrier; +} VkPhysicalDeviceShaderSplitBarrierFeaturesEXT; + +typedef struct VkPhysicalDeviceShaderSplitBarrierPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t splitBarrierReservedSharedMemory; +} VkPhysicalDeviceShaderSplitBarrierPropertiesEXT; + + + +// VK_QCOM_tile_shading is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_tile_shading 1 +#define VK_QCOM_TILE_SHADING_SPEC_VERSION 2 +#define VK_QCOM_TILE_SHADING_EXTENSION_NAME "VK_QCOM_tile_shading" + +typedef enum VkTileShadingRenderPassFlagBitsQCOM { + VK_TILE_SHADING_RENDER_PASS_ENABLE_BIT_QCOM = 0x00000001, + VK_TILE_SHADING_RENDER_PASS_PER_TILE_EXECUTION_BIT_QCOM = 0x00000002, + VK_TILE_SHADING_RENDER_PASS_FLAG_BITS_MAX_ENUM_QCOM = 0x7FFFFFFF +} VkTileShadingRenderPassFlagBitsQCOM; +typedef VkFlags VkTileShadingRenderPassFlagsQCOM; +typedef struct VkPhysicalDeviceTileShadingFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 tileShading; + VkBool32 tileShadingFragmentStage; + VkBool32 tileShadingColorAttachments; + VkBool32 tileShadingDepthAttachments; + VkBool32 tileShadingStencilAttachments; + VkBool32 tileShadingInputAttachments; + VkBool32 tileShadingSampledAttachments; + VkBool32 tileShadingPerTileDraw; + VkBool32 tileShadingPerTileDispatch; + VkBool32 tileShadingDispatchTile; + VkBool32 tileShadingApron; + VkBool32 tileShadingAnisotropicApron; + VkBool32 tileShadingAtomicOps; + VkBool32 tileShadingImageProcessing; +} VkPhysicalDeviceTileShadingFeaturesQCOM; + +typedef struct VkPhysicalDeviceTileShadingPropertiesQCOM { + VkStructureType sType; + void* pNext; + uint32_t maxApronSize; + VkBool32 preferNonCoherent; + VkExtent2D tileGranularity; + VkExtent2D maxTileShadingRate; +} VkPhysicalDeviceTileShadingPropertiesQCOM; + +typedef struct VkRenderPassTileShadingCreateInfoQCOM { + VkStructureType sType; + const void* pNext; + VkTileShadingRenderPassFlagsQCOM flags; + VkExtent2D tileApronSize; +} VkRenderPassTileShadingCreateInfoQCOM; + +typedef struct VkPerTileBeginInfoQCOM { + VkStructureType sType; + const void* pNext; +} VkPerTileBeginInfoQCOM; + +typedef struct VkPerTileEndInfoQCOM { + VkStructureType sType; + const void* pNext; +} VkPerTileEndInfoQCOM; + +typedef struct VkDispatchTileInfoQCOM { + VkStructureType sType; + const void* pNext; +} VkDispatchTileInfoQCOM; + +typedef void (VKAPI_PTR *PFN_vkCmdDispatchTileQCOM)(VkCommandBuffer commandBuffer, const VkDispatchTileInfoQCOM* pDispatchTileInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBeginPerTileExecutionQCOM)(VkCommandBuffer commandBuffer, const VkPerTileBeginInfoQCOM* pPerTileBeginInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndPerTileExecutionQCOM)(VkCommandBuffer commandBuffer, const VkPerTileEndInfoQCOM* pPerTileEndInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchTileQCOM( + VkCommandBuffer commandBuffer, + const VkDispatchTileInfoQCOM* pDispatchTileInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginPerTileExecutionQCOM( + VkCommandBuffer commandBuffer, + const VkPerTileBeginInfoQCOM* pPerTileBeginInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdEndPerTileExecutionQCOM( + VkCommandBuffer commandBuffer, + const VkPerTileEndInfoQCOM* pPerTileEndInfo); +#endif +#endif + + +// VK_NV_low_latency is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_low_latency 1 +#define VK_NV_LOW_LATENCY_SPEC_VERSION 2 +#define VK_NV_LOW_LATENCY_EXTENSION_NAME "VK_NV_low_latency" +typedef struct VkQueryLowLatencySupportNV { + VkStructureType sType; + const void* pNext; + void* pQueriedLowLatencyData; +} VkQueryLowLatencySupportNV; + +typedef void (VKAPI_PTR *PFN_vkSetLatencySleepModeLegacyNV)(VkDevice device, VkBool32 lowLatencyMode, VkBool32 lowLatencyBoost, uint32_t minimumIntervalUs); +typedef void (VKAPI_PTR *PFN_vkLatencySleepLegacyNV)(VkDevice device, VkSemaphore signalSemaphore, uint64_t value); +typedef void (VKAPI_PTR *PFN_vkSetLatencyMarkerLegacyNV)(VkDevice device, uint64_t frameID, uint32_t marker); +typedef void (VKAPI_PTR *PFN_vkGetLatencyTimingsLegacyNV)(VkDevice device, void* pTimings); +typedef void (VKAPI_PTR *PFN_vkQueueNotifyOutOfBandLegacyNV)(VkQueue queue, uint32_t queueType); +typedef void (VKAPI_PTR *PFN_vkGetSleepStatusLegacyNV)(VkDevice device, VkBool32* pLowLatencyMode); +typedef void (VKAPI_PTR *PFN_vkShutdownLatencyDeviceLegacyNV)(VkDevice device); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkSetLatencySleepModeLegacyNV( + VkDevice device, + VkBool32 lowLatencyMode, + VkBool32 lowLatencyBoost, + uint32_t minimumIntervalUs); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkLatencySleepLegacyNV( + VkDevice device, + VkSemaphore signalSemaphore, + uint64_t value); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkSetLatencyMarkerLegacyNV( + VkDevice device, + uint64_t frameID, + uint32_t marker); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetLatencyTimingsLegacyNV( + VkDevice device, + void* pTimings); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkQueueNotifyOutOfBandLegacyNV( + VkQueue queue, + uint32_t queueType); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetSleepStatusLegacyNV( + VkDevice device, + VkBool32* pLowLatencyMode); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkShutdownLatencyDeviceLegacyNV( + VkDevice device); +#endif +#endif + + +// VK_EXT_descriptor_buffer is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_descriptor_buffer 1 +#define VK_EXT_DESCRIPTOR_BUFFER_SPEC_VERSION 1 +#define VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME "VK_EXT_descriptor_buffer" +typedef struct VkPhysicalDeviceDescriptorBufferPropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 combinedImageSamplerDescriptorSingleArray; + VkBool32 bufferlessPushDescriptors; + VkBool32 allowSamplerImageViewPostSubmitCreation; + VkDeviceSize descriptorBufferOffsetAlignment; + uint32_t maxDescriptorBufferBindings; + uint32_t maxResourceDescriptorBufferBindings; + uint32_t maxSamplerDescriptorBufferBindings; + uint32_t maxEmbeddedImmutableSamplerBindings; + uint32_t maxEmbeddedImmutableSamplers; + size_t bufferCaptureReplayDescriptorDataSize; + size_t imageCaptureReplayDescriptorDataSize; + size_t imageViewCaptureReplayDescriptorDataSize; + size_t samplerCaptureReplayDescriptorDataSize; + size_t accelerationStructureCaptureReplayDescriptorDataSize; + size_t samplerDescriptorSize; + size_t combinedImageSamplerDescriptorSize; + size_t sampledImageDescriptorSize; + size_t storageImageDescriptorSize; + size_t uniformTexelBufferDescriptorSize; + size_t robustUniformTexelBufferDescriptorSize; + size_t storageTexelBufferDescriptorSize; + size_t robustStorageTexelBufferDescriptorSize; + size_t uniformBufferDescriptorSize; + size_t robustUniformBufferDescriptorSize; + size_t storageBufferDescriptorSize; + size_t robustStorageBufferDescriptorSize; + size_t inputAttachmentDescriptorSize; + size_t accelerationStructureDescriptorSize; + VkDeviceSize maxSamplerDescriptorBufferRange; + VkDeviceSize maxResourceDescriptorBufferRange; + VkDeviceSize samplerDescriptorBufferAddressSpaceSize; + VkDeviceSize resourceDescriptorBufferAddressSpaceSize; + VkDeviceSize descriptorBufferAddressSpaceSize; +} VkPhysicalDeviceDescriptorBufferPropertiesEXT; + +typedef struct VkPhysicalDeviceDescriptorBufferFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 descriptorBuffer; + VkBool32 descriptorBufferCaptureReplay; + VkBool32 descriptorBufferImageLayoutIgnored; + VkBool32 descriptorBufferPushDescriptors; +} VkPhysicalDeviceDescriptorBufferFeaturesEXT; + +typedef struct VkDescriptorAddressInfoEXT { + VkStructureType sType; + void* pNext; + VkDeviceAddress address; + VkDeviceSize range; + VkFormat format; +} VkDescriptorAddressInfoEXT; + +typedef struct VkDescriptorBufferBindingInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceAddress address; + VkBufferUsageFlags usage; +} VkDescriptorBufferBindingInfoEXT; + +typedef struct VkDescriptorBufferBindingPushDescriptorBufferHandleEXT { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkDescriptorBufferBindingPushDescriptorBufferHandleEXT; + +typedef union VkDescriptorDataEXT { + const VkSampler* pSampler; + const VkDescriptorImageInfo* pCombinedImageSampler; + const VkDescriptorImageInfo* pInputAttachmentImage; + const VkDescriptorImageInfo* pSampledImage; + const VkDescriptorImageInfo* pStorageImage; + const VkDescriptorAddressInfoEXT* pUniformTexelBuffer; + const VkDescriptorAddressInfoEXT* pStorageTexelBuffer; + const VkDescriptorAddressInfoEXT* pUniformBuffer; + const VkDescriptorAddressInfoEXT* pStorageBuffer; + VkDeviceAddress accelerationStructure; +} VkDescriptorDataEXT; + +typedef struct VkDescriptorGetInfoEXT { + VkStructureType sType; + const void* pNext; + VkDescriptorType type; + VkDescriptorDataEXT data; +} VkDescriptorGetInfoEXT; + +typedef struct VkBufferCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferCaptureDescriptorDataInfoEXT; + +typedef struct VkImageCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void* pNext; + VkImage image; +} VkImageCaptureDescriptorDataInfoEXT; + +typedef struct VkImageViewCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void* pNext; + VkImageView imageView; +} VkImageViewCaptureDescriptorDataInfoEXT; + +typedef struct VkSamplerCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void* pNext; + VkSampler sampler; +} VkSamplerCaptureDescriptorDataInfoEXT; + +typedef struct VkOpaqueCaptureDescriptorDataCreateInfoEXT { + VkStructureType sType; + const void* pNext; + const void* opaqueCaptureDescriptorData; +} VkOpaqueCaptureDescriptorDataCreateInfoEXT; + +typedef struct VkAccelerationStructureCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureKHR accelerationStructure; + VkAccelerationStructureNV accelerationStructureNV; +} VkAccelerationStructureCaptureDescriptorDataInfoEXT; + +typedef struct VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT { + VkStructureType sType; + void* pNext; + size_t combinedImageSamplerDensityMapDescriptorSize; +} VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT; + +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSizeEXT)(VkDevice device, VkDescriptorSetLayout layout, VkDeviceSize* pLayoutSizeInBytes); +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutBindingOffsetEXT)(VkDevice device, VkDescriptorSetLayout layout, uint32_t binding, VkDeviceSize* pOffset); +typedef void (VKAPI_PTR *PFN_vkGetDescriptorEXT)(VkDevice device, const VkDescriptorGetInfoEXT* pDescriptorInfo, size_t dataSize, void* pDescriptor); +typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorBuffersEXT)(VkCommandBuffer commandBuffer, uint32_t bufferCount, const VkDescriptorBufferBindingInfoEXT* pBindingInfos); +typedef void (VKAPI_PTR *PFN_vkCmdSetDescriptorBufferOffsetsEXT)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount, const uint32_t* pBufferIndices, const VkDeviceSize* pOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set); +typedef VkResult (VKAPI_PTR *PFN_vkGetBufferOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkBufferCaptureDescriptorDataInfoEXT* pInfo, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetImageOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkImageCaptureDescriptorDataInfoEXT* pInfo, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkImageViewCaptureDescriptorDataInfoEXT* pInfo, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetSamplerOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkSamplerCaptureDescriptorDataInfoEXT* pInfo, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkAccelerationStructureCaptureDescriptorDataInfoEXT* pInfo, void* pData); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSizeEXT( + VkDevice device, + VkDescriptorSetLayout layout, + VkDeviceSize* pLayoutSizeInBytes); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutBindingOffsetEXT( + VkDevice device, + VkDescriptorSetLayout layout, + uint32_t binding, + VkDeviceSize* pOffset); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorEXT( + VkDevice device, + const VkDescriptorGetInfoEXT* pDescriptorInfo, + size_t dataSize, + void* pDescriptor); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorBuffersEXT( + VkCommandBuffer commandBuffer, + uint32_t bufferCount, + const VkDescriptorBufferBindingInfoEXT* pBindingInfos); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDescriptorBufferOffsetsEXT( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, + uint32_t firstSet, + uint32_t setCount, + const uint32_t* pBufferIndices, + const VkDeviceSize* pOffsets); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorBufferEmbeddedSamplersEXT( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, + uint32_t set); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetBufferOpaqueCaptureDescriptorDataEXT( + VkDevice device, + const VkBufferCaptureDescriptorDataInfoEXT* pInfo, + void* pData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetImageOpaqueCaptureDescriptorDataEXT( + VkDevice device, + const VkImageCaptureDescriptorDataInfoEXT* pInfo, + void* pData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetImageViewOpaqueCaptureDescriptorDataEXT( + VkDevice device, + const VkImageViewCaptureDescriptorDataInfoEXT* pInfo, + void* pData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetSamplerOpaqueCaptureDescriptorDataEXT( + VkDevice device, + const VkSamplerCaptureDescriptorDataInfoEXT* pInfo, + void* pData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT( + VkDevice device, + const VkAccelerationStructureCaptureDescriptorDataInfoEXT* pInfo, + void* pData); +#endif +#endif + + +// VK_EXT_graphics_pipeline_library is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_graphics_pipeline_library 1 +#define VK_EXT_GRAPHICS_PIPELINE_LIBRARY_SPEC_VERSION 1 +#define VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME "VK_EXT_graphics_pipeline_library" + +typedef enum VkGraphicsPipelineLibraryFlagBitsEXT { + VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT = 0x00000001, + VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT = 0x00000002, + VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT = 0x00000004, + VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT = 0x00000008, + VK_GRAPHICS_PIPELINE_LIBRARY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkGraphicsPipelineLibraryFlagBitsEXT; +typedef VkFlags VkGraphicsPipelineLibraryFlagsEXT; +typedef struct VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 graphicsPipelineLibrary; +} VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT; + +typedef struct VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 graphicsPipelineLibraryFastLinking; + VkBool32 graphicsPipelineLibraryIndependentInterpolationDecoration; +} VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT; + +typedef struct VkGraphicsPipelineLibraryCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkGraphicsPipelineLibraryFlagsEXT flags; +} VkGraphicsPipelineLibraryCreateInfoEXT; + + + +// VK_AMD_shader_early_and_late_fragment_tests is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_shader_early_and_late_fragment_tests 1 +#define VK_AMD_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_SPEC_VERSION 1 +#define VK_AMD_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_EXTENSION_NAME "VK_AMD_shader_early_and_late_fragment_tests" +typedef struct VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD { + VkStructureType sType; + void* pNext; + VkBool32 shaderEarlyAndLateFragmentTests; +} VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD; + + + +// VK_NV_fragment_shading_rate_enums is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_fragment_shading_rate_enums 1 +#define VK_NV_FRAGMENT_SHADING_RATE_ENUMS_SPEC_VERSION 1 +#define VK_NV_FRAGMENT_SHADING_RATE_ENUMS_EXTENSION_NAME "VK_NV_fragment_shading_rate_enums" + +typedef enum VkFragmentShadingRateTypeNV { + VK_FRAGMENT_SHADING_RATE_TYPE_FRAGMENT_SIZE_NV = 0, + VK_FRAGMENT_SHADING_RATE_TYPE_ENUMS_NV = 1, + VK_FRAGMENT_SHADING_RATE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkFragmentShadingRateTypeNV; + +typedef enum VkFragmentShadingRateNV { + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_PIXEL_NV = 0, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_1X2_PIXELS_NV = 1, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X1_PIXELS_NV = 4, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X2_PIXELS_NV = 5, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X4_PIXELS_NV = 6, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X2_PIXELS_NV = 9, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X4_PIXELS_NV = 10, + VK_FRAGMENT_SHADING_RATE_2_INVOCATIONS_PER_PIXEL_NV = 11, + VK_FRAGMENT_SHADING_RATE_4_INVOCATIONS_PER_PIXEL_NV = 12, + VK_FRAGMENT_SHADING_RATE_8_INVOCATIONS_PER_PIXEL_NV = 13, + VK_FRAGMENT_SHADING_RATE_16_INVOCATIONS_PER_PIXEL_NV = 14, + VK_FRAGMENT_SHADING_RATE_NO_INVOCATIONS_NV = 15, + VK_FRAGMENT_SHADING_RATE_MAX_ENUM_NV = 0x7FFFFFFF +} VkFragmentShadingRateNV; +typedef struct VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 fragmentShadingRateEnums; + VkBool32 supersampleFragmentShadingRates; + VkBool32 noInvocationFragmentShadingRates; +} VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV; + +typedef struct VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV { + VkStructureType sType; + void* pNext; + VkSampleCountFlagBits maxFragmentShadingRateInvocationCount; +} VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV; + +typedef struct VkPipelineFragmentShadingRateEnumStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkFragmentShadingRateTypeNV shadingRateType; + VkFragmentShadingRateNV shadingRate; + VkFragmentShadingRateCombinerOpKHR combinerOps[2]; +} VkPipelineFragmentShadingRateEnumStateCreateInfoNV; + +typedef void (VKAPI_PTR *PFN_vkCmdSetFragmentShadingRateEnumNV)(VkCommandBuffer commandBuffer, VkFragmentShadingRateNV shadingRate, const VkFragmentShadingRateCombinerOpKHR combinerOps[2]); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetFragmentShadingRateEnumNV( + VkCommandBuffer commandBuffer, + VkFragmentShadingRateNV shadingRate, + const VkFragmentShadingRateCombinerOpKHR combinerOps[2]); +#endif +#endif + + +// VK_NV_ray_tracing_motion_blur is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_ray_tracing_motion_blur 1 +#define VK_NV_RAY_TRACING_MOTION_BLUR_SPEC_VERSION 1 +#define VK_NV_RAY_TRACING_MOTION_BLUR_EXTENSION_NAME "VK_NV_ray_tracing_motion_blur" + +typedef enum VkAccelerationStructureMotionInstanceTypeNV { + VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_STATIC_NV = 0, + VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MATRIX_MOTION_NV = 1, + VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_SRT_MOTION_NV = 2, + VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkAccelerationStructureMotionInstanceTypeNV; +typedef VkFlags VkAccelerationStructureMotionInfoFlagsNV; +typedef VkFlags VkAccelerationStructureMotionInstanceFlagsNV; +typedef union VkDeviceOrHostAddressConstKHR { + VkDeviceAddress deviceAddress; + const void* hostAddress; +} VkDeviceOrHostAddressConstKHR; + +typedef struct VkAccelerationStructureGeometryMotionTrianglesDataNV { + VkStructureType sType; + const void* pNext; + VkDeviceOrHostAddressConstKHR vertexData; +} VkAccelerationStructureGeometryMotionTrianglesDataNV; + +typedef struct VkAccelerationStructureMotionInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t maxInstances; + VkAccelerationStructureMotionInfoFlagsNV flags; +} VkAccelerationStructureMotionInfoNV; + +typedef struct VkAccelerationStructureMatrixMotionInstanceNV { + VkTransformMatrixKHR transformT0; + VkTransformMatrixKHR transformT1; + uint32_t instanceCustomIndex:24; + uint32_t mask:8; + uint32_t instanceShaderBindingTableRecordOffset:24; + VkGeometryInstanceFlagsKHR flags:8; + uint64_t accelerationStructureReference; +} VkAccelerationStructureMatrixMotionInstanceNV; + +typedef struct VkSRTDataNV { + float sx; + float a; + float b; + float pvx; + float sy; + float c; + float pvy; + float sz; + float pvz; + float qx; + float qy; + float qz; + float qw; + float tx; + float ty; + float tz; +} VkSRTDataNV; + +typedef struct VkAccelerationStructureSRTMotionInstanceNV { + VkSRTDataNV transformT0; + VkSRTDataNV transformT1; + uint32_t instanceCustomIndex:24; + uint32_t mask:8; + uint32_t instanceShaderBindingTableRecordOffset:24; + VkGeometryInstanceFlagsKHR flags:8; + uint64_t accelerationStructureReference; +} VkAccelerationStructureSRTMotionInstanceNV; + +typedef union VkAccelerationStructureMotionInstanceDataNV { + VkAccelerationStructureInstanceKHR staticInstance; + VkAccelerationStructureMatrixMotionInstanceNV matrixMotionInstance; + VkAccelerationStructureSRTMotionInstanceNV srtMotionInstance; +} VkAccelerationStructureMotionInstanceDataNV; + +typedef struct VkAccelerationStructureMotionInstanceNV { + VkAccelerationStructureMotionInstanceTypeNV type; + VkAccelerationStructureMotionInstanceFlagsNV flags; + VkAccelerationStructureMotionInstanceDataNV data; +} VkAccelerationStructureMotionInstanceNV; + +typedef struct VkPhysicalDeviceRayTracingMotionBlurFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 rayTracingMotionBlur; + VkBool32 rayTracingMotionBlurPipelineTraceRaysIndirect; +} VkPhysicalDeviceRayTracingMotionBlurFeaturesNV; + + + +// VK_EXT_ycbcr_2plane_444_formats is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_ycbcr_2plane_444_formats 1 +#define VK_EXT_YCBCR_2PLANE_444_FORMATS_SPEC_VERSION 1 +#define VK_EXT_YCBCR_2PLANE_444_FORMATS_EXTENSION_NAME "VK_EXT_ycbcr_2plane_444_formats" +typedef struct VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 ycbcr2plane444Formats; +} VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT; + + + +// VK_EXT_fragment_density_map2 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_fragment_density_map2 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_2_SPEC_VERSION 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_2_EXTENSION_NAME "VK_EXT_fragment_density_map2" +typedef struct VkPhysicalDeviceFragmentDensityMap2FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 fragmentDensityMapDeferred; +} VkPhysicalDeviceFragmentDensityMap2FeaturesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMap2PropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 subsampledLoads; + VkBool32 subsampledCoarseReconstructionEarlyAccess; + uint32_t maxSubsampledArrayLayers; + uint32_t maxDescriptorSetSubsampledSamplers; +} VkPhysicalDeviceFragmentDensityMap2PropertiesEXT; + + + +// VK_QCOM_rotated_copy_commands is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_rotated_copy_commands 1 +#define VK_QCOM_ROTATED_COPY_COMMANDS_SPEC_VERSION 2 +#define VK_QCOM_ROTATED_COPY_COMMANDS_EXTENSION_NAME "VK_QCOM_rotated_copy_commands" +typedef struct VkCopyCommandTransformInfoQCOM { + VkStructureType sType; + const void* pNext; + VkSurfaceTransformFlagBitsKHR transform; +} VkCopyCommandTransformInfoQCOM; + + + +// VK_EXT_image_robustness is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_image_robustness 1 +#define VK_EXT_IMAGE_ROBUSTNESS_SPEC_VERSION 1 +#define VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME "VK_EXT_image_robustness" +typedef VkPhysicalDeviceImageRobustnessFeatures VkPhysicalDeviceImageRobustnessFeaturesEXT; + + + +// VK_EXT_image_compression_control is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_image_compression_control 1 +#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SPEC_VERSION 1 +#define VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME "VK_EXT_image_compression_control" + +typedef enum VkImageCompressionFlagBitsEXT { + VK_IMAGE_COMPRESSION_DEFAULT_EXT = 0, + VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT = 0x00000001, + VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT = 0x00000002, + VK_IMAGE_COMPRESSION_DISABLED_EXT = 0x00000004, + VK_IMAGE_COMPRESSION_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkImageCompressionFlagBitsEXT; +typedef VkFlags VkImageCompressionFlagsEXT; + +typedef enum VkImageCompressionFixedRateFlagBitsEXT { + VK_IMAGE_COMPRESSION_FIXED_RATE_NONE_EXT = 0, + VK_IMAGE_COMPRESSION_FIXED_RATE_1BPC_BIT_EXT = 0x00000001, + VK_IMAGE_COMPRESSION_FIXED_RATE_2BPC_BIT_EXT = 0x00000002, + VK_IMAGE_COMPRESSION_FIXED_RATE_3BPC_BIT_EXT = 0x00000004, + VK_IMAGE_COMPRESSION_FIXED_RATE_4BPC_BIT_EXT = 0x00000008, + VK_IMAGE_COMPRESSION_FIXED_RATE_5BPC_BIT_EXT = 0x00000010, + VK_IMAGE_COMPRESSION_FIXED_RATE_6BPC_BIT_EXT = 0x00000020, + VK_IMAGE_COMPRESSION_FIXED_RATE_7BPC_BIT_EXT = 0x00000040, + VK_IMAGE_COMPRESSION_FIXED_RATE_8BPC_BIT_EXT = 0x00000080, + VK_IMAGE_COMPRESSION_FIXED_RATE_9BPC_BIT_EXT = 0x00000100, + VK_IMAGE_COMPRESSION_FIXED_RATE_10BPC_BIT_EXT = 0x00000200, + VK_IMAGE_COMPRESSION_FIXED_RATE_11BPC_BIT_EXT = 0x00000400, + VK_IMAGE_COMPRESSION_FIXED_RATE_12BPC_BIT_EXT = 0x00000800, + VK_IMAGE_COMPRESSION_FIXED_RATE_13BPC_BIT_EXT = 0x00001000, + VK_IMAGE_COMPRESSION_FIXED_RATE_14BPC_BIT_EXT = 0x00002000, + VK_IMAGE_COMPRESSION_FIXED_RATE_15BPC_BIT_EXT = 0x00004000, + VK_IMAGE_COMPRESSION_FIXED_RATE_16BPC_BIT_EXT = 0x00008000, + VK_IMAGE_COMPRESSION_FIXED_RATE_17BPC_BIT_EXT = 0x00010000, + VK_IMAGE_COMPRESSION_FIXED_RATE_18BPC_BIT_EXT = 0x00020000, + VK_IMAGE_COMPRESSION_FIXED_RATE_19BPC_BIT_EXT = 0x00040000, + VK_IMAGE_COMPRESSION_FIXED_RATE_20BPC_BIT_EXT = 0x00080000, + VK_IMAGE_COMPRESSION_FIXED_RATE_21BPC_BIT_EXT = 0x00100000, + VK_IMAGE_COMPRESSION_FIXED_RATE_22BPC_BIT_EXT = 0x00200000, + VK_IMAGE_COMPRESSION_FIXED_RATE_23BPC_BIT_EXT = 0x00400000, + VK_IMAGE_COMPRESSION_FIXED_RATE_24BPC_BIT_EXT = 0x00800000, + VK_IMAGE_COMPRESSION_FIXED_RATE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkImageCompressionFixedRateFlagBitsEXT; +typedef VkFlags VkImageCompressionFixedRateFlagsEXT; +typedef struct VkPhysicalDeviceImageCompressionControlFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 imageCompressionControl; +} VkPhysicalDeviceImageCompressionControlFeaturesEXT; + +typedef struct VkImageCompressionControlEXT { + VkStructureType sType; + const void* pNext; + VkImageCompressionFlagsEXT flags; + uint32_t compressionControlPlaneCount; + VkImageCompressionFixedRateFlagsEXT* pFixedRateFlags; +} VkImageCompressionControlEXT; + +typedef struct VkImageCompressionPropertiesEXT { + VkStructureType sType; + void* pNext; + VkImageCompressionFlagsEXT imageCompressionFlags; + VkImageCompressionFixedRateFlagsEXT imageCompressionFixedRateFlags; +} VkImageCompressionPropertiesEXT; + + + +// VK_EXT_attachment_feedback_loop_layout is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_attachment_feedback_loop_layout 1 +#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_SPEC_VERSION 2 +#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_EXTENSION_NAME "VK_EXT_attachment_feedback_loop_layout" +typedef struct VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 attachmentFeedbackLoopLayout; +} VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT; + + + +// VK_EXT_4444_formats is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_4444_formats 1 +#define VK_EXT_4444_FORMATS_SPEC_VERSION 1 +#define VK_EXT_4444_FORMATS_EXTENSION_NAME "VK_EXT_4444_formats" +typedef struct VkPhysicalDevice4444FormatsFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 formatA4R4G4B4; + VkBool32 formatA4B4G4R4; +} VkPhysicalDevice4444FormatsFeaturesEXT; + + + +// VK_EXT_device_fault is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_device_fault 1 +#define VK_EXT_DEVICE_FAULT_SPEC_VERSION 2 +#define VK_EXT_DEVICE_FAULT_EXTENSION_NAME "VK_EXT_device_fault" +typedef VkDeviceFaultAddressTypeKHR VkDeviceFaultAddressTypeEXT; + +typedef VkDeviceFaultVendorBinaryHeaderVersionKHR VkDeviceFaultVendorBinaryHeaderVersionEXT; + +typedef struct VkPhysicalDeviceFaultFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 deviceFault; + VkBool32 deviceFaultVendorBinary; +} VkPhysicalDeviceFaultFeaturesEXT; + +typedef struct VkDeviceFaultCountsEXT { + VkStructureType sType; + void* pNext; + uint32_t addressInfoCount; + uint32_t vendorInfoCount; + VkDeviceSize vendorBinarySize; +} VkDeviceFaultCountsEXT; + +typedef struct VkDeviceFaultInfoEXT { + VkStructureType sType; + void* pNext; + char description[VK_MAX_DESCRIPTION_SIZE]; + VkDeviceFaultAddressInfoKHR* pAddressInfos; + VkDeviceFaultVendorInfoKHR* pVendorInfos; + void* pVendorBinaryData; +} VkDeviceFaultInfoEXT; + +typedef VkDeviceFaultAddressInfoKHR VkDeviceFaultAddressInfoEXT; + +typedef VkDeviceFaultVendorInfoKHR VkDeviceFaultVendorInfoEXT; + +typedef VkDeviceFaultVendorBinaryHeaderVersionOneKHR VkDeviceFaultVendorBinaryHeaderVersionOneEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceFaultInfoEXT)(VkDevice device, VkDeviceFaultCountsEXT* pFaultCounts, VkDeviceFaultInfoEXT* pFaultInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceFaultInfoEXT( + VkDevice device, + VkDeviceFaultCountsEXT* pFaultCounts, + VkDeviceFaultInfoEXT* pFaultInfo); +#endif +#endif + + +// VK_ARM_rasterization_order_attachment_access is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_rasterization_order_attachment_access 1 +#define VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION 1 +#define VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME "VK_ARM_rasterization_order_attachment_access" +typedef struct VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 rasterizationOrderColorAttachmentAccess; + VkBool32 rasterizationOrderDepthAttachmentAccess; + VkBool32 rasterizationOrderStencilAttachmentAccess; +} VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT; + +typedef VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM; + + + +// VK_EXT_rgba10x6_formats is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_rgba10x6_formats 1 +#define VK_EXT_RGBA10X6_FORMATS_SPEC_VERSION 1 +#define VK_EXT_RGBA10X6_FORMATS_EXTENSION_NAME "VK_EXT_rgba10x6_formats" +typedef struct VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 formatRgba10x6WithoutYCbCrSampler; +} VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT; + + + +// VK_VALVE_mutable_descriptor_type is a preprocessor guard. Do not pass it to API calls. +#define VK_VALVE_mutable_descriptor_type 1 +#define VK_VALVE_MUTABLE_DESCRIPTOR_TYPE_SPEC_VERSION 1 +#define VK_VALVE_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME "VK_VALVE_mutable_descriptor_type" +typedef struct VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 mutableDescriptorType; +} VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT; + +typedef VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE; + +typedef struct VkMutableDescriptorTypeListEXT { + uint32_t descriptorTypeCount; + const VkDescriptorType* pDescriptorTypes; +} VkMutableDescriptorTypeListEXT; + +typedef VkMutableDescriptorTypeListEXT VkMutableDescriptorTypeListVALVE; + +typedef struct VkMutableDescriptorTypeCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t mutableDescriptorTypeListCount; + const VkMutableDescriptorTypeListEXT* pMutableDescriptorTypeLists; +} VkMutableDescriptorTypeCreateInfoEXT; + +typedef VkMutableDescriptorTypeCreateInfoEXT VkMutableDescriptorTypeCreateInfoVALVE; + + + +// VK_EXT_vertex_input_dynamic_state is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_vertex_input_dynamic_state 1 +#define VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_SPEC_VERSION 2 +#define VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME "VK_EXT_vertex_input_dynamic_state" +typedef struct VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 vertexInputDynamicState; +} VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT; + +typedef struct VkVertexInputBindingDescription2EXT { + VkStructureType sType; + void* pNext; + uint32_t binding; + uint32_t stride; + VkVertexInputRate inputRate; + uint32_t divisor; +} VkVertexInputBindingDescription2EXT; + +typedef struct VkVertexInputAttributeDescription2EXT { + VkStructureType sType; + void* pNext; + uint32_t location; + uint32_t binding; + VkFormat format; + uint32_t offset; +} VkVertexInputAttributeDescription2EXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetVertexInputEXT)(VkCommandBuffer commandBuffer, uint32_t vertexBindingDescriptionCount, const VkVertexInputBindingDescription2EXT* pVertexBindingDescriptions, uint32_t vertexAttributeDescriptionCount, const VkVertexInputAttributeDescription2EXT* pVertexAttributeDescriptions); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetVertexInputEXT( + VkCommandBuffer commandBuffer, + uint32_t vertexBindingDescriptionCount, + const VkVertexInputBindingDescription2EXT* pVertexBindingDescriptions, + uint32_t vertexAttributeDescriptionCount, + const VkVertexInputAttributeDescription2EXT* pVertexAttributeDescriptions); +#endif +#endif + + +// VK_EXT_physical_device_drm is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_physical_device_drm 1 +#define VK_EXT_PHYSICAL_DEVICE_DRM_SPEC_VERSION 1 +#define VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME "VK_EXT_physical_device_drm" +typedef struct VkPhysicalDeviceDrmPropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 hasPrimary; + VkBool32 hasRender; + int64_t primaryMajor; + int64_t primaryMinor; + int64_t renderMajor; + int64_t renderMinor; +} VkPhysicalDeviceDrmPropertiesEXT; + + + +// VK_EXT_device_address_binding_report is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_device_address_binding_report 1 +#define VK_EXT_DEVICE_ADDRESS_BINDING_REPORT_SPEC_VERSION 1 +#define VK_EXT_DEVICE_ADDRESS_BINDING_REPORT_EXTENSION_NAME "VK_EXT_device_address_binding_report" + +typedef enum VkDeviceAddressBindingTypeEXT { + VK_DEVICE_ADDRESS_BINDING_TYPE_BIND_EXT = 0, + VK_DEVICE_ADDRESS_BINDING_TYPE_UNBIND_EXT = 1, + VK_DEVICE_ADDRESS_BINDING_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceAddressBindingTypeEXT; + +typedef enum VkDeviceAddressBindingFlagBitsEXT { + VK_DEVICE_ADDRESS_BINDING_INTERNAL_OBJECT_BIT_EXT = 0x00000001, + VK_DEVICE_ADDRESS_BINDING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceAddressBindingFlagBitsEXT; +typedef VkFlags VkDeviceAddressBindingFlagsEXT; +typedef struct VkPhysicalDeviceAddressBindingReportFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 reportAddressBinding; +} VkPhysicalDeviceAddressBindingReportFeaturesEXT; + +typedef struct VkDeviceAddressBindingCallbackDataEXT { + VkStructureType sType; + void* pNext; + VkDeviceAddressBindingFlagsEXT flags; + VkDeviceAddress baseAddress; + VkDeviceSize size; + VkDeviceAddressBindingTypeEXT bindingType; +} VkDeviceAddressBindingCallbackDataEXT; + + + +// VK_EXT_depth_clip_control is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_depth_clip_control 1 +#define VK_EXT_DEPTH_CLIP_CONTROL_SPEC_VERSION 1 +#define VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME "VK_EXT_depth_clip_control" +typedef struct VkPhysicalDeviceDepthClipControlFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 depthClipControl; +} VkPhysicalDeviceDepthClipControlFeaturesEXT; + +typedef struct VkPipelineViewportDepthClipControlCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 negativeOneToOne; +} VkPipelineViewportDepthClipControlCreateInfoEXT; + + + +// VK_EXT_primitive_topology_list_restart is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_primitive_topology_list_restart 1 +#define VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_SPEC_VERSION 1 +#define VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME "VK_EXT_primitive_topology_list_restart" +typedef struct VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 primitiveTopologyListRestart; + VkBool32 primitiveTopologyPatchListRestart; +} VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT; + + + +// VK_EXT_present_mode_fifo_latest_ready is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_present_mode_fifo_latest_ready 1 +#define VK_EXT_PRESENT_MODE_FIFO_LATEST_READY_SPEC_VERSION 1 +#define VK_EXT_PRESENT_MODE_FIFO_LATEST_READY_EXTENSION_NAME "VK_EXT_present_mode_fifo_latest_ready" +typedef VkPhysicalDevicePresentModeFifoLatestReadyFeaturesKHR VkPhysicalDevicePresentModeFifoLatestReadyFeaturesEXT; + + + +// VK_HUAWEI_subpass_shading is a preprocessor guard. Do not pass it to API calls. +#define VK_HUAWEI_subpass_shading 1 +#define VK_HUAWEI_SUBPASS_SHADING_SPEC_VERSION 3 +#define VK_HUAWEI_SUBPASS_SHADING_EXTENSION_NAME "VK_HUAWEI_subpass_shading" +typedef struct VkSubpassShadingPipelineCreateInfoHUAWEI { + VkStructureType sType; + void* pNext; + VkRenderPass renderPass; + uint32_t subpass; +} VkSubpassShadingPipelineCreateInfoHUAWEI; + +typedef struct VkPhysicalDeviceSubpassShadingFeaturesHUAWEI { + VkStructureType sType; + void* pNext; + VkBool32 subpassShading; +} VkPhysicalDeviceSubpassShadingFeaturesHUAWEI; + +typedef struct VkPhysicalDeviceSubpassShadingPropertiesHUAWEI { + VkStructureType sType; + void* pNext; + uint32_t maxSubpassShadingWorkgroupSizeAspectRatio; +} VkPhysicalDeviceSubpassShadingPropertiesHUAWEI; + +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI)(VkDevice device, VkRenderPass renderpass, VkExtent2D* pMaxWorkgroupSize); +typedef void (VKAPI_PTR *PFN_vkCmdSubpassShadingHUAWEI)(VkCommandBuffer commandBuffer); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI( + VkDevice device, + VkRenderPass renderpass, + VkExtent2D* pMaxWorkgroupSize); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSubpassShadingHUAWEI( + VkCommandBuffer commandBuffer); +#endif +#endif + + +// VK_HUAWEI_invocation_mask is a preprocessor guard. Do not pass it to API calls. +#define VK_HUAWEI_invocation_mask 1 +#define VK_HUAWEI_INVOCATION_MASK_SPEC_VERSION 1 +#define VK_HUAWEI_INVOCATION_MASK_EXTENSION_NAME "VK_HUAWEI_invocation_mask" +typedef struct VkPhysicalDeviceInvocationMaskFeaturesHUAWEI { + VkStructureType sType; + void* pNext; + VkBool32 invocationMask; +} VkPhysicalDeviceInvocationMaskFeaturesHUAWEI; + +typedef void (VKAPI_PTR *PFN_vkCmdBindInvocationMaskHUAWEI)(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindInvocationMaskHUAWEI( + VkCommandBuffer commandBuffer, + VkImageView imageView, + VkImageLayout imageLayout); +#endif +#endif + + +// VK_NV_external_memory_rdma is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_external_memory_rdma 1 +typedef void* VkRemoteAddressNV; +#define VK_NV_EXTERNAL_MEMORY_RDMA_SPEC_VERSION 1 +#define VK_NV_EXTERNAL_MEMORY_RDMA_EXTENSION_NAME "VK_NV_external_memory_rdma" +typedef struct VkMemoryGetRemoteAddressInfoNV { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkMemoryGetRemoteAddressInfoNV; + +typedef struct VkPhysicalDeviceExternalMemoryRDMAFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 externalMemoryRDMA; +} VkPhysicalDeviceExternalMemoryRDMAFeaturesNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryRemoteAddressNV)(VkDevice device, const VkMemoryGetRemoteAddressInfoNV* pMemoryGetRemoteAddressInfo, VkRemoteAddressNV* pAddress); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryRemoteAddressNV( + VkDevice device, + const VkMemoryGetRemoteAddressInfoNV* pMemoryGetRemoteAddressInfo, + VkRemoteAddressNV* pAddress); +#endif +#endif + + +// VK_EXT_pipeline_properties is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_pipeline_properties 1 +#define VK_EXT_PIPELINE_PROPERTIES_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_PROPERTIES_EXTENSION_NAME "VK_EXT_pipeline_properties" +typedef VkPipelineInfoKHR VkPipelineInfoEXT; + +typedef struct VkPipelinePropertiesIdentifierEXT { + VkStructureType sType; + void* pNext; + uint8_t pipelineIdentifier[VK_UUID_SIZE]; +} VkPipelinePropertiesIdentifierEXT; + +typedef struct VkPhysicalDevicePipelinePropertiesFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 pipelinePropertiesIdentifier; +} VkPhysicalDevicePipelinePropertiesFeaturesEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelinePropertiesEXT)(VkDevice device, const VkPipelineInfoKHR* pPipelineInfo, VkBaseOutStructure* pPipelineProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelinePropertiesEXT( + VkDevice device, + const VkPipelineInfoKHR* pPipelineInfo, + VkBaseOutStructure* pPipelineProperties); +#endif +#endif + + +// VK_EXT_frame_boundary is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_frame_boundary 1 +#define VK_EXT_FRAME_BOUNDARY_SPEC_VERSION 1 +#define VK_EXT_FRAME_BOUNDARY_EXTENSION_NAME "VK_EXT_frame_boundary" + +typedef enum VkFrameBoundaryFlagBitsEXT { + VK_FRAME_BOUNDARY_FRAME_END_BIT_EXT = 0x00000001, + VK_FRAME_BOUNDARY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkFrameBoundaryFlagBitsEXT; +typedef VkFlags VkFrameBoundaryFlagsEXT; +typedef struct VkPhysicalDeviceFrameBoundaryFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 frameBoundary; +} VkPhysicalDeviceFrameBoundaryFeaturesEXT; + +typedef struct VkFrameBoundaryEXT { + VkStructureType sType; + const void* pNext; + VkFrameBoundaryFlagsEXT flags; + uint64_t frameID; + uint32_t imageCount; + const VkImage* pImages; + uint32_t bufferCount; + const VkBuffer* pBuffers; + uint64_t tagName; + size_t tagSize; + const void* pTag; +} VkFrameBoundaryEXT; + + + +// VK_EXT_multisampled_render_to_single_sampled is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_multisampled_render_to_single_sampled 1 +#define VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_SPEC_VERSION 1 +#define VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXTENSION_NAME "VK_EXT_multisampled_render_to_single_sampled" +typedef struct VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 multisampledRenderToSingleSampled; +} VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT; + +typedef struct VkSubpassResolvePerformanceQueryEXT { + VkStructureType sType; + void* pNext; + VkBool32 optimal; +} VkSubpassResolvePerformanceQueryEXT; + +typedef struct VkMultisampledRenderToSingleSampledInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 multisampledRenderToSingleSampledEnable; + VkSampleCountFlagBits rasterizationSamples; +} VkMultisampledRenderToSingleSampledInfoEXT; + + + +// VK_EXT_extended_dynamic_state2 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_extended_dynamic_state2 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_2_SPEC_VERSION 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME "VK_EXT_extended_dynamic_state2" +typedef struct VkPhysicalDeviceExtendedDynamicState2FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 extendedDynamicState2; + VkBool32 extendedDynamicState2LogicOp; + VkBool32 extendedDynamicState2PatchControlPoints; +} VkPhysicalDeviceExtendedDynamicState2FeaturesEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetPatchControlPointsEXT)(VkCommandBuffer commandBuffer, uint32_t patchControlPoints); +typedef void (VKAPI_PTR *PFN_vkCmdSetRasterizerDiscardEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 rasterizerDiscardEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBiasEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetLogicOpEXT)(VkCommandBuffer commandBuffer, VkLogicOp logicOp); +typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveRestartEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 primitiveRestartEnable); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetPatchControlPointsEXT( + VkCommandBuffer commandBuffer, + uint32_t patchControlPoints); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetRasterizerDiscardEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 rasterizerDiscardEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBiasEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthBiasEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetLogicOpEXT( + VkCommandBuffer commandBuffer, + VkLogicOp logicOp); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetPrimitiveRestartEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 primitiveRestartEnable); +#endif +#endif + + +// VK_EXT_color_write_enable is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_color_write_enable 1 +#define VK_EXT_COLOR_WRITE_ENABLE_SPEC_VERSION 1 +#define VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME "VK_EXT_color_write_enable" +typedef struct VkPhysicalDeviceColorWriteEnableFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 colorWriteEnable; +} VkPhysicalDeviceColorWriteEnableFeaturesEXT; + +typedef struct VkPipelineColorWriteCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t attachmentCount; + const VkBool32* pColorWriteEnables; +} VkPipelineColorWriteCreateInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetColorWriteEnableEXT)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkBool32* pColorWriteEnables); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetColorWriteEnableEXT( + VkCommandBuffer commandBuffer, + uint32_t attachmentCount, + const VkBool32* pColorWriteEnables); +#endif +#endif + + +// VK_EXT_primitives_generated_query is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_primitives_generated_query 1 +#define VK_EXT_PRIMITIVES_GENERATED_QUERY_SPEC_VERSION 1 +#define VK_EXT_PRIMITIVES_GENERATED_QUERY_EXTENSION_NAME "VK_EXT_primitives_generated_query" +typedef struct VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 primitivesGeneratedQuery; + VkBool32 primitivesGeneratedQueryWithRasterizerDiscard; + VkBool32 primitivesGeneratedQueryWithNonZeroStreams; +} VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT; + + + +// VK_EXT_global_priority_query is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_global_priority_query 1 +#define VK_EXT_GLOBAL_PRIORITY_QUERY_SPEC_VERSION 1 +#define VK_EXT_GLOBAL_PRIORITY_QUERY_EXTENSION_NAME "VK_EXT_global_priority_query" +#define VK_MAX_GLOBAL_PRIORITY_SIZE_EXT VK_MAX_GLOBAL_PRIORITY_SIZE +typedef VkPhysicalDeviceGlobalPriorityQueryFeatures VkPhysicalDeviceGlobalPriorityQueryFeaturesEXT; + +typedef VkQueueFamilyGlobalPriorityProperties VkQueueFamilyGlobalPriorityPropertiesEXT; + + + +// VK_VALVE_video_encode_rgb_conversion is a preprocessor guard. Do not pass it to API calls. +#define VK_VALVE_video_encode_rgb_conversion 1 +#define VK_VALVE_VIDEO_ENCODE_RGB_CONVERSION_SPEC_VERSION 1 +#define VK_VALVE_VIDEO_ENCODE_RGB_CONVERSION_EXTENSION_NAME "VK_VALVE_video_encode_rgb_conversion" + +typedef enum VkVideoEncodeRgbModelConversionFlagBitsVALVE { + VK_VIDEO_ENCODE_RGB_MODEL_CONVERSION_RGB_IDENTITY_BIT_VALVE = 0x00000001, + VK_VIDEO_ENCODE_RGB_MODEL_CONVERSION_YCBCR_IDENTITY_BIT_VALVE = 0x00000002, + VK_VIDEO_ENCODE_RGB_MODEL_CONVERSION_YCBCR_709_BIT_VALVE = 0x00000004, + VK_VIDEO_ENCODE_RGB_MODEL_CONVERSION_YCBCR_601_BIT_VALVE = 0x00000008, + VK_VIDEO_ENCODE_RGB_MODEL_CONVERSION_YCBCR_2020_BIT_VALVE = 0x00000010, + VK_VIDEO_ENCODE_RGB_MODEL_CONVERSION_FLAG_BITS_MAX_ENUM_VALVE = 0x7FFFFFFF +} VkVideoEncodeRgbModelConversionFlagBitsVALVE; +typedef VkFlags VkVideoEncodeRgbModelConversionFlagsVALVE; + +typedef enum VkVideoEncodeRgbRangeCompressionFlagBitsVALVE { + VK_VIDEO_ENCODE_RGB_RANGE_COMPRESSION_FULL_RANGE_BIT_VALVE = 0x00000001, + VK_VIDEO_ENCODE_RGB_RANGE_COMPRESSION_NARROW_RANGE_BIT_VALVE = 0x00000002, + VK_VIDEO_ENCODE_RGB_RANGE_COMPRESSION_FLAG_BITS_MAX_ENUM_VALVE = 0x7FFFFFFF +} VkVideoEncodeRgbRangeCompressionFlagBitsVALVE; +typedef VkFlags VkVideoEncodeRgbRangeCompressionFlagsVALVE; + +typedef enum VkVideoEncodeRgbChromaOffsetFlagBitsVALVE { + VK_VIDEO_ENCODE_RGB_CHROMA_OFFSET_COSITED_EVEN_BIT_VALVE = 0x00000001, + VK_VIDEO_ENCODE_RGB_CHROMA_OFFSET_MIDPOINT_BIT_VALVE = 0x00000002, + VK_VIDEO_ENCODE_RGB_CHROMA_OFFSET_FLAG_BITS_MAX_ENUM_VALVE = 0x7FFFFFFF +} VkVideoEncodeRgbChromaOffsetFlagBitsVALVE; +typedef VkFlags VkVideoEncodeRgbChromaOffsetFlagsVALVE; +typedef struct VkPhysicalDeviceVideoEncodeRgbConversionFeaturesVALVE { + VkStructureType sType; + void* pNext; + VkBool32 videoEncodeRgbConversion; +} VkPhysicalDeviceVideoEncodeRgbConversionFeaturesVALVE; + +typedef struct VkVideoEncodeRgbConversionCapabilitiesVALVE { + VkStructureType sType; + void* pNext; + VkVideoEncodeRgbModelConversionFlagsVALVE rgbModels; + VkVideoEncodeRgbRangeCompressionFlagsVALVE rgbRanges; + VkVideoEncodeRgbChromaOffsetFlagsVALVE xChromaOffsets; + VkVideoEncodeRgbChromaOffsetFlagsVALVE yChromaOffsets; +} VkVideoEncodeRgbConversionCapabilitiesVALVE; + +typedef struct VkVideoEncodeProfileRgbConversionInfoVALVE { + VkStructureType sType; + const void* pNext; + VkBool32 performEncodeRgbConversion; +} VkVideoEncodeProfileRgbConversionInfoVALVE; + +typedef struct VkVideoEncodeSessionRgbConversionCreateInfoVALVE { + VkStructureType sType; + const void* pNext; + VkVideoEncodeRgbModelConversionFlagBitsVALVE rgbModel; + VkVideoEncodeRgbRangeCompressionFlagBitsVALVE rgbRange; + VkVideoEncodeRgbChromaOffsetFlagBitsVALVE xChromaOffset; + VkVideoEncodeRgbChromaOffsetFlagBitsVALVE yChromaOffset; +} VkVideoEncodeSessionRgbConversionCreateInfoVALVE; + + + +// VK_EXT_image_view_min_lod is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_image_view_min_lod 1 +#define VK_EXT_IMAGE_VIEW_MIN_LOD_SPEC_VERSION 1 +#define VK_EXT_IMAGE_VIEW_MIN_LOD_EXTENSION_NAME "VK_EXT_image_view_min_lod" +typedef struct VkPhysicalDeviceImageViewMinLodFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 minLod; +} VkPhysicalDeviceImageViewMinLodFeaturesEXT; + +typedef struct VkImageViewMinLodCreateInfoEXT { + VkStructureType sType; + const void* pNext; + float minLod; +} VkImageViewMinLodCreateInfoEXT; + + + +// VK_EXT_multi_draw is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_multi_draw 1 +#define VK_EXT_MULTI_DRAW_SPEC_VERSION 1 +#define VK_EXT_MULTI_DRAW_EXTENSION_NAME "VK_EXT_multi_draw" +typedef struct VkPhysicalDeviceMultiDrawFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 multiDraw; +} VkPhysicalDeviceMultiDrawFeaturesEXT; + +typedef struct VkPhysicalDeviceMultiDrawPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxMultiDrawCount; +} VkPhysicalDeviceMultiDrawPropertiesEXT; + +typedef struct VkMultiDrawInfoEXT { + uint32_t firstVertex; + uint32_t vertexCount; +} VkMultiDrawInfoEXT; + +typedef struct VkMultiDrawIndexedInfoEXT { + uint32_t firstIndex; + uint32_t indexCount; + int32_t vertexOffset; +} VkMultiDrawIndexedInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdDrawMultiEXT)(VkCommandBuffer commandBuffer, uint32_t drawCount, const VkMultiDrawInfoEXT* pVertexInfo, uint32_t instanceCount, uint32_t firstInstance, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawMultiIndexedEXT)(VkCommandBuffer commandBuffer, uint32_t drawCount, const VkMultiDrawIndexedInfoEXT* pIndexInfo, uint32_t instanceCount, uint32_t firstInstance, uint32_t stride, const int32_t* pVertexOffset); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMultiEXT( + VkCommandBuffer commandBuffer, + uint32_t drawCount, + const VkMultiDrawInfoEXT* pVertexInfo, + uint32_t instanceCount, + uint32_t firstInstance, + uint32_t stride); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMultiIndexedEXT( + VkCommandBuffer commandBuffer, + uint32_t drawCount, + const VkMultiDrawIndexedInfoEXT* pIndexInfo, + uint32_t instanceCount, + uint32_t firstInstance, + uint32_t stride, + const int32_t* pVertexOffset); +#endif +#endif + + +// VK_EXT_image_2d_view_of_3d is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_image_2d_view_of_3d 1 +#define VK_EXT_IMAGE_2D_VIEW_OF_3D_SPEC_VERSION 1 +#define VK_EXT_IMAGE_2D_VIEW_OF_3D_EXTENSION_NAME "VK_EXT_image_2d_view_of_3d" +typedef struct VkPhysicalDeviceImage2DViewOf3DFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 image2DViewOf3D; + VkBool32 sampler2DViewOf3D; +} VkPhysicalDeviceImage2DViewOf3DFeaturesEXT; + + + +// VK_EXT_shader_tile_image is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_tile_image 1 +#define VK_EXT_SHADER_TILE_IMAGE_SPEC_VERSION 1 +#define VK_EXT_SHADER_TILE_IMAGE_EXTENSION_NAME "VK_EXT_shader_tile_image" +typedef struct VkPhysicalDeviceShaderTileImageFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderTileImageColorReadAccess; + VkBool32 shaderTileImageDepthReadAccess; + VkBool32 shaderTileImageStencilReadAccess; +} VkPhysicalDeviceShaderTileImageFeaturesEXT; + +typedef struct VkPhysicalDeviceShaderTileImagePropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderTileImageCoherentReadAccelerated; + VkBool32 shaderTileImageReadSampleFromPixelRateInvocation; + VkBool32 shaderTileImageReadFromHelperInvocation; +} VkPhysicalDeviceShaderTileImagePropertiesEXT; + + + +// VK_EXT_opacity_micromap is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_opacity_micromap 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkMicromapEXT) +#define VK_EXT_OPACITY_MICROMAP_SPEC_VERSION 2 +#define VK_EXT_OPACITY_MICROMAP_EXTENSION_NAME "VK_EXT_opacity_micromap" + +typedef enum VkMicromapTypeEXT { + VK_MICROMAP_TYPE_OPACITY_MICROMAP_EXT = 0, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_MICROMAP_TYPE_DISPLACEMENT_MICROMAP_NV = 1000397000, +#endif + VK_MICROMAP_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkMicromapTypeEXT; + +typedef enum VkBuildMicromapModeEXT { + VK_BUILD_MICROMAP_MODE_BUILD_EXT = 0, + VK_BUILD_MICROMAP_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkBuildMicromapModeEXT; + +typedef enum VkCopyMicromapModeEXT { + VK_COPY_MICROMAP_MODE_CLONE_EXT = 0, + VK_COPY_MICROMAP_MODE_SERIALIZE_EXT = 1, + VK_COPY_MICROMAP_MODE_DESERIALIZE_EXT = 2, + VK_COPY_MICROMAP_MODE_COMPACT_EXT = 3, + VK_COPY_MICROMAP_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkCopyMicromapModeEXT; +typedef VkOpacityMicromapFormatKHR VkOpacityMicromapFormatEXT; + +typedef VkOpacityMicromapSpecialIndexKHR VkOpacityMicromapSpecialIndexEXT; + + +typedef enum VkAccelerationStructureCompatibilityKHR { + VK_ACCELERATION_STRUCTURE_COMPATIBILITY_COMPATIBLE_KHR = 0, + VK_ACCELERATION_STRUCTURE_COMPATIBILITY_INCOMPATIBLE_KHR = 1, + VK_ACCELERATION_STRUCTURE_COMPATIBILITY_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureCompatibilityKHR; + +typedef enum VkAccelerationStructureBuildTypeKHR { + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR = 0, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR = 1, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR = 2, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureBuildTypeKHR; + +typedef enum VkBuildMicromapFlagBitsEXT { + VK_BUILD_MICROMAP_PREFER_FAST_TRACE_BIT_EXT = 0x00000001, + VK_BUILD_MICROMAP_PREFER_FAST_BUILD_BIT_EXT = 0x00000002, + VK_BUILD_MICROMAP_ALLOW_COMPACTION_BIT_EXT = 0x00000004, + VK_BUILD_MICROMAP_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkBuildMicromapFlagBitsEXT; +typedef VkFlags VkBuildMicromapFlagsEXT; + +typedef enum VkMicromapCreateFlagBitsEXT { + VK_MICROMAP_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT = 0x00000001, + VK_MICROMAP_CREATE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkMicromapCreateFlagBitsEXT; +typedef VkFlags VkMicromapCreateFlagsEXT; +typedef struct VkMicromapUsageEXT { + uint32_t count; + uint32_t subdivisionLevel; + uint32_t format; +} VkMicromapUsageEXT; + +typedef union VkDeviceOrHostAddressKHR { + VkDeviceAddress deviceAddress; + void* hostAddress; +} VkDeviceOrHostAddressKHR; + +typedef struct VkMicromapBuildInfoEXT { + VkStructureType sType; + const void* pNext; + VkMicromapTypeEXT type; + VkBuildMicromapFlagsEXT flags; + VkBuildMicromapModeEXT mode; + VkMicromapEXT dstMicromap; + uint32_t usageCountsCount; + const VkMicromapUsageEXT* pUsageCounts; + const VkMicromapUsageEXT* const* ppUsageCounts; + VkDeviceOrHostAddressConstKHR data; + VkDeviceOrHostAddressKHR scratchData; + VkDeviceOrHostAddressConstKHR triangleArray; + VkDeviceSize triangleArrayStride; +} VkMicromapBuildInfoEXT; + +typedef struct VkMicromapCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkMicromapCreateFlagsEXT createFlags; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; + VkMicromapTypeEXT type; + VkDeviceAddress deviceAddress; +} VkMicromapCreateInfoEXT; + +typedef struct VkPhysicalDeviceOpacityMicromapFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 micromap; + VkBool32 micromapCaptureReplay; + // micromapHostCommands is legacy, but no reason was given in the API XML + VkBool32 micromapHostCommands; +} VkPhysicalDeviceOpacityMicromapFeaturesEXT; + +typedef struct VkPhysicalDeviceOpacityMicromapPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxOpacity2StateSubdivisionLevel; + uint32_t maxOpacity4StateSubdivisionLevel; +} VkPhysicalDeviceOpacityMicromapPropertiesEXT; + +typedef struct VkMicromapVersionInfoEXT { + VkStructureType sType; + const void* pNext; + const uint8_t* pVersionData; +} VkMicromapVersionInfoEXT; + +typedef struct VkCopyMicromapToMemoryInfoEXT { + VkStructureType sType; + const void* pNext; + VkMicromapEXT src; + VkDeviceOrHostAddressKHR dst; + VkCopyMicromapModeEXT mode; +} VkCopyMicromapToMemoryInfoEXT; + +typedef struct VkCopyMemoryToMicromapInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceOrHostAddressConstKHR src; + VkMicromapEXT dst; + VkCopyMicromapModeEXT mode; +} VkCopyMemoryToMicromapInfoEXT; + +typedef struct VkCopyMicromapInfoEXT { + VkStructureType sType; + const void* pNext; + VkMicromapEXT src; + VkMicromapEXT dst; + VkCopyMicromapModeEXT mode; +} VkCopyMicromapInfoEXT; + +typedef struct VkMicromapBuildSizesInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceSize micromapSize; + VkDeviceSize buildScratchSize; + VkBool32 discardable; +} VkMicromapBuildSizesInfoEXT; + +typedef struct VkAccelerationStructureTrianglesOpacityMicromapEXT { + VkStructureType sType; + void* pNext; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexBuffer; + VkDeviceSize indexStride; + uint32_t baseTriangle; + uint32_t usageCountsCount; + const VkMicromapUsageEXT* pUsageCounts; + const VkMicromapUsageEXT* const* ppUsageCounts; + VkMicromapEXT micromap; +} VkAccelerationStructureTrianglesOpacityMicromapEXT; + +typedef VkMicromapTriangleKHR VkMicromapTriangleEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateMicromapEXT)(VkDevice device, const VkMicromapCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkMicromapEXT* pMicromap); +typedef void (VKAPI_PTR *PFN_vkDestroyMicromapEXT)(VkDevice device, VkMicromapEXT micromap, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkCmdBuildMicromapsEXT)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkMicromapBuildInfoEXT* pInfos); +typedef VkResult (VKAPI_PTR *PFN_vkBuildMicromapsEXT)(VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount, const VkMicromapBuildInfoEXT* pInfos); +typedef VkResult (VKAPI_PTR *PFN_vkCopyMicromapEXT)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMicromapInfoEXT* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyMicromapToMemoryEXT)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMicromapToMemoryInfoEXT* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyMemoryToMicromapEXT)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMemoryToMicromapInfoEXT* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkWriteMicromapsPropertiesEXT)(VkDevice device, uint32_t micromapCount, const VkMicromapEXT* pMicromaps, VkQueryType queryType, size_t dataSize, void* pData, size_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdCopyMicromapEXT)(VkCommandBuffer commandBuffer, const VkCopyMicromapInfoEXT* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyMicromapToMemoryEXT)(VkCommandBuffer commandBuffer, const VkCopyMicromapToMemoryInfoEXT* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryToMicromapEXT)(VkCommandBuffer commandBuffer, const VkCopyMemoryToMicromapInfoEXT* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdWriteMicromapsPropertiesEXT)(VkCommandBuffer commandBuffer, uint32_t micromapCount, const VkMicromapEXT* pMicromaps, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); +typedef void (VKAPI_PTR *PFN_vkGetDeviceMicromapCompatibilityEXT)(VkDevice device, const VkMicromapVersionInfoEXT* pVersionInfo, VkAccelerationStructureCompatibilityKHR* pCompatibility); +typedef void (VKAPI_PTR *PFN_vkGetMicromapBuildSizesEXT)(VkDevice device, VkAccelerationStructureBuildTypeKHR buildType, const VkMicromapBuildInfoEXT* pBuildInfo, VkMicromapBuildSizesInfoEXT* pSizeInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateMicromapEXT( + VkDevice device, + const VkMicromapCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkMicromapEXT* pMicromap); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyMicromapEXT( + VkDevice device, + VkMicromapEXT micromap, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBuildMicromapsEXT( + VkCommandBuffer commandBuffer, + uint32_t infoCount, + const VkMicromapBuildInfoEXT* pInfos); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkBuildMicromapsEXT( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + uint32_t infoCount, + const VkMicromapBuildInfoEXT* pInfos); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCopyMicromapEXT( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + const VkCopyMicromapInfoEXT* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCopyMicromapToMemoryEXT( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + const VkCopyMicromapToMemoryInfoEXT* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCopyMemoryToMicromapEXT( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + const VkCopyMemoryToMicromapInfoEXT* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkWriteMicromapsPropertiesEXT( + VkDevice device, + uint32_t micromapCount, + const VkMicromapEXT* pMicromaps, + VkQueryType queryType, + size_t dataSize, + void* pData, + size_t stride); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMicromapEXT( + VkCommandBuffer commandBuffer, + const VkCopyMicromapInfoEXT* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMicromapToMemoryEXT( + VkCommandBuffer commandBuffer, + const VkCopyMicromapToMemoryInfoEXT* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMemoryToMicromapEXT( + VkCommandBuffer commandBuffer, + const VkCopyMemoryToMicromapInfoEXT* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdWriteMicromapsPropertiesEXT( + VkCommandBuffer commandBuffer, + uint32_t micromapCount, + const VkMicromapEXT* pMicromaps, + VkQueryType queryType, + VkQueryPool queryPool, + uint32_t firstQuery); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDeviceMicromapCompatibilityEXT( + VkDevice device, + const VkMicromapVersionInfoEXT* pVersionInfo, + VkAccelerationStructureCompatibilityKHR* pCompatibility); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetMicromapBuildSizesEXT( + VkDevice device, + VkAccelerationStructureBuildTypeKHR buildType, + const VkMicromapBuildInfoEXT* pBuildInfo, + VkMicromapBuildSizesInfoEXT* pSizeInfo); +#endif +#endif + + +// VK_EXT_load_store_op_none is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_load_store_op_none 1 +#define VK_EXT_LOAD_STORE_OP_NONE_SPEC_VERSION 1 +#define VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME "VK_EXT_load_store_op_none" + + +// VK_HUAWEI_cluster_culling_shader is a preprocessor guard. Do not pass it to API calls. +#define VK_HUAWEI_cluster_culling_shader 1 +#define VK_HUAWEI_CLUSTER_CULLING_SHADER_SPEC_VERSION 3 +#define VK_HUAWEI_CLUSTER_CULLING_SHADER_EXTENSION_NAME "VK_HUAWEI_cluster_culling_shader" +typedef struct VkPhysicalDeviceClusterCullingShaderFeaturesHUAWEI { + VkStructureType sType; + void* pNext; + VkBool32 clustercullingShader; + VkBool32 multiviewClusterCullingShader; +} VkPhysicalDeviceClusterCullingShaderFeaturesHUAWEI; + +typedef struct VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI { + VkStructureType sType; + void* pNext; + uint32_t maxWorkGroupCount[3]; + uint32_t maxWorkGroupSize[3]; + uint32_t maxOutputClusterCount; + VkDeviceSize indirectBufferOffsetAlignment; +} VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI; + +typedef struct VkPhysicalDeviceClusterCullingShaderVrsFeaturesHUAWEI { + VkStructureType sType; + void* pNext; + VkBool32 clusterShadingRate; +} VkPhysicalDeviceClusterCullingShaderVrsFeaturesHUAWEI; + +typedef void (VKAPI_PTR *PFN_vkCmdDrawClusterHUAWEI)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef void (VKAPI_PTR *PFN_vkCmdDrawClusterIndirectHUAWEI)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawClusterHUAWEI( + VkCommandBuffer commandBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawClusterIndirectHUAWEI( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset); +#endif +#endif + + +// VK_EXT_border_color_swizzle is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_border_color_swizzle 1 +#define VK_EXT_BORDER_COLOR_SWIZZLE_SPEC_VERSION 1 +#define VK_EXT_BORDER_COLOR_SWIZZLE_EXTENSION_NAME "VK_EXT_border_color_swizzle" +typedef struct VkPhysicalDeviceBorderColorSwizzleFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 borderColorSwizzle; + VkBool32 borderColorSwizzleFromImage; +} VkPhysicalDeviceBorderColorSwizzleFeaturesEXT; + +typedef struct VkSamplerBorderColorComponentMappingCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkComponentMapping components; + VkBool32 srgb; +} VkSamplerBorderColorComponentMappingCreateInfoEXT; + + + +// VK_EXT_pageable_device_local_memory is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_pageable_device_local_memory 1 +#define VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_SPEC_VERSION 1 +#define VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_EXTENSION_NAME "VK_EXT_pageable_device_local_memory" +typedef struct VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 pageableDeviceLocalMemory; +} VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT; + +typedef void (VKAPI_PTR *PFN_vkSetDeviceMemoryPriorityEXT)(VkDevice device, VkDeviceMemory memory, float priority); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkSetDeviceMemoryPriorityEXT( + VkDevice device, + VkDeviceMemory memory, + float priority); +#endif +#endif + + +// VK_ARM_shader_core_properties is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_shader_core_properties 1 +#define VK_ARM_SHADER_CORE_PROPERTIES_SPEC_VERSION 1 +#define VK_ARM_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_ARM_shader_core_properties" +typedef struct VkPhysicalDeviceShaderCorePropertiesARM { + VkStructureType sType; + void* pNext; + uint32_t pixelRate; + uint32_t texelRate; + uint32_t fmaRate; +} VkPhysicalDeviceShaderCorePropertiesARM; + + + +// VK_ARM_scheduling_controls is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_scheduling_controls 1 +#define VK_ARM_SCHEDULING_CONTROLS_SPEC_VERSION 2 +#define VK_ARM_SCHEDULING_CONTROLS_EXTENSION_NAME "VK_ARM_scheduling_controls" +typedef VkFlags64 VkPhysicalDeviceSchedulingControlsFlagsARM; + +// Flag bits for VkPhysicalDeviceSchedulingControlsFlagBitsARM +typedef VkFlags64 VkPhysicalDeviceSchedulingControlsFlagBitsARM; +static const VkPhysicalDeviceSchedulingControlsFlagBitsARM VK_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_SHADER_CORE_COUNT_ARM = 0x00000001ULL; +static const VkPhysicalDeviceSchedulingControlsFlagBitsARM VK_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_DISPATCH_PARAMETERS_ARM = 0x00000002ULL; + +typedef struct VkDeviceQueueShaderCoreControlCreateInfoARM { + VkStructureType sType; + void* pNext; + uint32_t shaderCoreCount; +} VkDeviceQueueShaderCoreControlCreateInfoARM; + +typedef struct VkPhysicalDeviceSchedulingControlsFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 schedulingControls; +} VkPhysicalDeviceSchedulingControlsFeaturesARM; + +typedef struct VkPhysicalDeviceSchedulingControlsPropertiesARM { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceSchedulingControlsFlagsARM schedulingControlsFlags; +} VkPhysicalDeviceSchedulingControlsPropertiesARM; + +typedef struct VkDispatchParametersARM { + VkStructureType sType; + void* pNext; + uint32_t workGroupBatchSize; + uint32_t maxQueuedWorkGroupBatches; + uint32_t maxWarpsPerShaderCore; +} VkDispatchParametersARM; + +typedef struct VkPhysicalDeviceSchedulingControlsDispatchParametersPropertiesARM { + VkStructureType sType; + void* pNext; + uint32_t schedulingControlsMaxWarpsCount; + uint32_t schedulingControlsMaxQueuedBatchesCount; + uint32_t schedulingControlsMaxWorkGroupBatchSize; +} VkPhysicalDeviceSchedulingControlsDispatchParametersPropertiesARM; + +typedef void (VKAPI_PTR *PFN_vkCmdSetDispatchParametersARM)(VkCommandBuffer commandBuffer, const VkDispatchParametersARM* pDispatchParameters); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDispatchParametersARM( + VkCommandBuffer commandBuffer, + const VkDispatchParametersARM* pDispatchParameters); +#endif +#endif + + +// VK_EXT_image_sliced_view_of_3d is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_image_sliced_view_of_3d 1 +#define VK_EXT_IMAGE_SLICED_VIEW_OF_3D_SPEC_VERSION 1 +#define VK_EXT_IMAGE_SLICED_VIEW_OF_3D_EXTENSION_NAME "VK_EXT_image_sliced_view_of_3d" +#define VK_REMAINING_3D_SLICES_EXT (~0U) +typedef struct VkPhysicalDeviceImageSlicedViewOf3DFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 imageSlicedViewOf3D; +} VkPhysicalDeviceImageSlicedViewOf3DFeaturesEXT; + +typedef struct VkImageViewSlicedCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t sliceOffset; + uint32_t sliceCount; +} VkImageViewSlicedCreateInfoEXT; + + + +// VK_VALVE_descriptor_set_host_mapping is a preprocessor guard. Do not pass it to API calls. +#define VK_VALVE_descriptor_set_host_mapping 1 +#define VK_VALVE_DESCRIPTOR_SET_HOST_MAPPING_SPEC_VERSION 1 +#define VK_VALVE_DESCRIPTOR_SET_HOST_MAPPING_EXTENSION_NAME "VK_VALVE_descriptor_set_host_mapping" +typedef struct VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE { + VkStructureType sType; + void* pNext; + VkBool32 descriptorSetHostMapping; +} VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE; + +typedef struct VkDescriptorSetBindingReferenceVALVE { + VkStructureType sType; + const void* pNext; + VkDescriptorSetLayout descriptorSetLayout; + uint32_t binding; +} VkDescriptorSetBindingReferenceVALVE; + +typedef struct VkDescriptorSetLayoutHostMappingInfoVALVE { + VkStructureType sType; + void* pNext; + size_t descriptorOffset; + uint32_t descriptorSize; +} VkDescriptorSetLayoutHostMappingInfoVALVE; + +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE)(VkDevice device, const VkDescriptorSetBindingReferenceVALVE* pBindingReference, VkDescriptorSetLayoutHostMappingInfoVALVE* pHostMapping); +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetHostMappingVALVE)(VkDevice device, VkDescriptorSet descriptorSet, void** ppData); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutHostMappingInfoVALVE( + VkDevice device, + const VkDescriptorSetBindingReferenceVALVE* pBindingReference, + VkDescriptorSetLayoutHostMappingInfoVALVE* pHostMapping); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetHostMappingVALVE( + VkDevice device, + VkDescriptorSet descriptorSet, + void** ppData); +#endif +#endif + + +// VK_EXT_depth_clamp_zero_one is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_depth_clamp_zero_one 1 +#define VK_EXT_DEPTH_CLAMP_ZERO_ONE_SPEC_VERSION 1 +#define VK_EXT_DEPTH_CLAMP_ZERO_ONE_EXTENSION_NAME "VK_EXT_depth_clamp_zero_one" +typedef VkPhysicalDeviceDepthClampZeroOneFeaturesKHR VkPhysicalDeviceDepthClampZeroOneFeaturesEXT; + + + +// VK_EXT_non_seamless_cube_map is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_non_seamless_cube_map 1 +#define VK_EXT_NON_SEAMLESS_CUBE_MAP_SPEC_VERSION 1 +#define VK_EXT_NON_SEAMLESS_CUBE_MAP_EXTENSION_NAME "VK_EXT_non_seamless_cube_map" +typedef struct VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 nonSeamlessCubeMap; +} VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT; + + + +// VK_ARM_render_pass_striped is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_render_pass_striped 1 +#define VK_ARM_RENDER_PASS_STRIPED_SPEC_VERSION 1 +#define VK_ARM_RENDER_PASS_STRIPED_EXTENSION_NAME "VK_ARM_render_pass_striped" +typedef struct VkPhysicalDeviceRenderPassStripedFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 renderPassStriped; +} VkPhysicalDeviceRenderPassStripedFeaturesARM; + +typedef struct VkPhysicalDeviceRenderPassStripedPropertiesARM { + VkStructureType sType; + void* pNext; + VkExtent2D renderPassStripeGranularity; + uint32_t maxRenderPassStripes; +} VkPhysicalDeviceRenderPassStripedPropertiesARM; + +typedef struct VkRenderPassStripeInfoARM { + VkStructureType sType; + const void* pNext; + VkRect2D stripeArea; +} VkRenderPassStripeInfoARM; + +typedef struct VkRenderPassStripeBeginInfoARM { + VkStructureType sType; + const void* pNext; + uint32_t stripeInfoCount; + const VkRenderPassStripeInfoARM* pStripeInfos; +} VkRenderPassStripeBeginInfoARM; + +typedef struct VkRenderPassStripeSubmitInfoARM { + VkStructureType sType; + const void* pNext; + uint32_t stripeSemaphoreInfoCount; + const VkSemaphoreSubmitInfo* pStripeSemaphoreInfos; +} VkRenderPassStripeSubmitInfoARM; + + + +// VK_QCOM_fragment_density_map_offset is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_fragment_density_map_offset 1 +#define VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_SPEC_VERSION 3 +#define VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_EXTENSION_NAME "VK_QCOM_fragment_density_map_offset" +typedef struct VkPhysicalDeviceFragmentDensityMapOffsetFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 fragmentDensityMapOffset; +} VkPhysicalDeviceFragmentDensityMapOffsetFeaturesEXT; + +typedef VkPhysicalDeviceFragmentDensityMapOffsetFeaturesEXT VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM; + +typedef struct VkPhysicalDeviceFragmentDensityMapOffsetPropertiesEXT { + VkStructureType sType; + void* pNext; + VkExtent2D fragmentDensityOffsetGranularity; +} VkPhysicalDeviceFragmentDensityMapOffsetPropertiesEXT; + +typedef VkPhysicalDeviceFragmentDensityMapOffsetPropertiesEXT VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM; + +typedef struct VkRenderPassFragmentDensityMapOffsetEndInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t fragmentDensityOffsetCount; + const VkOffset2D* pFragmentDensityOffsets; +} VkRenderPassFragmentDensityMapOffsetEndInfoEXT; + +typedef VkRenderPassFragmentDensityMapOffsetEndInfoEXT VkSubpassFragmentDensityMapOffsetEndInfoQCOM; + + + +// VK_NV_copy_memory_indirect is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_copy_memory_indirect 1 +#define VK_NV_COPY_MEMORY_INDIRECT_SPEC_VERSION 1 +#define VK_NV_COPY_MEMORY_INDIRECT_EXTENSION_NAME "VK_NV_copy_memory_indirect" +typedef VkCopyMemoryIndirectCommandKHR VkCopyMemoryIndirectCommandNV; + +typedef VkCopyMemoryToImageIndirectCommandKHR VkCopyMemoryToImageIndirectCommandNV; + +typedef struct VkPhysicalDeviceCopyMemoryIndirectFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 indirectCopy; +} VkPhysicalDeviceCopyMemoryIndirectFeaturesNV; + +typedef VkPhysicalDeviceCopyMemoryIndirectPropertiesKHR VkPhysicalDeviceCopyMemoryIndirectPropertiesNV; + +typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryIndirectNV)(VkCommandBuffer commandBuffer, VkDeviceAddress copyBufferAddress, uint32_t copyCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryToImageIndirectNV)(VkCommandBuffer commandBuffer, VkDeviceAddress copyBufferAddress, uint32_t copyCount, uint32_t stride, VkImage dstImage, VkImageLayout dstImageLayout, const VkImageSubresourceLayers* pImageSubresources); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMemoryIndirectNV( + VkCommandBuffer commandBuffer, + VkDeviceAddress copyBufferAddress, + uint32_t copyCount, + uint32_t stride); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMemoryToImageIndirectNV( + VkCommandBuffer commandBuffer, + VkDeviceAddress copyBufferAddress, + uint32_t copyCount, + uint32_t stride, + VkImage dstImage, + VkImageLayout dstImageLayout, + const VkImageSubresourceLayers* pImageSubresources); +#endif +#endif + + +// VK_NV_memory_decompression is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_memory_decompression 1 +#define VK_NV_MEMORY_DECOMPRESSION_SPEC_VERSION 1 +#define VK_NV_MEMORY_DECOMPRESSION_EXTENSION_NAME "VK_NV_memory_decompression" + +// Flag bits for VkMemoryDecompressionMethodFlagBitsEXT +typedef VkFlags64 VkMemoryDecompressionMethodFlagBitsEXT; +static const VkMemoryDecompressionMethodFlagBitsEXT VK_MEMORY_DECOMPRESSION_METHOD_GDEFLATE_1_0_BIT_EXT = 0x00000001ULL; +static const VkMemoryDecompressionMethodFlagBitsEXT VK_MEMORY_DECOMPRESSION_METHOD_GDEFLATE_1_0_BIT_NV = 0x00000001ULL; + +typedef VkMemoryDecompressionMethodFlagBitsEXT VkMemoryDecompressionMethodFlagBitsNV; + +typedef VkFlags64 VkMemoryDecompressionMethodFlagsEXT; +typedef VkMemoryDecompressionMethodFlagsEXT VkMemoryDecompressionMethodFlagsNV; + +typedef struct VkDecompressMemoryRegionNV { + VkDeviceAddress srcAddress; + VkDeviceAddress dstAddress; + VkDeviceSize compressedSize; + VkDeviceSize decompressedSize; + VkMemoryDecompressionMethodFlagsEXT decompressionMethod; +} VkDecompressMemoryRegionNV; + +typedef struct VkPhysicalDeviceMemoryDecompressionFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 memoryDecompression; +} VkPhysicalDeviceMemoryDecompressionFeaturesEXT; + +typedef VkPhysicalDeviceMemoryDecompressionFeaturesEXT VkPhysicalDeviceMemoryDecompressionFeaturesNV; + +typedef struct VkPhysicalDeviceMemoryDecompressionPropertiesEXT { + VkStructureType sType; + void* pNext; + VkMemoryDecompressionMethodFlagsEXT decompressionMethods; + uint64_t maxDecompressionIndirectCount; +} VkPhysicalDeviceMemoryDecompressionPropertiesEXT; + +typedef VkPhysicalDeviceMemoryDecompressionPropertiesEXT VkPhysicalDeviceMemoryDecompressionPropertiesNV; + +typedef void (VKAPI_PTR *PFN_vkCmdDecompressMemoryNV)(VkCommandBuffer commandBuffer, uint32_t decompressRegionCount, const VkDecompressMemoryRegionNV* pDecompressMemoryRegions); +typedef void (VKAPI_PTR *PFN_vkCmdDecompressMemoryIndirectCountNV)(VkCommandBuffer commandBuffer, VkDeviceAddress indirectCommandsAddress, VkDeviceAddress indirectCommandsCountAddress, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDecompressMemoryNV( + VkCommandBuffer commandBuffer, + uint32_t decompressRegionCount, + const VkDecompressMemoryRegionNV* pDecompressMemoryRegions); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDecompressMemoryIndirectCountNV( + VkCommandBuffer commandBuffer, + VkDeviceAddress indirectCommandsAddress, + VkDeviceAddress indirectCommandsCountAddress, + uint32_t stride); +#endif +#endif + + +// VK_NV_device_generated_commands_compute is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_device_generated_commands_compute 1 +#define VK_NV_DEVICE_GENERATED_COMMANDS_COMPUTE_SPEC_VERSION 2 +#define VK_NV_DEVICE_GENERATED_COMMANDS_COMPUTE_EXTENSION_NAME "VK_NV_device_generated_commands_compute" +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsComputeFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 deviceGeneratedCompute; + VkBool32 deviceGeneratedComputePipelines; + VkBool32 deviceGeneratedComputeCaptureReplay; +} VkPhysicalDeviceDeviceGeneratedCommandsComputeFeaturesNV; + +typedef struct VkComputePipelineIndirectBufferInfoNV { + VkStructureType sType; + const void* pNext; + VkDeviceAddress deviceAddress; + VkDeviceSize size; + VkDeviceAddress pipelineDeviceAddressCaptureReplay; +} VkComputePipelineIndirectBufferInfoNV; + +typedef struct VkPipelineIndirectDeviceAddressInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineBindPoint pipelineBindPoint; + VkPipeline pipeline; +} VkPipelineIndirectDeviceAddressInfoNV; + +typedef struct VkBindPipelineIndirectCommandNV { + VkDeviceAddress pipelineAddress; +} VkBindPipelineIndirectCommandNV; + +typedef void (VKAPI_PTR *PFN_vkGetPipelineIndirectMemoryRequirementsNV)(VkDevice device, const VkComputePipelineCreateInfo* pCreateInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkCmdUpdatePipelineIndirectBufferNV)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetPipelineIndirectDeviceAddressNV)(VkDevice device, const VkPipelineIndirectDeviceAddressInfoNV* pInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPipelineIndirectMemoryRequirementsNV( + VkDevice device, + const VkComputePipelineCreateInfo* pCreateInfo, + VkMemoryRequirements2* pMemoryRequirements); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdUpdatePipelineIndirectBufferNV( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipeline pipeline); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetPipelineIndirectDeviceAddressNV( + VkDevice device, + const VkPipelineIndirectDeviceAddressInfoNV* pInfo); +#endif +#endif + + +// VK_NV_ray_tracing_linear_swept_spheres is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_ray_tracing_linear_swept_spheres 1 +#define VK_NV_RAY_TRACING_LINEAR_SWEPT_SPHERES_SPEC_VERSION 1 +#define VK_NV_RAY_TRACING_LINEAR_SWEPT_SPHERES_EXTENSION_NAME "VK_NV_ray_tracing_linear_swept_spheres" + +typedef enum VkRayTracingLssIndexingModeNV { + VK_RAY_TRACING_LSS_INDEXING_MODE_LIST_NV = 0, + VK_RAY_TRACING_LSS_INDEXING_MODE_SUCCESSIVE_NV = 1, + VK_RAY_TRACING_LSS_INDEXING_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkRayTracingLssIndexingModeNV; + +typedef enum VkRayTracingLssPrimitiveEndCapsModeNV { + VK_RAY_TRACING_LSS_PRIMITIVE_END_CAPS_MODE_NONE_NV = 0, + VK_RAY_TRACING_LSS_PRIMITIVE_END_CAPS_MODE_CHAINED_NV = 1, + VK_RAY_TRACING_LSS_PRIMITIVE_END_CAPS_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkRayTracingLssPrimitiveEndCapsModeNV; +typedef struct VkPhysicalDeviceRayTracingLinearSweptSpheresFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 spheres; + VkBool32 linearSweptSpheres; +} VkPhysicalDeviceRayTracingLinearSweptSpheresFeaturesNV; + +typedef struct VkAccelerationStructureGeometryLinearSweptSpheresDataNV { + VkStructureType sType; + const void* pNext; + VkFormat vertexFormat; + VkDeviceOrHostAddressConstKHR vertexData; + VkDeviceSize vertexStride; + VkFormat radiusFormat; + VkDeviceOrHostAddressConstKHR radiusData; + VkDeviceSize radiusStride; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexData; + VkDeviceSize indexStride; + VkRayTracingLssIndexingModeNV indexingMode; + VkRayTracingLssPrimitiveEndCapsModeNV endCapsMode; +} VkAccelerationStructureGeometryLinearSweptSpheresDataNV; + +typedef struct VkAccelerationStructureGeometrySpheresDataNV { + VkStructureType sType; + const void* pNext; + VkFormat vertexFormat; + VkDeviceOrHostAddressConstKHR vertexData; + VkDeviceSize vertexStride; + VkFormat radiusFormat; + VkDeviceOrHostAddressConstKHR radiusData; + VkDeviceSize radiusStride; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexData; + VkDeviceSize indexStride; +} VkAccelerationStructureGeometrySpheresDataNV; + + + +// VK_NV_linear_color_attachment is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_linear_color_attachment 1 +#define VK_NV_LINEAR_COLOR_ATTACHMENT_SPEC_VERSION 1 +#define VK_NV_LINEAR_COLOR_ATTACHMENT_EXTENSION_NAME "VK_NV_linear_color_attachment" +typedef struct VkPhysicalDeviceLinearColorAttachmentFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 linearColorAttachment; +} VkPhysicalDeviceLinearColorAttachmentFeaturesNV; + + + +// VK_GOOGLE_surfaceless_query is a preprocessor guard. Do not pass it to API calls. +#define VK_GOOGLE_surfaceless_query 1 +#define VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION 2 +#define VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME "VK_GOOGLE_surfaceless_query" + + +// VK_EXT_image_compression_control_swapchain is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_image_compression_control_swapchain 1 +#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_SPEC_VERSION 1 +#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_EXTENSION_NAME "VK_EXT_image_compression_control_swapchain" +typedef struct VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 imageCompressionControlSwapchain; +} VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT; + + + +// VK_QCOM_image_processing is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_image_processing 1 +#define VK_QCOM_IMAGE_PROCESSING_SPEC_VERSION 1 +#define VK_QCOM_IMAGE_PROCESSING_EXTENSION_NAME "VK_QCOM_image_processing" +typedef struct VkImageViewSampleWeightCreateInfoQCOM { + VkStructureType sType; + const void* pNext; + VkOffset2D filterCenter; + VkExtent2D filterSize; + uint32_t numPhases; +} VkImageViewSampleWeightCreateInfoQCOM; + +typedef struct VkPhysicalDeviceImageProcessingFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 textureSampleWeighted; + VkBool32 textureBoxFilter; + VkBool32 textureBlockMatch; +} VkPhysicalDeviceImageProcessingFeaturesQCOM; + +typedef struct VkPhysicalDeviceImageProcessingPropertiesQCOM { + VkStructureType sType; + void* pNext; + uint32_t maxWeightFilterPhases; + VkExtent2D maxWeightFilterDimension; + VkExtent2D maxBlockMatchRegion; + VkExtent2D maxBoxFilterBlockSize; +} VkPhysicalDeviceImageProcessingPropertiesQCOM; + + + +// VK_EXT_nested_command_buffer is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_nested_command_buffer 1 +#define VK_EXT_NESTED_COMMAND_BUFFER_SPEC_VERSION 1 +#define VK_EXT_NESTED_COMMAND_BUFFER_EXTENSION_NAME "VK_EXT_nested_command_buffer" +typedef struct VkPhysicalDeviceNestedCommandBufferFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 nestedCommandBuffer; + VkBool32 nestedCommandBufferRendering; + VkBool32 nestedCommandBufferSimultaneousUse; +} VkPhysicalDeviceNestedCommandBufferFeaturesEXT; + +typedef struct VkPhysicalDeviceNestedCommandBufferPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxCommandBufferNestingLevel; +} VkPhysicalDeviceNestedCommandBufferPropertiesEXT; + + + +// VK_EXT_external_memory_acquire_unmodified is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_external_memory_acquire_unmodified 1 +#define VK_EXT_EXTERNAL_MEMORY_ACQUIRE_UNMODIFIED_SPEC_VERSION 1 +#define VK_EXT_EXTERNAL_MEMORY_ACQUIRE_UNMODIFIED_EXTENSION_NAME "VK_EXT_external_memory_acquire_unmodified" +typedef struct VkExternalMemoryAcquireUnmodifiedEXT { + VkStructureType sType; + const void* pNext; + VkBool32 acquireUnmodifiedMemory; +} VkExternalMemoryAcquireUnmodifiedEXT; + + + +// VK_EXT_extended_dynamic_state3 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_extended_dynamic_state3 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_3_SPEC_VERSION 2 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME "VK_EXT_extended_dynamic_state3" +typedef struct VkPhysicalDeviceExtendedDynamicState3FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 extendedDynamicState3TessellationDomainOrigin; + VkBool32 extendedDynamicState3DepthClampEnable; + VkBool32 extendedDynamicState3PolygonMode; + VkBool32 extendedDynamicState3RasterizationSamples; + VkBool32 extendedDynamicState3SampleMask; + VkBool32 extendedDynamicState3AlphaToCoverageEnable; + VkBool32 extendedDynamicState3AlphaToOneEnable; + VkBool32 extendedDynamicState3LogicOpEnable; + VkBool32 extendedDynamicState3ColorBlendEnable; + VkBool32 extendedDynamicState3ColorBlendEquation; + VkBool32 extendedDynamicState3ColorWriteMask; + VkBool32 extendedDynamicState3RasterizationStream; + VkBool32 extendedDynamicState3ConservativeRasterizationMode; + VkBool32 extendedDynamicState3ExtraPrimitiveOverestimationSize; + VkBool32 extendedDynamicState3DepthClipEnable; + VkBool32 extendedDynamicState3SampleLocationsEnable; + VkBool32 extendedDynamicState3ColorBlendAdvanced; + VkBool32 extendedDynamicState3ProvokingVertexMode; + VkBool32 extendedDynamicState3LineRasterizationMode; + VkBool32 extendedDynamicState3LineStippleEnable; + VkBool32 extendedDynamicState3DepthClipNegativeOneToOne; + VkBool32 extendedDynamicState3ViewportWScalingEnable; + VkBool32 extendedDynamicState3ViewportSwizzle; + VkBool32 extendedDynamicState3CoverageToColorEnable; + VkBool32 extendedDynamicState3CoverageToColorLocation; + VkBool32 extendedDynamicState3CoverageModulationMode; + VkBool32 extendedDynamicState3CoverageModulationTableEnable; + VkBool32 extendedDynamicState3CoverageModulationTable; + VkBool32 extendedDynamicState3CoverageReductionMode; + VkBool32 extendedDynamicState3RepresentativeFragmentTestEnable; + VkBool32 extendedDynamicState3ShadingRateImageEnable; +} VkPhysicalDeviceExtendedDynamicState3FeaturesEXT; + +typedef struct VkPhysicalDeviceExtendedDynamicState3PropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 dynamicPrimitiveTopologyUnrestricted; +} VkPhysicalDeviceExtendedDynamicState3PropertiesEXT; + +typedef struct VkColorBlendEquationEXT { + VkBlendFactor srcColorBlendFactor; + VkBlendFactor dstColorBlendFactor; + VkBlendOp colorBlendOp; + VkBlendFactor srcAlphaBlendFactor; + VkBlendFactor dstAlphaBlendFactor; + VkBlendOp alphaBlendOp; +} VkColorBlendEquationEXT; + +typedef struct VkColorBlendAdvancedEXT { + VkBlendOp advancedBlendOp; + VkBool32 srcPremultiplied; + VkBool32 dstPremultiplied; + VkBlendOverlapEXT blendOverlap; + VkBool32 clampResults; +} VkColorBlendAdvancedEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthClampEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthClampEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetPolygonModeEXT)(VkCommandBuffer commandBuffer, VkPolygonMode polygonMode); +typedef void (VKAPI_PTR *PFN_vkCmdSetRasterizationSamplesEXT)(VkCommandBuffer commandBuffer, VkSampleCountFlagBits rasterizationSamples); +typedef void (VKAPI_PTR *PFN_vkCmdSetSampleMaskEXT)(VkCommandBuffer commandBuffer, VkSampleCountFlagBits samples, const VkSampleMask* pSampleMask); +typedef void (VKAPI_PTR *PFN_vkCmdSetAlphaToCoverageEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 alphaToCoverageEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetAlphaToOneEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 alphaToOneEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetLogicOpEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 logicOpEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetColorBlendEnableEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkBool32* pColorBlendEnables); +typedef void (VKAPI_PTR *PFN_vkCmdSetColorBlendEquationEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorBlendEquationEXT* pColorBlendEquations); +typedef void (VKAPI_PTR *PFN_vkCmdSetColorWriteMaskEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorComponentFlags* pColorWriteMasks); +typedef void (VKAPI_PTR *PFN_vkCmdSetTessellationDomainOriginEXT)(VkCommandBuffer commandBuffer, VkTessellationDomainOrigin domainOrigin); +typedef void (VKAPI_PTR *PFN_vkCmdSetRasterizationStreamEXT)(VkCommandBuffer commandBuffer, uint32_t rasterizationStream); +typedef void (VKAPI_PTR *PFN_vkCmdSetConservativeRasterizationModeEXT)(VkCommandBuffer commandBuffer, VkConservativeRasterizationModeEXT conservativeRasterizationMode); +typedef void (VKAPI_PTR *PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT)(VkCommandBuffer commandBuffer, float extraPrimitiveOverestimationSize); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthClipEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthClipEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetSampleLocationsEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 sampleLocationsEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetColorBlendAdvancedEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorBlendAdvancedEXT* pColorBlendAdvanced); +typedef void (VKAPI_PTR *PFN_vkCmdSetProvokingVertexModeEXT)(VkCommandBuffer commandBuffer, VkProvokingVertexModeEXT provokingVertexMode); +typedef void (VKAPI_PTR *PFN_vkCmdSetLineRasterizationModeEXT)(VkCommandBuffer commandBuffer, VkLineRasterizationModeEXT lineRasterizationMode); +typedef void (VKAPI_PTR *PFN_vkCmdSetLineStippleEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 stippledLineEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthClipNegativeOneToOneEXT)(VkCommandBuffer commandBuffer, VkBool32 negativeOneToOne); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWScalingEnableNV)(VkCommandBuffer commandBuffer, VkBool32 viewportWScalingEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportSwizzleNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportSwizzleNV* pViewportSwizzles); +typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageToColorEnableNV)(VkCommandBuffer commandBuffer, VkBool32 coverageToColorEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageToColorLocationNV)(VkCommandBuffer commandBuffer, uint32_t coverageToColorLocation); +typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageModulationModeNV)(VkCommandBuffer commandBuffer, VkCoverageModulationModeNV coverageModulationMode); +typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageModulationTableEnableNV)(VkCommandBuffer commandBuffer, VkBool32 coverageModulationTableEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageModulationTableNV)(VkCommandBuffer commandBuffer, uint32_t coverageModulationTableCount, const float* pCoverageModulationTable); +typedef void (VKAPI_PTR *PFN_vkCmdSetShadingRateImageEnableNV)(VkCommandBuffer commandBuffer, VkBool32 shadingRateImageEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetRepresentativeFragmentTestEnableNV)(VkCommandBuffer commandBuffer, VkBool32 representativeFragmentTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageReductionModeNV)(VkCommandBuffer commandBuffer, VkCoverageReductionModeNV coverageReductionMode); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthClampEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthClampEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetPolygonModeEXT( + VkCommandBuffer commandBuffer, + VkPolygonMode polygonMode); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetRasterizationSamplesEXT( + VkCommandBuffer commandBuffer, + VkSampleCountFlagBits rasterizationSamples); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetSampleMaskEXT( + VkCommandBuffer commandBuffer, + VkSampleCountFlagBits samples, + const VkSampleMask* pSampleMask); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetAlphaToCoverageEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 alphaToCoverageEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetAlphaToOneEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 alphaToOneEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetLogicOpEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 logicOpEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetColorBlendEnableEXT( + VkCommandBuffer commandBuffer, + uint32_t firstAttachment, + uint32_t attachmentCount, + const VkBool32* pColorBlendEnables); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetColorBlendEquationEXT( + VkCommandBuffer commandBuffer, + uint32_t firstAttachment, + uint32_t attachmentCount, + const VkColorBlendEquationEXT* pColorBlendEquations); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetColorWriteMaskEXT( + VkCommandBuffer commandBuffer, + uint32_t firstAttachment, + uint32_t attachmentCount, + const VkColorComponentFlags* pColorWriteMasks); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetTessellationDomainOriginEXT( + VkCommandBuffer commandBuffer, + VkTessellationDomainOrigin domainOrigin); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetRasterizationStreamEXT( + VkCommandBuffer commandBuffer, + uint32_t rasterizationStream); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetConservativeRasterizationModeEXT( + VkCommandBuffer commandBuffer, + VkConservativeRasterizationModeEXT conservativeRasterizationMode); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetExtraPrimitiveOverestimationSizeEXT( + VkCommandBuffer commandBuffer, + float extraPrimitiveOverestimationSize); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthClipEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthClipEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetSampleLocationsEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 sampleLocationsEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetColorBlendAdvancedEXT( + VkCommandBuffer commandBuffer, + uint32_t firstAttachment, + uint32_t attachmentCount, + const VkColorBlendAdvancedEXT* pColorBlendAdvanced); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetProvokingVertexModeEXT( + VkCommandBuffer commandBuffer, + VkProvokingVertexModeEXT provokingVertexMode); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetLineRasterizationModeEXT( + VkCommandBuffer commandBuffer, + VkLineRasterizationModeEXT lineRasterizationMode); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetLineStippleEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 stippledLineEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthClipNegativeOneToOneEXT( + VkCommandBuffer commandBuffer, + VkBool32 negativeOneToOne); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWScalingEnableNV( + VkCommandBuffer commandBuffer, + VkBool32 viewportWScalingEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportSwizzleNV( + VkCommandBuffer commandBuffer, + uint32_t firstViewport, + uint32_t viewportCount, + const VkViewportSwizzleNV* pViewportSwizzles); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetCoverageToColorEnableNV( + VkCommandBuffer commandBuffer, + VkBool32 coverageToColorEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetCoverageToColorLocationNV( + VkCommandBuffer commandBuffer, + uint32_t coverageToColorLocation); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetCoverageModulationModeNV( + VkCommandBuffer commandBuffer, + VkCoverageModulationModeNV coverageModulationMode); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetCoverageModulationTableEnableNV( + VkCommandBuffer commandBuffer, + VkBool32 coverageModulationTableEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetCoverageModulationTableNV( + VkCommandBuffer commandBuffer, + uint32_t coverageModulationTableCount, + const float* pCoverageModulationTable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetShadingRateImageEnableNV( + VkCommandBuffer commandBuffer, + VkBool32 shadingRateImageEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetRepresentativeFragmentTestEnableNV( + VkCommandBuffer commandBuffer, + VkBool32 representativeFragmentTestEnable); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetCoverageReductionModeNV( + VkCommandBuffer commandBuffer, + VkCoverageReductionModeNV coverageReductionMode); +#endif +#endif + + +// VK_EXT_subpass_merge_feedback is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_subpass_merge_feedback 1 +#define VK_EXT_SUBPASS_MERGE_FEEDBACK_SPEC_VERSION 2 +#define VK_EXT_SUBPASS_MERGE_FEEDBACK_EXTENSION_NAME "VK_EXT_subpass_merge_feedback" + +typedef enum VkSubpassMergeStatusEXT { + VK_SUBPASS_MERGE_STATUS_MERGED_EXT = 0, + VK_SUBPASS_MERGE_STATUS_DISALLOWED_EXT = 1, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SIDE_EFFECTS_EXT = 2, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SAMPLES_MISMATCH_EXT = 3, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_VIEWS_MISMATCH_EXT = 4, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_ALIASING_EXT = 5, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_DEPENDENCIES_EXT = 6, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_INCOMPATIBLE_INPUT_ATTACHMENT_EXT = 7, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_TOO_MANY_ATTACHMENTS_EXT = 8, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_INSUFFICIENT_STORAGE_EXT = 9, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_DEPTH_STENCIL_COUNT_EXT = 10, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_RESOLVE_ATTACHMENT_REUSE_EXT = 11, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SINGLE_SUBPASS_EXT = 12, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_UNSPECIFIED_EXT = 13, + VK_SUBPASS_MERGE_STATUS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkSubpassMergeStatusEXT; +typedef struct VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 subpassMergeFeedback; +} VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT; + +typedef struct VkRenderPassCreationControlEXT { + VkStructureType sType; + const void* pNext; + VkBool32 disallowMerging; +} VkRenderPassCreationControlEXT; + +typedef struct VkRenderPassCreationFeedbackInfoEXT { + uint32_t postMergeSubpassCount; +} VkRenderPassCreationFeedbackInfoEXT; + +typedef struct VkRenderPassCreationFeedbackCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkRenderPassCreationFeedbackInfoEXT* pRenderPassFeedback; +} VkRenderPassCreationFeedbackCreateInfoEXT; + +typedef struct VkRenderPassSubpassFeedbackInfoEXT { + VkSubpassMergeStatusEXT subpassMergeStatus; + char description[VK_MAX_DESCRIPTION_SIZE]; + uint32_t postMergeIndex; +} VkRenderPassSubpassFeedbackInfoEXT; + +typedef struct VkRenderPassSubpassFeedbackCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkRenderPassSubpassFeedbackInfoEXT* pSubpassFeedback; +} VkRenderPassSubpassFeedbackCreateInfoEXT; + + + +// VK_LUNARG_direct_driver_loading is a preprocessor guard. Do not pass it to API calls. +#define VK_LUNARG_direct_driver_loading 1 +#define VK_LUNARG_DIRECT_DRIVER_LOADING_SPEC_VERSION 1 +#define VK_LUNARG_DIRECT_DRIVER_LOADING_EXTENSION_NAME "VK_LUNARG_direct_driver_loading" + +typedef enum VkDirectDriverLoadingModeLUNARG { + VK_DIRECT_DRIVER_LOADING_MODE_EXCLUSIVE_LUNARG = 0, + VK_DIRECT_DRIVER_LOADING_MODE_INCLUSIVE_LUNARG = 1, + VK_DIRECT_DRIVER_LOADING_MODE_MAX_ENUM_LUNARG = 0x7FFFFFFF +} VkDirectDriverLoadingModeLUNARG; +typedef VkFlags VkDirectDriverLoadingFlagsLUNARG; +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddrLUNARG)( + VkInstance instance, + const char* pName); + +typedef struct VkDirectDriverLoadingInfoLUNARG { + VkStructureType sType; + void* pNext; + VkDirectDriverLoadingFlagsLUNARG flags; + PFN_vkGetInstanceProcAddrLUNARG pfnGetInstanceProcAddr; +} VkDirectDriverLoadingInfoLUNARG; + +typedef struct VkDirectDriverLoadingListLUNARG { + VkStructureType sType; + const void* pNext; + VkDirectDriverLoadingModeLUNARG mode; + uint32_t driverCount; + const VkDirectDriverLoadingInfoLUNARG* pDrivers; +} VkDirectDriverLoadingListLUNARG; + + + +// VK_ARM_tensors is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_tensors 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkTensorViewARM) +#define VK_ARM_TENSORS_SPEC_VERSION 2 +#define VK_ARM_TENSORS_EXTENSION_NAME "VK_ARM_tensors" + +typedef enum VkTensorTilingARM { + VK_TENSOR_TILING_OPTIMAL_ARM = 0, + VK_TENSOR_TILING_LINEAR_ARM = 1, + VK_TENSOR_TILING_BRICK_16_WIDE_ARM = 1000565000, + VK_TENSOR_TILING_BRICK_8_WIDE_ARM = 1000565001, + VK_TENSOR_TILING_BRICK_4_WIDE_ARM = 1000565002, + VK_TENSOR_TILING_BLOCK_U_INTERLEAVED_ARM = 1000565003, + VK_TENSOR_TILING_BLOCK_U_INTERLEAVED_64K_ARM = 1000565004, + VK_TENSOR_TILING_MAX_ENUM_ARM = 0x7FFFFFFF +} VkTensorTilingARM; +typedef VkFlags64 VkTensorCreateFlagsARM; + +// Flag bits for VkTensorCreateFlagBitsARM +typedef VkFlags64 VkTensorCreateFlagBitsARM; +static const VkTensorCreateFlagBitsARM VK_TENSOR_CREATE_MUTABLE_FORMAT_BIT_ARM = 0x00000001ULL; +static const VkTensorCreateFlagBitsARM VK_TENSOR_CREATE_PROTECTED_BIT_ARM = 0x00000002ULL; +static const VkTensorCreateFlagBitsARM VK_TENSOR_CREATE_DESCRIPTOR_HEAP_CAPTURE_REPLAY_BIT_ARM = 0x00000008ULL; +static const VkTensorCreateFlagBitsARM VK_TENSOR_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_ARM = 0x00000004ULL; + +typedef VkFlags64 VkTensorUsageFlagsARM; + +// Flag bits for VkTensorUsageFlagBitsARM +typedef VkFlags64 VkTensorUsageFlagBitsARM; +static const VkTensorUsageFlagBitsARM VK_TENSOR_USAGE_SHADER_BIT_ARM = 0x00000002ULL; +static const VkTensorUsageFlagBitsARM VK_TENSOR_USAGE_TRANSFER_SRC_BIT_ARM = 0x00000004ULL; +static const VkTensorUsageFlagBitsARM VK_TENSOR_USAGE_TRANSFER_DST_BIT_ARM = 0x00000008ULL; +static const VkTensorUsageFlagBitsARM VK_TENSOR_USAGE_IMAGE_ALIASING_BIT_ARM = 0x00000010ULL; +static const VkTensorUsageFlagBitsARM VK_TENSOR_USAGE_DATA_GRAPH_BIT_ARM = 0x00000020ULL; + +typedef struct VkTensorDescriptionARM { + VkStructureType sType; + const void* pNext; + VkTensorTilingARM tiling; + VkFormat format; + uint32_t dimensionCount; + const int64_t* pDimensions; + const int64_t* pStrides; + VkTensorUsageFlagsARM usage; +} VkTensorDescriptionARM; + +typedef struct VkTensorCreateInfoARM { + VkStructureType sType; + const void* pNext; + VkTensorCreateFlagsARM flags; + const VkTensorDescriptionARM* pDescription; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; +} VkTensorCreateInfoARM; + +typedef struct VkTensorMemoryRequirementsInfoARM { + VkStructureType sType; + const void* pNext; + VkTensorARM tensor; +} VkTensorMemoryRequirementsInfoARM; + +typedef struct VkBindTensorMemoryInfoARM { + VkStructureType sType; + const void* pNext; + VkTensorARM tensor; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; +} VkBindTensorMemoryInfoARM; + +typedef struct VkWriteDescriptorSetTensorARM { + VkStructureType sType; + const void* pNext; + uint32_t tensorViewCount; + const VkTensorViewARM* pTensorViews; +} VkWriteDescriptorSetTensorARM; + +typedef struct VkTensorFormatPropertiesARM { + VkStructureType sType; + void* pNext; + VkFormatFeatureFlags2 optimalTilingTensorFeatures; + VkFormatFeatureFlags2 linearTilingTensorFeatures; +} VkTensorFormatPropertiesARM; + +typedef struct VkPhysicalDeviceTensorPropertiesARM { + VkStructureType sType; + void* pNext; + uint32_t maxTensorDimensionCount; + uint64_t maxTensorElements; + uint64_t maxPerDimensionTensorElements; + int64_t maxTensorStride; + uint64_t maxTensorSize; + uint32_t maxTensorShaderAccessArrayLength; + uint32_t maxTensorShaderAccessSize; + uint32_t maxDescriptorSetStorageTensors; + uint32_t maxPerStageDescriptorSetStorageTensors; + uint32_t maxDescriptorSetUpdateAfterBindStorageTensors; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageTensors; + VkBool32 shaderStorageTensorArrayNonUniformIndexingNative; + VkShaderStageFlags shaderTensorSupportedStages; +} VkPhysicalDeviceTensorPropertiesARM; + +typedef struct VkTensorMemoryBarrierARM { + VkStructureType sType; + const void* pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkTensorARM tensor; +} VkTensorMemoryBarrierARM; + +typedef struct VkTensorDependencyInfoARM { + VkStructureType sType; + const void* pNext; + uint32_t tensorMemoryBarrierCount; + const VkTensorMemoryBarrierARM* pTensorMemoryBarriers; +} VkTensorDependencyInfoARM; + +typedef struct VkPhysicalDeviceTensorFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 tensorNonPacked; + VkBool32 shaderTensorAccess; + VkBool32 shaderStorageTensorArrayDynamicIndexing; + VkBool32 shaderStorageTensorArrayNonUniformIndexing; + VkBool32 descriptorBindingStorageTensorUpdateAfterBind; + VkBool32 tensors; +} VkPhysicalDeviceTensorFeaturesARM; + +typedef struct VkDeviceTensorMemoryRequirementsARM { + VkStructureType sType; + const void* pNext; + const VkTensorCreateInfoARM* pCreateInfo; +} VkDeviceTensorMemoryRequirementsARM; + +typedef struct VkTensorCopyARM { + VkStructureType sType; + const void* pNext; + uint32_t dimensionCount; + const uint64_t* pSrcOffset; + const uint64_t* pDstOffset; + const uint64_t* pExtent; +} VkTensorCopyARM; + +typedef struct VkCopyTensorInfoARM { + VkStructureType sType; + const void* pNext; + VkTensorARM srcTensor; + VkTensorARM dstTensor; + uint32_t regionCount; + const VkTensorCopyARM* pRegions; +} VkCopyTensorInfoARM; + +typedef struct VkMemoryDedicatedAllocateInfoTensorARM { + VkStructureType sType; + const void* pNext; + VkTensorARM tensor; +} VkMemoryDedicatedAllocateInfoTensorARM; + +typedef struct VkPhysicalDeviceExternalTensorInfoARM { + VkStructureType sType; + const void* pNext; + VkTensorCreateFlagsARM flags; + const VkTensorDescriptionARM* pDescription; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalTensorInfoARM; + +typedef struct VkExternalTensorPropertiesARM { + VkStructureType sType; + const void* pNext; + VkExternalMemoryProperties externalMemoryProperties; +} VkExternalTensorPropertiesARM; + +typedef struct VkExternalMemoryTensorCreateInfoARM { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExternalMemoryTensorCreateInfoARM; + +typedef struct VkPhysicalDeviceDescriptorBufferTensorFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 descriptorBufferTensorDescriptors; +} VkPhysicalDeviceDescriptorBufferTensorFeaturesARM; + +typedef struct VkPhysicalDeviceDescriptorBufferTensorPropertiesARM { + VkStructureType sType; + void* pNext; + size_t tensorCaptureReplayDescriptorDataSize; + size_t tensorViewCaptureReplayDescriptorDataSize; + size_t tensorDescriptorSize; +} VkPhysicalDeviceDescriptorBufferTensorPropertiesARM; + +typedef struct VkDescriptorGetTensorInfoARM { + VkStructureType sType; + const void* pNext; + VkTensorViewARM tensorView; +} VkDescriptorGetTensorInfoARM; + +typedef struct VkTensorCaptureDescriptorDataInfoARM { + VkStructureType sType; + const void* pNext; + VkTensorARM tensor; +} VkTensorCaptureDescriptorDataInfoARM; + +typedef struct VkTensorViewCaptureDescriptorDataInfoARM { + VkStructureType sType; + const void* pNext; + VkTensorViewARM tensorView; +} VkTensorViewCaptureDescriptorDataInfoARM; + +typedef struct VkFrameBoundaryTensorsARM { + VkStructureType sType; + const void* pNext; + uint32_t tensorCount; + const VkTensorARM* pTensors; +} VkFrameBoundaryTensorsARM; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateTensorARM)(VkDevice device, const VkTensorCreateInfoARM* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkTensorARM* pTensor); +typedef void (VKAPI_PTR *PFN_vkDestroyTensorARM)(VkDevice device, VkTensorARM tensor, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateTensorViewARM)(VkDevice device, const VkTensorViewCreateInfoARM* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkTensorViewARM* pView); +typedef void (VKAPI_PTR *PFN_vkDestroyTensorViewARM)(VkDevice device, VkTensorViewARM tensorView, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetTensorMemoryRequirementsARM)(VkDevice device, const VkTensorMemoryRequirementsInfoARM* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef VkResult (VKAPI_PTR *PFN_vkBindTensorMemoryARM)(VkDevice device, uint32_t bindInfoCount, const VkBindTensorMemoryInfoARM* pBindInfos); +typedef void (VKAPI_PTR *PFN_vkGetDeviceTensorMemoryRequirementsARM)(VkDevice device, const VkDeviceTensorMemoryRequirementsARM* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkCmdCopyTensorARM)(VkCommandBuffer commandBuffer, const VkCopyTensorInfoARM* pCopyTensorInfo); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalTensorPropertiesARM)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalTensorInfoARM* pExternalTensorInfo, VkExternalTensorPropertiesARM* pExternalTensorProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetTensorOpaqueCaptureDescriptorDataARM)(VkDevice device, const VkTensorCaptureDescriptorDataInfoARM* pInfo, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetTensorViewOpaqueCaptureDescriptorDataARM)(VkDevice device, const VkTensorViewCaptureDescriptorDataInfoARM* pInfo, void* pData); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateTensorARM( + VkDevice device, + const VkTensorCreateInfoARM* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkTensorARM* pTensor); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyTensorARM( + VkDevice device, + VkTensorARM tensor, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateTensorViewARM( + VkDevice device, + const VkTensorViewCreateInfoARM* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkTensorViewARM* pView); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyTensorViewARM( + VkDevice device, + VkTensorViewARM tensorView, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetTensorMemoryRequirementsARM( + VkDevice device, + const VkTensorMemoryRequirementsInfoARM* pInfo, + VkMemoryRequirements2* pMemoryRequirements); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkBindTensorMemoryARM( + VkDevice device, + uint32_t bindInfoCount, + const VkBindTensorMemoryInfoARM* pBindInfos); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDeviceTensorMemoryRequirementsARM( + VkDevice device, + const VkDeviceTensorMemoryRequirementsARM* pInfo, + VkMemoryRequirements2* pMemoryRequirements); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyTensorARM( + VkCommandBuffer commandBuffer, + const VkCopyTensorInfoARM* pCopyTensorInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalTensorPropertiesARM( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalTensorInfoARM* pExternalTensorInfo, + VkExternalTensorPropertiesARM* pExternalTensorProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetTensorOpaqueCaptureDescriptorDataARM( + VkDevice device, + const VkTensorCaptureDescriptorDataInfoARM* pInfo, + void* pData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetTensorViewOpaqueCaptureDescriptorDataARM( + VkDevice device, + const VkTensorViewCaptureDescriptorDataInfoARM* pInfo, + void* pData); +#endif +#endif + + +// VK_EXT_shader_module_identifier is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_module_identifier 1 +#define VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT 32U +#define VK_EXT_SHADER_MODULE_IDENTIFIER_SPEC_VERSION 1 +#define VK_EXT_SHADER_MODULE_IDENTIFIER_EXTENSION_NAME "VK_EXT_shader_module_identifier" +typedef struct VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderModuleIdentifier; +} VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT; + +typedef struct VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT { + VkStructureType sType; + void* pNext; + uint8_t shaderModuleIdentifierAlgorithmUUID[VK_UUID_SIZE]; +} VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT; + +typedef struct VkPipelineShaderStageModuleIdentifierCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t identifierSize; + const uint8_t* pIdentifier; +} VkPipelineShaderStageModuleIdentifierCreateInfoEXT; + +typedef struct VkShaderModuleIdentifierEXT { + VkStructureType sType; + void* pNext; + uint32_t identifierSize; + uint8_t identifier[VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT]; +} VkShaderModuleIdentifierEXT; + +typedef void (VKAPI_PTR *PFN_vkGetShaderModuleIdentifierEXT)(VkDevice device, VkShaderModule shaderModule, VkShaderModuleIdentifierEXT* pIdentifier); +typedef void (VKAPI_PTR *PFN_vkGetShaderModuleCreateInfoIdentifierEXT)(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, VkShaderModuleIdentifierEXT* pIdentifier); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetShaderModuleIdentifierEXT( + VkDevice device, + VkShaderModule shaderModule, + VkShaderModuleIdentifierEXT* pIdentifier); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetShaderModuleCreateInfoIdentifierEXT( + VkDevice device, + const VkShaderModuleCreateInfo* pCreateInfo, + VkShaderModuleIdentifierEXT* pIdentifier); +#endif +#endif + + +// VK_EXT_rasterization_order_attachment_access is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_rasterization_order_attachment_access 1 +#define VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION 1 +#define VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME "VK_EXT_rasterization_order_attachment_access" + + +// VK_NV_optical_flow is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_optical_flow 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkOpticalFlowSessionNV) +#define VK_NV_OPTICAL_FLOW_SPEC_VERSION 1 +#define VK_NV_OPTICAL_FLOW_EXTENSION_NAME "VK_NV_optical_flow" + +typedef enum VkOpticalFlowPerformanceLevelNV { + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_UNKNOWN_NV = 0, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_SLOW_NV = 1, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_MEDIUM_NV = 2, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_FAST_NV = 3, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowPerformanceLevelNV; + +typedef enum VkOpticalFlowSessionBindingPointNV { + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_UNKNOWN_NV = 0, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_INPUT_NV = 1, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_REFERENCE_NV = 2, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_HINT_NV = 3, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_FLOW_VECTOR_NV = 4, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_BACKWARD_FLOW_VECTOR_NV = 5, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_COST_NV = 6, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_BACKWARD_COST_NV = 7, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_GLOBAL_FLOW_NV = 8, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowSessionBindingPointNV; + +typedef enum VkOpticalFlowGridSizeFlagBitsNV { + VK_OPTICAL_FLOW_GRID_SIZE_UNKNOWN_NV = 0, + VK_OPTICAL_FLOW_GRID_SIZE_1X1_BIT_NV = 0x00000001, + VK_OPTICAL_FLOW_GRID_SIZE_2X2_BIT_NV = 0x00000002, + VK_OPTICAL_FLOW_GRID_SIZE_4X4_BIT_NV = 0x00000004, + VK_OPTICAL_FLOW_GRID_SIZE_8X8_BIT_NV = 0x00000008, + VK_OPTICAL_FLOW_GRID_SIZE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowGridSizeFlagBitsNV; +typedef VkFlags VkOpticalFlowGridSizeFlagsNV; + +typedef enum VkOpticalFlowUsageFlagBitsNV { + VK_OPTICAL_FLOW_USAGE_UNKNOWN_NV = 0, + VK_OPTICAL_FLOW_USAGE_INPUT_BIT_NV = 0x00000001, + VK_OPTICAL_FLOW_USAGE_OUTPUT_BIT_NV = 0x00000002, + VK_OPTICAL_FLOW_USAGE_HINT_BIT_NV = 0x00000004, + VK_OPTICAL_FLOW_USAGE_COST_BIT_NV = 0x00000008, + VK_OPTICAL_FLOW_USAGE_GLOBAL_FLOW_BIT_NV = 0x00000010, + VK_OPTICAL_FLOW_USAGE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowUsageFlagBitsNV; +typedef VkFlags VkOpticalFlowUsageFlagsNV; + +typedef enum VkOpticalFlowSessionCreateFlagBitsNV { + VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_HINT_BIT_NV = 0x00000001, + VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_COST_BIT_NV = 0x00000002, + VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_GLOBAL_FLOW_BIT_NV = 0x00000004, + VK_OPTICAL_FLOW_SESSION_CREATE_ALLOW_REGIONS_BIT_NV = 0x00000008, + VK_OPTICAL_FLOW_SESSION_CREATE_BOTH_DIRECTIONS_BIT_NV = 0x00000010, + VK_OPTICAL_FLOW_SESSION_CREATE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowSessionCreateFlagBitsNV; +typedef VkFlags VkOpticalFlowSessionCreateFlagsNV; + +typedef enum VkOpticalFlowExecuteFlagBitsNV { + VK_OPTICAL_FLOW_EXECUTE_DISABLE_TEMPORAL_HINTS_BIT_NV = 0x00000001, + VK_OPTICAL_FLOW_EXECUTE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowExecuteFlagBitsNV; +typedef VkFlags VkOpticalFlowExecuteFlagsNV; +typedef struct VkPhysicalDeviceOpticalFlowFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 opticalFlow; +} VkPhysicalDeviceOpticalFlowFeaturesNV; + +typedef struct VkPhysicalDeviceOpticalFlowPropertiesNV { + VkStructureType sType; + void* pNext; + VkOpticalFlowGridSizeFlagsNV supportedOutputGridSizes; + VkOpticalFlowGridSizeFlagsNV supportedHintGridSizes; + VkBool32 hintSupported; + VkBool32 costSupported; + VkBool32 bidirectionalFlowSupported; + VkBool32 globalFlowSupported; + uint32_t minWidth; + uint32_t minHeight; + uint32_t maxWidth; + uint32_t maxHeight; + uint32_t maxNumRegionsOfInterest; +} VkPhysicalDeviceOpticalFlowPropertiesNV; + +typedef struct VkOpticalFlowImageFormatInfoNV { + VkStructureType sType; + const void* pNext; + VkOpticalFlowUsageFlagsNV usage; +} VkOpticalFlowImageFormatInfoNV; + +typedef struct VkOpticalFlowImageFormatPropertiesNV { + VkStructureType sType; + void* pNext; + VkFormat format; +} VkOpticalFlowImageFormatPropertiesNV; + +typedef struct VkOpticalFlowSessionCreateInfoNV { + VkStructureType sType; + void* pNext; + uint32_t width; + uint32_t height; + VkFormat imageFormat; + VkFormat flowVectorFormat; + VkFormat costFormat; + VkOpticalFlowGridSizeFlagsNV outputGridSize; + VkOpticalFlowGridSizeFlagsNV hintGridSize; + VkOpticalFlowPerformanceLevelNV performanceLevel; + VkOpticalFlowSessionCreateFlagsNV flags; +} VkOpticalFlowSessionCreateInfoNV; + +typedef struct VkOpticalFlowSessionCreatePrivateDataInfoNV { + VkStructureType sType; + void* pNext; + uint32_t id; + uint32_t size; + const void* pPrivateData; +} VkOpticalFlowSessionCreatePrivateDataInfoNV; + +typedef struct VkOpticalFlowExecuteInfoNV { + VkStructureType sType; + void* pNext; + VkOpticalFlowExecuteFlagsNV flags; + uint32_t regionCount; + const VkRect2D* pRegions; +} VkOpticalFlowExecuteInfoNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV)(VkPhysicalDevice physicalDevice, const VkOpticalFlowImageFormatInfoNV* pOpticalFlowImageFormatInfo, uint32_t* pFormatCount, VkOpticalFlowImageFormatPropertiesNV* pImageFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkCreateOpticalFlowSessionNV)(VkDevice device, const VkOpticalFlowSessionCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkOpticalFlowSessionNV* pSession); +typedef void (VKAPI_PTR *PFN_vkDestroyOpticalFlowSessionNV)(VkDevice device, VkOpticalFlowSessionNV session, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkBindOpticalFlowSessionImageNV)(VkDevice device, VkOpticalFlowSessionNV session, VkOpticalFlowSessionBindingPointNV bindingPoint, VkImageView view, VkImageLayout layout); +typedef void (VKAPI_PTR *PFN_vkCmdOpticalFlowExecuteNV)(VkCommandBuffer commandBuffer, VkOpticalFlowSessionNV session, const VkOpticalFlowExecuteInfoNV* pExecuteInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceOpticalFlowImageFormatsNV( + VkPhysicalDevice physicalDevice, + const VkOpticalFlowImageFormatInfoNV* pOpticalFlowImageFormatInfo, + uint32_t* pFormatCount, + VkOpticalFlowImageFormatPropertiesNV* pImageFormatProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateOpticalFlowSessionNV( + VkDevice device, + const VkOpticalFlowSessionCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkOpticalFlowSessionNV* pSession); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyOpticalFlowSessionNV( + VkDevice device, + VkOpticalFlowSessionNV session, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkBindOpticalFlowSessionImageNV( + VkDevice device, + VkOpticalFlowSessionNV session, + VkOpticalFlowSessionBindingPointNV bindingPoint, + VkImageView view, + VkImageLayout layout); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdOpticalFlowExecuteNV( + VkCommandBuffer commandBuffer, + VkOpticalFlowSessionNV session, + const VkOpticalFlowExecuteInfoNV* pExecuteInfo); +#endif +#endif + + +// VK_EXT_legacy_dithering is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_legacy_dithering 1 +#define VK_EXT_LEGACY_DITHERING_SPEC_VERSION 2 +#define VK_EXT_LEGACY_DITHERING_EXTENSION_NAME "VK_EXT_legacy_dithering" +typedef struct VkPhysicalDeviceLegacyDitheringFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 legacyDithering; +} VkPhysicalDeviceLegacyDitheringFeaturesEXT; + + + +// VK_EXT_pipeline_protected_access is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_pipeline_protected_access 1 +#define VK_EXT_PIPELINE_PROTECTED_ACCESS_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_PROTECTED_ACCESS_EXTENSION_NAME "VK_EXT_pipeline_protected_access" +typedef VkPhysicalDevicePipelineProtectedAccessFeatures VkPhysicalDevicePipelineProtectedAccessFeaturesEXT; + + + +// VK_AMD_anti_lag is a preprocessor guard. Do not pass it to API calls. +#define VK_AMD_anti_lag 1 +#define VK_AMD_ANTI_LAG_SPEC_VERSION 1 +#define VK_AMD_ANTI_LAG_EXTENSION_NAME "VK_AMD_anti_lag" + +typedef enum VkAntiLagModeAMD { + VK_ANTI_LAG_MODE_DRIVER_CONTROL_AMD = 0, + VK_ANTI_LAG_MODE_ON_AMD = 1, + VK_ANTI_LAG_MODE_OFF_AMD = 2, + VK_ANTI_LAG_MODE_MAX_ENUM_AMD = 0x7FFFFFFF +} VkAntiLagModeAMD; + +typedef enum VkAntiLagStageAMD { + VK_ANTI_LAG_STAGE_INPUT_AMD = 0, + VK_ANTI_LAG_STAGE_PRESENT_AMD = 1, + VK_ANTI_LAG_STAGE_MAX_ENUM_AMD = 0x7FFFFFFF +} VkAntiLagStageAMD; +typedef struct VkPhysicalDeviceAntiLagFeaturesAMD { + VkStructureType sType; + void* pNext; + VkBool32 antiLag; +} VkPhysicalDeviceAntiLagFeaturesAMD; + +typedef struct VkAntiLagPresentationInfoAMD { + VkStructureType sType; + void* pNext; + VkAntiLagStageAMD stage; + uint64_t frameIndex; +} VkAntiLagPresentationInfoAMD; + +typedef struct VkAntiLagDataAMD { + VkStructureType sType; + const void* pNext; + VkAntiLagModeAMD mode; + uint32_t maxFPS; + const VkAntiLagPresentationInfoAMD* pPresentationInfo; +} VkAntiLagDataAMD; + +typedef void (VKAPI_PTR *PFN_vkAntiLagUpdateAMD)(VkDevice device, const VkAntiLagDataAMD* pData); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkAntiLagUpdateAMD( + VkDevice device, + const VkAntiLagDataAMD* pData); +#endif +#endif + + +// VK_EXT_shader_object is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_object 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderEXT) +#define VK_EXT_SHADER_OBJECT_SPEC_VERSION 1 +#define VK_EXT_SHADER_OBJECT_EXTENSION_NAME "VK_EXT_shader_object" + +typedef enum VkShaderCodeTypeEXT { + VK_SHADER_CODE_TYPE_BINARY_EXT = 0, + VK_SHADER_CODE_TYPE_SPIRV_EXT = 1, + VK_SHADER_CODE_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkShaderCodeTypeEXT; + +typedef enum VkDepthClampModeEXT { + VK_DEPTH_CLAMP_MODE_VIEWPORT_RANGE_EXT = 0, + VK_DEPTH_CLAMP_MODE_USER_DEFINED_RANGE_EXT = 1, + VK_DEPTH_CLAMP_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDepthClampModeEXT; + +typedef enum VkShaderCreateFlagBitsEXT { + VK_SHADER_CREATE_LINK_STAGE_BIT_EXT = 0x00000001, + VK_SHADER_CREATE_DESCRIPTOR_HEAP_BIT_EXT = 0x00000400, + VK_SHADER_CREATE_INSTRUMENT_SHADER_BIT_ARM = 0x00000800, + VK_SHADER_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT = 0x00000002, + VK_SHADER_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT = 0x00000004, + VK_SHADER_CREATE_NO_TASK_SHADER_BIT_EXT = 0x00000008, + VK_SHADER_CREATE_DISPATCH_BASE_BIT_EXT = 0x00000010, + VK_SHADER_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_EXT = 0x00000020, + VK_SHADER_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 0x00000040, + VK_SHADER_CREATE_INDIRECT_BINDABLE_BIT_EXT = 0x00000080, + VK_SHADER_CREATE_OPACITY_MICROMAP_DISALLOW_MIXED_SPECIAL_INDEX_BIT_EXT = 0x00001000, + VK_SHADER_CREATE_64_BIT_INDEXING_BIT_EXT = 0x00008000, + VK_SHADER_CREATE_INDEPENDENT_SETS_BIT_KHR = 0x00040000, + VK_SHADER_CREATE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkShaderCreateFlagBitsEXT; +typedef VkFlags VkShaderCreateFlagsEXT; +typedef struct VkPhysicalDeviceShaderObjectFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderObject; +} VkPhysicalDeviceShaderObjectFeaturesEXT; + +typedef struct VkPhysicalDeviceShaderObjectPropertiesEXT { + VkStructureType sType; + void* pNext; + uint8_t shaderBinaryUUID[VK_UUID_SIZE]; + uint32_t shaderBinaryVersion; +} VkPhysicalDeviceShaderObjectPropertiesEXT; + +typedef struct VkShaderCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkShaderCreateFlagsEXT flags; + VkShaderStageFlagBits stage; + VkShaderStageFlags nextStage; + VkShaderCodeTypeEXT codeType; + size_t codeSize; + const void* pCode; + const char* pName; + uint32_t setLayoutCount; + const VkDescriptorSetLayout* pSetLayouts; + uint32_t pushConstantRangeCount; + const VkPushConstantRange* pPushConstantRanges; + const VkSpecializationInfo* pSpecializationInfo; +} VkShaderCreateInfoEXT; + +typedef VkPipelineShaderStageRequiredSubgroupSizeCreateInfo VkShaderRequiredSubgroupSizeCreateInfoEXT; + +typedef struct VkDepthClampRangeEXT { + float minDepthClamp; + float maxDepthClamp; +} VkDepthClampRangeEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateShadersEXT)(VkDevice device, uint32_t createInfoCount, const VkShaderCreateInfoEXT* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkShaderEXT* pShaders); +typedef void (VKAPI_PTR *PFN_vkDestroyShaderEXT)(VkDevice device, VkShaderEXT shader, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetShaderBinaryDataEXT)(VkDevice device, VkShaderEXT shader, size_t* pDataSize, void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdBindShadersEXT)(VkCommandBuffer commandBuffer, uint32_t stageCount, const VkShaderStageFlagBits* pStages, const VkShaderEXT* pShaders); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthClampRangeEXT)(VkCommandBuffer commandBuffer, VkDepthClampModeEXT depthClampMode, const VkDepthClampRangeEXT* pDepthClampRange); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateShadersEXT( + VkDevice device, + uint32_t createInfoCount, + const VkShaderCreateInfoEXT* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkShaderEXT* pShaders); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyShaderEXT( + VkDevice device, + VkShaderEXT shader, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetShaderBinaryDataEXT( + VkDevice device, + VkShaderEXT shader, + size_t* pDataSize, + void* pData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindShadersEXT( + VkCommandBuffer commandBuffer, + uint32_t stageCount, + const VkShaderStageFlagBits* pStages, + const VkShaderEXT* pShaders); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthClampRangeEXT( + VkCommandBuffer commandBuffer, + VkDepthClampModeEXT depthClampMode, + const VkDepthClampRangeEXT* pDepthClampRange); +#endif +#endif + + +// VK_QCOM_tile_properties is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_tile_properties 1 +#define VK_QCOM_TILE_PROPERTIES_SPEC_VERSION 1 +#define VK_QCOM_TILE_PROPERTIES_EXTENSION_NAME "VK_QCOM_tile_properties" +typedef struct VkPhysicalDeviceTilePropertiesFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 tileProperties; +} VkPhysicalDeviceTilePropertiesFeaturesQCOM; + +typedef struct VkTilePropertiesQCOM { + VkStructureType sType; + void* pNext; + VkExtent3D tileSize; + VkExtent2D apronSize; + VkOffset2D origin; +} VkTilePropertiesQCOM; + +typedef VkResult (VKAPI_PTR *PFN_vkGetFramebufferTilePropertiesQCOM)(VkDevice device, VkFramebuffer framebuffer, uint32_t* pPropertiesCount, VkTilePropertiesQCOM* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetDynamicRenderingTilePropertiesQCOM)(VkDevice device, const VkRenderingInfo* pRenderingInfo, VkTilePropertiesQCOM* pProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetFramebufferTilePropertiesQCOM( + VkDevice device, + VkFramebuffer framebuffer, + uint32_t* pPropertiesCount, + VkTilePropertiesQCOM* pProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDynamicRenderingTilePropertiesQCOM( + VkDevice device, + const VkRenderingInfo* pRenderingInfo, + VkTilePropertiesQCOM* pProperties); +#endif +#endif + + +// VK_SEC_amigo_profiling is a preprocessor guard. Do not pass it to API calls. +#define VK_SEC_amigo_profiling 1 +#define VK_SEC_AMIGO_PROFILING_SPEC_VERSION 1 +#define VK_SEC_AMIGO_PROFILING_EXTENSION_NAME "VK_SEC_amigo_profiling" +typedef struct VkPhysicalDeviceAmigoProfilingFeaturesSEC { + VkStructureType sType; + void* pNext; + VkBool32 amigoProfiling; +} VkPhysicalDeviceAmigoProfilingFeaturesSEC; + +typedef struct VkAmigoProfilingSubmitInfoSEC { + VkStructureType sType; + const void* pNext; + uint64_t firstDrawTimestamp; + uint64_t swapBufferTimestamp; +} VkAmigoProfilingSubmitInfoSEC; + + + +// VK_QCOM_multiview_per_view_viewports is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_multiview_per_view_viewports 1 +#define VK_QCOM_MULTIVIEW_PER_VIEW_VIEWPORTS_SPEC_VERSION 1 +#define VK_QCOM_MULTIVIEW_PER_VIEW_VIEWPORTS_EXTENSION_NAME "VK_QCOM_multiview_per_view_viewports" +typedef struct VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 multiviewPerViewViewports; +} VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM; + + + +// VK_NV_ray_tracing_invocation_reorder is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_ray_tracing_invocation_reorder 1 +#define VK_NV_RAY_TRACING_INVOCATION_REORDER_SPEC_VERSION 1 +#define VK_NV_RAY_TRACING_INVOCATION_REORDER_EXTENSION_NAME "VK_NV_ray_tracing_invocation_reorder" + +typedef enum VkRayTracingInvocationReorderModeEXT { + VK_RAY_TRACING_INVOCATION_REORDER_MODE_NONE_EXT = 0, + VK_RAY_TRACING_INVOCATION_REORDER_MODE_REORDER_EXT = 1, + VK_RAY_TRACING_INVOCATION_REORDER_MODE_NONE_NV = VK_RAY_TRACING_INVOCATION_REORDER_MODE_NONE_EXT, + VK_RAY_TRACING_INVOCATION_REORDER_MODE_REORDER_NV = VK_RAY_TRACING_INVOCATION_REORDER_MODE_REORDER_EXT, + VK_RAY_TRACING_INVOCATION_REORDER_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkRayTracingInvocationReorderModeEXT; +typedef VkRayTracingInvocationReorderModeEXT VkRayTracingInvocationReorderModeNV; + +typedef struct VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV { + VkStructureType sType; + void* pNext; + VkRayTracingInvocationReorderModeEXT rayTracingInvocationReorderReorderingHint; +} VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV; + +typedef struct VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 rayTracingInvocationReorder; +} VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV; + + + +// VK_NV_cooperative_vector is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_cooperative_vector 1 +#define VK_NV_COOPERATIVE_VECTOR_SPEC_VERSION 4 +#define VK_NV_COOPERATIVE_VECTOR_EXTENSION_NAME "VK_NV_cooperative_vector" + +typedef enum VkCooperativeVectorMatrixLayoutNV { + VK_COOPERATIVE_VECTOR_MATRIX_LAYOUT_ROW_MAJOR_NV = 0, + VK_COOPERATIVE_VECTOR_MATRIX_LAYOUT_COLUMN_MAJOR_NV = 1, + VK_COOPERATIVE_VECTOR_MATRIX_LAYOUT_INFERENCING_OPTIMAL_NV = 2, + VK_COOPERATIVE_VECTOR_MATRIX_LAYOUT_TRAINING_OPTIMAL_NV = 3, + VK_COOPERATIVE_VECTOR_MATRIX_LAYOUT_MAX_ENUM_NV = 0x7FFFFFFF +} VkCooperativeVectorMatrixLayoutNV; +typedef struct VkPhysicalDeviceCooperativeVectorPropertiesNV { + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeVectorSupportedStages; + VkBool32 cooperativeVectorTrainingFloat16Accumulation; + VkBool32 cooperativeVectorTrainingFloat32Accumulation; + uint32_t maxCooperativeVectorComponents; +} VkPhysicalDeviceCooperativeVectorPropertiesNV; + +typedef struct VkPhysicalDeviceCooperativeVectorFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 cooperativeVector; + VkBool32 cooperativeVectorTraining; +} VkPhysicalDeviceCooperativeVectorFeaturesNV; + +typedef struct VkCooperativeVectorPropertiesNV { + VkStructureType sType; + void* pNext; + VkComponentTypeKHR inputType; + VkComponentTypeKHR inputInterpretation; + VkComponentTypeKHR matrixInterpretation; + VkComponentTypeKHR biasInterpretation; + VkComponentTypeKHR resultType; + VkBool32 transpose; +} VkCooperativeVectorPropertiesNV; + +typedef struct VkConvertCooperativeVectorMatrixInfoNV { + VkStructureType sType; + const void* pNext; + size_t srcSize; + VkDeviceOrHostAddressConstKHR srcData; + size_t* pDstSize; + VkDeviceOrHostAddressKHR dstData; + VkComponentTypeKHR srcComponentType; + VkComponentTypeKHR dstComponentType; + uint32_t numRows; + uint32_t numColumns; + VkCooperativeVectorMatrixLayoutNV srcLayout; + size_t srcStride; + VkCooperativeVectorMatrixLayoutNV dstLayout; + size_t dstStride; +} VkConvertCooperativeVectorMatrixInfoNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCooperativeVectorPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeVectorPropertiesNV* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkConvertCooperativeVectorMatrixNV)(VkDevice device, const VkConvertCooperativeVectorMatrixInfoNV* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdConvertCooperativeVectorMatrixNV)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkConvertCooperativeVectorMatrixInfoNV* pInfos); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCooperativeVectorPropertiesNV( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkCooperativeVectorPropertiesNV* pProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkConvertCooperativeVectorMatrixNV( + VkDevice device, + const VkConvertCooperativeVectorMatrixInfoNV* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdConvertCooperativeVectorMatrixNV( + VkCommandBuffer commandBuffer, + uint32_t infoCount, + const VkConvertCooperativeVectorMatrixInfoNV* pInfos); +#endif +#endif + + +// VK_NV_extended_sparse_address_space is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_extended_sparse_address_space 1 +#define VK_NV_EXTENDED_SPARSE_ADDRESS_SPACE_SPEC_VERSION 1 +#define VK_NV_EXTENDED_SPARSE_ADDRESS_SPACE_EXTENSION_NAME "VK_NV_extended_sparse_address_space" +typedef struct VkPhysicalDeviceExtendedSparseAddressSpaceFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 extendedSparseAddressSpace; +} VkPhysicalDeviceExtendedSparseAddressSpaceFeaturesNV; + +typedef struct VkPhysicalDeviceExtendedSparseAddressSpacePropertiesNV { + VkStructureType sType; + void* pNext; + VkDeviceSize extendedSparseAddressSpaceSize; + VkImageUsageFlags extendedSparseImageUsageFlags; + VkBufferUsageFlags extendedSparseBufferUsageFlags; +} VkPhysicalDeviceExtendedSparseAddressSpacePropertiesNV; + + + +// VK_EXT_mutable_descriptor_type is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_mutable_descriptor_type 1 +#define VK_EXT_MUTABLE_DESCRIPTOR_TYPE_SPEC_VERSION 1 +#define VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME "VK_EXT_mutable_descriptor_type" + + +// VK_EXT_legacy_vertex_attributes is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_legacy_vertex_attributes 1 +#define VK_EXT_LEGACY_VERTEX_ATTRIBUTES_SPEC_VERSION 1 +#define VK_EXT_LEGACY_VERTEX_ATTRIBUTES_EXTENSION_NAME "VK_EXT_legacy_vertex_attributes" +typedef struct VkPhysicalDeviceLegacyVertexAttributesFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 legacyVertexAttributes; +} VkPhysicalDeviceLegacyVertexAttributesFeaturesEXT; + +typedef struct VkPhysicalDeviceLegacyVertexAttributesPropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 nativeUnalignedPerformance; +} VkPhysicalDeviceLegacyVertexAttributesPropertiesEXT; + + + +// VK_EXT_layer_settings is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_layer_settings 1 +#define VK_EXT_LAYER_SETTINGS_SPEC_VERSION 2 +#define VK_EXT_LAYER_SETTINGS_EXTENSION_NAME "VK_EXT_layer_settings" + +typedef enum VkLayerSettingTypeEXT { + VK_LAYER_SETTING_TYPE_BOOL32_EXT = 0, + VK_LAYER_SETTING_TYPE_INT32_EXT = 1, + VK_LAYER_SETTING_TYPE_INT64_EXT = 2, + VK_LAYER_SETTING_TYPE_UINT32_EXT = 3, + VK_LAYER_SETTING_TYPE_UINT64_EXT = 4, + VK_LAYER_SETTING_TYPE_FLOAT32_EXT = 5, + VK_LAYER_SETTING_TYPE_FLOAT64_EXT = 6, + VK_LAYER_SETTING_TYPE_STRING_EXT = 7, + VK_LAYER_SETTING_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkLayerSettingTypeEXT; +typedef struct VkLayerSettingEXT { + const char* pLayerName; + const char* pSettingName; + VkLayerSettingTypeEXT type; + uint32_t valueCount; + const void* pValues; +} VkLayerSettingEXT; + +typedef struct VkLayerSettingsCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t settingCount; + const VkLayerSettingEXT* pSettings; +} VkLayerSettingsCreateInfoEXT; + + + +// VK_ARM_shader_core_builtins is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_shader_core_builtins 1 +#define VK_ARM_SHADER_CORE_BUILTINS_SPEC_VERSION 2 +#define VK_ARM_SHADER_CORE_BUILTINS_EXTENSION_NAME "VK_ARM_shader_core_builtins" +typedef struct VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 shaderCoreBuiltins; +} VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM; + +typedef struct VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM { + VkStructureType sType; + void* pNext; + uint64_t shaderCoreMask; + uint32_t shaderCoreCount; + uint32_t shaderWarpsPerCore; +} VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM; + + + +// VK_EXT_pipeline_library_group_handles is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_pipeline_library_group_handles 1 +#define VK_EXT_PIPELINE_LIBRARY_GROUP_HANDLES_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_LIBRARY_GROUP_HANDLES_EXTENSION_NAME "VK_EXT_pipeline_library_group_handles" +typedef struct VkPhysicalDevicePipelineLibraryGroupHandlesFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 pipelineLibraryGroupHandles; +} VkPhysicalDevicePipelineLibraryGroupHandlesFeaturesEXT; + + + +// VK_EXT_dynamic_rendering_unused_attachments is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_dynamic_rendering_unused_attachments 1 +#define VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_SPEC_VERSION 1 +#define VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_EXTENSION_NAME "VK_EXT_dynamic_rendering_unused_attachments" +typedef struct VkPhysicalDeviceDynamicRenderingUnusedAttachmentsFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 dynamicRenderingUnusedAttachments; +} VkPhysicalDeviceDynamicRenderingUnusedAttachmentsFeaturesEXT; + + + +// VK_NV_low_latency2 is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_low_latency2 1 +#define VK_NV_LOW_LATENCY_2_SPEC_VERSION 2 +#define VK_NV_LOW_LATENCY_2_EXTENSION_NAME "VK_NV_low_latency2" + +typedef enum VkLatencyMarkerNV { + VK_LATENCY_MARKER_SIMULATION_START_NV = 0, + VK_LATENCY_MARKER_SIMULATION_END_NV = 1, + VK_LATENCY_MARKER_RENDERSUBMIT_START_NV = 2, + VK_LATENCY_MARKER_RENDERSUBMIT_END_NV = 3, + VK_LATENCY_MARKER_PRESENT_START_NV = 4, + VK_LATENCY_MARKER_PRESENT_END_NV = 5, + VK_LATENCY_MARKER_INPUT_SAMPLE_NV = 6, + VK_LATENCY_MARKER_TRIGGER_FLASH_NV = 7, + VK_LATENCY_MARKER_OUT_OF_BAND_RENDERSUBMIT_START_NV = 8, + VK_LATENCY_MARKER_OUT_OF_BAND_RENDERSUBMIT_END_NV = 9, + VK_LATENCY_MARKER_OUT_OF_BAND_PRESENT_START_NV = 10, + VK_LATENCY_MARKER_OUT_OF_BAND_PRESENT_END_NV = 11, + VK_LATENCY_MARKER_MAX_ENUM_NV = 0x7FFFFFFF +} VkLatencyMarkerNV; + +typedef enum VkOutOfBandQueueTypeNV { + VK_OUT_OF_BAND_QUEUE_TYPE_RENDER_NV = 0, + VK_OUT_OF_BAND_QUEUE_TYPE_PRESENT_NV = 1, + VK_OUT_OF_BAND_QUEUE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkOutOfBandQueueTypeNV; +typedef struct VkLatencySleepModeInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 lowLatencyMode; + VkBool32 lowLatencyBoost; + uint32_t minimumIntervalUs; +} VkLatencySleepModeInfoNV; + +typedef struct VkLatencySleepInfoNV { + VkStructureType sType; + const void* pNext; + VkSemaphore signalSemaphore; + uint64_t value; +} VkLatencySleepInfoNV; + +typedef struct VkSetLatencyMarkerInfoNV { + VkStructureType sType; + const void* pNext; + uint64_t presentID; + VkLatencyMarkerNV marker; +} VkSetLatencyMarkerInfoNV; + +typedef struct VkLatencyTimingsFrameReportNV { + VkStructureType sType; + void* pNext; + uint64_t presentID; + uint64_t inputSampleTimeUs; + uint64_t simStartTimeUs; + uint64_t simEndTimeUs; + uint64_t renderSubmitStartTimeUs; + uint64_t renderSubmitEndTimeUs; + uint64_t presentStartTimeUs; + uint64_t presentEndTimeUs; + uint64_t driverStartTimeUs; + uint64_t driverEndTimeUs; + uint64_t osRenderQueueStartTimeUs; + uint64_t osRenderQueueEndTimeUs; + uint64_t gpuRenderStartTimeUs; + uint64_t gpuRenderEndTimeUs; +} VkLatencyTimingsFrameReportNV; + +typedef struct VkGetLatencyMarkerInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t timingCount; + VkLatencyTimingsFrameReportNV* pTimings; +} VkGetLatencyMarkerInfoNV; + +typedef struct VkLatencySubmissionPresentIdNV { + VkStructureType sType; + const void* pNext; + uint64_t presentID; +} VkLatencySubmissionPresentIdNV; + +typedef struct VkSwapchainLatencyCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 latencyModeEnable; +} VkSwapchainLatencyCreateInfoNV; + +typedef struct VkOutOfBandQueueTypeInfoNV { + VkStructureType sType; + const void* pNext; + VkOutOfBandQueueTypeNV queueType; +} VkOutOfBandQueueTypeInfoNV; + +typedef struct VkLatencySurfaceCapabilitiesNV { + VkStructureType sType; + const void* pNext; + uint32_t presentModeCount; + VkPresentModeKHR* pPresentModes; +} VkLatencySurfaceCapabilitiesNV; + +typedef VkResult (VKAPI_PTR *PFN_vkSetLatencySleepModeNV)(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepModeInfoNV* pSleepModeInfo); +typedef VkResult (VKAPI_PTR *PFN_vkLatencySleepNV)(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepInfoNV* pSleepInfo); +typedef void (VKAPI_PTR *PFN_vkSetLatencyMarkerNV)(VkDevice device, VkSwapchainKHR swapchain, const VkSetLatencyMarkerInfoNV* pLatencyMarkerInfo); +typedef void (VKAPI_PTR *PFN_vkGetLatencyTimingsNV)(VkDevice device, VkSwapchainKHR swapchain, VkGetLatencyMarkerInfoNV* pLatencyMarkerInfo); +typedef void (VKAPI_PTR *PFN_vkQueueNotifyOutOfBandNV)(VkQueue queue, const VkOutOfBandQueueTypeInfoNV* pQueueTypeInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkSetLatencySleepModeNV( + VkDevice device, + VkSwapchainKHR swapchain, + const VkLatencySleepModeInfoNV* pSleepModeInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkLatencySleepNV( + VkDevice device, + VkSwapchainKHR swapchain, + const VkLatencySleepInfoNV* pSleepInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkSetLatencyMarkerNV( + VkDevice device, + VkSwapchainKHR swapchain, + const VkSetLatencyMarkerInfoNV* pLatencyMarkerInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetLatencyTimingsNV( + VkDevice device, + VkSwapchainKHR swapchain, + VkGetLatencyMarkerInfoNV* pLatencyMarkerInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkQueueNotifyOutOfBandNV( + VkQueue queue, + const VkOutOfBandQueueTypeInfoNV* pQueueTypeInfo); +#endif +#endif + + +// VK_ARM_data_graph is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_data_graph 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDataGraphPipelineSessionARM) +#define VK_MAX_PHYSICAL_DEVICE_DATA_GRAPH_OPERATION_SET_NAME_SIZE_ARM 128U +#define VK_ARM_DATA_GRAPH_SPEC_VERSION 1 +#define VK_ARM_DATA_GRAPH_EXTENSION_NAME "VK_ARM_data_graph" + +typedef enum VkDataGraphPipelineSessionBindPointARM { + VK_DATA_GRAPH_PIPELINE_SESSION_BIND_POINT_TRANSIENT_ARM = 0, + VK_DATA_GRAPH_PIPELINE_SESSION_BIND_POINT_OPTICAL_FLOW_CACHE_ARM = 1000631001, + VK_DATA_GRAPH_PIPELINE_SESSION_BIND_POINT_NEURAL_ACCELERATOR_STATISTICS_ARM = 1000676000, + VK_DATA_GRAPH_PIPELINE_SESSION_BIND_POINT_MAX_ENUM_ARM = 0x7FFFFFFF +} VkDataGraphPipelineSessionBindPointARM; + +typedef enum VkDataGraphPipelineSessionBindPointTypeARM { + VK_DATA_GRAPH_PIPELINE_SESSION_BIND_POINT_TYPE_MEMORY_ARM = 0, + VK_DATA_GRAPH_PIPELINE_SESSION_BIND_POINT_TYPE_MAX_ENUM_ARM = 0x7FFFFFFF +} VkDataGraphPipelineSessionBindPointTypeARM; + +typedef enum VkDataGraphPipelinePropertyARM { + VK_DATA_GRAPH_PIPELINE_PROPERTY_CREATION_LOG_ARM = 0, + VK_DATA_GRAPH_PIPELINE_PROPERTY_IDENTIFIER_ARM = 1, + VK_DATA_GRAPH_PIPELINE_PROPERTY_NEURAL_ACCELERATOR_DEBUG_DATABASE_ARM = 1000676000, + VK_DATA_GRAPH_PIPELINE_PROPERTY_NEURAL_ACCELERATOR_STATISTICS_INFO_ARM = 1000676001, + VK_DATA_GRAPH_PIPELINE_PROPERTY_MAX_ENUM_ARM = 0x7FFFFFFF +} VkDataGraphPipelinePropertyARM; + +typedef enum VkPhysicalDeviceDataGraphProcessingEngineTypeARM { + VK_PHYSICAL_DEVICE_DATA_GRAPH_PROCESSING_ENGINE_TYPE_DEFAULT_ARM = 0, + VK_PHYSICAL_DEVICE_DATA_GRAPH_PROCESSING_ENGINE_TYPE_NEURAL_QCOM = 1000629000, + VK_PHYSICAL_DEVICE_DATA_GRAPH_PROCESSING_ENGINE_TYPE_COMPUTE_QCOM = 1000629001, + VK_PHYSICAL_DEVICE_DATA_GRAPH_PROCESSING_ENGINE_TYPE_MAX_ENUM_ARM = 0x7FFFFFFF +} VkPhysicalDeviceDataGraphProcessingEngineTypeARM; + +typedef enum VkPhysicalDeviceDataGraphOperationTypeARM { + VK_PHYSICAL_DEVICE_DATA_GRAPH_OPERATION_TYPE_SPIRV_EXTENDED_INSTRUCTION_SET_ARM = 0, + VK_PHYSICAL_DEVICE_DATA_GRAPH_OPERATION_TYPE_NEURAL_MODEL_QCOM = 1000629000, + VK_PHYSICAL_DEVICE_DATA_GRAPH_OPERATION_TYPE_BUILTIN_MODEL_QCOM = 1000629001, + VK_PHYSICAL_DEVICE_DATA_GRAPH_OPERATION_TYPE_OPTICAL_FLOW_ARM = 1000631000, + VK_PHYSICAL_DEVICE_DATA_GRAPH_OPERATION_TYPE_MAX_ENUM_ARM = 0x7FFFFFFF +} VkPhysicalDeviceDataGraphOperationTypeARM; +typedef VkFlags64 VkDataGraphPipelineSessionCreateFlagsARM; + +// Flag bits for VkDataGraphPipelineSessionCreateFlagBitsARM +typedef VkFlags64 VkDataGraphPipelineSessionCreateFlagBitsARM; +static const VkDataGraphPipelineSessionCreateFlagBitsARM VK_DATA_GRAPH_PIPELINE_SESSION_CREATE_PROTECTED_BIT_ARM = 0x00000001ULL; +static const VkDataGraphPipelineSessionCreateFlagBitsARM VK_DATA_GRAPH_PIPELINE_SESSION_CREATE_OPTICAL_FLOW_CACHE_BIT_ARM = 0x00000002ULL; + +typedef VkFlags64 VkDataGraphPipelineDispatchFlagsARM; + +// Flag bits for VkDataGraphPipelineDispatchFlagBitsARM +typedef VkFlags64 VkDataGraphPipelineDispatchFlagBitsARM; + +typedef struct VkPhysicalDeviceDataGraphFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 dataGraph; + VkBool32 dataGraphUpdateAfterBind; + VkBool32 dataGraphSpecializationConstants; + VkBool32 dataGraphDescriptorBuffer; + VkBool32 dataGraphShaderModule; +} VkPhysicalDeviceDataGraphFeaturesARM; + +typedef struct VkDataGraphPipelineConstantARM { + VkStructureType sType; + const void* pNext; + uint32_t id; + const void* pConstantData; +} VkDataGraphPipelineConstantARM; + +typedef struct VkDataGraphPipelineResourceInfoARM { + VkStructureType sType; + const void* pNext; + uint32_t descriptorSet; + uint32_t binding; + uint32_t arrayElement; +} VkDataGraphPipelineResourceInfoARM; + +typedef struct VkDataGraphPipelineCompilerControlCreateInfoARM { + VkStructureType sType; + const void* pNext; + const char* pVendorOptions; +} VkDataGraphPipelineCompilerControlCreateInfoARM; + +typedef struct VkDataGraphPipelineCreateInfoARM { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags2 flags; + VkPipelineLayout layout; + uint32_t resourceInfoCount; + const VkDataGraphPipelineResourceInfoARM* pResourceInfos; +} VkDataGraphPipelineCreateInfoARM; + +typedef struct VkDataGraphPipelineShaderModuleCreateInfoARM { + VkStructureType sType; + const void* pNext; + VkShaderModule module; + const char* pName; + const VkSpecializationInfo* pSpecializationInfo; + uint32_t constantCount; + const VkDataGraphPipelineConstantARM* pConstants; +} VkDataGraphPipelineShaderModuleCreateInfoARM; + +typedef struct VkDataGraphPipelineSessionCreateInfoARM { + VkStructureType sType; + const void* pNext; + VkDataGraphPipelineSessionCreateFlagsARM flags; + VkPipeline dataGraphPipeline; +} VkDataGraphPipelineSessionCreateInfoARM; + +typedef struct VkDataGraphPipelineSessionBindPointRequirementsInfoARM { + VkStructureType sType; + const void* pNext; + VkDataGraphPipelineSessionARM session; +} VkDataGraphPipelineSessionBindPointRequirementsInfoARM; + +typedef struct VkDataGraphPipelineSessionBindPointRequirementARM { + VkStructureType sType; + void* pNext; + VkDataGraphPipelineSessionBindPointARM bindPoint; + VkDataGraphPipelineSessionBindPointTypeARM bindPointType; + uint32_t numObjects; +} VkDataGraphPipelineSessionBindPointRequirementARM; + +typedef struct VkDataGraphPipelineSessionMemoryRequirementsInfoARM { + VkStructureType sType; + const void* pNext; + VkDataGraphPipelineSessionARM session; + VkDataGraphPipelineSessionBindPointARM bindPoint; + uint32_t objectIndex; +} VkDataGraphPipelineSessionMemoryRequirementsInfoARM; + +typedef struct VkBindDataGraphPipelineSessionMemoryInfoARM { + VkStructureType sType; + const void* pNext; + VkDataGraphPipelineSessionARM session; + VkDataGraphPipelineSessionBindPointARM bindPoint; + uint32_t objectIndex; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; +} VkBindDataGraphPipelineSessionMemoryInfoARM; + +typedef struct VkDataGraphPipelineInfoARM { + VkStructureType sType; + const void* pNext; + VkPipeline dataGraphPipeline; +} VkDataGraphPipelineInfoARM; + +typedef struct VkDataGraphPipelinePropertyQueryResultARM { + VkStructureType sType; + void* pNext; + VkDataGraphPipelinePropertyARM property; + VkBool32 isText; + size_t dataSize; + void* pData; +} VkDataGraphPipelinePropertyQueryResultARM; + +typedef struct VkDataGraphPipelineIdentifierCreateInfoARM { + VkStructureType sType; + const void* pNext; + uint32_t identifierSize; + const uint8_t* pIdentifier; +} VkDataGraphPipelineIdentifierCreateInfoARM; + +typedef struct VkDataGraphPipelineDispatchInfoARM { + VkStructureType sType; + void* pNext; + VkDataGraphPipelineDispatchFlagsARM flags; +} VkDataGraphPipelineDispatchInfoARM; + +typedef struct VkPhysicalDeviceDataGraphProcessingEngineARM { + VkPhysicalDeviceDataGraphProcessingEngineTypeARM type; + VkBool32 isForeign; +} VkPhysicalDeviceDataGraphProcessingEngineARM; + +typedef struct VkPhysicalDeviceDataGraphOperationSupportARM { + VkPhysicalDeviceDataGraphOperationTypeARM operationType; + char name[VK_MAX_PHYSICAL_DEVICE_DATA_GRAPH_OPERATION_SET_NAME_SIZE_ARM]; + uint32_t version; +} VkPhysicalDeviceDataGraphOperationSupportARM; + +typedef struct VkQueueFamilyDataGraphPropertiesARM { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceDataGraphProcessingEngineARM engine; + VkPhysicalDeviceDataGraphOperationSupportARM operation; +} VkQueueFamilyDataGraphPropertiesARM; + +typedef struct VkDataGraphProcessingEngineCreateInfoARM { + VkStructureType sType; + const void* pNext; + uint32_t processingEngineCount; + VkPhysicalDeviceDataGraphProcessingEngineARM* pProcessingEngines; +} VkDataGraphProcessingEngineCreateInfoARM; + +typedef struct VkPhysicalDeviceQueueFamilyDataGraphProcessingEngineInfoARM { + VkStructureType sType; + const void* pNext; + uint32_t queueFamilyIndex; + VkPhysicalDeviceDataGraphProcessingEngineTypeARM engineType; +} VkPhysicalDeviceQueueFamilyDataGraphProcessingEngineInfoARM; + +typedef struct VkQueueFamilyDataGraphProcessingEnginePropertiesARM { + VkStructureType sType; + void* pNext; + VkExternalSemaphoreHandleTypeFlags foreignSemaphoreHandleTypes; + VkExternalMemoryHandleTypeFlags foreignMemoryHandleTypes; +} VkQueueFamilyDataGraphProcessingEnginePropertiesARM; + +typedef struct VkDataGraphPipelineConstantTensorSemiStructuredSparsityInfoARM { + VkStructureType sType; + const void* pNext; + uint32_t dimension; + uint32_t zeroCount; + uint32_t groupSize; +} VkDataGraphPipelineConstantTensorSemiStructuredSparsityInfoARM; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateDataGraphPipelinesARM)(VkDevice device, VkDeferredOperationKHR deferredOperation, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkDataGraphPipelineCreateInfoARM* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDataGraphPipelineSessionARM)(VkDevice device, const VkDataGraphPipelineSessionCreateInfoARM* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDataGraphPipelineSessionARM* pSession); +typedef VkResult (VKAPI_PTR *PFN_vkGetDataGraphPipelineSessionBindPointRequirementsARM)(VkDevice device, const VkDataGraphPipelineSessionBindPointRequirementsInfoARM* pInfo, uint32_t* pBindPointRequirementCount, VkDataGraphPipelineSessionBindPointRequirementARM* pBindPointRequirements); +typedef void (VKAPI_PTR *PFN_vkGetDataGraphPipelineSessionMemoryRequirementsARM)(VkDevice device, const VkDataGraphPipelineSessionMemoryRequirementsInfoARM* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef VkResult (VKAPI_PTR *PFN_vkBindDataGraphPipelineSessionMemoryARM)(VkDevice device, uint32_t bindInfoCount, const VkBindDataGraphPipelineSessionMemoryInfoARM* pBindInfos); +typedef void (VKAPI_PTR *PFN_vkDestroyDataGraphPipelineSessionARM)(VkDevice device, VkDataGraphPipelineSessionARM session, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchDataGraphARM)(VkCommandBuffer commandBuffer, VkDataGraphPipelineSessionARM session, const VkDataGraphPipelineDispatchInfoARM* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetDataGraphPipelineAvailablePropertiesARM)(VkDevice device, const VkDataGraphPipelineInfoARM* pPipelineInfo, uint32_t* pPropertiesCount, VkDataGraphPipelinePropertyARM* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetDataGraphPipelinePropertiesARM)(VkDevice device, const VkDataGraphPipelineInfoARM* pPipelineInfo, uint32_t propertiesCount, VkDataGraphPipelinePropertyQueryResultARM* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, uint32_t* pQueueFamilyDataGraphPropertyCount, VkQueueFamilyDataGraphPropertiesARM* pQueueFamilyDataGraphProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyDataGraphProcessingEnginePropertiesARM)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceQueueFamilyDataGraphProcessingEngineInfoARM* pQueueFamilyDataGraphProcessingEngineInfo, VkQueueFamilyDataGraphProcessingEnginePropertiesARM* pQueueFamilyDataGraphProcessingEngineProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDataGraphPipelinesARM( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkDataGraphPipelineCreateInfoARM* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDataGraphPipelineSessionARM( + VkDevice device, + const VkDataGraphPipelineSessionCreateInfoARM* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDataGraphPipelineSessionARM* pSession); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDataGraphPipelineSessionBindPointRequirementsARM( + VkDevice device, + const VkDataGraphPipelineSessionBindPointRequirementsInfoARM* pInfo, + uint32_t* pBindPointRequirementCount, + VkDataGraphPipelineSessionBindPointRequirementARM* pBindPointRequirements); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDataGraphPipelineSessionMemoryRequirementsARM( + VkDevice device, + const VkDataGraphPipelineSessionMemoryRequirementsInfoARM* pInfo, + VkMemoryRequirements2* pMemoryRequirements); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkBindDataGraphPipelineSessionMemoryARM( + VkDevice device, + uint32_t bindInfoCount, + const VkBindDataGraphPipelineSessionMemoryInfoARM* pBindInfos); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyDataGraphPipelineSessionARM( + VkDevice device, + VkDataGraphPipelineSessionARM session, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchDataGraphARM( + VkCommandBuffer commandBuffer, + VkDataGraphPipelineSessionARM session, + const VkDataGraphPipelineDispatchInfoARM* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDataGraphPipelineAvailablePropertiesARM( + VkDevice device, + const VkDataGraphPipelineInfoARM* pPipelineInfo, + uint32_t* pPropertiesCount, + VkDataGraphPipelinePropertyARM* pProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDataGraphPipelinePropertiesARM( + VkDevice device, + const VkDataGraphPipelineInfoARM* pPipelineInfo, + uint32_t propertiesCount, + VkDataGraphPipelinePropertyQueryResultARM* pProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + uint32_t* pQueueFamilyDataGraphPropertyCount, + VkQueueFamilyDataGraphPropertiesARM* pQueueFamilyDataGraphProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyDataGraphProcessingEnginePropertiesARM( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceQueueFamilyDataGraphProcessingEngineInfoARM* pQueueFamilyDataGraphProcessingEngineInfo, + VkQueueFamilyDataGraphProcessingEnginePropertiesARM* pQueueFamilyDataGraphProcessingEngineProperties); +#endif +#endif + + +// VK_ARM_data_graph_instruction_set_tosa is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_data_graph_instruction_set_tosa 1 +#define VK_MAX_DATA_GRAPH_TOSA_NAME_SIZE_ARM 128U +#define VK_ARM_DATA_GRAPH_INSTRUCTION_SET_TOSA_SPEC_VERSION 1 +#define VK_ARM_DATA_GRAPH_INSTRUCTION_SET_TOSA_EXTENSION_NAME "VK_ARM_data_graph_instruction_set_tosa" + +typedef enum VkDataGraphTOSALevelARM { + VK_DATA_GRAPH_TOSA_LEVEL_NONE_ARM = 0, + VK_DATA_GRAPH_TOSA_LEVEL_8K_ARM = 1, + VK_DATA_GRAPH_TOSALEVEL_MAX_ENUM_ARM = 0x7FFFFFFF +} VkDataGraphTOSALevelARM; + +typedef enum VkDataGraphTOSAQualityFlagBitsARM { + VK_DATA_GRAPH_TOSA_QUALITY_ACCELERATED_ARM = 0x00000001, + VK_DATA_GRAPH_TOSA_QUALITY_CONFORMANT_ARM = 0x00000002, + VK_DATA_GRAPH_TOSA_QUALITY_EXPERIMENTAL_ARM = 0x00000004, + VK_DATA_GRAPH_TOSA_QUALITY_DEPRECATED_ARM = 0x00000008, + VK_DATA_GRAPH_TOSAQUALITY_FLAG_BITS_MAX_ENUM_ARM = 0x7FFFFFFF +} VkDataGraphTOSAQualityFlagBitsARM; +typedef VkFlags VkDataGraphTOSAQualityFlagsARM; +typedef struct VkDataGraphTOSANameQualityARM { + char name[VK_MAX_DATA_GRAPH_TOSA_NAME_SIZE_ARM]; + VkDataGraphTOSAQualityFlagsARM qualityFlags; +} VkDataGraphTOSANameQualityARM; + +typedef struct VkQueueFamilyDataGraphTOSAPropertiesARM { + VkStructureType sType; + void* pNext; + uint32_t profileCount; + const VkDataGraphTOSANameQualityARM* pProfiles; + uint32_t extensionCount; + const VkDataGraphTOSANameQualityARM* pExtensions; + VkDataGraphTOSALevelARM level; +} VkQueueFamilyDataGraphTOSAPropertiesARM; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, const VkQueueFamilyDataGraphPropertiesARM* pQueueFamilyDataGraphProperties, VkBaseOutStructure* pProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + const VkQueueFamilyDataGraphPropertiesARM* pQueueFamilyDataGraphProperties, + VkBaseOutStructure* pProperties); +#endif +#endif + + +// VK_QCOM_multiview_per_view_render_areas is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_multiview_per_view_render_areas 1 +#define VK_QCOM_MULTIVIEW_PER_VIEW_RENDER_AREAS_SPEC_VERSION 1 +#define VK_QCOM_MULTIVIEW_PER_VIEW_RENDER_AREAS_EXTENSION_NAME "VK_QCOM_multiview_per_view_render_areas" +typedef struct VkPhysicalDeviceMultiviewPerViewRenderAreasFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 multiviewPerViewRenderAreas; +} VkPhysicalDeviceMultiviewPerViewRenderAreasFeaturesQCOM; + +typedef struct VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM { + VkStructureType sType; + const void* pNext; + uint32_t perViewRenderAreaCount; + const VkRect2D* pPerViewRenderAreas; +} VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM; + + + +// VK_NV_per_stage_descriptor_set is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_per_stage_descriptor_set 1 +#define VK_NV_PER_STAGE_DESCRIPTOR_SET_SPEC_VERSION 1 +#define VK_NV_PER_STAGE_DESCRIPTOR_SET_EXTENSION_NAME "VK_NV_per_stage_descriptor_set" +typedef struct VkPhysicalDevicePerStageDescriptorSetFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 perStageDescriptorSet; + VkBool32 dynamicPipelineLayout; +} VkPhysicalDevicePerStageDescriptorSetFeaturesNV; + + + +// VK_QCOM_image_processing2 is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_image_processing2 1 +#define VK_QCOM_IMAGE_PROCESSING_2_SPEC_VERSION 1 +#define VK_QCOM_IMAGE_PROCESSING_2_EXTENSION_NAME "VK_QCOM_image_processing2" + +typedef enum VkBlockMatchWindowCompareModeQCOM { + VK_BLOCK_MATCH_WINDOW_COMPARE_MODE_MIN_QCOM = 0, + VK_BLOCK_MATCH_WINDOW_COMPARE_MODE_MAX_QCOM = 1, + VK_BLOCK_MATCH_WINDOW_COMPARE_MODE_MAX_ENUM_QCOM = 0x7FFFFFFF +} VkBlockMatchWindowCompareModeQCOM; +typedef struct VkPhysicalDeviceImageProcessing2FeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 textureBlockMatch2; +} VkPhysicalDeviceImageProcessing2FeaturesQCOM; + +typedef struct VkPhysicalDeviceImageProcessing2PropertiesQCOM { + VkStructureType sType; + void* pNext; + VkExtent2D maxBlockMatchWindow; +} VkPhysicalDeviceImageProcessing2PropertiesQCOM; + +typedef struct VkSamplerBlockMatchWindowCreateInfoQCOM { + VkStructureType sType; + const void* pNext; + VkExtent2D windowExtent; + VkBlockMatchWindowCompareModeQCOM windowCompareMode; +} VkSamplerBlockMatchWindowCreateInfoQCOM; + + + +// VK_QCOM_filter_cubic_weights is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_filter_cubic_weights 1 +#define VK_QCOM_FILTER_CUBIC_WEIGHTS_SPEC_VERSION 1 +#define VK_QCOM_FILTER_CUBIC_WEIGHTS_EXTENSION_NAME "VK_QCOM_filter_cubic_weights" + +typedef enum VkCubicFilterWeightsQCOM { + VK_CUBIC_FILTER_WEIGHTS_CATMULL_ROM_QCOM = 0, + VK_CUBIC_FILTER_WEIGHTS_ZERO_TANGENT_CARDINAL_QCOM = 1, + VK_CUBIC_FILTER_WEIGHTS_B_SPLINE_QCOM = 2, + VK_CUBIC_FILTER_WEIGHTS_MITCHELL_NETRAVALI_QCOM = 3, + VK_CUBIC_FILTER_WEIGHTS_MAX_ENUM_QCOM = 0x7FFFFFFF +} VkCubicFilterWeightsQCOM; +typedef struct VkPhysicalDeviceCubicWeightsFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 selectableCubicWeights; +} VkPhysicalDeviceCubicWeightsFeaturesQCOM; + +typedef struct VkSamplerCubicWeightsCreateInfoQCOM { + VkStructureType sType; + const void* pNext; + VkCubicFilterWeightsQCOM cubicWeights; +} VkSamplerCubicWeightsCreateInfoQCOM; + +typedef struct VkBlitImageCubicWeightsInfoQCOM { + VkStructureType sType; + const void* pNext; + VkCubicFilterWeightsQCOM cubicWeights; +} VkBlitImageCubicWeightsInfoQCOM; + + + +// VK_QCOM_ycbcr_degamma is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_ycbcr_degamma 1 +#define VK_QCOM_YCBCR_DEGAMMA_SPEC_VERSION 1 +#define VK_QCOM_YCBCR_DEGAMMA_EXTENSION_NAME "VK_QCOM_ycbcr_degamma" +typedef struct VkPhysicalDeviceYcbcrDegammaFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 ycbcrDegamma; +} VkPhysicalDeviceYcbcrDegammaFeaturesQCOM; + +typedef struct VkSamplerYcbcrConversionYcbcrDegammaCreateInfoQCOM { + VkStructureType sType; + void* pNext; + VkBool32 enableYDegamma; + VkBool32 enableCbCrDegamma; +} VkSamplerYcbcrConversionYcbcrDegammaCreateInfoQCOM; + + + +// VK_QCOM_filter_cubic_clamp is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_filter_cubic_clamp 1 +#define VK_QCOM_FILTER_CUBIC_CLAMP_SPEC_VERSION 1 +#define VK_QCOM_FILTER_CUBIC_CLAMP_EXTENSION_NAME "VK_QCOM_filter_cubic_clamp" +typedef struct VkPhysicalDeviceCubicClampFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 cubicRangeClamp; +} VkPhysicalDeviceCubicClampFeaturesQCOM; + + + +// VK_EXT_attachment_feedback_loop_dynamic_state is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_attachment_feedback_loop_dynamic_state 1 +#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_SPEC_VERSION 1 +#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_EXTENSION_NAME "VK_EXT_attachment_feedback_loop_dynamic_state" +typedef struct VkPhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 attachmentFeedbackLoopDynamicState; +} VkPhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetAttachmentFeedbackLoopEnableEXT)(VkCommandBuffer commandBuffer, VkImageAspectFlags aspectMask); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetAttachmentFeedbackLoopEnableEXT( + VkCommandBuffer commandBuffer, + VkImageAspectFlags aspectMask); +#endif +#endif + + +// VK_MSFT_layered_driver is a preprocessor guard. Do not pass it to API calls. +#define VK_MSFT_layered_driver 1 +#define VK_MSFT_LAYERED_DRIVER_SPEC_VERSION 1 +#define VK_MSFT_LAYERED_DRIVER_EXTENSION_NAME "VK_MSFT_layered_driver" + +typedef enum VkLayeredDriverUnderlyingApiMSFT { + VK_LAYERED_DRIVER_UNDERLYING_API_NONE_MSFT = 0, + VK_LAYERED_DRIVER_UNDERLYING_API_D3D12_MSFT = 1, + VK_LAYERED_DRIVER_UNDERLYING_API_MAX_ENUM_MSFT = 0x7FFFFFFF +} VkLayeredDriverUnderlyingApiMSFT; +typedef struct VkPhysicalDeviceLayeredDriverPropertiesMSFT { + VkStructureType sType; + void* pNext; + VkLayeredDriverUnderlyingApiMSFT underlyingAPI; +} VkPhysicalDeviceLayeredDriverPropertiesMSFT; + + + +// VK_NV_descriptor_pool_overallocation is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_descriptor_pool_overallocation 1 +#define VK_NV_DESCRIPTOR_POOL_OVERALLOCATION_SPEC_VERSION 1 +#define VK_NV_DESCRIPTOR_POOL_OVERALLOCATION_EXTENSION_NAME "VK_NV_descriptor_pool_overallocation" +typedef struct VkPhysicalDeviceDescriptorPoolOverallocationFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 descriptorPoolOverallocation; +} VkPhysicalDeviceDescriptorPoolOverallocationFeaturesNV; + + + +// VK_QCOM_tile_memory_heap is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_tile_memory_heap 1 +#define VK_QCOM_TILE_MEMORY_HEAP_SPEC_VERSION 1 +#define VK_QCOM_TILE_MEMORY_HEAP_EXTENSION_NAME "VK_QCOM_tile_memory_heap" +typedef struct VkPhysicalDeviceTileMemoryHeapFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 tileMemoryHeap; +} VkPhysicalDeviceTileMemoryHeapFeaturesQCOM; + +typedef struct VkPhysicalDeviceTileMemoryHeapPropertiesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 queueSubmitBoundary; + VkBool32 tileBufferTransfers; +} VkPhysicalDeviceTileMemoryHeapPropertiesQCOM; + +typedef struct VkTileMemoryRequirementsQCOM { + VkStructureType sType; + void* pNext; + VkDeviceSize size; + VkDeviceSize alignment; +} VkTileMemoryRequirementsQCOM; + +typedef struct VkTileMemoryBindInfoQCOM { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; +} VkTileMemoryBindInfoQCOM; + +typedef struct VkTileMemorySizeInfoQCOM { + VkStructureType sType; + const void* pNext; + VkDeviceSize size; +} VkTileMemorySizeInfoQCOM; + +typedef void (VKAPI_PTR *PFN_vkCmdBindTileMemoryQCOM)(VkCommandBuffer commandBuffer, const VkTileMemoryBindInfoQCOM* pTileMemoryBindInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindTileMemoryQCOM( + VkCommandBuffer commandBuffer, + const VkTileMemoryBindInfoQCOM* pTileMemoryBindInfo); +#endif +#endif + + +// VK_EXT_memory_decompression is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_memory_decompression 1 +#define VK_EXT_MEMORY_DECOMPRESSION_SPEC_VERSION 1 +#define VK_EXT_MEMORY_DECOMPRESSION_EXTENSION_NAME "VK_EXT_memory_decompression" +typedef struct VkDecompressMemoryRegionEXT { + VkDeviceAddress srcAddress; + VkDeviceAddress dstAddress; + VkDeviceSize compressedSize; + VkDeviceSize decompressedSize; +} VkDecompressMemoryRegionEXT; + +typedef struct VkDecompressMemoryInfoEXT { + VkStructureType sType; + const void* pNext; + VkMemoryDecompressionMethodFlagsEXT decompressionMethod; + uint32_t regionCount; + const VkDecompressMemoryRegionEXT* pRegions; +} VkDecompressMemoryInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdDecompressMemoryEXT)(VkCommandBuffer commandBuffer, const VkDecompressMemoryInfoEXT* pDecompressMemoryInfoEXT); +typedef void (VKAPI_PTR *PFN_vkCmdDecompressMemoryIndirectCountEXT)(VkCommandBuffer commandBuffer, VkMemoryDecompressionMethodFlagsEXT decompressionMethod, VkDeviceAddress indirectCommandsAddress, VkDeviceAddress indirectCommandsCountAddress, uint32_t maxDecompressionCount, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDecompressMemoryEXT( + VkCommandBuffer commandBuffer, + const VkDecompressMemoryInfoEXT* pDecompressMemoryInfoEXT); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDecompressMemoryIndirectCountEXT( + VkCommandBuffer commandBuffer, + VkMemoryDecompressionMethodFlagsEXT decompressionMethod, + VkDeviceAddress indirectCommandsAddress, + VkDeviceAddress indirectCommandsCountAddress, + uint32_t maxDecompressionCount, + uint32_t stride); +#endif +#endif + + +// VK_NV_display_stereo is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_display_stereo 1 +#define VK_NV_DISPLAY_STEREO_SPEC_VERSION 1 +#define VK_NV_DISPLAY_STEREO_EXTENSION_NAME "VK_NV_display_stereo" + +typedef enum VkDisplaySurfaceStereoTypeNV { + VK_DISPLAY_SURFACE_STEREO_TYPE_NONE_NV = 0, + VK_DISPLAY_SURFACE_STEREO_TYPE_ONBOARD_DIN_NV = 1, + VK_DISPLAY_SURFACE_STEREO_TYPE_HDMI_3D_NV = 2, + VK_DISPLAY_SURFACE_STEREO_TYPE_INBAND_DISPLAYPORT_NV = 3, + VK_DISPLAY_SURFACE_STEREO_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkDisplaySurfaceStereoTypeNV; +typedef struct VkDisplaySurfaceStereoCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkDisplaySurfaceStereoTypeNV stereoType; +} VkDisplaySurfaceStereoCreateInfoNV; + +typedef struct VkDisplayModeStereoPropertiesNV { + VkStructureType sType; + void* pNext; + VkBool32 hdmi3DSupported; +} VkDisplayModeStereoPropertiesNV; + + + +// VK_NV_raw_access_chains is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_raw_access_chains 1 +#define VK_NV_RAW_ACCESS_CHAINS_SPEC_VERSION 1 +#define VK_NV_RAW_ACCESS_CHAINS_EXTENSION_NAME "VK_NV_raw_access_chains" +typedef struct VkPhysicalDeviceRawAccessChainsFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 shaderRawAccessChains; +} VkPhysicalDeviceRawAccessChainsFeaturesNV; + + + +// VK_NV_external_compute_queue is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_external_compute_queue 1 +VK_DEFINE_HANDLE(VkExternalComputeQueueNV) +#define VK_NV_EXTERNAL_COMPUTE_QUEUE_SPEC_VERSION 1 +#define VK_NV_EXTERNAL_COMPUTE_QUEUE_EXTENSION_NAME "VK_NV_external_compute_queue" +typedef struct VkExternalComputeQueueDeviceCreateInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t reservedExternalQueues; +} VkExternalComputeQueueDeviceCreateInfoNV; + +typedef struct VkExternalComputeQueueCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkQueue preferredQueue; +} VkExternalComputeQueueCreateInfoNV; + +typedef struct VkExternalComputeQueueDataParamsNV { + VkStructureType sType; + const void* pNext; + uint32_t deviceIndex; +} VkExternalComputeQueueDataParamsNV; + +typedef struct VkPhysicalDeviceExternalComputeQueuePropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t externalDataSize; + uint32_t maxExternalQueues; +} VkPhysicalDeviceExternalComputeQueuePropertiesNV; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateExternalComputeQueueNV)(VkDevice device, const VkExternalComputeQueueCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkExternalComputeQueueNV* pExternalQueue); +typedef void (VKAPI_PTR *PFN_vkDestroyExternalComputeQueueNV)(VkDevice device, VkExternalComputeQueueNV externalQueue, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetExternalComputeQueueDataNV)(VkExternalComputeQueueNV externalQueue, VkExternalComputeQueueDataParamsNV* params, void* pData); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateExternalComputeQueueNV( + VkDevice device, + const VkExternalComputeQueueCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkExternalComputeQueueNV* pExternalQueue); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyExternalComputeQueueNV( + VkDevice device, + VkExternalComputeQueueNV externalQueue, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetExternalComputeQueueDataNV( + VkExternalComputeQueueNV externalQueue, + VkExternalComputeQueueDataParamsNV* params, + void* pData); +#endif +#endif + + +// VK_NV_command_buffer_inheritance is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_command_buffer_inheritance 1 +#define VK_NV_COMMAND_BUFFER_INHERITANCE_SPEC_VERSION 1 +#define VK_NV_COMMAND_BUFFER_INHERITANCE_EXTENSION_NAME "VK_NV_command_buffer_inheritance" +typedef struct VkPhysicalDeviceCommandBufferInheritanceFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 commandBufferInheritance; +} VkPhysicalDeviceCommandBufferInheritanceFeaturesNV; + + + +// VK_NV_shader_atomic_float16_vector is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_shader_atomic_float16_vector 1 +#define VK_NV_SHADER_ATOMIC_FLOAT16_VECTOR_SPEC_VERSION 1 +#define VK_NV_SHADER_ATOMIC_FLOAT16_VECTOR_EXTENSION_NAME "VK_NV_shader_atomic_float16_vector" +typedef struct VkPhysicalDeviceShaderAtomicFloat16VectorFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat16VectorAtomics; +} VkPhysicalDeviceShaderAtomicFloat16VectorFeaturesNV; + + + +// VK_EXT_shader_replicated_composites is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_replicated_composites 1 +#define VK_EXT_SHADER_REPLICATED_COMPOSITES_SPEC_VERSION 1 +#define VK_EXT_SHADER_REPLICATED_COMPOSITES_EXTENSION_NAME "VK_EXT_shader_replicated_composites" +typedef struct VkPhysicalDeviceShaderReplicatedCompositesFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderReplicatedComposites; +} VkPhysicalDeviceShaderReplicatedCompositesFeaturesEXT; + + + +// VK_ARM_tensor_controls is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_tensor_controls 1 +#define VK_MAX_TENSOR_CREATE_INFO_ROLLING_BACKING_WRAP_COUNT_ARM 4U +#define VK_ARM_TENSOR_CONTROLS_SPEC_VERSION 1 +#define VK_ARM_TENSOR_CONTROLS_EXTENSION_NAME "VK_ARM_tensor_controls" +typedef struct VkTensorRollingBackingCreateInfoARM { + VkStructureType sType; + const void* pNext; + uint32_t wraps[VK_MAX_TENSOR_CREATE_INFO_ROLLING_BACKING_WRAP_COUNT_ARM]; +} VkTensorRollingBackingCreateInfoARM; + +typedef struct VkTensorExplicitTilingFormatPropertiesARM { + VkStructureType sType; + void* pNext; + VkFormatFeatureFlags2 brick16TilingTensorFeatures; + VkFormatFeatureFlags2 brick8TilingTensorFeatures; + VkFormatFeatureFlags2 brick4TilingTensorFeatures; + VkFormatFeatureFlags2 blockUTilingTensorFeatures; + VkFormatFeatureFlags2 blockU64kTilingTensorFeatures; +} VkTensorExplicitTilingFormatPropertiesARM; + + + +// VK_EXT_shader_float8 is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_float8 1 +#define VK_EXT_SHADER_FLOAT8_SPEC_VERSION 1 +#define VK_EXT_SHADER_FLOAT8_EXTENSION_NAME "VK_EXT_shader_float8" +typedef struct VkPhysicalDeviceShaderFloat8FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat8; + VkBool32 shaderFloat8CooperativeMatrix; +} VkPhysicalDeviceShaderFloat8FeaturesEXT; + + + +// VK_NV_ray_tracing_validation is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_ray_tracing_validation 1 +#define VK_NV_RAY_TRACING_VALIDATION_SPEC_VERSION 1 +#define VK_NV_RAY_TRACING_VALIDATION_EXTENSION_NAME "VK_NV_ray_tracing_validation" +typedef struct VkPhysicalDeviceRayTracingValidationFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 rayTracingValidation; +} VkPhysicalDeviceRayTracingValidationFeaturesNV; + + + +// VK_NV_cluster_acceleration_structure is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_cluster_acceleration_structure 1 +#define VK_NV_CLUSTER_ACCELERATION_STRUCTURE_SPEC_VERSION 4 +#define VK_NV_CLUSTER_ACCELERATION_STRUCTURE_EXTENSION_NAME "VK_NV_cluster_acceleration_structure" + +typedef enum VkClusterAccelerationStructureTypeNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_TYPE_CLUSTERS_BOTTOM_LEVEL_NV = 0, + VK_CLUSTER_ACCELERATION_STRUCTURE_TYPE_TRIANGLE_CLUSTER_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_TYPE_TRIANGLE_CLUSTER_TEMPLATE_NV = 2, + VK_CLUSTER_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureTypeNV; + +typedef enum VkClusterAccelerationStructureOpTypeNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_MOVE_OBJECTS_NV = 0, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_CLUSTERS_BOTTOM_LEVEL_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_NV = 2, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_TEMPLATE_NV = 3, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_INSTANTIATE_TRIANGLE_CLUSTER_NV = 4, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_GET_CLUSTER_TEMPLATE_INDICES_NV = 5, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureOpTypeNV; + +typedef enum VkClusterAccelerationStructureOpModeNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_IMPLICIT_DESTINATIONS_NV = 0, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_EXPLICIT_DESTINATIONS_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_COMPUTE_SIZES_NV = 2, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureOpModeNV; + +typedef enum VkClusterAccelerationStructureAddressResolutionFlagBitsNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_NONE_NV = 0, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_DST_IMPLICIT_DATA_BIT_NV = 0x00000001, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_SCRATCH_DATA_BIT_NV = 0x00000002, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_DST_ADDRESS_ARRAY_BIT_NV = 0x00000004, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_DST_SIZES_ARRAY_BIT_NV = 0x00000008, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_SRC_INFOS_ARRAY_BIT_NV = 0x00000010, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_SRC_INFOS_COUNT_BIT_NV = 0x00000020, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureAddressResolutionFlagBitsNV; +typedef VkFlags VkClusterAccelerationStructureAddressResolutionFlagsNV; + +typedef enum VkClusterAccelerationStructureClusterFlagBitsNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_CLUSTER_ALLOW_DISABLE_OPACITY_MICROMAPS_NV = 0x00000001, + VK_CLUSTER_ACCELERATION_STRUCTURE_CLUSTER_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureClusterFlagBitsNV; +typedef VkFlags VkClusterAccelerationStructureClusterFlagsNV; + +typedef enum VkClusterAccelerationStructureGeometryFlagBitsNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_GEOMETRY_CULL_DISABLE_BIT_NV = 0x00000001, + VK_CLUSTER_ACCELERATION_STRUCTURE_GEOMETRY_NO_DUPLICATE_ANYHIT_INVOCATION_BIT_NV = 0x00000002, + VK_CLUSTER_ACCELERATION_STRUCTURE_GEOMETRY_OPAQUE_BIT_NV = 0x00000004, + VK_CLUSTER_ACCELERATION_STRUCTURE_GEOMETRY_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureGeometryFlagBitsNV; +typedef VkFlags VkClusterAccelerationStructureGeometryFlagsNV; + +typedef enum VkClusterAccelerationStructureIndexFormatFlagBitsNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_INDEX_FORMAT_8BIT_NV = 0x00000001, + VK_CLUSTER_ACCELERATION_STRUCTURE_INDEX_FORMAT_16BIT_NV = 0x00000002, + VK_CLUSTER_ACCELERATION_STRUCTURE_INDEX_FORMAT_32BIT_NV = 0x00000004, + VK_CLUSTER_ACCELERATION_STRUCTURE_INDEX_FORMAT_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureIndexFormatFlagBitsNV; +typedef VkFlags VkClusterAccelerationStructureIndexFormatFlagsNV; +typedef struct VkPhysicalDeviceClusterAccelerationStructureFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 clusterAccelerationStructure; +} VkPhysicalDeviceClusterAccelerationStructureFeaturesNV; + +typedef struct VkPhysicalDeviceClusterAccelerationStructurePropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t maxVerticesPerCluster; + uint32_t maxTrianglesPerCluster; + uint32_t clusterScratchByteAlignment; + uint32_t clusterByteAlignment; + uint32_t clusterTemplateByteAlignment; + uint32_t clusterBottomLevelByteAlignment; + uint32_t clusterTemplateBoundsByteAlignment; + uint32_t maxClusterGeometryIndex; +} VkPhysicalDeviceClusterAccelerationStructurePropertiesNV; + +typedef struct VkClusterAccelerationStructureClustersBottomLevelInputNV { + VkStructureType sType; + void* pNext; + uint32_t maxTotalClusterCount; + uint32_t maxClusterCountPerAccelerationStructure; +} VkClusterAccelerationStructureClustersBottomLevelInputNV; + +typedef struct VkClusterAccelerationStructureTriangleClusterInputNV { + VkStructureType sType; + void* pNext; + VkFormat vertexFormat; + uint32_t maxGeometryIndexValue; + uint32_t maxClusterUniqueGeometryCount; + uint32_t maxClusterTriangleCount; + uint32_t maxClusterVertexCount; + uint32_t maxTotalTriangleCount; + uint32_t maxTotalVertexCount; + uint32_t minPositionTruncateBitCount; +} VkClusterAccelerationStructureTriangleClusterInputNV; + +typedef struct VkClusterAccelerationStructureMoveObjectsInputNV { + VkStructureType sType; + void* pNext; + VkClusterAccelerationStructureTypeNV type; + VkBool32 noMoveOverlap; + VkDeviceSize maxMovedBytes; +} VkClusterAccelerationStructureMoveObjectsInputNV; + +typedef union VkClusterAccelerationStructureOpInputNV { + VkClusterAccelerationStructureClustersBottomLevelInputNV* pClustersBottomLevel; + VkClusterAccelerationStructureTriangleClusterInputNV* pTriangleClusters; + VkClusterAccelerationStructureMoveObjectsInputNV* pMoveObjects; +} VkClusterAccelerationStructureOpInputNV; + +typedef struct VkClusterAccelerationStructureInputInfoNV { + VkStructureType sType; + void* pNext; + uint32_t maxAccelerationStructureCount; + VkBuildAccelerationStructureFlagsKHR flags; + VkClusterAccelerationStructureOpTypeNV opType; + VkClusterAccelerationStructureOpModeNV opMode; + VkClusterAccelerationStructureOpInputNV opInput; +} VkClusterAccelerationStructureInputInfoNV; + +typedef struct VkStridedDeviceAddressRegionKHR { + VkDeviceAddress deviceAddress; + VkDeviceSize stride; + VkDeviceSize size; +} VkStridedDeviceAddressRegionKHR; + +typedef struct VkClusterAccelerationStructureCommandsInfoNV { + VkStructureType sType; + void* pNext; + VkClusterAccelerationStructureInputInfoNV input; + VkDeviceAddress dstImplicitData; + VkDeviceAddress scratchData; + VkStridedDeviceAddressRegionKHR dstAddressesArray; + VkStridedDeviceAddressRegionKHR dstSizesArray; + VkStridedDeviceAddressRegionKHR srcInfosArray; + VkDeviceAddress srcInfosCount; + VkClusterAccelerationStructureAddressResolutionFlagsNV addressResolutionFlags; +} VkClusterAccelerationStructureCommandsInfoNV; + +typedef struct VkStridedDeviceAddressNV { + VkDeviceAddress startAddress; + VkDeviceSize strideInBytes; +} VkStridedDeviceAddressNV; + +typedef struct VkClusterAccelerationStructureGeometryIndexAndGeometryFlagsNV { + uint32_t geometryIndex:24; + uint32_t reserved:5; + uint32_t geometryFlags:3; +} VkClusterAccelerationStructureGeometryIndexAndGeometryFlagsNV; + +typedef struct VkClusterAccelerationStructureMoveObjectsInfoNV { + VkDeviceAddress srcAccelerationStructure; +} VkClusterAccelerationStructureMoveObjectsInfoNV; + +typedef struct VkClusterAccelerationStructureBuildClustersBottomLevelInfoNV { + uint32_t clusterReferencesCount; + uint32_t clusterReferencesStride; + VkDeviceAddress clusterReferences; +} VkClusterAccelerationStructureBuildClustersBottomLevelInfoNV; + +typedef struct VkClusterAccelerationStructureBuildTriangleClusterInfoNV { + uint32_t clusterID; + VkClusterAccelerationStructureClusterFlagsNV clusterFlags; + uint32_t triangleCount:9; + uint32_t vertexCount:9; + uint32_t positionTruncateBitCount:6; + uint32_t indexType:4; + uint32_t opacityMicromapIndexType:4; + VkClusterAccelerationStructureGeometryIndexAndGeometryFlagsNV baseGeometryIndexAndGeometryFlags; + uint16_t indexBufferStride; + uint16_t vertexBufferStride; + uint16_t geometryIndexAndFlagsBufferStride; + uint16_t opacityMicromapIndexBufferStride; + VkDeviceAddress indexBuffer; + VkDeviceAddress vertexBuffer; + VkDeviceAddress geometryIndexAndFlagsBuffer; + VkDeviceAddress opacityMicromapArray; + VkDeviceAddress opacityMicromapIndexBuffer; +} VkClusterAccelerationStructureBuildTriangleClusterInfoNV; + +typedef struct VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV { + uint32_t clusterID; + VkClusterAccelerationStructureClusterFlagsNV clusterFlags; + uint32_t triangleCount:9; + uint32_t vertexCount:9; + uint32_t positionTruncateBitCount:6; + uint32_t indexType:4; + uint32_t opacityMicromapIndexType:4; + VkClusterAccelerationStructureGeometryIndexAndGeometryFlagsNV baseGeometryIndexAndGeometryFlags; + uint16_t indexBufferStride; + uint16_t vertexBufferStride; + uint16_t geometryIndexAndFlagsBufferStride; + uint16_t opacityMicromapIndexBufferStride; + VkDeviceAddress indexBuffer; + VkDeviceAddress vertexBuffer; + VkDeviceAddress geometryIndexAndFlagsBuffer; + VkDeviceAddress opacityMicromapArray; + VkDeviceAddress opacityMicromapIndexBuffer; + VkDeviceAddress instantiationBoundingBoxLimit; +} VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV; + +typedef struct VkClusterAccelerationStructureInstantiateClusterInfoNV { + uint32_t clusterIdOffset; + uint32_t geometryIndexOffset:24; + uint32_t reserved:8; + VkDeviceAddress clusterTemplateAddress; + VkStridedDeviceAddressNV vertexBuffer; +} VkClusterAccelerationStructureInstantiateClusterInfoNV; + +typedef struct VkClusterAccelerationStructureGetTemplateIndicesInfoNV { + VkDeviceAddress clusterTemplateAddress; +} VkClusterAccelerationStructureGetTemplateIndicesInfoNV; + +typedef struct VkAccelerationStructureBuildSizesInfoKHR { + VkStructureType sType; + void* pNext; + VkDeviceSize accelerationStructureSize; + VkDeviceSize updateScratchSize; + VkDeviceSize buildScratchSize; +} VkAccelerationStructureBuildSizesInfoKHR; + +typedef struct VkRayTracingPipelineClusterAccelerationStructureCreateInfoNV { + VkStructureType sType; + void* pNext; + VkBool32 allowClusterAccelerationStructure; +} VkRayTracingPipelineClusterAccelerationStructureCreateInfoNV; + +typedef void (VKAPI_PTR *PFN_vkGetClusterAccelerationStructureBuildSizesNV)(VkDevice device, const VkClusterAccelerationStructureInputInfoNV* pInfo, VkAccelerationStructureBuildSizesInfoKHR* pSizeInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBuildClusterAccelerationStructureIndirectNV)(VkCommandBuffer commandBuffer, const VkClusterAccelerationStructureCommandsInfoNV* pCommandInfos); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetClusterAccelerationStructureBuildSizesNV( + VkDevice device, + const VkClusterAccelerationStructureInputInfoNV* pInfo, + VkAccelerationStructureBuildSizesInfoKHR* pSizeInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBuildClusterAccelerationStructureIndirectNV( + VkCommandBuffer commandBuffer, + const VkClusterAccelerationStructureCommandsInfoNV* pCommandInfos); +#endif +#endif + + +// VK_NV_partitioned_acceleration_structure is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_partitioned_acceleration_structure 1 +#define VK_NV_PARTITIONED_ACCELERATION_STRUCTURE_SPEC_VERSION 1 +#define VK_NV_PARTITIONED_ACCELERATION_STRUCTURE_EXTENSION_NAME "VK_NV_partitioned_acceleration_structure" +#define VK_PARTITIONED_ACCELERATION_STRUCTURE_PARTITION_INDEX_GLOBAL_NV (~0U) + +typedef enum VkPartitionedAccelerationStructureOpTypeNV { + VK_PARTITIONED_ACCELERATION_STRUCTURE_OP_TYPE_WRITE_INSTANCE_NV = 0, + VK_PARTITIONED_ACCELERATION_STRUCTURE_OP_TYPE_UPDATE_INSTANCE_NV = 1, + VK_PARTITIONED_ACCELERATION_STRUCTURE_OP_TYPE_WRITE_PARTITION_TRANSLATION_NV = 2, + VK_PARTITIONED_ACCELERATION_STRUCTURE_OP_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkPartitionedAccelerationStructureOpTypeNV; + +typedef enum VkPartitionedAccelerationStructureInstanceFlagBitsNV { + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE_BIT_NV = 0x00000001, + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FLIP_FACING_BIT_NV = 0x00000002, + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE_BIT_NV = 0x00000004, + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE_BIT_NV = 0x00000008, + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_ENABLE_EXPLICIT_BOUNDING_BOX_NV = 0x00000010, + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkPartitionedAccelerationStructureInstanceFlagBitsNV; +typedef VkFlags VkPartitionedAccelerationStructureInstanceFlagsNV; +typedef struct VkPhysicalDevicePartitionedAccelerationStructureFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 partitionedAccelerationStructure; +} VkPhysicalDevicePartitionedAccelerationStructureFeaturesNV; + +typedef struct VkPhysicalDevicePartitionedAccelerationStructurePropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t maxPartitionCount; +} VkPhysicalDevicePartitionedAccelerationStructurePropertiesNV; + +typedef struct VkPartitionedAccelerationStructureFlagsNV { + VkStructureType sType; + void* pNext; + VkBool32 enablePartitionTranslation; +} VkPartitionedAccelerationStructureFlagsNV; + +typedef struct VkBuildPartitionedAccelerationStructureIndirectCommandNV { + VkPartitionedAccelerationStructureOpTypeNV opType; + uint32_t argCount; + VkStridedDeviceAddressNV argData; +} VkBuildPartitionedAccelerationStructureIndirectCommandNV; + +typedef struct VkPartitionedAccelerationStructureWriteInstanceDataNV { + VkTransformMatrixKHR transform; + float explicitAABB[6]; + uint32_t instanceID; + uint32_t instanceMask; + uint32_t instanceContributionToHitGroupIndex; + VkPartitionedAccelerationStructureInstanceFlagsNV instanceFlags; + uint32_t instanceIndex; + uint32_t partitionIndex; + VkDeviceAddress accelerationStructure; +} VkPartitionedAccelerationStructureWriteInstanceDataNV; + +typedef struct VkPartitionedAccelerationStructureUpdateInstanceDataNV { + uint32_t instanceIndex; + uint32_t instanceContributionToHitGroupIndex; + VkDeviceAddress accelerationStructure; +} VkPartitionedAccelerationStructureUpdateInstanceDataNV; + +typedef struct VkPartitionedAccelerationStructureWritePartitionTranslationDataNV { + uint32_t partitionIndex; + float partitionTranslation[3]; +} VkPartitionedAccelerationStructureWritePartitionTranslationDataNV; + +typedef struct VkWriteDescriptorSetPartitionedAccelerationStructureNV { + VkStructureType sType; + void* pNext; + uint32_t accelerationStructureCount; + const VkDeviceAddress* pAccelerationStructures; +} VkWriteDescriptorSetPartitionedAccelerationStructureNV; + +typedef struct VkPartitionedAccelerationStructureInstancesInputNV { + VkStructureType sType; + void* pNext; + VkBuildAccelerationStructureFlagsKHR flags; + uint32_t instanceCount; + uint32_t maxInstancePerPartitionCount; + uint32_t partitionCount; + uint32_t maxInstanceInGlobalPartitionCount; +} VkPartitionedAccelerationStructureInstancesInputNV; + +typedef struct VkBuildPartitionedAccelerationStructureInfoNV { + VkStructureType sType; + void* pNext; + VkPartitionedAccelerationStructureInstancesInputNV input; + VkDeviceAddress srcAccelerationStructureData; + VkDeviceAddress dstAccelerationStructureData; + VkDeviceAddress scratchData; + VkDeviceAddress srcInfos; + VkDeviceAddress srcInfosCount; +} VkBuildPartitionedAccelerationStructureInfoNV; + +typedef void (VKAPI_PTR *PFN_vkGetPartitionedAccelerationStructuresBuildSizesNV)(VkDevice device, const VkPartitionedAccelerationStructureInstancesInputNV* pInfo, VkAccelerationStructureBuildSizesInfoKHR* pSizeInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBuildPartitionedAccelerationStructuresNV)(VkCommandBuffer commandBuffer, const VkBuildPartitionedAccelerationStructureInfoNV* pBuildInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPartitionedAccelerationStructuresBuildSizesNV( + VkDevice device, + const VkPartitionedAccelerationStructureInstancesInputNV* pInfo, + VkAccelerationStructureBuildSizesInfoKHR* pSizeInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBuildPartitionedAccelerationStructuresNV( + VkCommandBuffer commandBuffer, + const VkBuildPartitionedAccelerationStructureInfoNV* pBuildInfo); +#endif +#endif + + +// VK_EXT_device_generated_commands is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_device_generated_commands 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectExecutionSetEXT) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutEXT) +#define VK_EXT_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 1 +#define VK_EXT_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_EXT_device_generated_commands" + +typedef enum VkIndirectExecutionSetInfoTypeEXT { + VK_INDIRECT_EXECUTION_SET_INFO_TYPE_PIPELINES_EXT = 0, + VK_INDIRECT_EXECUTION_SET_INFO_TYPE_SHADER_OBJECTS_EXT = 1, + VK_INDIRECT_EXECUTION_SET_INFO_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkIndirectExecutionSetInfoTypeEXT; + +typedef enum VkIndirectCommandsTokenTypeEXT { + VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT = 0, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_EXT = 1, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_SEQUENCE_INDEX_EXT = 2, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_EXT = 3, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_EXT = 4, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_EXT = 5, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT = 6, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_COUNT_EXT = 7, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_COUNT_EXT = 8, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_EXT = 9, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_DATA_EXT = 1000135000, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_DATA_SEQUENCE_INDEX_EXT = 1000135001, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV_EXT = 1000202002, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_NV_EXT = 1000202003, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_EXT = 1000328000, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_EXT = 1000328001, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_TRACE_RAYS2_EXT = 1000386004, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkIndirectCommandsTokenTypeEXT; + +typedef enum VkIndirectCommandsInputModeFlagBitsEXT { + VK_INDIRECT_COMMANDS_INPUT_MODE_VULKAN_INDEX_BUFFER_EXT = 0x00000001, + VK_INDIRECT_COMMANDS_INPUT_MODE_DXGI_INDEX_BUFFER_EXT = 0x00000002, + VK_INDIRECT_COMMANDS_INPUT_MODE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkIndirectCommandsInputModeFlagBitsEXT; +typedef VkFlags VkIndirectCommandsInputModeFlagsEXT; + +typedef enum VkIndirectCommandsLayoutUsageFlagBitsEXT { + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_EXT = 0x00000001, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_EXT = 0x00000002, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkIndirectCommandsLayoutUsageFlagBitsEXT; +typedef VkFlags VkIndirectCommandsLayoutUsageFlagsEXT; +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 deviceGeneratedCommands; + VkBool32 dynamicGeneratedPipelineLayout; +} VkPhysicalDeviceDeviceGeneratedCommandsFeaturesEXT; + +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxIndirectPipelineCount; + uint32_t maxIndirectShaderObjectCount; + uint32_t maxIndirectSequenceCount; + uint32_t maxIndirectCommandsTokenCount; + uint32_t maxIndirectCommandsTokenOffset; + uint32_t maxIndirectCommandsIndirectStride; + VkIndirectCommandsInputModeFlagsEXT supportedIndirectCommandsInputModes; + VkShaderStageFlags supportedIndirectCommandsShaderStages; + VkShaderStageFlags supportedIndirectCommandsShaderStagesPipelineBinding; + VkShaderStageFlags supportedIndirectCommandsShaderStagesShaderBinding; + VkBool32 deviceGeneratedCommandsTransformFeedback; + VkBool32 deviceGeneratedCommandsMultiDrawIndirectCount; +} VkPhysicalDeviceDeviceGeneratedCommandsPropertiesEXT; + +typedef struct VkGeneratedCommandsMemoryRequirementsInfoEXT { + VkStructureType sType; + const void* pNext; + VkIndirectExecutionSetEXT indirectExecutionSet; + VkIndirectCommandsLayoutEXT indirectCommandsLayout; + uint32_t maxSequenceCount; + uint32_t maxDrawCount; +} VkGeneratedCommandsMemoryRequirementsInfoEXT; + +typedef struct VkIndirectExecutionSetPipelineInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipeline initialPipeline; + uint32_t maxPipelineCount; +} VkIndirectExecutionSetPipelineInfoEXT; + +typedef struct VkIndirectExecutionSetShaderLayoutInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t setLayoutCount; + const VkDescriptorSetLayout* pSetLayouts; +} VkIndirectExecutionSetShaderLayoutInfoEXT; + +typedef struct VkIndirectExecutionSetShaderInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t shaderCount; + const VkShaderEXT* pInitialShaders; + const VkIndirectExecutionSetShaderLayoutInfoEXT* pSetLayoutInfos; + uint32_t maxShaderCount; + uint32_t pushConstantRangeCount; + const VkPushConstantRange* pPushConstantRanges; +} VkIndirectExecutionSetShaderInfoEXT; + +typedef union VkIndirectExecutionSetInfoEXT { + const VkIndirectExecutionSetPipelineInfoEXT* pPipelineInfo; + const VkIndirectExecutionSetShaderInfoEXT* pShaderInfo; +} VkIndirectExecutionSetInfoEXT; + +typedef struct VkIndirectExecutionSetCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkIndirectExecutionSetInfoTypeEXT type; + VkIndirectExecutionSetInfoEXT info; +} VkIndirectExecutionSetCreateInfoEXT; + +typedef struct VkGeneratedCommandsInfoEXT { + VkStructureType sType; + const void* pNext; + VkShaderStageFlags shaderStages; + VkIndirectExecutionSetEXT indirectExecutionSet; + VkIndirectCommandsLayoutEXT indirectCommandsLayout; + VkDeviceAddress indirectAddress; + VkDeviceSize indirectAddressSize; + VkDeviceAddress preprocessAddress; + VkDeviceSize preprocessSize; + uint32_t maxSequenceCount; + VkDeviceAddress sequenceCountAddress; + uint32_t maxDrawCount; +} VkGeneratedCommandsInfoEXT; + +typedef struct VkWriteIndirectExecutionSetPipelineEXT { + VkStructureType sType; + const void* pNext; + uint32_t index; + VkPipeline pipeline; +} VkWriteIndirectExecutionSetPipelineEXT; + +typedef struct VkIndirectCommandsPushConstantTokenEXT { + VkPushConstantRange updateRange; +} VkIndirectCommandsPushConstantTokenEXT; + +typedef struct VkIndirectCommandsVertexBufferTokenEXT { + uint32_t vertexBindingUnit; +} VkIndirectCommandsVertexBufferTokenEXT; + +typedef struct VkIndirectCommandsIndexBufferTokenEXT { + VkIndirectCommandsInputModeFlagBitsEXT mode; +} VkIndirectCommandsIndexBufferTokenEXT; + +typedef struct VkIndirectCommandsExecutionSetTokenEXT { + VkIndirectExecutionSetInfoTypeEXT type; + VkShaderStageFlags shaderStages; +} VkIndirectCommandsExecutionSetTokenEXT; + +typedef union VkIndirectCommandsTokenDataEXT { + const VkIndirectCommandsPushConstantTokenEXT* pPushConstant; + const VkIndirectCommandsVertexBufferTokenEXT* pVertexBuffer; + const VkIndirectCommandsIndexBufferTokenEXT* pIndexBuffer; + const VkIndirectCommandsExecutionSetTokenEXT* pExecutionSet; +} VkIndirectCommandsTokenDataEXT; + +typedef struct VkIndirectCommandsLayoutTokenEXT { + VkStructureType sType; + const void* pNext; + VkIndirectCommandsTokenTypeEXT type; + VkIndirectCommandsTokenDataEXT data; + uint32_t offset; +} VkIndirectCommandsLayoutTokenEXT; + +typedef struct VkIndirectCommandsLayoutCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkIndirectCommandsLayoutUsageFlagsEXT flags; + VkShaderStageFlags shaderStages; + uint32_t indirectStride; + VkPipelineLayout pipelineLayout; + uint32_t tokenCount; + const VkIndirectCommandsLayoutTokenEXT* pTokens; +} VkIndirectCommandsLayoutCreateInfoEXT; + +typedef struct VkDrawIndirectCountIndirectCommandEXT { + VkDeviceAddress bufferAddress; + uint32_t stride; + uint32_t commandCount; +} VkDrawIndirectCountIndirectCommandEXT; + +typedef struct VkBindVertexBufferIndirectCommandEXT { + VkDeviceAddress bufferAddress; + uint32_t size; + uint32_t stride; +} VkBindVertexBufferIndirectCommandEXT; + +typedef struct VkBindIndexBufferIndirectCommandEXT { + VkDeviceAddress bufferAddress; + uint32_t size; + VkIndexType indexType; +} VkBindIndexBufferIndirectCommandEXT; + +typedef struct VkGeneratedCommandsPipelineInfoEXT { + VkStructureType sType; + void* pNext; + VkPipeline pipeline; +} VkGeneratedCommandsPipelineInfoEXT; + +typedef struct VkGeneratedCommandsShaderInfoEXT { + VkStructureType sType; + void* pNext; + uint32_t shaderCount; + const VkShaderEXT* pShaders; +} VkGeneratedCommandsShaderInfoEXT; + +typedef struct VkWriteIndirectExecutionSetShaderEXT { + VkStructureType sType; + const void* pNext; + uint32_t index; + VkShaderEXT shader; +} VkWriteIndirectExecutionSetShaderEXT; + +typedef void (VKAPI_PTR *PFN_vkGetGeneratedCommandsMemoryRequirementsEXT)(VkDevice device, const VkGeneratedCommandsMemoryRequirementsInfoEXT* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkCmdPreprocessGeneratedCommandsEXT)(VkCommandBuffer commandBuffer, const VkGeneratedCommandsInfoEXT* pGeneratedCommandsInfo, VkCommandBuffer stateCommandBuffer); +typedef void (VKAPI_PTR *PFN_vkCmdExecuteGeneratedCommandsEXT)(VkCommandBuffer commandBuffer, VkBool32 isPreprocessed, const VkGeneratedCommandsInfoEXT* pGeneratedCommandsInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCreateIndirectCommandsLayoutEXT)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkIndirectCommandsLayoutEXT* pIndirectCommandsLayout); +typedef void (VKAPI_PTR *PFN_vkDestroyIndirectCommandsLayoutEXT)(VkDevice device, VkIndirectCommandsLayoutEXT indirectCommandsLayout, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateIndirectExecutionSetEXT)(VkDevice device, const VkIndirectExecutionSetCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkIndirectExecutionSetEXT* pIndirectExecutionSet); +typedef void (VKAPI_PTR *PFN_vkDestroyIndirectExecutionSetEXT)(VkDevice device, VkIndirectExecutionSetEXT indirectExecutionSet, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkUpdateIndirectExecutionSetPipelineEXT)(VkDevice device, VkIndirectExecutionSetEXT indirectExecutionSet, uint32_t executionSetWriteCount, const VkWriteIndirectExecutionSetPipelineEXT* pExecutionSetWrites); +typedef void (VKAPI_PTR *PFN_vkUpdateIndirectExecutionSetShaderEXT)(VkDevice device, VkIndirectExecutionSetEXT indirectExecutionSet, uint32_t executionSetWriteCount, const VkWriteIndirectExecutionSetShaderEXT* pExecutionSetWrites); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetGeneratedCommandsMemoryRequirementsEXT( + VkDevice device, + const VkGeneratedCommandsMemoryRequirementsInfoEXT* pInfo, + VkMemoryRequirements2* pMemoryRequirements); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdPreprocessGeneratedCommandsEXT( + VkCommandBuffer commandBuffer, + const VkGeneratedCommandsInfoEXT* pGeneratedCommandsInfo, + VkCommandBuffer stateCommandBuffer); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdExecuteGeneratedCommandsEXT( + VkCommandBuffer commandBuffer, + VkBool32 isPreprocessed, + const VkGeneratedCommandsInfoEXT* pGeneratedCommandsInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateIndirectCommandsLayoutEXT( + VkDevice device, + const VkIndirectCommandsLayoutCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkIndirectCommandsLayoutEXT* pIndirectCommandsLayout); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyIndirectCommandsLayoutEXT( + VkDevice device, + VkIndirectCommandsLayoutEXT indirectCommandsLayout, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateIndirectExecutionSetEXT( + VkDevice device, + const VkIndirectExecutionSetCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkIndirectExecutionSetEXT* pIndirectExecutionSet); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyIndirectExecutionSetEXT( + VkDevice device, + VkIndirectExecutionSetEXT indirectExecutionSet, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkUpdateIndirectExecutionSetPipelineEXT( + VkDevice device, + VkIndirectExecutionSetEXT indirectExecutionSet, + uint32_t executionSetWriteCount, + const VkWriteIndirectExecutionSetPipelineEXT* pExecutionSetWrites); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkUpdateIndirectExecutionSetShaderEXT( + VkDevice device, + VkIndirectExecutionSetEXT indirectExecutionSet, + uint32_t executionSetWriteCount, + const VkWriteIndirectExecutionSetShaderEXT* pExecutionSetWrites); +#endif +#endif + + +// VK_MESA_image_alignment_control is a preprocessor guard. Do not pass it to API calls. +#define VK_MESA_image_alignment_control 1 +#define VK_MESA_IMAGE_ALIGNMENT_CONTROL_SPEC_VERSION 1 +#define VK_MESA_IMAGE_ALIGNMENT_CONTROL_EXTENSION_NAME "VK_MESA_image_alignment_control" +typedef struct VkPhysicalDeviceImageAlignmentControlFeaturesMESA { + VkStructureType sType; + void* pNext; + VkBool32 imageAlignmentControl; +} VkPhysicalDeviceImageAlignmentControlFeaturesMESA; + +typedef struct VkPhysicalDeviceImageAlignmentControlPropertiesMESA { + VkStructureType sType; + void* pNext; + uint32_t supportedImageAlignmentMask; +} VkPhysicalDeviceImageAlignmentControlPropertiesMESA; + +typedef struct VkImageAlignmentControlCreateInfoMESA { + VkStructureType sType; + const void* pNext; + uint32_t maximumRequestedAlignment; +} VkImageAlignmentControlCreateInfoMESA; + + + +// VK_NV_push_constant_bank is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_push_constant_bank 1 +#define VK_NV_PUSH_CONSTANT_BANK_SPEC_VERSION 1 +#define VK_NV_PUSH_CONSTANT_BANK_EXTENSION_NAME "VK_NV_push_constant_bank" +typedef struct VkPushConstantBankInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t bank; +} VkPushConstantBankInfoNV; + +typedef struct VkPhysicalDevicePushConstantBankFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 pushConstantBank; +} VkPhysicalDevicePushConstantBankFeaturesNV; + +typedef struct VkPhysicalDevicePushConstantBankPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t maxGraphicsPushConstantBanks; + uint32_t maxComputePushConstantBanks; + uint32_t maxGraphicsPushDataBanks; + uint32_t maxComputePushDataBanks; +} VkPhysicalDevicePushConstantBankPropertiesNV; + + + +// VK_EXT_ray_tracing_invocation_reorder is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_ray_tracing_invocation_reorder 1 +#define VK_EXT_RAY_TRACING_INVOCATION_REORDER_SPEC_VERSION 2 +#define VK_EXT_RAY_TRACING_INVOCATION_REORDER_EXTENSION_NAME "VK_EXT_ray_tracing_invocation_reorder" +typedef struct VkPhysicalDeviceRayTracingInvocationReorderPropertiesEXT { + VkStructureType sType; + void* pNext; + VkRayTracingInvocationReorderModeEXT rayTracingInvocationReorderReorderingHint; + uint32_t maxShaderBindingTableRecordIndex; +} VkPhysicalDeviceRayTracingInvocationReorderPropertiesEXT; + +typedef struct VkPhysicalDeviceRayTracingInvocationReorderFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 rayTracingInvocationReorder; +} VkPhysicalDeviceRayTracingInvocationReorderFeaturesEXT; + + + +// VK_EXT_depth_clamp_control is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_depth_clamp_control 1 +#define VK_EXT_DEPTH_CLAMP_CONTROL_SPEC_VERSION 1 +#define VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME "VK_EXT_depth_clamp_control" +typedef struct VkPhysicalDeviceDepthClampControlFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 depthClampControl; +} VkPhysicalDeviceDepthClampControlFeaturesEXT; + +typedef struct VkPipelineViewportDepthClampControlCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDepthClampModeEXT depthClampMode; + const VkDepthClampRangeEXT* pDepthClampRange; +} VkPipelineViewportDepthClampControlCreateInfoEXT; + + + +// VK_HUAWEI_hdr_vivid is a preprocessor guard. Do not pass it to API calls. +#define VK_HUAWEI_hdr_vivid 1 +#define VK_HUAWEI_HDR_VIVID_SPEC_VERSION 1 +#define VK_HUAWEI_HDR_VIVID_EXTENSION_NAME "VK_HUAWEI_hdr_vivid" +typedef struct VkPhysicalDeviceHdrVividFeaturesHUAWEI { + VkStructureType sType; + void* pNext; + VkBool32 hdrVivid; +} VkPhysicalDeviceHdrVividFeaturesHUAWEI; + +typedef struct VkHdrVividDynamicMetadataHUAWEI { + VkStructureType sType; + const void* pNext; + size_t dynamicMetadataSize; + const void* pDynamicMetadata; +} VkHdrVividDynamicMetadataHUAWEI; + + + +// VK_NV_cooperative_matrix2 is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_cooperative_matrix2 1 +#define VK_NV_COOPERATIVE_MATRIX_2_SPEC_VERSION 1 +#define VK_NV_COOPERATIVE_MATRIX_2_EXTENSION_NAME "VK_NV_cooperative_matrix2" +typedef struct VkCooperativeMatrixFlexibleDimensionsPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t MGranularity; + uint32_t NGranularity; + uint32_t KGranularity; + VkComponentTypeKHR AType; + VkComponentTypeKHR BType; + VkComponentTypeKHR CType; + VkComponentTypeKHR ResultType; + VkBool32 saturatingAccumulation; + VkScopeKHR scope; + uint32_t workgroupInvocations; +} VkCooperativeMatrixFlexibleDimensionsPropertiesNV; + +typedef struct VkPhysicalDeviceCooperativeMatrix2FeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrixWorkgroupScope; + VkBool32 cooperativeMatrixFlexibleDimensions; + VkBool32 cooperativeMatrixReductions; + VkBool32 cooperativeMatrixConversions; + VkBool32 cooperativeMatrixPerElementOperations; + VkBool32 cooperativeMatrixTensorAddressing; + VkBool32 cooperativeMatrixBlockLoads; +} VkPhysicalDeviceCooperativeMatrix2FeaturesNV; + +typedef struct VkPhysicalDeviceCooperativeMatrix2PropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t cooperativeMatrixWorkgroupScopeMaxWorkgroupSize; + uint32_t cooperativeMatrixFlexibleDimensionsMaxDimension; + uint32_t cooperativeMatrixWorkgroupScopeReservedSharedMemory; +} VkPhysicalDeviceCooperativeMatrix2PropertiesNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixFlexibleDimensionsPropertiesNV* pProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkCooperativeMatrixFlexibleDimensionsPropertiesNV* pProperties); +#endif +#endif + + +// VK_ARM_pipeline_opacity_micromap is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_pipeline_opacity_micromap 1 +#define VK_ARM_PIPELINE_OPACITY_MICROMAP_SPEC_VERSION 1 +#define VK_ARM_PIPELINE_OPACITY_MICROMAP_EXTENSION_NAME "VK_ARM_pipeline_opacity_micromap" +typedef struct VkPhysicalDevicePipelineOpacityMicromapFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 pipelineOpacityMicromap; +} VkPhysicalDevicePipelineOpacityMicromapFeaturesARM; + + + +// VK_IMG_filter_linear_2d is a preprocessor guard. Do not pass it to API calls. +#define VK_IMG_filter_linear_2d 1 +#define VK_IMG_FILTER_LINEAR_2D_SPEC_VERSION 1 +#define VK_IMG_FILTER_LINEAR_2D_EXTENSION_NAME "VK_IMG_filter_linear_2d" + + +// VK_ARM_performance_counters_by_region is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_performance_counters_by_region 1 +#define VK_ARM_PERFORMANCE_COUNTERS_BY_REGION_SPEC_VERSION 1 +#define VK_ARM_PERFORMANCE_COUNTERS_BY_REGION_EXTENSION_NAME "VK_ARM_performance_counters_by_region" +typedef VkFlags VkPerformanceCounterDescriptionFlagsARM; +typedef struct VkPhysicalDevicePerformanceCountersByRegionFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 performanceCountersByRegion; +} VkPhysicalDevicePerformanceCountersByRegionFeaturesARM; + +typedef struct VkPhysicalDevicePerformanceCountersByRegionPropertiesARM { + VkStructureType sType; + void* pNext; + uint32_t maxPerRegionPerformanceCounters; + VkExtent2D performanceCounterRegionSize; + uint32_t rowStrideAlignment; + uint32_t regionAlignment; + VkBool32 identityTransformOrder; +} VkPhysicalDevicePerformanceCountersByRegionPropertiesARM; + +typedef struct VkPerformanceCounterARM { + VkStructureType sType; + void* pNext; + uint32_t counterID; +} VkPerformanceCounterARM; + +typedef struct VkPerformanceCounterDescriptionARM { + VkStructureType sType; + void* pNext; + VkPerformanceCounterDescriptionFlagsARM flags; + char name[VK_MAX_DESCRIPTION_SIZE]; +} VkPerformanceCounterDescriptionARM; + +typedef struct VkRenderPassPerformanceCountersByRegionBeginInfoARM { + VkStructureType sType; + void* pNext; + uint32_t counterAddressCount; + const VkDeviceAddress* pCounterAddresses; + VkBool32 serializeRegions; + uint32_t counterIndexCount; + uint32_t* pCounterIndices; +} VkRenderPassPerformanceCountersByRegionBeginInfoARM; + +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceCountersByRegionARM)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, uint32_t* pCounterCount, VkPerformanceCounterARM* pCounters, VkPerformanceCounterDescriptionARM* pCounterDescriptions); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceQueueFamilyPerformanceCountersByRegionARM( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + uint32_t* pCounterCount, + VkPerformanceCounterARM* pCounters, + VkPerformanceCounterDescriptionARM* pCounterDescriptions); +#endif +#endif + + +// VK_ARM_shader_instrumentation is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_shader_instrumentation 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderInstrumentationARM) +#define VK_ARM_SHADER_INSTRUMENTATION_SPEC_VERSION 1 +#define VK_ARM_SHADER_INSTRUMENTATION_EXTENSION_NAME "VK_ARM_shader_instrumentation" +typedef VkFlags VkShaderInstrumentationValuesFlagsARM; +typedef struct VkPhysicalDeviceShaderInstrumentationFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 shaderInstrumentation; +} VkPhysicalDeviceShaderInstrumentationFeaturesARM; + +typedef struct VkPhysicalDeviceShaderInstrumentationPropertiesARM { + VkStructureType sType; + void* pNext; + uint32_t numMetrics; + VkBool32 perBasicBlockGranularity; +} VkPhysicalDeviceShaderInstrumentationPropertiesARM; + +typedef struct VkShaderInstrumentationCreateInfoARM { + VkStructureType sType; + void* pNext; +} VkShaderInstrumentationCreateInfoARM; + +typedef struct VkShaderInstrumentationMetricDescriptionARM { + VkStructureType sType; + void* pNext; + char name[VK_MAX_DESCRIPTION_SIZE]; + char description[VK_MAX_DESCRIPTION_SIZE]; +} VkShaderInstrumentationMetricDescriptionARM; + +typedef struct VkShaderInstrumentationMetricDataHeaderARM { + uint32_t resultIndex; + uint32_t resultSubIndex; + VkShaderStageFlags stages; + uint32_t basicBlockIndex; +} VkShaderInstrumentationMetricDataHeaderARM; + +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceShaderInstrumentationMetricsARM)(VkPhysicalDevice physicalDevice, uint32_t* pDescriptionCount, VkShaderInstrumentationMetricDescriptionARM* pDescriptions); +typedef VkResult (VKAPI_PTR *PFN_vkCreateShaderInstrumentationARM)(VkDevice device, const VkShaderInstrumentationCreateInfoARM* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderInstrumentationARM* pInstrumentation); +typedef void (VKAPI_PTR *PFN_vkDestroyShaderInstrumentationARM)(VkDevice device, VkShaderInstrumentationARM instrumentation, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkCmdBeginShaderInstrumentationARM)(VkCommandBuffer commandBuffer, VkShaderInstrumentationARM instrumentation); +typedef void (VKAPI_PTR *PFN_vkCmdEndShaderInstrumentationARM)(VkCommandBuffer commandBuffer); +typedef VkResult (VKAPI_PTR *PFN_vkGetShaderInstrumentationValuesARM)(VkDevice device, VkShaderInstrumentationARM instrumentation, uint32_t* pMetricBlockCount, void* pMetricValues, VkShaderInstrumentationValuesFlagsARM flags); +typedef void (VKAPI_PTR *PFN_vkClearShaderInstrumentationMetricsARM)(VkDevice device, VkShaderInstrumentationARM instrumentation); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceShaderInstrumentationMetricsARM( + VkPhysicalDevice physicalDevice, + uint32_t* pDescriptionCount, + VkShaderInstrumentationMetricDescriptionARM* pDescriptions); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderInstrumentationARM( + VkDevice device, + const VkShaderInstrumentationCreateInfoARM* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkShaderInstrumentationARM* pInstrumentation); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyShaderInstrumentationARM( + VkDevice device, + VkShaderInstrumentationARM instrumentation, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginShaderInstrumentationARM( + VkCommandBuffer commandBuffer, + VkShaderInstrumentationARM instrumentation); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdEndShaderInstrumentationARM( + VkCommandBuffer commandBuffer); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetShaderInstrumentationValuesARM( + VkDevice device, + VkShaderInstrumentationARM instrumentation, + uint32_t* pMetricBlockCount, + void* pMetricValues, + VkShaderInstrumentationValuesFlagsARM flags); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkClearShaderInstrumentationMetricsARM( + VkDevice device, + VkShaderInstrumentationARM instrumentation); +#endif +#endif + + +// VK_EXT_vertex_attribute_robustness is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_vertex_attribute_robustness 1 +#define VK_EXT_VERTEX_ATTRIBUTE_ROBUSTNESS_SPEC_VERSION 1 +#define VK_EXT_VERTEX_ATTRIBUTE_ROBUSTNESS_EXTENSION_NAME "VK_EXT_vertex_attribute_robustness" +typedef struct VkPhysicalDeviceVertexAttributeRobustnessFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 vertexAttributeRobustness; +} VkPhysicalDeviceVertexAttributeRobustnessFeaturesEXT; + + + +// VK_ARM_format_pack is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_format_pack 1 +#define VK_ARM_FORMAT_PACK_SPEC_VERSION 1 +#define VK_ARM_FORMAT_PACK_EXTENSION_NAME "VK_ARM_format_pack" +typedef struct VkPhysicalDeviceFormatPackFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 formatPack; +} VkPhysicalDeviceFormatPackFeaturesARM; + + + +// VK_VALVE_fragment_density_map_layered is a preprocessor guard. Do not pass it to API calls. +#define VK_VALVE_fragment_density_map_layered 1 +#define VK_VALVE_FRAGMENT_DENSITY_MAP_LAYERED_SPEC_VERSION 1 +#define VK_VALVE_FRAGMENT_DENSITY_MAP_LAYERED_EXTENSION_NAME "VK_VALVE_fragment_density_map_layered" +typedef struct VkPhysicalDeviceFragmentDensityMapLayeredFeaturesVALVE { + VkStructureType sType; + void* pNext; + VkBool32 fragmentDensityMapLayered; +} VkPhysicalDeviceFragmentDensityMapLayeredFeaturesVALVE; + +typedef struct VkPhysicalDeviceFragmentDensityMapLayeredPropertiesVALVE { + VkStructureType sType; + void* pNext; + uint32_t maxFragmentDensityMapLayers; +} VkPhysicalDeviceFragmentDensityMapLayeredPropertiesVALVE; + +typedef struct VkPipelineFragmentDensityMapLayeredCreateInfoVALVE { + VkStructureType sType; + const void* pNext; + uint32_t maxFragmentDensityMapLayers; +} VkPipelineFragmentDensityMapLayeredCreateInfoVALVE; + + + +// VK_NV_present_metering is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_present_metering 1 +#define VK_NV_PRESENT_METERING_SPEC_VERSION 1 +#define VK_NV_PRESENT_METERING_EXTENSION_NAME "VK_NV_present_metering" +typedef struct VkSetPresentConfigNV { + VkStructureType sType; + const void* pNext; + uint32_t numFramesPerBatch; + uint32_t presentConfigFeedback; +} VkSetPresentConfigNV; + +typedef struct VkPhysicalDevicePresentMeteringFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 presentMetering; +} VkPhysicalDevicePresentMeteringFeaturesNV; + + + +// VK_EXT_multisampled_render_to_swapchain is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_multisampled_render_to_swapchain 1 +#define VK_EXT_MULTISAMPLED_RENDER_TO_SWAPCHAIN_SPEC_VERSION 1 +#define VK_EXT_MULTISAMPLED_RENDER_TO_SWAPCHAIN_EXTENSION_NAME "VK_EXT_multisampled_render_to_swapchain" +typedef struct VkPhysicalDeviceMultisampledRenderToSwapchainFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 multisampledRenderToSwapchain; +} VkPhysicalDeviceMultisampledRenderToSwapchainFeaturesEXT; + +typedef struct VkSwapchainFlagsSurfaceCapabilitiesEXT { + VkStructureType sType; + void* pNext; + VkSwapchainCreateFlagsKHR swapchainSupportedFlags; +} VkSwapchainFlagsSurfaceCapabilitiesEXT; + + + +// VK_EXT_fragment_density_map_offset is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_fragment_density_map_offset 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_OFFSET_SPEC_VERSION 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_OFFSET_EXTENSION_NAME "VK_EXT_fragment_density_map_offset" +typedef VkRenderingEndInfoKHR VkRenderingEndInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdEndRendering2EXT)(VkCommandBuffer commandBuffer, const VkRenderingEndInfoKHR* pRenderingEndInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdEndRendering2EXT( + VkCommandBuffer commandBuffer, + const VkRenderingEndInfoKHR* pRenderingEndInfo); +#endif +#endif + + +// VK_EXT_zero_initialize_device_memory is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_zero_initialize_device_memory 1 +#define VK_EXT_ZERO_INITIALIZE_DEVICE_MEMORY_SPEC_VERSION 1 +#define VK_EXT_ZERO_INITIALIZE_DEVICE_MEMORY_EXTENSION_NAME "VK_EXT_zero_initialize_device_memory" +typedef struct VkPhysicalDeviceZeroInitializeDeviceMemoryFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 zeroInitializeDeviceMemory; +} VkPhysicalDeviceZeroInitializeDeviceMemoryFeaturesEXT; + + + +// VK_EXT_shader_64bit_indexing is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_64bit_indexing 1 +#define VK_EXT_SHADER_64BIT_INDEXING_SPEC_VERSION 1 +#define VK_EXT_SHADER_64BIT_INDEXING_EXTENSION_NAME "VK_EXT_shader_64bit_indexing" +typedef struct VkPhysicalDeviceShader64BitIndexingFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shader64BitIndexing; +} VkPhysicalDeviceShader64BitIndexingFeaturesEXT; + + + +// VK_EXT_custom_resolve is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_custom_resolve 1 +#define VK_EXT_CUSTOM_RESOLVE_SPEC_VERSION 1 +#define VK_EXT_CUSTOM_RESOLVE_EXTENSION_NAME "VK_EXT_custom_resolve" +typedef struct VkPhysicalDeviceCustomResolveFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 customResolve; +} VkPhysicalDeviceCustomResolveFeaturesEXT; + +typedef struct VkBeginCustomResolveInfoEXT { + VkStructureType sType; + void* pNext; +} VkBeginCustomResolveInfoEXT; + +typedef struct VkCustomResolveCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 customResolve; + uint32_t colorAttachmentCount; + const VkFormat* pColorAttachmentFormats; + VkFormat depthAttachmentFormat; + VkFormat stencilAttachmentFormat; +} VkCustomResolveCreateInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdBeginCustomResolveEXT)(VkCommandBuffer commandBuffer, const VkBeginCustomResolveInfoEXT* pBeginCustomResolveInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginCustomResolveEXT( + VkCommandBuffer commandBuffer, + const VkBeginCustomResolveInfoEXT* pBeginCustomResolveInfo); +#endif +#endif + + +// VK_QCOM_data_graph_model is a preprocessor guard. Do not pass it to API calls. +#define VK_QCOM_data_graph_model 1 +#define VK_DATA_GRAPH_MODEL_TOOLCHAIN_VERSION_LENGTH_QCOM 3U +#define VK_QCOM_DATA_GRAPH_MODEL_SPEC_VERSION 1 +#define VK_QCOM_DATA_GRAPH_MODEL_EXTENSION_NAME "VK_QCOM_data_graph_model" + +typedef enum VkDataGraphModelCacheTypeQCOM { + VK_DATA_GRAPH_MODEL_CACHE_TYPE_GENERIC_BINARY_QCOM = 0, + VK_DATA_GRAPH_MODEL_CACHE_TYPE_MAX_ENUM_QCOM = 0x7FFFFFFF +} VkDataGraphModelCacheTypeQCOM; +typedef struct VkPipelineCacheHeaderVersionDataGraphQCOM { + uint32_t headerSize; + VkPipelineCacheHeaderVersion headerVersion; + VkDataGraphModelCacheTypeQCOM cacheType; + uint32_t cacheVersion; + uint32_t toolchainVersion[VK_DATA_GRAPH_MODEL_TOOLCHAIN_VERSION_LENGTH_QCOM]; +} VkPipelineCacheHeaderVersionDataGraphQCOM; + +typedef struct VkDataGraphPipelineBuiltinModelCreateInfoQCOM { + VkStructureType sType; + const void* pNext; + const VkPhysicalDeviceDataGraphOperationSupportARM* pOperation; +} VkDataGraphPipelineBuiltinModelCreateInfoQCOM; + +typedef struct VkPhysicalDeviceDataGraphModelFeaturesQCOM { + VkStructureType sType; + void* pNext; + VkBool32 dataGraphModel; +} VkPhysicalDeviceDataGraphModelFeaturesQCOM; + + + +// VK_ARM_data_graph_optical_flow is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_data_graph_optical_flow 1 +#define VK_ARM_DATA_GRAPH_OPTICAL_FLOW_SPEC_VERSION 1 +#define VK_ARM_DATA_GRAPH_OPTICAL_FLOW_EXTENSION_NAME "VK_ARM_data_graph_optical_flow" + +typedef enum VkDataGraphOpticalFlowPerformanceLevelARM { + VK_DATA_GRAPH_OPTICAL_FLOW_PERFORMANCE_LEVEL_UNKNOWN_ARM = 0, + VK_DATA_GRAPH_OPTICAL_FLOW_PERFORMANCE_LEVEL_SLOW_ARM = 1, + VK_DATA_GRAPH_OPTICAL_FLOW_PERFORMANCE_LEVEL_MEDIUM_ARM = 2, + VK_DATA_GRAPH_OPTICAL_FLOW_PERFORMANCE_LEVEL_FAST_ARM = 3, + VK_DATA_GRAPH_OPTICAL_FLOW_PERFORMANCE_LEVEL_MAX_ENUM_ARM = 0x7FFFFFFF +} VkDataGraphOpticalFlowPerformanceLevelARM; + +typedef enum VkDataGraphPipelineNodeTypeARM { + VK_DATA_GRAPH_PIPELINE_NODE_TYPE_OPTICAL_FLOW_ARM = 1000631000, + VK_DATA_GRAPH_PIPELINE_NODE_TYPE_MAX_ENUM_ARM = 0x7FFFFFFF +} VkDataGraphPipelineNodeTypeARM; + +typedef enum VkDataGraphPipelineNodeConnectionTypeARM { + VK_DATA_GRAPH_PIPELINE_NODE_CONNECTION_TYPE_OPTICAL_FLOW_INPUT_ARM = 1000631000, + VK_DATA_GRAPH_PIPELINE_NODE_CONNECTION_TYPE_OPTICAL_FLOW_REFERENCE_ARM = 1000631001, + VK_DATA_GRAPH_PIPELINE_NODE_CONNECTION_TYPE_OPTICAL_FLOW_HINT_ARM = 1000631002, + VK_DATA_GRAPH_PIPELINE_NODE_CONNECTION_TYPE_OPTICAL_FLOW_FLOW_VECTOR_ARM = 1000631003, + VK_DATA_GRAPH_PIPELINE_NODE_CONNECTION_TYPE_OPTICAL_FLOW_COST_ARM = 1000631004, + VK_DATA_GRAPH_PIPELINE_NODE_CONNECTION_TYPE_MAX_ENUM_ARM = 0x7FFFFFFF +} VkDataGraphPipelineNodeConnectionTypeARM; + +typedef enum VkDataGraphOpticalFlowGridSizeFlagBitsARM { + VK_DATA_GRAPH_OPTICAL_FLOW_GRID_SIZE_UNKNOWN_ARM = 0, + VK_DATA_GRAPH_OPTICAL_FLOW_GRID_SIZE_1X1_BIT_ARM = 0x00000001, + VK_DATA_GRAPH_OPTICAL_FLOW_GRID_SIZE_2X2_BIT_ARM = 0x00000002, + VK_DATA_GRAPH_OPTICAL_FLOW_GRID_SIZE_4X4_BIT_ARM = 0x00000004, + VK_DATA_GRAPH_OPTICAL_FLOW_GRID_SIZE_8X8_BIT_ARM = 0x00000008, + VK_DATA_GRAPH_OPTICAL_FLOW_GRID_SIZE_FLAG_BITS_MAX_ENUM_ARM = 0x7FFFFFFF +} VkDataGraphOpticalFlowGridSizeFlagBitsARM; +typedef VkFlags VkDataGraphOpticalFlowGridSizeFlagsARM; + +typedef enum VkDataGraphOpticalFlowCreateFlagBitsARM { + VK_DATA_GRAPH_OPTICAL_FLOW_CREATE_ENABLE_HINT_BIT_ARM = 0x00000001, + VK_DATA_GRAPH_OPTICAL_FLOW_CREATE_ENABLE_COST_BIT_ARM = 0x00000002, + VK_DATA_GRAPH_OPTICAL_FLOW_CREATE_RESERVED_30_BIT_ARM = 0x40000000, + VK_DATA_GRAPH_OPTICAL_FLOW_CREATE_FLAG_BITS_MAX_ENUM_ARM = 0x7FFFFFFF +} VkDataGraphOpticalFlowCreateFlagBitsARM; +typedef VkFlags VkDataGraphOpticalFlowCreateFlagsARM; + +typedef enum VkDataGraphOpticalFlowImageUsageFlagBitsARM { + VK_DATA_GRAPH_OPTICAL_FLOW_IMAGE_USAGE_UNKNOWN_ARM = 0, + VK_DATA_GRAPH_OPTICAL_FLOW_IMAGE_USAGE_INPUT_BIT_ARM = 0x00000001, + VK_DATA_GRAPH_OPTICAL_FLOW_IMAGE_USAGE_OUTPUT_BIT_ARM = 0x00000002, + VK_DATA_GRAPH_OPTICAL_FLOW_IMAGE_USAGE_HINT_BIT_ARM = 0x00000004, + VK_DATA_GRAPH_OPTICAL_FLOW_IMAGE_USAGE_COST_BIT_ARM = 0x00000008, + VK_DATA_GRAPH_OPTICAL_FLOW_IMAGE_USAGE_FLAG_BITS_MAX_ENUM_ARM = 0x7FFFFFFF +} VkDataGraphOpticalFlowImageUsageFlagBitsARM; +typedef VkFlags VkDataGraphOpticalFlowImageUsageFlagsARM; + +typedef enum VkDataGraphOpticalFlowExecuteFlagBitsARM { + VK_DATA_GRAPH_OPTICAL_FLOW_EXECUTE_DISABLE_TEMPORAL_HINTS_BIT_ARM = 0x00000001, + VK_DATA_GRAPH_OPTICAL_FLOW_EXECUTE_INPUT_UNCHANGED_BIT_ARM = 0x00000002, + VK_DATA_GRAPH_OPTICAL_FLOW_EXECUTE_REFERENCE_UNCHANGED_BIT_ARM = 0x00000004, + VK_DATA_GRAPH_OPTICAL_FLOW_EXECUTE_INPUT_IS_PREVIOUS_REFERENCE_BIT_ARM = 0x00000008, + VK_DATA_GRAPH_OPTICAL_FLOW_EXECUTE_REFERENCE_IS_PREVIOUS_INPUT_BIT_ARM = 0x00000010, + VK_DATA_GRAPH_OPTICAL_FLOW_EXECUTE_FLAG_BITS_MAX_ENUM_ARM = 0x7FFFFFFF +} VkDataGraphOpticalFlowExecuteFlagBitsARM; +typedef VkFlags VkDataGraphOpticalFlowExecuteFlagsARM; +typedef struct VkPhysicalDeviceDataGraphOpticalFlowFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 dataGraphOpticalFlow; +} VkPhysicalDeviceDataGraphOpticalFlowFeaturesARM; + +typedef struct VkQueueFamilyDataGraphOpticalFlowPropertiesARM { + VkStructureType sType; + void* pNext; + VkDataGraphOpticalFlowGridSizeFlagsARM supportedOutputGridSizes; + VkDataGraphOpticalFlowGridSizeFlagsARM supportedHintGridSizes; + VkBool32 hintSupported; + VkBool32 costSupported; + uint32_t minWidth; + uint32_t minHeight; + uint32_t maxWidth; + uint32_t maxHeight; +} VkQueueFamilyDataGraphOpticalFlowPropertiesARM; + +typedef struct VkDataGraphPipelineOpticalFlowCreateInfoARM { + VkStructureType sType; + void* pNext; + uint32_t width; + uint32_t height; + VkFormat imageFormat; + VkFormat flowVectorFormat; + VkFormat costFormat; + VkDataGraphOpticalFlowGridSizeFlagsARM outputGridSize; + VkDataGraphOpticalFlowGridSizeFlagsARM hintGridSize; + VkDataGraphOpticalFlowPerformanceLevelARM performanceLevel; + VkDataGraphOpticalFlowCreateFlagsARM flags; +} VkDataGraphPipelineOpticalFlowCreateInfoARM; + +typedef struct VkDataGraphOpticalFlowImageFormatPropertiesARM { + VkStructureType sType; + void* pNext; + VkFormat format; +} VkDataGraphOpticalFlowImageFormatPropertiesARM; + +typedef struct VkDataGraphOpticalFlowImageFormatInfoARM { + VkStructureType sType; + const void* pNext; + VkDataGraphOpticalFlowImageUsageFlagsARM usage; +} VkDataGraphOpticalFlowImageFormatInfoARM; + +typedef struct VkDataGraphPipelineOpticalFlowDispatchInfoARM { + VkStructureType sType; + void* pNext; + VkDataGraphOpticalFlowExecuteFlagsARM flags; + uint32_t meanFlowL1NormHint; +} VkDataGraphPipelineOpticalFlowDispatchInfoARM; + +typedef struct VkDataGraphPipelineResourceInfoImageLayoutARM { + VkStructureType sType; + const void* pNext; + VkImageLayout layout; +} VkDataGraphPipelineResourceInfoImageLayoutARM; + +typedef struct VkDataGraphPipelineSingleNodeConnectionARM { + VkStructureType sType; + void* pNext; + uint32_t set; + uint32_t binding; + VkDataGraphPipelineNodeConnectionTypeARM connection; +} VkDataGraphPipelineSingleNodeConnectionARM; + +typedef struct VkDataGraphPipelineSingleNodeCreateInfoARM { + VkStructureType sType; + void* pNext; + VkDataGraphPipelineNodeTypeARM nodeType; + uint32_t connectionCount; + const VkDataGraphPipelineSingleNodeConnectionARM* pConnections; +} VkDataGraphPipelineSingleNodeCreateInfoARM; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyDataGraphOpticalFlowImageFormatsARM)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, const VkQueueFamilyDataGraphPropertiesARM* pQueueFamilyDataGraphProperties, const VkDataGraphOpticalFlowImageFormatInfoARM* pOpticalFlowImageFormatInfo, uint32_t* pFormatCount, VkDataGraphOpticalFlowImageFormatPropertiesARM* pImageFormatProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceQueueFamilyDataGraphOpticalFlowImageFormatsARM( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + const VkQueueFamilyDataGraphPropertiesARM* pQueueFamilyDataGraphProperties, + const VkDataGraphOpticalFlowImageFormatInfoARM* pOpticalFlowImageFormatInfo, + uint32_t* pFormatCount, + VkDataGraphOpticalFlowImageFormatPropertiesARM* pImageFormatProperties); +#endif +#endif + + +// VK_EXT_shader_long_vector is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_long_vector 1 +#define VK_EXT_SHADER_LONG_VECTOR_SPEC_VERSION 1 +#define VK_EXT_SHADER_LONG_VECTOR_EXTENSION_NAME "VK_EXT_shader_long_vector" +typedef struct VkPhysicalDeviceShaderLongVectorFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 longVector; +} VkPhysicalDeviceShaderLongVectorFeaturesEXT; + +typedef struct VkPhysicalDeviceShaderLongVectorPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxVectorComponents; +} VkPhysicalDeviceShaderLongVectorPropertiesEXT; + + + +// VK_SEC_pipeline_cache_incremental_mode is a preprocessor guard. Do not pass it to API calls. +#define VK_SEC_pipeline_cache_incremental_mode 1 +#define VK_SEC_PIPELINE_CACHE_INCREMENTAL_MODE_SPEC_VERSION 1 +#define VK_SEC_PIPELINE_CACHE_INCREMENTAL_MODE_EXTENSION_NAME "VK_SEC_pipeline_cache_incremental_mode" +typedef struct VkPhysicalDevicePipelineCacheIncrementalModeFeaturesSEC { + VkStructureType sType; + void* pNext; + VkBool32 pipelineCacheIncrementalMode; +} VkPhysicalDevicePipelineCacheIncrementalModeFeaturesSEC; + + + +// VK_EXT_shader_uniform_buffer_unsized_array is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_uniform_buffer_unsized_array 1 +#define VK_EXT_SHADER_UNIFORM_BUFFER_UNSIZED_ARRAY_SPEC_VERSION 1 +#define VK_EXT_SHADER_UNIFORM_BUFFER_UNSIZED_ARRAY_EXTENSION_NAME "VK_EXT_shader_uniform_buffer_unsized_array" +typedef struct VkPhysicalDeviceShaderUniformBufferUnsizedArrayFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderUniformBufferUnsizedArray; +} VkPhysicalDeviceShaderUniformBufferUnsizedArrayFeaturesEXT; + + + +// VK_NV_compute_occupancy_priority is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_compute_occupancy_priority 1 +#define VK_NV_COMPUTE_OCCUPANCY_PRIORITY_SPEC_VERSION 1 +#define VK_NV_COMPUTE_OCCUPANCY_PRIORITY_EXTENSION_NAME "VK_NV_compute_occupancy_priority" +#define VK_COMPUTE_OCCUPANCY_PRIORITY_LOW_NV 0.25f +#define VK_COMPUTE_OCCUPANCY_PRIORITY_NORMAL_NV 0.50f +#define VK_COMPUTE_OCCUPANCY_PRIORITY_HIGH_NV 0.75f +typedef struct VkComputeOccupancyPriorityParametersNV { + VkStructureType sType; + const void* pNext; + float occupancyPriority; + float occupancyThrottling; +} VkComputeOccupancyPriorityParametersNV; + +typedef struct VkPhysicalDeviceComputeOccupancyPriorityFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 computeOccupancyPriority; +} VkPhysicalDeviceComputeOccupancyPriorityFeaturesNV; + +typedef void (VKAPI_PTR *PFN_vkCmdSetComputeOccupancyPriorityNV)(VkCommandBuffer commandBuffer, const VkComputeOccupancyPriorityParametersNV* pParameters); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetComputeOccupancyPriorityNV( + VkCommandBuffer commandBuffer, + const VkComputeOccupancyPriorityParametersNV* pParameters); +#endif +#endif + + +// VK_EXT_shader_subgroup_partitioned is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_subgroup_partitioned 1 +#define VK_EXT_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION 1 +#define VK_EXT_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME "VK_EXT_shader_subgroup_partitioned" +typedef struct VkPhysicalDeviceShaderSubgroupPartitionedFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderSubgroupPartitioned; +} VkPhysicalDeviceShaderSubgroupPartitionedFeaturesEXT; + + + +// VK_EXT_shader_ocp_microscaling_types is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_shader_ocp_microscaling_types 1 +#define VK_EXT_SHADER_OCP_MICROSCALING_TYPES_SPEC_VERSION 1 +#define VK_EXT_SHADER_OCP_MICROSCALING_TYPES_EXTENSION_NAME "VK_EXT_shader_ocp_microscaling_types" +typedef struct VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat4; + VkBool32 shaderFloat6; + VkBool32 shaderFloat8UnsignedE8M0; + VkBool32 shaderMXInt8; +} VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT; + + + +// VK_VALVE_shader_mixed_float_dot_product is a preprocessor guard. Do not pass it to API calls. +#define VK_VALVE_shader_mixed_float_dot_product 1 +#define VK_VALVE_SHADER_MIXED_FLOAT_DOT_PRODUCT_SPEC_VERSION 1 +#define VK_VALVE_SHADER_MIXED_FLOAT_DOT_PRODUCT_EXTENSION_NAME "VK_VALVE_shader_mixed_float_dot_product" +typedef struct VkPhysicalDeviceShaderMixedFloatDotProductFeaturesVALVE { + VkStructureType sType; + void* pNext; + VkBool32 shaderMixedFloatDotProductFloat16AccFloat32; + VkBool32 shaderMixedFloatDotProductFloat16AccFloat16; + VkBool32 shaderMixedFloatDotProductBFloat16Acc; + VkBool32 shaderMixedFloatDotProductFloat8AccFloat32; +} VkPhysicalDeviceShaderMixedFloatDotProductFeaturesVALVE; + + + +// VK_SEC_throttle_hint is a preprocessor guard. Do not pass it to API calls. +#define VK_SEC_throttle_hint 1 +#define VK_SEC_THROTTLE_HINT_SPEC_VERSION 1 +#define VK_SEC_THROTTLE_HINT_EXTENSION_NAME "VK_SEC_throttle_hint" + +typedef enum VkThrottleHintTypeSEC { + VK_THROTTLE_HINT_TYPE_DEFAULT_SEC = 0, + VK_THROTTLE_HINT_TYPE_LOW_SEC = 1, + VK_THROTTLE_HINT_TYPE_HIGH_SEC = 2, + VK_THROTTLE_HINT_TYPE_MAX_ENUM_SEC = 0x7FFFFFFF +} VkThrottleHintTypeSEC; +typedef struct VkThrottleHintSubmitInfoSEC { + VkStructureType sType; + const void* pNext; + VkThrottleHintTypeSEC throttleHint; +} VkThrottleHintSubmitInfoSEC; + +typedef struct VkPhysicalDeviceThrottleHintFeaturesSEC { + VkStructureType sType; + void* pNext; + VkBool32 throttleHint; +} VkPhysicalDeviceThrottleHintFeaturesSEC; + + + +// VK_ARM_data_graph_neural_accelerator_statistics is a preprocessor guard. Do not pass it to API calls. +#define VK_ARM_data_graph_neural_accelerator_statistics 1 +#define VK_ARM_DATA_GRAPH_NEURAL_ACCELERATOR_STATISTICS_SPEC_VERSION 1 +#define VK_ARM_DATA_GRAPH_NEURAL_ACCELERATOR_STATISTICS_EXTENSION_NAME "VK_ARM_data_graph_neural_accelerator_statistics" + +typedef enum VkNeuralAcceleratorStatisticsModeARM { + VK_NEURAL_ACCELERATOR_STATISTICS_MODE_DISABLED_ARM = 0, + VK_NEURAL_ACCELERATOR_STATISTICS_MODE_STATISTICS0_ARM = 1, + VK_NEURAL_ACCELERATOR_STATISTICS_MODE_STATISTICS1_ARM = 2, + VK_NEURAL_ACCELERATOR_STATISTICS_MODE_MAX_ENUM_ARM = 0x7FFFFFFF +} VkNeuralAcceleratorStatisticsModeARM; +typedef struct VkPhysicalDeviceDataGraphNeuralAcceleratorStatisticsFeaturesARM { + VkStructureType sType; + void* pNext; + VkBool32 dataGraphNeuralAcceleratorStatistics; +} VkPhysicalDeviceDataGraphNeuralAcceleratorStatisticsFeaturesARM; + +typedef struct VkDataGraphPipelineNeuralStatisticsCreateInfoARM { + VkStructureType sType; + const void* pNext; + VkBool32 allowNeuralStatistics; +} VkDataGraphPipelineNeuralStatisticsCreateInfoARM; + +typedef struct VkDataGraphPipelineSessionNeuralStatisticsCreateInfoARM { + VkStructureType sType; + const void* pNext; + VkNeuralAcceleratorStatisticsModeARM mode; +} VkDataGraphPipelineSessionNeuralStatisticsCreateInfoARM; + + + +// VK_EXT_primitive_restart_index is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_primitive_restart_index 1 +#define VK_EXT_PRIMITIVE_RESTART_INDEX_SPEC_VERSION 1 +#define VK_EXT_PRIMITIVE_RESTART_INDEX_EXTENSION_NAME "VK_EXT_primitive_restart_index" +typedef struct VkPhysicalDevicePrimitiveRestartIndexFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 primitiveRestartIndex; +} VkPhysicalDevicePrimitiveRestartIndexFeaturesEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveRestartIndexEXT)(VkCommandBuffer commandBuffer, uint32_t primitiveRestartIndex); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetPrimitiveRestartIndexEXT( + VkCommandBuffer commandBuffer, + uint32_t primitiveRestartIndex); +#endif +#endif + + +// VK_NV_cooperative_matrix_decode_vector is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_cooperative_matrix_decode_vector 1 +#define VK_NV_COOPERATIVE_MATRIX_DECODE_VECTOR_SPEC_VERSION 1 +#define VK_NV_COOPERATIVE_MATRIX_DECODE_VECTOR_EXTENSION_NAME "VK_NV_cooperative_matrix_decode_vector" +typedef struct VkPhysicalDeviceCooperativeMatrixDecodeVectorFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrixDecodeVector; +} VkPhysicalDeviceCooperativeMatrixDecodeVectorFeaturesNV; + + + +// VK_KHR_acceleration_structure is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_acceleration_structure 1 +#define VK_KHR_ACCELERATION_STRUCTURE_SPEC_VERSION 13 +#define VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME "VK_KHR_acceleration_structure" + +typedef enum VkBuildAccelerationStructureModeKHR { + VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR = 0, + VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR = 1, + VK_BUILD_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkBuildAccelerationStructureModeKHR; +typedef struct VkAccelerationStructureBuildRangeInfoKHR { + uint32_t primitiveCount; + uint32_t primitiveOffset; + uint32_t firstVertex; + uint32_t transformOffset; +} VkAccelerationStructureBuildRangeInfoKHR; + +typedef struct VkAccelerationStructureGeometryTrianglesDataKHR { + VkStructureType sType; + const void* pNext; + VkFormat vertexFormat; + VkDeviceOrHostAddressConstKHR vertexData; + VkDeviceSize vertexStride; + uint32_t maxVertex; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexData; + VkDeviceOrHostAddressConstKHR transformData; +} VkAccelerationStructureGeometryTrianglesDataKHR; + +typedef struct VkAccelerationStructureGeometryAabbsDataKHR { + VkStructureType sType; + const void* pNext; + VkDeviceOrHostAddressConstKHR data; + VkDeviceSize stride; +} VkAccelerationStructureGeometryAabbsDataKHR; + +typedef struct VkAccelerationStructureGeometryInstancesDataKHR { + VkStructureType sType; + const void* pNext; + VkBool32 arrayOfPointers; + VkDeviceOrHostAddressConstKHR data; +} VkAccelerationStructureGeometryInstancesDataKHR; + +typedef union VkAccelerationStructureGeometryDataKHR { + VkAccelerationStructureGeometryTrianglesDataKHR triangles; + VkAccelerationStructureGeometryAabbsDataKHR aabbs; + VkAccelerationStructureGeometryInstancesDataKHR instances; +} VkAccelerationStructureGeometryDataKHR; + +typedef struct VkAccelerationStructureGeometryKHR { + VkStructureType sType; + const void* pNext; + VkGeometryTypeKHR geometryType; + VkAccelerationStructureGeometryDataKHR geometry; + VkGeometryFlagsKHR flags; +} VkAccelerationStructureGeometryKHR; + +typedef struct VkAccelerationStructureBuildGeometryInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureTypeKHR type; + VkBuildAccelerationStructureFlagsKHR flags; + VkBuildAccelerationStructureModeKHR mode; + VkAccelerationStructureKHR srcAccelerationStructure; + VkAccelerationStructureKHR dstAccelerationStructure; + uint32_t geometryCount; + const VkAccelerationStructureGeometryKHR* pGeometries; + const VkAccelerationStructureGeometryKHR* const* ppGeometries; + VkDeviceOrHostAddressKHR scratchData; +} VkAccelerationStructureBuildGeometryInfoKHR; + +typedef struct VkAccelerationStructureCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureCreateFlagsKHR createFlags; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; + VkAccelerationStructureTypeKHR type; + VkDeviceAddress deviceAddress; +} VkAccelerationStructureCreateInfoKHR; + +typedef struct VkWriteDescriptorSetAccelerationStructureKHR { + VkStructureType sType; + const void* pNext; + uint32_t accelerationStructureCount; + const VkAccelerationStructureKHR* pAccelerationStructures; +} VkWriteDescriptorSetAccelerationStructureKHR; + +typedef struct VkPhysicalDeviceAccelerationStructureFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 accelerationStructure; + VkBool32 accelerationStructureCaptureReplay; + VkBool32 accelerationStructureIndirectBuild; + // accelerationStructureHostCommands is legacy, but no reason was given in the API XML + VkBool32 accelerationStructureHostCommands; + VkBool32 descriptorBindingAccelerationStructureUpdateAfterBind; +} VkPhysicalDeviceAccelerationStructureFeaturesKHR; + +typedef struct VkPhysicalDeviceAccelerationStructurePropertiesKHR { + VkStructureType sType; + void* pNext; + uint64_t maxGeometryCount; + uint64_t maxInstanceCount; + uint64_t maxPrimitiveCount; + uint32_t maxPerStageDescriptorAccelerationStructures; + uint32_t maxPerStageDescriptorUpdateAfterBindAccelerationStructures; + uint32_t maxDescriptorSetAccelerationStructures; + uint32_t maxDescriptorSetUpdateAfterBindAccelerationStructures; + uint32_t minAccelerationStructureScratchOffsetAlignment; +} VkPhysicalDeviceAccelerationStructurePropertiesKHR; + +typedef struct VkAccelerationStructureDeviceAddressInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureKHR accelerationStructure; +} VkAccelerationStructureDeviceAddressInfoKHR; + +typedef struct VkAccelerationStructureVersionInfoKHR { + VkStructureType sType; + const void* pNext; + const uint8_t* pVersionData; +} VkAccelerationStructureVersionInfoKHR; + +typedef struct VkCopyAccelerationStructureToMemoryInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureKHR src; + VkDeviceOrHostAddressKHR dst; + VkCopyAccelerationStructureModeKHR mode; +} VkCopyAccelerationStructureToMemoryInfoKHR; + +typedef struct VkCopyMemoryToAccelerationStructureInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceOrHostAddressConstKHR src; + VkAccelerationStructureKHR dst; + VkCopyAccelerationStructureModeKHR mode; +} VkCopyMemoryToAccelerationStructureInfoKHR; + +typedef struct VkCopyAccelerationStructureInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureKHR src; + VkAccelerationStructureKHR dst; + VkCopyAccelerationStructureModeKHR mode; +} VkCopyAccelerationStructureInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureKHR)(VkDevice device, const VkAccelerationStructureCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureKHR* pAccelerationStructure); +typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureKHR)(VkDevice device, VkAccelerationStructureKHR accelerationStructure, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructuresKHR)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos); +typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructuresIndirectKHR)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, const VkDeviceAddress* pIndirectDeviceAddresses, const uint32_t* pIndirectStrides, const uint32_t* const* ppMaxPrimitiveCounts); +typedef VkResult (VKAPI_PTR *PFN_vkBuildAccelerationStructuresKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos); +typedef VkResult (VKAPI_PTR *PFN_vkCopyAccelerationStructureKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyAccelerationStructureInfoKHR* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyAccelerationStructureToMemoryKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyMemoryToAccelerationStructureKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkWriteAccelerationStructuresPropertiesKHR)(VkDevice device, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR* pAccelerationStructures, VkQueryType queryType, size_t dataSize, void* pData, size_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureKHR)(VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureInfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureToMemoryKHR)(VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryToAccelerationStructureKHR)(VkCommandBuffer commandBuffer, const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo); +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetAccelerationStructureDeviceAddressKHR)(VkDevice device, const VkAccelerationStructureDeviceAddressInfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesKHR)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); +typedef void (VKAPI_PTR *PFN_vkGetDeviceAccelerationStructureCompatibilityKHR)(VkDevice device, const VkAccelerationStructureVersionInfoKHR* pVersionInfo, VkAccelerationStructureCompatibilityKHR* pCompatibility); +typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureBuildSizesKHR)(VkDevice device, VkAccelerationStructureBuildTypeKHR buildType, const VkAccelerationStructureBuildGeometryInfoKHR* pBuildInfo, const uint32_t* pMaxPrimitiveCounts, VkAccelerationStructureBuildSizesInfoKHR* pSizeInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureKHR( + VkDevice device, + const VkAccelerationStructureCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkAccelerationStructureKHR* pAccelerationStructure); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureKHR( + VkDevice device, + VkAccelerationStructureKHR accelerationStructure, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructuresKHR( + VkCommandBuffer commandBuffer, + uint32_t infoCount, + const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, + const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructuresIndirectKHR( + VkCommandBuffer commandBuffer, + uint32_t infoCount, + const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, + const VkDeviceAddress* pIndirectDeviceAddresses, + const uint32_t* pIndirectStrides, + const uint32_t* const* ppMaxPrimitiveCounts); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkBuildAccelerationStructuresKHR( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + uint32_t infoCount, + const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, + const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCopyAccelerationStructureKHR( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + const VkCopyAccelerationStructureInfoKHR* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCopyAccelerationStructureToMemoryKHR( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCopyMemoryToAccelerationStructureKHR( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkWriteAccelerationStructuresPropertiesKHR( + VkDevice device, + uint32_t accelerationStructureCount, + const VkAccelerationStructureKHR* pAccelerationStructures, + VkQueryType queryType, + size_t dataSize, + void* pData, + size_t stride); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureKHR( + VkCommandBuffer commandBuffer, + const VkCopyAccelerationStructureInfoKHR* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureToMemoryKHR( + VkCommandBuffer commandBuffer, + const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMemoryToAccelerationStructureKHR( + VkCommandBuffer commandBuffer, + const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetAccelerationStructureDeviceAddressKHR( + VkDevice device, + const VkAccelerationStructureDeviceAddressInfoKHR* pInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructuresPropertiesKHR( + VkCommandBuffer commandBuffer, + uint32_t accelerationStructureCount, + const VkAccelerationStructureKHR* pAccelerationStructures, + VkQueryType queryType, + VkQueryPool queryPool, + uint32_t firstQuery); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDeviceAccelerationStructureCompatibilityKHR( + VkDevice device, + const VkAccelerationStructureVersionInfoKHR* pVersionInfo, + VkAccelerationStructureCompatibilityKHR* pCompatibility); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureBuildSizesKHR( + VkDevice device, + VkAccelerationStructureBuildTypeKHR buildType, + const VkAccelerationStructureBuildGeometryInfoKHR* pBuildInfo, + const uint32_t* pMaxPrimitiveCounts, + VkAccelerationStructureBuildSizesInfoKHR* pSizeInfo); +#endif +#endif + + +// VK_KHR_ray_tracing_pipeline is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_ray_tracing_pipeline 1 +#define VK_KHR_RAY_TRACING_PIPELINE_SPEC_VERSION 1 +#define VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME "VK_KHR_ray_tracing_pipeline" + +typedef enum VkShaderGroupShaderKHR { + VK_SHADER_GROUP_SHADER_GENERAL_KHR = 0, + VK_SHADER_GROUP_SHADER_CLOSEST_HIT_KHR = 1, + VK_SHADER_GROUP_SHADER_ANY_HIT_KHR = 2, + VK_SHADER_GROUP_SHADER_INTERSECTION_KHR = 3, + VK_SHADER_GROUP_SHADER_MAX_ENUM_KHR = 0x7FFFFFFF +} VkShaderGroupShaderKHR; +typedef struct VkRayTracingShaderGroupCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkRayTracingShaderGroupTypeKHR type; + uint32_t generalShader; + uint32_t closestHitShader; + uint32_t anyHitShader; + uint32_t intersectionShader; + const void* pShaderGroupCaptureReplayHandle; +} VkRayTracingShaderGroupCreateInfoKHR; + +typedef struct VkRayTracingPipelineInterfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t maxPipelineRayPayloadSize; + uint32_t maxPipelineRayHitAttributeSize; +} VkRayTracingPipelineInterfaceCreateInfoKHR; + +typedef struct VkRayTracingPipelineCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + uint32_t groupCount; + const VkRayTracingShaderGroupCreateInfoKHR* pGroups; + uint32_t maxPipelineRayRecursionDepth; + const VkPipelineLibraryCreateInfoKHR* pLibraryInfo; + const VkRayTracingPipelineInterfaceCreateInfoKHR* pLibraryInterface; + const VkPipelineDynamicStateCreateInfo* pDynamicState; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkRayTracingPipelineCreateInfoKHR; + +typedef struct VkPhysicalDeviceRayTracingPipelineFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 rayTracingPipeline; + VkBool32 rayTracingPipelineShaderGroupHandleCaptureReplay; + VkBool32 rayTracingPipelineShaderGroupHandleCaptureReplayMixed; + VkBool32 rayTracingPipelineTraceRaysIndirect; + VkBool32 rayTraversalPrimitiveCulling; +} VkPhysicalDeviceRayTracingPipelineFeaturesKHR; + +typedef struct VkPhysicalDeviceRayTracingPipelinePropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t shaderGroupHandleSize; + uint32_t maxRayRecursionDepth; + uint32_t maxShaderGroupStride; + uint32_t shaderGroupBaseAlignment; + uint32_t shaderGroupHandleCaptureReplaySize; + uint32_t maxRayDispatchInvocationCount; + uint32_t shaderGroupHandleAlignment; + uint32_t maxRayHitAttributeSize; +} VkPhysicalDeviceRayTracingPipelinePropertiesKHR; + +typedef struct VkTraceRaysIndirectCommandKHR { + uint32_t width; + uint32_t height; + uint32_t depth; +} VkTraceRaysIndirectCommandKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysKHR)(VkCommandBuffer commandBuffer, const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, uint32_t width, uint32_t height, uint32_t depth); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRayTracingPipelinesKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysIndirectKHR)(VkCommandBuffer commandBuffer, const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, VkDeviceAddress indirectDeviceAddress); +typedef VkDeviceSize (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupStackSizeKHR)(VkDevice device, VkPipeline pipeline, uint32_t group, VkShaderGroupShaderKHR groupShader); +typedef void (VKAPI_PTR *PFN_vkCmdSetRayTracingPipelineStackSizeKHR)(VkCommandBuffer commandBuffer, uint32_t pipelineStackSize); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysKHR( + VkCommandBuffer commandBuffer, + const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, + uint32_t width, + uint32_t height, + uint32_t depth); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRayTracingPipelinesKHR( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkRayTracingPipelineCreateInfoKHR* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingCaptureReplayShaderGroupHandlesKHR( + VkDevice device, + VkPipeline pipeline, + uint32_t firstGroup, + uint32_t groupCount, + size_t dataSize, + void* pData); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysIndirectKHR( + VkCommandBuffer commandBuffer, + const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, + VkDeviceAddress indirectDeviceAddress); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkDeviceSize VKAPI_CALL vkGetRayTracingShaderGroupStackSizeKHR( + VkDevice device, + VkPipeline pipeline, + uint32_t group, + VkShaderGroupShaderKHR groupShader); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetRayTracingPipelineStackSizeKHR( + VkCommandBuffer commandBuffer, + uint32_t pipelineStackSize); +#endif +#endif + + +// VK_KHR_ray_query is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_ray_query 1 +#define VK_KHR_RAY_QUERY_SPEC_VERSION 1 +#define VK_KHR_RAY_QUERY_EXTENSION_NAME "VK_KHR_ray_query" +typedef struct VkPhysicalDeviceRayQueryFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 rayQuery; +} VkPhysicalDeviceRayQueryFeaturesKHR; + + + +// VK_EXT_mesh_shader is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_mesh_shader 1 +#define VK_EXT_MESH_SHADER_SPEC_VERSION 1 +#define VK_EXT_MESH_SHADER_EXTENSION_NAME "VK_EXT_mesh_shader" +typedef struct VkPhysicalDeviceMeshShaderFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 taskShader; + VkBool32 meshShader; + VkBool32 multiviewMeshShader; + VkBool32 primitiveFragmentShadingRateMeshShader; + VkBool32 meshShaderQueries; +} VkPhysicalDeviceMeshShaderFeaturesEXT; + +typedef struct VkPhysicalDeviceMeshShaderPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxTaskWorkGroupTotalCount; + uint32_t maxTaskWorkGroupCount[3]; + uint32_t maxTaskWorkGroupInvocations; + uint32_t maxTaskWorkGroupSize[3]; + uint32_t maxTaskPayloadSize; + uint32_t maxTaskSharedMemorySize; + uint32_t maxTaskPayloadAndSharedMemorySize; + uint32_t maxMeshWorkGroupTotalCount; + uint32_t maxMeshWorkGroupCount[3]; + uint32_t maxMeshWorkGroupInvocations; + uint32_t maxMeshWorkGroupSize[3]; + uint32_t maxMeshSharedMemorySize; + uint32_t maxMeshPayloadAndSharedMemorySize; + uint32_t maxMeshOutputMemorySize; + uint32_t maxMeshPayloadAndOutputMemorySize; + uint32_t maxMeshOutputComponents; + uint32_t maxMeshOutputVertices; + uint32_t maxMeshOutputPrimitives; + uint32_t maxMeshOutputLayers; + uint32_t maxMeshMultiviewViewCount; + uint32_t meshOutputPerVertexGranularity; + uint32_t meshOutputPerPrimitiveGranularity; + uint32_t maxPreferredTaskWorkGroupInvocations; + uint32_t maxPreferredMeshWorkGroupInvocations; + VkBool32 prefersLocalInvocationVertexOutput; + VkBool32 prefersLocalInvocationPrimitiveOutput; + VkBool32 prefersCompactVertexOutput; + VkBool32 prefersCompactPrimitiveOutput; +} VkPhysicalDeviceMeshShaderPropertiesEXT; + +typedef struct VkDrawMeshTasksIndirectCommandEXT { + uint32_t groupCountX; + uint32_t groupCountY; + uint32_t groupCountZ; +} VkDrawMeshTasksIndirectCommandEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksEXT)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectEXT)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectCountEXT)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksEXT( + VkCommandBuffer commandBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectEXT( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectCountEXT( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_directfb.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_directfb.h new file mode 100644 index 000000000..527331a61 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_directfb.h @@ -0,0 +1,59 @@ +#ifndef VULKAN_DIRECTFB_H_ +#define VULKAN_DIRECTFB_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_EXT_directfb_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_directfb_surface 1 +#define VK_EXT_DIRECTFB_SURFACE_SPEC_VERSION 1 +#define VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME "VK_EXT_directfb_surface" +typedef VkFlags VkDirectFBSurfaceCreateFlagsEXT; +typedef struct VkDirectFBSurfaceCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDirectFBSurfaceCreateFlagsEXT flags; + IDirectFB* dfb; + IDirectFBSurface* surface; +} VkDirectFBSurfaceCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateDirectFBSurfaceEXT)(VkInstance instance, const VkDirectFBSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, IDirectFB* dfb); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDirectFBSurfaceEXT( + VkInstance instance, + const VkDirectFBSurfaceCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceDirectFBPresentationSupportEXT( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + IDirectFB* dfb); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_fuchsia.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_fuchsia.h new file mode 100644 index 000000000..bfeee3943 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_fuchsia.h @@ -0,0 +1,282 @@ +#ifndef VULKAN_FUCHSIA_H_ +#define VULKAN_FUCHSIA_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_FUCHSIA_imagepipe_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_FUCHSIA_imagepipe_surface 1 +#define VK_FUCHSIA_IMAGEPIPE_SURFACE_SPEC_VERSION 1 +#define VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME "VK_FUCHSIA_imagepipe_surface" +typedef VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA; +typedef struct VkImagePipeSurfaceCreateInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkImagePipeSurfaceCreateFlagsFUCHSIA flags; + zx_handle_t imagePipeHandle; +} VkImagePipeSurfaceCreateInfoFUCHSIA; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateImagePipeSurfaceFUCHSIA)(VkInstance instance, const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateImagePipeSurfaceFUCHSIA( + VkInstance instance, + const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif +#endif + + +// VK_FUCHSIA_external_memory is a preprocessor guard. Do not pass it to API calls. +#define VK_FUCHSIA_external_memory 1 +#define VK_FUCHSIA_EXTERNAL_MEMORY_SPEC_VERSION 1 +#define VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME "VK_FUCHSIA_external_memory" +typedef struct VkImportMemoryZirconHandleInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + zx_handle_t handle; +} VkImportMemoryZirconHandleInfoFUCHSIA; + +typedef struct VkMemoryZirconHandlePropertiesFUCHSIA { + VkStructureType sType; + void* pNext; + uint32_t memoryTypeBits; +} VkMemoryZirconHandlePropertiesFUCHSIA; + +typedef struct VkMemoryGetZirconHandleInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkMemoryGetZirconHandleInfoFUCHSIA; + +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryZirconHandleFUCHSIA)(VkDevice device, const VkMemoryGetZirconHandleInfoFUCHSIA* pGetZirconHandleInfo, zx_handle_t* pZirconHandle); +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, zx_handle_t zirconHandle, VkMemoryZirconHandlePropertiesFUCHSIA* pMemoryZirconHandleProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryZirconHandleFUCHSIA( + VkDevice device, + const VkMemoryGetZirconHandleInfoFUCHSIA* pGetZirconHandleInfo, + zx_handle_t* pZirconHandle); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryZirconHandlePropertiesFUCHSIA( + VkDevice device, + VkExternalMemoryHandleTypeFlagBits handleType, + zx_handle_t zirconHandle, + VkMemoryZirconHandlePropertiesFUCHSIA* pMemoryZirconHandleProperties); +#endif +#endif + + +// VK_FUCHSIA_external_semaphore is a preprocessor guard. Do not pass it to API calls. +#define VK_FUCHSIA_external_semaphore 1 +#define VK_FUCHSIA_EXTERNAL_SEMAPHORE_SPEC_VERSION 1 +#define VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_FUCHSIA_external_semaphore" +typedef struct VkImportSemaphoreZirconHandleInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkSemaphoreImportFlags flags; + VkExternalSemaphoreHandleTypeFlagBits handleType; + zx_handle_t zirconHandle; +} VkImportSemaphoreZirconHandleInfoFUCHSIA; + +typedef struct VkSemaphoreGetZirconHandleInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkExternalSemaphoreHandleTypeFlagBits handleType; +} VkSemaphoreGetZirconHandleInfoFUCHSIA; + +typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreZirconHandleFUCHSIA)(VkDevice device, const VkImportSemaphoreZirconHandleInfoFUCHSIA* pImportSemaphoreZirconHandleInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreZirconHandleFUCHSIA)(VkDevice device, const VkSemaphoreGetZirconHandleInfoFUCHSIA* pGetZirconHandleInfo, zx_handle_t* pZirconHandle); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreZirconHandleFUCHSIA( + VkDevice device, + const VkImportSemaphoreZirconHandleInfoFUCHSIA* pImportSemaphoreZirconHandleInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreZirconHandleFUCHSIA( + VkDevice device, + const VkSemaphoreGetZirconHandleInfoFUCHSIA* pGetZirconHandleInfo, + zx_handle_t* pZirconHandle); +#endif +#endif + + +// VK_FUCHSIA_buffer_collection is a preprocessor guard. Do not pass it to API calls. +#define VK_FUCHSIA_buffer_collection 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferCollectionFUCHSIA) +#define VK_FUCHSIA_BUFFER_COLLECTION_SPEC_VERSION 2 +#define VK_FUCHSIA_BUFFER_COLLECTION_EXTENSION_NAME "VK_FUCHSIA_buffer_collection" +typedef VkFlags VkImageFormatConstraintsFlagsFUCHSIA; + +typedef enum VkImageConstraintsInfoFlagBitsFUCHSIA { + VK_IMAGE_CONSTRAINTS_INFO_CPU_READ_RARELY_FUCHSIA = 0x00000001, + VK_IMAGE_CONSTRAINTS_INFO_CPU_READ_OFTEN_FUCHSIA = 0x00000002, + VK_IMAGE_CONSTRAINTS_INFO_CPU_WRITE_RARELY_FUCHSIA = 0x00000004, + VK_IMAGE_CONSTRAINTS_INFO_CPU_WRITE_OFTEN_FUCHSIA = 0x00000008, + VK_IMAGE_CONSTRAINTS_INFO_PROTECTED_OPTIONAL_FUCHSIA = 0x00000010, + VK_IMAGE_CONSTRAINTS_INFO_FLAG_BITS_MAX_ENUM_FUCHSIA = 0x7FFFFFFF +} VkImageConstraintsInfoFlagBitsFUCHSIA; +typedef VkFlags VkImageConstraintsInfoFlagsFUCHSIA; +typedef struct VkBufferCollectionCreateInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + zx_handle_t collectionToken; +} VkBufferCollectionCreateInfoFUCHSIA; + +typedef struct VkImportMemoryBufferCollectionFUCHSIA { + VkStructureType sType; + const void* pNext; + VkBufferCollectionFUCHSIA collection; + uint32_t index; +} VkImportMemoryBufferCollectionFUCHSIA; + +typedef struct VkBufferCollectionImageCreateInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkBufferCollectionFUCHSIA collection; + uint32_t index; +} VkBufferCollectionImageCreateInfoFUCHSIA; + +typedef struct VkBufferCollectionConstraintsInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + uint32_t minBufferCount; + uint32_t maxBufferCount; + uint32_t minBufferCountForCamping; + uint32_t minBufferCountForDedicatedSlack; + uint32_t minBufferCountForSharedSlack; +} VkBufferCollectionConstraintsInfoFUCHSIA; + +typedef struct VkBufferConstraintsInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkBufferCreateInfo createInfo; + VkFormatFeatureFlags requiredFormatFeatures; + VkBufferCollectionConstraintsInfoFUCHSIA bufferCollectionConstraints; +} VkBufferConstraintsInfoFUCHSIA; + +typedef struct VkBufferCollectionBufferCreateInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkBufferCollectionFUCHSIA collection; + uint32_t index; +} VkBufferCollectionBufferCreateInfoFUCHSIA; + +typedef struct VkSysmemColorSpaceFUCHSIA { + VkStructureType sType; + const void* pNext; + uint32_t colorSpace; +} VkSysmemColorSpaceFUCHSIA; + +typedef struct VkBufferCollectionPropertiesFUCHSIA { + VkStructureType sType; + void* pNext; + uint32_t memoryTypeBits; + uint32_t bufferCount; + uint32_t createInfoIndex; + uint64_t sysmemPixelFormat; + VkFormatFeatureFlags formatFeatures; + VkSysmemColorSpaceFUCHSIA sysmemColorSpaceIndex; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkBufferCollectionPropertiesFUCHSIA; + +typedef struct VkImageFormatConstraintsInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + VkImageCreateInfo imageCreateInfo; + VkFormatFeatureFlags requiredFormatFeatures; + VkImageFormatConstraintsFlagsFUCHSIA flags; + uint64_t sysmemPixelFormat; + uint32_t colorSpaceCount; + const VkSysmemColorSpaceFUCHSIA* pColorSpaces; +} VkImageFormatConstraintsInfoFUCHSIA; + +typedef struct VkImageConstraintsInfoFUCHSIA { + VkStructureType sType; + const void* pNext; + uint32_t formatConstraintsCount; + const VkImageFormatConstraintsInfoFUCHSIA* pFormatConstraints; + VkBufferCollectionConstraintsInfoFUCHSIA bufferCollectionConstraints; + VkImageConstraintsInfoFlagsFUCHSIA flags; +} VkImageConstraintsInfoFUCHSIA; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateBufferCollectionFUCHSIA)(VkDevice device, const VkBufferCollectionCreateInfoFUCHSIA* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferCollectionFUCHSIA* pCollection); +typedef VkResult (VKAPI_PTR *PFN_vkSetBufferCollectionImageConstraintsFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, const VkImageConstraintsInfoFUCHSIA* pImageConstraintsInfo); +typedef VkResult (VKAPI_PTR *PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo); +typedef void (VKAPI_PTR *PFN_vkDestroyBufferCollectionFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetBufferCollectionPropertiesFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, VkBufferCollectionPropertiesFUCHSIA* pProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferCollectionFUCHSIA( + VkDevice device, + const VkBufferCollectionCreateInfoFUCHSIA* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkBufferCollectionFUCHSIA* pCollection); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkSetBufferCollectionImageConstraintsFUCHSIA( + VkDevice device, + VkBufferCollectionFUCHSIA collection, + const VkImageConstraintsInfoFUCHSIA* pImageConstraintsInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkSetBufferCollectionBufferConstraintsFUCHSIA( + VkDevice device, + VkBufferCollectionFUCHSIA collection, + const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroyBufferCollectionFUCHSIA( + VkDevice device, + VkBufferCollectionFUCHSIA collection, + const VkAllocationCallbacks* pAllocator); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetBufferCollectionPropertiesFUCHSIA( + VkDevice device, + VkBufferCollectionFUCHSIA collection, + VkBufferCollectionPropertiesFUCHSIA* pProperties); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_ggp.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_ggp.h new file mode 100644 index 000000000..b8961089b --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_ggp.h @@ -0,0 +1,62 @@ +#ifndef VULKAN_GGP_H_ +#define VULKAN_GGP_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_GGP_stream_descriptor_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_GGP_stream_descriptor_surface 1 +#define VK_GGP_STREAM_DESCRIPTOR_SURFACE_SPEC_VERSION 1 +#define VK_GGP_STREAM_DESCRIPTOR_SURFACE_EXTENSION_NAME "VK_GGP_stream_descriptor_surface" +typedef VkFlags VkStreamDescriptorSurfaceCreateFlagsGGP; +typedef struct VkStreamDescriptorSurfaceCreateInfoGGP { + VkStructureType sType; + const void* pNext; + VkStreamDescriptorSurfaceCreateFlagsGGP flags; + GgpStreamDescriptor streamDescriptor; +} VkStreamDescriptorSurfaceCreateInfoGGP; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateStreamDescriptorSurfaceGGP)(VkInstance instance, const VkStreamDescriptorSurfaceCreateInfoGGP* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateStreamDescriptorSurfaceGGP( + VkInstance instance, + const VkStreamDescriptorSurfaceCreateInfoGGP* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif +#endif + + +// VK_GGP_frame_token is a preprocessor guard. Do not pass it to API calls. +#define VK_GGP_frame_token 1 +#define VK_GGP_FRAME_TOKEN_SPEC_VERSION 1 +#define VK_GGP_FRAME_TOKEN_EXTENSION_NAME "VK_GGP_frame_token" +typedef struct VkPresentFrameTokenGGP { + VkStructureType sType; + const void* pNext; + GgpFrameToken frameToken; +} VkPresentFrameTokenGGP; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_ios.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_ios.h new file mode 100644 index 000000000..d6f1ed53b --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_ios.h @@ -0,0 +1,50 @@ +#ifndef VULKAN_IOS_H_ +#define VULKAN_IOS_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_MVK_ios_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_MVK_ios_surface 1 +#define VK_MVK_IOS_SURFACE_SPEC_VERSION 3 +#define VK_MVK_IOS_SURFACE_EXTENSION_NAME "VK_MVK_ios_surface" +typedef VkFlags VkIOSSurfaceCreateFlagsMVK; +typedef struct VkIOSSurfaceCreateInfoMVK { + VkStructureType sType; + const void* pNext; + VkIOSSurfaceCreateFlagsMVK flags; + const void* pView; +} VkIOSSurfaceCreateInfoMVK; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateIOSSurfaceMVK)(VkInstance instance, const VkIOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateIOSSurfaceMVK( + VkInstance instance, + const VkIOSSurfaceCreateInfoMVK* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_macos.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_macos.h new file mode 100644 index 000000000..2459e69fb --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_macos.h @@ -0,0 +1,50 @@ +#ifndef VULKAN_MACOS_H_ +#define VULKAN_MACOS_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_MVK_macos_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_MVK_macos_surface 1 +#define VK_MVK_MACOS_SURFACE_SPEC_VERSION 3 +#define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface" +typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; +typedef struct VkMacOSSurfaceCreateInfoMVK { + VkStructureType sType; + const void* pNext; + VkMacOSSurfaceCreateFlagsMVK flags; + const void* pView; +} VkMacOSSurfaceCreateInfoMVK; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateMacOSSurfaceMVK)(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateMacOSSurfaceMVK( + VkInstance instance, + const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_metal.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_metal.h new file mode 100644 index 000000000..1029b3732 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_metal.h @@ -0,0 +1,244 @@ +#ifndef VULKAN_METAL_H_ +#define VULKAN_METAL_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_EXT_metal_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_metal_surface 1 +#ifdef __OBJC__ +@class CAMetalLayer; +#else +typedef void CAMetalLayer; +#endif + +#define VK_EXT_METAL_SURFACE_SPEC_VERSION 1 +#define VK_EXT_METAL_SURFACE_EXTENSION_NAME "VK_EXT_metal_surface" +typedef VkFlags VkMetalSurfaceCreateFlagsEXT; +typedef struct VkMetalSurfaceCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkMetalSurfaceCreateFlagsEXT flags; + const CAMetalLayer* pLayer; +} VkMetalSurfaceCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateMetalSurfaceEXT)(VkInstance instance, const VkMetalSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateMetalSurfaceEXT( + VkInstance instance, + const VkMetalSurfaceCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif +#endif + + +// VK_EXT_metal_objects is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_metal_objects 1 +#ifdef __OBJC__ +@protocol MTLDevice; +typedef __unsafe_unretained id MTLDevice_id; +#else +typedef void* MTLDevice_id; +#endif + +#ifdef __OBJC__ +@protocol MTLCommandQueue; +typedef __unsafe_unretained id MTLCommandQueue_id; +#else +typedef void* MTLCommandQueue_id; +#endif + +#ifdef __OBJC__ +@protocol MTLBuffer; +typedef __unsafe_unretained id MTLBuffer_id; +#else +typedef void* MTLBuffer_id; +#endif + +#ifdef __OBJC__ +@protocol MTLTexture; +typedef __unsafe_unretained id MTLTexture_id; +#else +typedef void* MTLTexture_id; +#endif + +typedef struct __IOSurface* IOSurfaceRef; +#ifdef __OBJC__ +@protocol MTLSharedEvent; +typedef __unsafe_unretained id MTLSharedEvent_id; +#else +typedef void* MTLSharedEvent_id; +#endif + +#define VK_EXT_METAL_OBJECTS_SPEC_VERSION 2 +#define VK_EXT_METAL_OBJECTS_EXTENSION_NAME "VK_EXT_metal_objects" + +typedef enum VkExportMetalObjectTypeFlagBitsEXT { + VK_EXPORT_METAL_OBJECT_TYPE_METAL_DEVICE_BIT_EXT = 0x00000001, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_COMMAND_QUEUE_BIT_EXT = 0x00000002, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_BUFFER_BIT_EXT = 0x00000004, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT = 0x00000008, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_IOSURFACE_BIT_EXT = 0x00000010, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_SHARED_EVENT_BIT_EXT = 0x00000020, + VK_EXPORT_METAL_OBJECT_TYPE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkExportMetalObjectTypeFlagBitsEXT; +typedef VkFlags VkExportMetalObjectTypeFlagsEXT; +typedef struct VkExportMetalObjectCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkExportMetalObjectTypeFlagBitsEXT exportObjectType; +} VkExportMetalObjectCreateInfoEXT; + +typedef struct VkExportMetalObjectsInfoEXT { + VkStructureType sType; + const void* pNext; +} VkExportMetalObjectsInfoEXT; + +typedef struct VkExportMetalDeviceInfoEXT { + VkStructureType sType; + const void* pNext; + MTLDevice_id mtlDevice; +} VkExportMetalDeviceInfoEXT; + +typedef struct VkExportMetalCommandQueueInfoEXT { + VkStructureType sType; + const void* pNext; + VkQueue queue; + MTLCommandQueue_id mtlCommandQueue; +} VkExportMetalCommandQueueInfoEXT; + +typedef struct VkExportMetalBufferInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + MTLBuffer_id mtlBuffer; +} VkExportMetalBufferInfoEXT; + +typedef struct VkImportMetalBufferInfoEXT { + VkStructureType sType; + const void* pNext; + MTLBuffer_id mtlBuffer; +} VkImportMetalBufferInfoEXT; + +typedef struct VkExportMetalTextureInfoEXT { + VkStructureType sType; + const void* pNext; + VkImage image; + VkImageView imageView; + VkBufferView bufferView; + VkImageAspectFlagBits plane; + MTLTexture_id mtlTexture; +} VkExportMetalTextureInfoEXT; + +typedef struct VkImportMetalTextureInfoEXT { + VkStructureType sType; + const void* pNext; + VkImageAspectFlagBits plane; + MTLTexture_id mtlTexture; +} VkImportMetalTextureInfoEXT; + +typedef struct VkExportMetalIOSurfaceInfoEXT { + VkStructureType sType; + const void* pNext; + VkImage image; + IOSurfaceRef ioSurface; +} VkExportMetalIOSurfaceInfoEXT; + +typedef struct VkImportMetalIOSurfaceInfoEXT { + VkStructureType sType; + const void* pNext; + IOSurfaceRef ioSurface; +} VkImportMetalIOSurfaceInfoEXT; + +typedef struct VkExportMetalSharedEventInfoEXT { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkEvent event; + MTLSharedEvent_id mtlSharedEvent; +} VkExportMetalSharedEventInfoEXT; + +typedef struct VkImportMetalSharedEventInfoEXT { + VkStructureType sType; + const void* pNext; + MTLSharedEvent_id mtlSharedEvent; +} VkImportMetalSharedEventInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkExportMetalObjectsEXT)(VkDevice device, VkExportMetalObjectsInfoEXT* pMetalObjectsInfo); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkExportMetalObjectsEXT( + VkDevice device, + VkExportMetalObjectsInfoEXT* pMetalObjectsInfo); +#endif +#endif + + +// VK_EXT_external_memory_metal is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_external_memory_metal 1 +#define VK_EXT_EXTERNAL_MEMORY_METAL_SPEC_VERSION 1 +#define VK_EXT_EXTERNAL_MEMORY_METAL_EXTENSION_NAME "VK_EXT_external_memory_metal" +typedef struct VkImportMemoryMetalHandleInfoEXT { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + void* handle; +} VkImportMemoryMetalHandleInfoEXT; + +typedef struct VkMemoryMetalHandlePropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t memoryTypeBits; +} VkMemoryMetalHandlePropertiesEXT; + +typedef struct VkMemoryGetMetalHandleInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkMemoryGetMetalHandleInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryMetalHandleEXT)(VkDevice device, const VkMemoryGetMetalHandleInfoEXT* pGetMetalHandleInfo, void** pHandle); +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryMetalHandlePropertiesEXT)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, const void* pHandle, VkMemoryMetalHandlePropertiesEXT* pMemoryMetalHandleProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryMetalHandleEXT( + VkDevice device, + const VkMemoryGetMetalHandleInfoEXT* pGetMetalHandleInfo, + void** pHandle); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryMetalHandlePropertiesEXT( + VkDevice device, + VkExternalMemoryHandleTypeFlagBits handleType, + const void* pHandle, + VkMemoryMetalHandlePropertiesEXT* pMemoryMetalHandleProperties); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_ohos.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_ohos.h new file mode 100644 index 000000000..e5cdd2d49 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_ohos.h @@ -0,0 +1,120 @@ +#ifndef VULKAN_OHOS_H_ +#define VULKAN_OHOS_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_OHOS_external_memory is a preprocessor guard. Do not pass it to API calls. +#define VK_OHOS_external_memory 1 +struct OH_NativeBuffer; +#define VK_OHOS_EXTERNAL_MEMORY_SPEC_VERSION 1 +#define VK_OHOS_EXTERNAL_MEMORY_EXTENSION_NAME "VK_OHOS_external_memory" +typedef struct VkNativeBufferUsageOHOS { + VkStructureType sType; + void* pNext; + uint64_t OHOSNativeBufferUsage; +} VkNativeBufferUsageOHOS; + +typedef struct VkNativeBufferPropertiesOHOS { + VkStructureType sType; + void* pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeBits; +} VkNativeBufferPropertiesOHOS; + +typedef struct VkNativeBufferFormatPropertiesOHOS { + VkStructureType sType; + void* pNext; + VkFormat format; + uint64_t externalFormat; + VkFormatFeatureFlags formatFeatures; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkNativeBufferFormatPropertiesOHOS; + +typedef struct VkImportNativeBufferInfoOHOS { + VkStructureType sType; + const void* pNext; + struct OH_NativeBuffer* buffer; +} VkImportNativeBufferInfoOHOS; + +typedef struct VkMemoryGetNativeBufferInfoOHOS { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; +} VkMemoryGetNativeBufferInfoOHOS; + +typedef struct VkExternalFormatOHOS { + VkStructureType sType; + void* pNext; + uint64_t externalFormat; +} VkExternalFormatOHOS; + +typedef VkResult (VKAPI_PTR *PFN_vkGetNativeBufferPropertiesOHOS)(VkDevice device, const struct OH_NativeBuffer* buffer, VkNativeBufferPropertiesOHOS* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryNativeBufferOHOS)(VkDevice device, const VkMemoryGetNativeBufferInfoOHOS* pInfo, struct OH_NativeBuffer** pBuffer); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetNativeBufferPropertiesOHOS( + VkDevice device, + const struct OH_NativeBuffer* buffer, + VkNativeBufferPropertiesOHOS* pProperties); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryNativeBufferOHOS( + VkDevice device, + const VkMemoryGetNativeBufferInfoOHOS* pInfo, + struct OH_NativeBuffer** pBuffer); +#endif +#endif + + +// VK_OHOS_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_OHOS_surface 1 +typedef struct NativeWindow OHNativeWindow; +#define VK_OHOS_SURFACE_SPEC_VERSION 1 +#define VK_OHOS_SURFACE_EXTENSION_NAME "VK_OHOS_surface" +typedef VkFlags VkSurfaceCreateFlagsOHOS; +typedef struct VkSurfaceCreateInfoOHOS { + VkStructureType sType; + const void* pNext; + VkSurfaceCreateFlagsOHOS flags; + OHNativeWindow* window; +} VkSurfaceCreateInfoOHOS; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateSurfaceOHOS)(VkInstance instance, const VkSurfaceCreateInfoOHOS* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSurfaceOHOS( + VkInstance instance, + const VkSurfaceCreateInfoOHOS* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_screen.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_screen.h new file mode 100644 index 000000000..460432a44 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_screen.h @@ -0,0 +1,114 @@ +#ifndef VULKAN_SCREEN_H_ +#define VULKAN_SCREEN_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_QNX_screen_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_QNX_screen_surface 1 +#define VK_QNX_SCREEN_SURFACE_SPEC_VERSION 1 +#define VK_QNX_SCREEN_SURFACE_EXTENSION_NAME "VK_QNX_screen_surface" +typedef VkFlags VkScreenSurfaceCreateFlagsQNX; +typedef struct VkScreenSurfaceCreateInfoQNX { + VkStructureType sType; + const void* pNext; + VkScreenSurfaceCreateFlagsQNX flags; + struct _screen_context* context; + struct _screen_window* window; +} VkScreenSurfaceCreateInfoQNX; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateScreenSurfaceQNX)(VkInstance instance, const VkScreenSurfaceCreateInfoQNX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct _screen_window* window); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateScreenSurfaceQNX( + VkInstance instance, + const VkScreenSurfaceCreateInfoQNX* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceScreenPresentationSupportQNX( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + struct _screen_window* window); +#endif +#endif + + +// VK_QNX_external_memory_screen_buffer is a preprocessor guard. Do not pass it to API calls. +#define VK_QNX_external_memory_screen_buffer 1 +#define VK_QNX_EXTERNAL_MEMORY_SCREEN_BUFFER_SPEC_VERSION 1 +#define VK_QNX_EXTERNAL_MEMORY_SCREEN_BUFFER_EXTENSION_NAME "VK_QNX_external_memory_screen_buffer" +typedef struct VkScreenBufferPropertiesQNX { + VkStructureType sType; + void* pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeBits; +} VkScreenBufferPropertiesQNX; + +typedef struct VkScreenBufferFormatPropertiesQNX { + VkStructureType sType; + void* pNext; + VkFormat format; + uint64_t externalFormat; + uint64_t screenUsage; + VkFormatFeatureFlags formatFeatures; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkScreenBufferFormatPropertiesQNX; + +typedef struct VkImportScreenBufferInfoQNX { + VkStructureType sType; + const void* pNext; + struct _screen_buffer* buffer; +} VkImportScreenBufferInfoQNX; + +typedef struct VkExternalFormatQNX { + VkStructureType sType; + void* pNext; + uint64_t externalFormat; +} VkExternalFormatQNX; + +typedef struct VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX { + VkStructureType sType; + void* pNext; + VkBool32 screenBufferImport; +} VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX; + +typedef VkResult (VKAPI_PTR *PFN_vkGetScreenBufferPropertiesQNX)(VkDevice device, const struct _screen_buffer* buffer, VkScreenBufferPropertiesQNX* pProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetScreenBufferPropertiesQNX( + VkDevice device, + const struct _screen_buffer* buffer, + VkScreenBufferPropertiesQNX* pProperties); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_ubm.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_ubm.h new file mode 100644 index 000000000..37cf6609b --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_ubm.h @@ -0,0 +1,59 @@ +#ifndef VULKAN_UBM_H_ +#define VULKAN_UBM_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_SEC_ubm_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_SEC_ubm_surface 1 +#define VK_SEC_UBM_SURFACE_SPEC_VERSION 1 +#define VK_SEC_UBM_SURFACE_EXTENSION_NAME "VK_SEC_ubm_surface" +typedef VkFlags VkUbmSurfaceCreateFlagsSEC; +typedef struct VkUbmSurfaceCreateInfoSEC { + VkStructureType sType; + const void* pNext; + VkUbmSurfaceCreateFlagsSEC flags; + struct ubm_device* device; + struct ubm_surface* surface; +} VkUbmSurfaceCreateInfoSEC; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateUbmSurfaceSEC)(VkInstance instance, const VkUbmSurfaceCreateInfoSEC* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceUbmPresentationSupportSEC)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct ubm_device* device); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateUbmSurfaceSEC( + VkInstance instance, + const VkUbmSurfaceCreateInfoSEC* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceUbmPresentationSupportSEC( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + struct ubm_device* device); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_vi.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_vi.h new file mode 100644 index 000000000..f5237e47b --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_vi.h @@ -0,0 +1,50 @@ +#ifndef VULKAN_VI_H_ +#define VULKAN_VI_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_NN_vi_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_NN_vi_surface 1 +#define VK_NN_VI_SURFACE_SPEC_VERSION 1 +#define VK_NN_VI_SURFACE_EXTENSION_NAME "VK_NN_vi_surface" +typedef VkFlags VkViSurfaceCreateFlagsNN; +typedef struct VkViSurfaceCreateInfoNN { + VkStructureType sType; + const void* pNext; + VkViSurfaceCreateFlagsNN flags; + void* window; +} VkViSurfaceCreateInfoNN; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateViSurfaceNN)(VkInstance instance, const VkViSurfaceCreateInfoNN* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateViSurfaceNN( + VkInstance instance, + const VkViSurfaceCreateInfoNN* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_wayland.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_wayland.h new file mode 100644 index 000000000..16645625f --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_wayland.h @@ -0,0 +1,59 @@ +#ifndef VULKAN_WAYLAND_H_ +#define VULKAN_WAYLAND_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_KHR_wayland_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_wayland_surface 1 +#define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6 +#define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface" +typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; +typedef struct VkWaylandSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkWaylandSurfaceCreateFlagsKHR flags; + struct wl_display* display; + struct wl_surface* surface; +} VkWaylandSurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateWaylandSurfaceKHR)(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct wl_display* display); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateWaylandSurfaceKHR( + VkInstance instance, + const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWaylandPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + struct wl_display* display); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_win32.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_win32.h new file mode 100644 index 000000000..075069277 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_win32.h @@ -0,0 +1,372 @@ +#ifndef VULKAN_WIN32_H_ +#define VULKAN_WIN32_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_KHR_win32_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_win32_surface 1 +#define VK_KHR_WIN32_SURFACE_SPEC_VERSION 6 +#define VK_KHR_WIN32_SURFACE_EXTENSION_NAME "VK_KHR_win32_surface" +typedef VkFlags VkWin32SurfaceCreateFlagsKHR; +typedef struct VkWin32SurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkWin32SurfaceCreateFlagsKHR flags; + HINSTANCE hinstance; + HWND hwnd; +} VkWin32SurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateWin32SurfaceKHR)(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateWin32SurfaceKHR( + VkInstance instance, + const VkWin32SurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWin32PresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex); +#endif +#endif + + +// VK_KHR_external_memory_win32 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_memory_win32 1 +#define VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHR_external_memory_win32" +typedef struct VkImportMemoryWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + HANDLE handle; + LPCWSTR name; +} VkImportMemoryWin32HandleInfoKHR; + +typedef struct VkExportMemoryWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + const SECURITY_ATTRIBUTES* pAttributes; + DWORD dwAccess; + LPCWSTR name; +} VkExportMemoryWin32HandleInfoKHR; + +typedef struct VkMemoryWin32HandlePropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t memoryTypeBits; +} VkMemoryWin32HandlePropertiesKHR; + +typedef struct VkMemoryGetWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkMemoryGetWin32HandleInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleKHR)(VkDevice device, const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle); +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandlePropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleKHR( + VkDevice device, + const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo, + HANDLE* pHandle); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandlePropertiesKHR( + VkDevice device, + VkExternalMemoryHandleTypeFlagBits handleType, + HANDLE handle, + VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties); +#endif +#endif + + +// VK_KHR_win32_keyed_mutex is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_win32_keyed_mutex 1 +#define VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION 1 +#define VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_KHR_win32_keyed_mutex" +typedef struct VkWin32KeyedMutexAcquireReleaseInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t acquireCount; + const VkDeviceMemory* pAcquireSyncs; + const uint64_t* pAcquireKeys; + const uint32_t* pAcquireTimeouts; + uint32_t releaseCount; + const VkDeviceMemory* pReleaseSyncs; + const uint64_t* pReleaseKeys; +} VkWin32KeyedMutexAcquireReleaseInfoKHR; + + + +// VK_KHR_external_semaphore_win32 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_semaphore_win32 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHR_external_semaphore_win32" +typedef struct VkImportSemaphoreWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkSemaphoreImportFlags flags; + VkExternalSemaphoreHandleTypeFlagBits handleType; + HANDLE handle; + LPCWSTR name; +} VkImportSemaphoreWin32HandleInfoKHR; + +typedef struct VkExportSemaphoreWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + const SECURITY_ATTRIBUTES* pAttributes; + DWORD dwAccess; + LPCWSTR name; +} VkExportSemaphoreWin32HandleInfoKHR; + +typedef struct VkD3D12FenceSubmitInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreValuesCount; + const uint64_t* pWaitSemaphoreValues; + uint32_t signalSemaphoreValuesCount; + const uint64_t* pSignalSemaphoreValues; +} VkD3D12FenceSubmitInfoKHR; + +typedef struct VkSemaphoreGetWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkExternalSemaphoreHandleTypeFlagBits handleType; +} VkSemaphoreGetWin32HandleInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreWin32HandleKHR)(VkDevice device, const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreWin32HandleKHR)(VkDevice device, const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreWin32HandleKHR( + VkDevice device, + const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreWin32HandleKHR( + VkDevice device, + const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo, + HANDLE* pHandle); +#endif +#endif + + +// VK_KHR_external_fence_win32 is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_external_fence_win32 1 +#define VK_KHR_EXTERNAL_FENCE_WIN32_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME "VK_KHR_external_fence_win32" +typedef struct VkImportFenceWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + VkFence fence; + VkFenceImportFlags flags; + VkExternalFenceHandleTypeFlagBits handleType; + HANDLE handle; + LPCWSTR name; +} VkImportFenceWin32HandleInfoKHR; + +typedef struct VkExportFenceWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + const SECURITY_ATTRIBUTES* pAttributes; + DWORD dwAccess; + LPCWSTR name; +} VkExportFenceWin32HandleInfoKHR; + +typedef struct VkFenceGetWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + VkFence fence; + VkExternalFenceHandleTypeFlagBits handleType; +} VkFenceGetWin32HandleInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkImportFenceWin32HandleKHR)(VkDevice device, const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetFenceWin32HandleKHR)(VkDevice device, const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkImportFenceWin32HandleKHR( + VkDevice device, + const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceWin32HandleKHR( + VkDevice device, + const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo, + HANDLE* pHandle); +#endif +#endif + + +// VK_NV_external_memory_win32 is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_external_memory_win32 1 +#define VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1 +#define VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_NV_external_memory_win32" +typedef struct VkImportMemoryWin32HandleInfoNV { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagsNV handleType; + HANDLE handle; +} VkImportMemoryWin32HandleInfoNV; + +typedef struct VkExportMemoryWin32HandleInfoNV { + VkStructureType sType; + const void* pNext; + const SECURITY_ATTRIBUTES* pAttributes; + DWORD dwAccess; +} VkExportMemoryWin32HandleInfoNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleNV)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagsNV handleType, HANDLE* pHandle); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleNV( + VkDevice device, + VkDeviceMemory memory, + VkExternalMemoryHandleTypeFlagsNV handleType, + HANDLE* pHandle); +#endif +#endif + + +// VK_NV_win32_keyed_mutex is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_win32_keyed_mutex 1 +#define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 2 +#define VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_NV_win32_keyed_mutex" +typedef struct VkWin32KeyedMutexAcquireReleaseInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t acquireCount; + const VkDeviceMemory* pAcquireSyncs; + const uint64_t* pAcquireKeys; + const uint32_t* pAcquireTimeoutMilliseconds; + uint32_t releaseCount; + const VkDeviceMemory* pReleaseSyncs; + const uint64_t* pReleaseKeys; +} VkWin32KeyedMutexAcquireReleaseInfoNV; + + + +// VK_EXT_full_screen_exclusive is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_full_screen_exclusive 1 +#define VK_EXT_FULL_SCREEN_EXCLUSIVE_SPEC_VERSION 4 +#define VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME "VK_EXT_full_screen_exclusive" + +typedef enum VkFullScreenExclusiveEXT { + VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT = 0, + VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT = 1, + VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT = 2, + VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT = 3, + VK_FULL_SCREEN_EXCLUSIVE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkFullScreenExclusiveEXT; +typedef struct VkSurfaceFullScreenExclusiveInfoEXT { + VkStructureType sType; + void* pNext; + VkFullScreenExclusiveEXT fullScreenExclusive; +} VkSurfaceFullScreenExclusiveInfoEXT; + +typedef struct VkSurfaceCapabilitiesFullScreenExclusiveEXT { + VkStructureType sType; + void* pNext; + VkBool32 fullScreenExclusiveSupported; +} VkSurfaceCapabilitiesFullScreenExclusiveEXT; + +typedef struct VkSurfaceFullScreenExclusiveWin32InfoEXT { + VkStructureType sType; + const void* pNext; + HMONITOR hmonitor; +} VkSurfaceFullScreenExclusiveWin32InfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes); +typedef VkResult (VKAPI_PTR *PFN_vkAcquireFullScreenExclusiveModeEXT)(VkDevice device, VkSwapchainKHR swapchain); +typedef VkResult (VKAPI_PTR *PFN_vkReleaseFullScreenExclusiveModeEXT)(VkDevice device, VkSwapchainKHR swapchain); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModes2EXT)(VkDevice device, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkDeviceGroupPresentModeFlagsKHR* pModes); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModes2EXT( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, + uint32_t* pPresentModeCount, + VkPresentModeKHR* pPresentModes); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireFullScreenExclusiveModeEXT( + VkDevice device, + VkSwapchainKHR swapchain); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkReleaseFullScreenExclusiveModeEXT( + VkDevice device, + VkSwapchainKHR swapchain); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModes2EXT( + VkDevice device, + const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, + VkDeviceGroupPresentModeFlagsKHR* pModes); +#endif +#endif + + +// VK_NV_acquire_winrt_display is a preprocessor guard. Do not pass it to API calls. +#define VK_NV_acquire_winrt_display 1 +#define VK_NV_ACQUIRE_WINRT_DISPLAY_SPEC_VERSION 1 +#define VK_NV_ACQUIRE_WINRT_DISPLAY_EXTENSION_NAME "VK_NV_acquire_winrt_display" +typedef VkResult (VKAPI_PTR *PFN_vkAcquireWinrtDisplayNV)(VkPhysicalDevice physicalDevice, VkDisplayKHR display); +typedef VkResult (VKAPI_PTR *PFN_vkGetWinrtDisplayNV)(VkPhysicalDevice physicalDevice, uint32_t deviceRelativeId, VkDisplayKHR* pDisplay); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireWinrtDisplayNV( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetWinrtDisplayNV( + VkPhysicalDevice physicalDevice, + uint32_t deviceRelativeId, + VkDisplayKHR* pDisplay); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_xcb.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_xcb.h new file mode 100644 index 000000000..439f65d54 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_xcb.h @@ -0,0 +1,60 @@ +#ifndef VULKAN_XCB_H_ +#define VULKAN_XCB_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_KHR_xcb_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_xcb_surface 1 +#define VK_KHR_XCB_SURFACE_SPEC_VERSION 6 +#define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface" +typedef VkFlags VkXcbSurfaceCreateFlagsKHR; +typedef struct VkXcbSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkXcbSurfaceCreateFlagsKHR flags; + xcb_connection_t* connection; + xcb_window_t window; +} VkXcbSurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR( + VkInstance instance, + const VkXcbSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + xcb_connection_t* connection, + xcb_visualid_t visual_id); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_xlib.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_xlib.h new file mode 100644 index 000000000..7394bf7c7 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_xlib.h @@ -0,0 +1,60 @@ +#ifndef VULKAN_XLIB_H_ +#define VULKAN_XLIB_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_KHR_xlib_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_xlib_surface 1 +#define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6 +#define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface" +typedef VkFlags VkXlibSurfaceCreateFlagsKHR; +typedef struct VkXlibSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkXlibSurfaceCreateFlagsKHR flags; + Display* dpy; + Window window; +} VkXlibSurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display* dpy, VisualID visualID); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR( + VkInstance instance, + const VkXlibSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + Display* dpy, + VisualID visualID); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_xlib_xrandr.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_xlib_xrandr.h new file mode 100644 index 000000000..4aabd6442 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/include/vulkan/vulkan_xlib_xrandr.h @@ -0,0 +1,50 @@ +#ifndef VULKAN_XLIB_XRANDR_H_ +#define VULKAN_XLIB_XRANDR_H_ 1 + +/* +** Copyright 2015-2026 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_EXT_acquire_xlib_display is a preprocessor guard. Do not pass it to API calls. +#define VK_EXT_acquire_xlib_display 1 +#define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1 +#define VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_xlib_display" +typedef VkResult (VKAPI_PTR *PFN_vkAcquireXlibDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, VkDisplayKHR display); +typedef VkResult (VKAPI_PTR *PFN_vkGetRandROutputDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, RROutput rrOutput, VkDisplayKHR* pDisplay); + +#ifndef VK_NO_PROTOTYPES +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireXlibDisplayEXT( + VkPhysicalDevice physicalDevice, + Display* dpy, + VkDisplayKHR display); +#endif + +#ifndef VK_ONLY_EXPORTED_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetRandROutputDisplayEXT( + VkPhysicalDevice physicalDevice, + Display* dpy, + RROutput rrOutput, + VkDisplayKHR* pDisplay); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/lib/pkgconfig/ffnvcodec.pc b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/lib/pkgconfig/ffnvcodec.pc new file mode 100644 index 000000000..19f01633e --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/bundled-headers/lib/pkgconfig/ffnvcodec.pc @@ -0,0 +1,7 @@ +prefix=${pcfiledir}/../.. +includedir=${prefix}/include + +Name: ffnvcodec +Description: Bundled FFmpeg NVIDIA codec interface headers +Version: 13.1.15.0.1 +Cflags: -I${includedir} diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/channel_layout_fixed.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/channel_layout_fixed.h new file mode 100644 index 000000000..d92a60d06 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/channel_layout_fixed.h @@ -0,0 +1,224 @@ +// Here until https://github.com/rust-lang/rust-bindgen/issues/2192 / +// https://github.com/rust-lang/rust-bindgen/issues/258 is fixed. +#include + +#if (LIBAVUTIL_VERSION_MAJOR >= 57 && LIBAVUTIL_VERSION_MINOR >= 28) || LIBAVUTIL_VERSION_MAJOR >= 58 + +#undef AV_CH_FRONT_LEFT +#undef AV_CH_FRONT_RIGHT +#undef AV_CH_FRONT_CENTER +#undef AV_CH_LOW_FREQUENCY +#undef AV_CH_BACK_LEFT +#undef AV_CH_BACK_RIGHT +#undef AV_CH_FRONT_LEFT_OF_CENTER +#undef AV_CH_FRONT_RIGHT_OF_CENTER +#undef AV_CH_BACK_CENTER +#undef AV_CH_SIDE_LEFT +#undef AV_CH_SIDE_RIGHT +#undef AV_CH_TOP_CENTER +#undef AV_CH_TOP_FRONT_LEFT +#undef AV_CH_TOP_FRONT_CENTER +#undef AV_CH_TOP_FRONT_RIGHT +#undef AV_CH_TOP_BACK_LEFT +#undef AV_CH_TOP_BACK_CENTER +#undef AV_CH_TOP_BACK_RIGHT +#undef AV_CH_STEREO_LEFT +#undef AV_CH_STEREO_RIGHT +#undef AV_CH_WIDE_LEFT +#undef AV_CH_WIDE_RIGHT +#undef AV_CH_SURROUND_DIRECT_LEFT +#undef AV_CH_SURROUND_DIRECT_RIGHT +#undef AV_CH_LOW_FREQUENCY_2 +#undef AV_CH_TOP_SIDE_LEFT +#undef AV_CH_TOP_SIDE_RIGHT +#undef AV_CH_BOTTOM_FRONT_CENTER +#undef AV_CH_BOTTOM_FRONT_LEFT +#undef AV_CH_BOTTOM_FRONT_RIGHT + +const unsigned long long AV_CH_FRONT_LEFT = (1ULL << AV_CHAN_FRONT_LEFT); +const unsigned long long AV_CH_FRONT_RIGHT = (1ULL << AV_CHAN_FRONT_RIGHT); +const unsigned long long AV_CH_FRONT_CENTER = + (1ULL << AV_CHAN_FRONT_CENTER); +const unsigned long long AV_CH_LOW_FREQUENCY = + (1ULL << AV_CHAN_LOW_FREQUENCY); +const unsigned long long AV_CH_BACK_LEFT = (1ULL << AV_CHAN_BACK_LEFT); +const unsigned long long AV_CH_BACK_RIGHT = (1ULL << AV_CHAN_BACK_RIGHT); +const unsigned long long AV_CH_FRONT_LEFT_OF_CENTER = + (1ULL << AV_CHAN_FRONT_LEFT_OF_CENTER); +const unsigned long long AV_CH_FRONT_RIGHT_OF_CENTER = + (1ULL << AV_CHAN_FRONT_RIGHT_OF_CENTER); +const unsigned long long AV_CH_BACK_CENTER = (1ULL << AV_CHAN_BACK_CENTER); +const unsigned long long AV_CH_SIDE_LEFT = (1ULL << AV_CHAN_SIDE_LEFT); +const unsigned long long AV_CH_SIDE_RIGHT = (1ULL << AV_CHAN_SIDE_RIGHT); +const unsigned long long AV_CH_TOP_CENTER = (1ULL << AV_CHAN_TOP_CENTER); +const unsigned long long AV_CH_TOP_FRONT_LEFT = + (1ULL << AV_CHAN_TOP_FRONT_LEFT); +const unsigned long long AV_CH_TOP_FRONT_CENTER = + (1ULL << AV_CHAN_TOP_FRONT_CENTER); +const unsigned long long AV_CH_TOP_FRONT_RIGHT = + (1ULL << AV_CHAN_TOP_FRONT_RIGHT); +const unsigned long long AV_CH_TOP_BACK_LEFT = + (1ULL << AV_CHAN_TOP_BACK_LEFT); +const unsigned long long AV_CH_TOP_BACK_CENTER = + (1ULL << AV_CHAN_TOP_BACK_CENTER); +const unsigned long long AV_CH_TOP_BACK_RIGHT = + (1ULL << AV_CHAN_TOP_BACK_RIGHT); +const unsigned long long AV_CH_STEREO_LEFT = (1ULL << AV_CHAN_STEREO_LEFT); +const unsigned long long AV_CH_STEREO_RIGHT = + (1ULL << AV_CHAN_STEREO_RIGHT); +const unsigned long long AV_CH_WIDE_LEFT = (1ULL << AV_CHAN_WIDE_LEFT); +const unsigned long long AV_CH_WIDE_RIGHT = (1ULL << AV_CHAN_WIDE_RIGHT); +const unsigned long long AV_CH_SURROUND_DIRECT_LEFT = + (1ULL << AV_CHAN_SURROUND_DIRECT_LEFT); +const unsigned long long AV_CH_SURROUND_DIRECT_RIGHT = + (1ULL << AV_CHAN_SURROUND_DIRECT_RIGHT); +const unsigned long long AV_CH_LOW_FREQUENCY_2 = + (1ULL << AV_CHAN_LOW_FREQUENCY_2); +const unsigned long long AV_CH_TOP_SIDE_LEFT = + (1ULL << AV_CHAN_TOP_SIDE_LEFT); +const unsigned long long AV_CH_TOP_SIDE_RIGHT = + (1ULL << AV_CHAN_TOP_SIDE_RIGHT); +const unsigned long long AV_CH_BOTTOM_FRONT_CENTER = + (1ULL << AV_CHAN_BOTTOM_FRONT_CENTER); +const unsigned long long AV_CH_BOTTOM_FRONT_LEFT = + (1ULL << AV_CHAN_BOTTOM_FRONT_LEFT); +const unsigned long long AV_CH_BOTTOM_FRONT_RIGHT = + (1ULL << AV_CHAN_BOTTOM_FRONT_RIGHT); + +#undef AV_CH_LAYOUT_MONO +#undef AV_CH_LAYOUT_STEREO +#undef AV_CH_LAYOUT_2POINT1 +#undef AV_CH_LAYOUT_2_1 +#undef AV_CH_LAYOUT_SURROUND +#undef AV_CH_LAYOUT_3POINT1 +#undef AV_CH_LAYOUT_4POINT0 +#undef AV_CH_LAYOUT_4POINT1 +#undef AV_CH_LAYOUT_2_2 +#undef AV_CH_LAYOUT_QUAD +#undef AV_CH_LAYOUT_5POINT0 +#undef AV_CH_LAYOUT_5POINT1 +#undef AV_CH_LAYOUT_5POINT0_BACK +#undef AV_CH_LAYOUT_5POINT1_BACK +#undef AV_CH_LAYOUT_6POINT0 +#undef AV_CH_LAYOUT_6POINT0_FRONT +#undef AV_CH_LAYOUT_HEXAGONAL +#undef AV_CH_LAYOUT_6POINT1 +#undef AV_CH_LAYOUT_6POINT1_BACK +#undef AV_CH_LAYOUT_6POINT1_FRONT +#undef AV_CH_LAYOUT_7POINT0 +#undef AV_CH_LAYOUT_7POINT0_FRONT +#undef AV_CH_LAYOUT_7POINT1 +#undef AV_CH_LAYOUT_7POINT1_WIDE +#undef AV_CH_LAYOUT_7POINT1_WIDE_BACK +#undef AV_CH_LAYOUT_OCTAGONAL +#undef AV_CH_LAYOUT_HEXADECAGONAL +#undef AV_CH_LAYOUT_STEREO_DOWNMIX +#undef AV_CH_LAYOUT_22POINT2 +#undef AV_CH_LAYOUT_CUBE + +const unsigned long long AV_CH_LAYOUT_MONO = (AV_CH_FRONT_CENTER); +const unsigned long long AV_CH_LAYOUT_STEREO = + (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT); +const unsigned long long AV_CH_LAYOUT_2POINT1 = + (AV_CH_LAYOUT_STEREO | AV_CH_LOW_FREQUENCY); +const unsigned long long AV_CH_LAYOUT_2_1 = + (AV_CH_LAYOUT_STEREO | AV_CH_BACK_CENTER); +const unsigned long long AV_CH_LAYOUT_SURROUND = + (AV_CH_LAYOUT_STEREO | AV_CH_FRONT_CENTER); +const unsigned long long AV_CH_LAYOUT_3POINT1 = + (AV_CH_LAYOUT_SURROUND | AV_CH_LOW_FREQUENCY); +const unsigned long long AV_CH_LAYOUT_4POINT0 = + (AV_CH_LAYOUT_SURROUND | AV_CH_BACK_CENTER); +const unsigned long long AV_CH_LAYOUT_4POINT1 = + (AV_CH_LAYOUT_4POINT0 | AV_CH_LOW_FREQUENCY); +const unsigned long long AV_CH_LAYOUT_2_2 = + (AV_CH_LAYOUT_STEREO | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT); +const unsigned long long AV_CH_LAYOUT_QUAD = + (AV_CH_LAYOUT_STEREO | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT); +const unsigned long long AV_CH_LAYOUT_5POINT0 = + (AV_CH_LAYOUT_SURROUND | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT); +const unsigned long long AV_CH_LAYOUT_5POINT1 = + (AV_CH_LAYOUT_5POINT0 | AV_CH_LOW_FREQUENCY); +const unsigned long long AV_CH_LAYOUT_5POINT0_BACK = + (AV_CH_LAYOUT_SURROUND | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT); +const unsigned long long AV_CH_LAYOUT_5POINT1_BACK = + (AV_CH_LAYOUT_5POINT0_BACK | AV_CH_LOW_FREQUENCY); +const unsigned long long AV_CH_LAYOUT_6POINT0 = + (AV_CH_LAYOUT_5POINT0 | AV_CH_BACK_CENTER); +const unsigned long long AV_CH_LAYOUT_6POINT0_FRONT = + (AV_CH_LAYOUT_2_2 | AV_CH_FRONT_LEFT_OF_CENTER | + AV_CH_FRONT_RIGHT_OF_CENTER); +const unsigned long long AV_CH_LAYOUT_HEXAGONAL = + (AV_CH_LAYOUT_5POINT0_BACK | AV_CH_BACK_CENTER); +const unsigned long long AV_CH_LAYOUT_6POINT1 = + (AV_CH_LAYOUT_5POINT1 | AV_CH_BACK_CENTER); +const unsigned long long AV_CH_LAYOUT_6POINT1_BACK = + (AV_CH_LAYOUT_5POINT1_BACK | AV_CH_BACK_CENTER); +const unsigned long long AV_CH_LAYOUT_6POINT1_FRONT = + (AV_CH_LAYOUT_6POINT0_FRONT | AV_CH_LOW_FREQUENCY); +const unsigned long long AV_CH_LAYOUT_7POINT0 = + (AV_CH_LAYOUT_5POINT0 | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT); +const unsigned long long AV_CH_LAYOUT_7POINT0_FRONT = + (AV_CH_LAYOUT_5POINT0 | AV_CH_FRONT_LEFT_OF_CENTER | + AV_CH_FRONT_RIGHT_OF_CENTER); +const unsigned long long AV_CH_LAYOUT_7POINT1 = + (AV_CH_LAYOUT_5POINT1 | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT); +const unsigned long long AV_CH_LAYOUT_7POINT1_WIDE = + (AV_CH_LAYOUT_5POINT1 | AV_CH_FRONT_LEFT_OF_CENTER | + AV_CH_FRONT_RIGHT_OF_CENTER); +const unsigned long long AV_CH_LAYOUT_7POINT1_WIDE_BACK = + (AV_CH_LAYOUT_5POINT1_BACK | AV_CH_FRONT_LEFT_OF_CENTER | + AV_CH_FRONT_RIGHT_OF_CENTER); +const unsigned long long AV_CH_LAYOUT_OCTAGONAL = + (AV_CH_LAYOUT_5POINT0 | AV_CH_BACK_LEFT | AV_CH_BACK_CENTER | + AV_CH_BACK_RIGHT); +const unsigned long long AV_CH_LAYOUT_HEXADECAGONAL = + (AV_CH_LAYOUT_OCTAGONAL | AV_CH_WIDE_LEFT | AV_CH_WIDE_RIGHT | + AV_CH_TOP_BACK_LEFT | AV_CH_TOP_BACK_RIGHT | AV_CH_TOP_BACK_CENTER | + AV_CH_TOP_FRONT_CENTER | AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT); +const unsigned long long AV_CH_LAYOUT_STEREO_DOWNMIX = + (AV_CH_STEREO_LEFT | AV_CH_STEREO_RIGHT); +const unsigned long long AV_CH_LAYOUT_22POINT2 = + (AV_CH_LAYOUT_5POINT1_BACK | AV_CH_FRONT_LEFT_OF_CENTER | + AV_CH_FRONT_RIGHT_OF_CENTER | AV_CH_BACK_CENTER | AV_CH_LOW_FREQUENCY_2 | + AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT | AV_CH_TOP_FRONT_LEFT | + AV_CH_TOP_FRONT_RIGHT | AV_CH_TOP_FRONT_CENTER | AV_CH_TOP_CENTER | + AV_CH_TOP_BACK_LEFT | AV_CH_TOP_BACK_RIGHT | AV_CH_TOP_SIDE_LEFT | + AV_CH_TOP_SIDE_RIGHT | AV_CH_TOP_BACK_CENTER | AV_CH_BOTTOM_FRONT_CENTER | + AV_CH_BOTTOM_FRONT_LEFT | AV_CH_BOTTOM_FRONT_RIGHT); +const unsigned long long AV_CH_LAYOUT_CUBE = + (AV_CH_LAYOUT_QUAD | AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT | AV_CH_TOP_BACK_LEFT | AV_CH_TOP_BACK_RIGHT); +#endif + +#if (LIBAVUTIL_VERSION_MAJOR >= 58 && LIBAVUTIL_VERSION_MINOR >= 29) || LIBAVUTIL_VERSION_MAJOR >= 59 + +#undef AV_CH_LAYOUT_3POINT1POINT2 +#undef AV_CH_LAYOUT_5POINT1POINT2_BACK +#undef AV_CH_LAYOUT_5POINT1POINT4_BACK +#undef AV_CH_LAYOUT_7POINT1POINT2 +#undef AV_CH_LAYOUT_7POINT1POINT4_BACK + +const unsigned long long AV_CH_LAYOUT_3POINT1POINT2 = + (AV_CH_LAYOUT_3POINT1 | AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT); +const unsigned long long AV_CH_LAYOUT_5POINT1POINT2_BACK = + (AV_CH_LAYOUT_5POINT1_BACK | AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT); +const unsigned long long AV_CH_LAYOUT_5POINT1POINT4_BACK = + (AV_CH_LAYOUT_5POINT1POINT2_BACK | AV_CH_TOP_BACK_LEFT | AV_CH_TOP_BACK_RIGHT); +const unsigned long long AV_CH_LAYOUT_7POINT1POINT2 = + (AV_CH_LAYOUT_7POINT1 | AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT); +const unsigned long long AV_CH_LAYOUT_7POINT1POINT4_BACK = + (AV_CH_LAYOUT_7POINT1POINT2 | AV_CH_TOP_BACK_LEFT | AV_CH_TOP_BACK_RIGHT); + +#endif + +#if (LIBAVUTIL_VERSION_MAJOR >= 59) + +#undef AV_CH_LAYOUT_7POINT2POINT3 +#undef AV_CH_LAYOUT_9POINT1POINT4_BACK + +const unsigned long long AV_CH_LAYOUT_7POINT2POINT3 = + (AV_CH_LAYOUT_7POINT1POINT2 | AV_CH_TOP_BACK_CENTER | AV_CH_LOW_FREQUENCY_2); +const unsigned long long AV_CH_LAYOUT_9POINT1POINT4_BACK = + (AV_CH_LAYOUT_7POINT1POINT4_BACK | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER); + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_stubs/VideoToolbox/VideoToolbox.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_stubs/VideoToolbox/VideoToolbox.h new file mode 100644 index 000000000..f7dabaee0 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_stubs/VideoToolbox/VideoToolbox.h @@ -0,0 +1,11 @@ +// Shim for during bindgen: AVVTFramesContext needs +// no VT types, but the header's function decls reference these CF/CV handles. +#ifndef HWCONTEXT_STUB_VIDEOTOOLBOX_H +#define HWCONTEXT_STUB_VIDEOTOOLBOX_H + +#include + +typedef const struct __CFString *CFStringRef; +typedef struct __CVBuffer *CVPixelBufferRef; + +#endif /* HWCONTEXT_STUB_VIDEOTOOLBOX_H */ diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_stubs/mfx/mfxvideo.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_stubs/mfx/mfxvideo.h new file mode 100644 index 000000000..6d8d106dc --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_stubs/mfx/mfxvideo.h @@ -0,0 +1,3 @@ +// hwcontext_qsv.h includes (oneVPL) on some builds and +// (Media SDK layout) on others; shim both paths. +#include diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_stubs/mfxvideo.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_stubs/mfxvideo.h new file mode 100644 index 000000000..c30749063 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_stubs/mfxvideo.h @@ -0,0 +1,10 @@ +// Shim for during bindgen: hwcontext_qsv.h needs only these QSV +// handle types (session handle; frame structs only by pointer), not the SDK. +#ifndef HWCONTEXT_STUB_MFXVIDEO_H +#define HWCONTEXT_STUB_MFXVIDEO_H + +typedef struct _mfxSession *mfxSession; +typedef struct mfxFrameSurface1 mfxFrameSurface1; /* opaque; by pointer */ +typedef struct mfxFrameInfo mfxFrameInfo; /* opaque; by pointer */ + +#endif /* HWCONTEXT_STUB_MFXVIDEO_H */ diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_stubs/va/va.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_stubs/va/va.h new file mode 100644 index 000000000..67ef6afb8 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_stubs/va/va.h @@ -0,0 +1,11 @@ +// Shim for during bindgen: hwcontext_vaapi.h needs only these VA +// handle types (opaque handles / uint32 IDs), not the libva API. +#ifndef HWCONTEXT_STUB_VA_H +#define HWCONTEXT_STUB_VA_H + +typedef void *VADisplay; +typedef unsigned int VASurfaceID; +typedef unsigned int VAConfigID; +typedef struct VASurfaceAttrib VASurfaceAttrib; /* opaque; by pointer */ + +#endif /* HWCONTEXT_STUB_VA_H */ diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_stubs/vulkan/vulkan.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_stubs/vulkan/vulkan.h new file mode 100644 index 000000000..5af497d80 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_stubs/vulkan/vulkan.h @@ -0,0 +1,67 @@ +// Minimal shim for during bindgen only. +// +// hwcontext_vulkan.h #includes unconditionally, but we don't +// want the whole Vulkan API in the bindings, nor a hard Vulkan-SDK build +// dependency. +// This shim defines only the types that FFmpeg internal Vulkan code references, +// so bindgen emits those AV structs with their real, linked-FFmpeg layout. +// +// VkPhysicalDeviceFeatures2 is the one struct embedded BY VALUE, so its +// size/alignment must match. +#ifndef VULKAN_H_ +#define VULKAN_H_ + +#include +#include + +typedef uint32_t VkBool32; +typedef uint32_t VkFlags; +typedef uint64_t VkFlags64; + +// Dispatchable handles - pointers. +typedef struct VkInstance_T *VkInstance; +typedef struct VkPhysicalDevice_T *VkPhysicalDevice; +typedef struct VkDevice_T *VkDevice; + +// Non-dispatchable handles - 64-bit on all platforms. +typedef uint64_t VkImage; +typedef uint64_t VkDeviceMemory; +typedef uint64_t VkSemaphore; + +// Enums are int-width. +typedef int VkStructureType; +typedef int VkFormat; +typedef int VkImageTiling; +typedef int VkImageLayout; +typedef unsigned int VkQueueFlagBits; // bitmask (u32) +typedef int VkVideoCodecOperationFlagBitsKHR; +typedef int VkImageUsageFlagBits; +typedef int VkMemoryPropertyFlagBits; +typedef int VkAccessFlagBits; // libavutil 60 (FFmpeg 8.1): AVVkFrame.access + +// Flag bitmasks. +typedef VkFlags VkImageCreateFlags; +typedef VkFlags VkImageUsageFlags; +typedef VkFlags VkDeviceQueueCreateFlags; +typedef VkFlags64 VkAccessFlags2; +typedef VkFlags64 VkAccessFlagBits2; // libavutil 61 (FFmpeg 9.0): .access + +// Only ever referenced through a pointer. +typedef struct VkAllocationCallbacks VkAllocationCallbacks; + +// vkGetInstanceProcAddr loader pointer - pointer-sized. +typedef void (*PFN_vkVoidFunction)(void); +typedef PFN_vkVoidFunction (*PFN_vkGetInstanceProcAddr)(VkInstance, const char *); + +// Embedded BY VALUE, so its size must be exact. Defined structurally (the frozen +// Vulkan 1.1 layout) so clang derives size = 240; _Static_assert pins it. The +// "55" is VkPhysicalDeviceFeatures's member count (frozen; grows via pNext). +typedef struct VkPhysicalDeviceFeatures2 { + VkStructureType sType; + void *pNext; + VkBool32 features[55]; +} VkPhysicalDeviceFeatures2; +_Static_assert(sizeof(VkPhysicalDeviceFeatures2) == 240, + "VkPhysicalDeviceFeatures2 must be 240 bytes (Vulkan 1.1 frozen ABI)"); + +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_wrapper.h b/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_wrapper.h new file mode 100644 index 000000000..3ba258521 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/hwcontext_wrapper.h @@ -0,0 +1,71 @@ +// Binds FFmpeg's per-API hwcontext structs from the real +// headers without pulling in the vendor SDKs. Each +// block is `__has_include`-gated on its libavutil header, so a build binds only +// what it ships. The vendor SDK header each one #includes is handled two ways: +// * CUDA / D3D11 / D3D12 - suppressed via its include guard (CUDA: CUDA_VERSION; +// D3D: __d3dNN_h__) with opaque handle / int-enum stand-ins inline; D3D is +// also gated on (Windows-only). +// * Vulkan / VideoToolbox / VAAPI / QSV - SDK header not reliably present at +// bindgen time, so a shim in hwcontext_stubs/ stands in for it. + +// ── CUDA (hwcontext_cuda.h guards its include with CUDA_VERSION) ── +#if __has_include() +#define CUDA_VERSION 12000 +typedef struct CUctx_st *CUcontext; +typedef struct CUstream_st *CUstream; +#include +#endif + +// ── MediaCodec (no external SDK dependency) ─────────────────────────────── +#if __has_include() +#include +#endif + +// ── D3D11VA (Windows only: gated on ) ──────────────────────────── +#if __has_include() && __has_include() +#define __d3d11_h__ +typedef struct ID3D11Device ID3D11Device; +typedef struct ID3D11DeviceContext ID3D11DeviceContext; +typedef struct ID3D11VideoDevice ID3D11VideoDevice; +typedef struct ID3D11VideoContext ID3D11VideoContext; +typedef struct ID3D11Texture2D ID3D11Texture2D; +typedef unsigned int UINT; +#include +#endif + +// ── D3D12VA (Windows only: gated on ) ──────────────────────────── +#if __has_include() && __has_include() +#define __d3d12_h__ +#define __d3d12sdklayers_h__ +#define __d3d12video_h__ +typedef struct ID3D12Device ID3D12Device; +typedef struct ID3D12VideoDevice ID3D12VideoDevice; +typedef struct ID3D12Fence ID3D12Fence; +typedef struct ID3D12Resource ID3D12Resource; +typedef void *HANDLE; +typedef int DXGI_FORMAT; +// int-width flag enums; emit as u32 (ABI-identical, 4 bytes). +typedef unsigned int D3D12_RESOURCE_FLAGS; +typedef unsigned int D3D12_HEAP_FLAGS; +#include +#endif + +// ── VideoToolbox (shim: hwcontext_stubs/VideoToolbox/VideoToolbox.h) ────── +#if __has_include() +#include +#endif + +// ── Vulkan (shim: hwcontext_stubs/vulkan/vulkan.h) ──────────────────────── +#if __has_include() +#include +#endif + +// ── VAAPI (shim: hwcontext_stubs/va/va.h) ───────────────────────────────── +#if __has_include() +#include +#endif + +// ── QSV (shim: hwcontext_stubs/mfxvideo.h) ──────────────────────────────── +#if __has_include() +#include +#endif diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/error.rs b/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/error.rs new file mode 100644 index 000000000..790b11474 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/error.rs @@ -0,0 +1,71 @@ +use libc::{c_char, c_int, size_t}; + +// Note: FFmpeg's AVERROR and AVUNERROR are conditionally defined based on +// whether EDOM is positive, claiming that "Some platforms have E* and errno +// already negated". This can be traced to a commit in 2007 where "some +// platforms" were specifically identified as BeOS (so maybe also Haiku?): +// https://github.com/FFmpeg/FFmpeg/commit/8fa36ae09dddb1b639b4df5d505c0dbcf4e916e4 +// constness is more valuable than BeOS support, so if someone really needs it, +// send a patch with cfg_attr. + +#[inline(always)] +pub const fn AVERROR(e: c_int) -> c_int { + -e +} + +#[inline(always)] +pub const fn AVUNERROR(e: c_int) -> c_int { + -e +} + +macro_rules! FFERRTAG { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + -MKTAG!($a, $b, $c, $d) as c_int + }; +} + +pub const AVERROR_BSF_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'B', b'S', b'F'); +pub const AVERROR_BUG: c_int = FFERRTAG!(b'B', b'U', b'G', b'!'); +pub const AVERROR_BUFFER_TOO_SMALL: c_int = FFERRTAG!(b'B', b'U', b'F', b'S'); +pub const AVERROR_DECODER_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'D', b'E', b'C'); +pub const AVERROR_DEMUXER_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'D', b'E', b'M'); +pub const AVERROR_ENCODER_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'E', b'N', b'C'); +pub const AVERROR_EOF: c_int = FFERRTAG!(b'E', b'O', b'F', b' '); +pub const AVERROR_EXIT: c_int = FFERRTAG!(b'E', b'X', b'I', b'T'); +pub const AVERROR_EXTERNAL: c_int = FFERRTAG!(b'E', b'X', b'T', b' '); +pub const AVERROR_FILTER_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'F', b'I', b'L'); +pub const AVERROR_INVALIDDATA: c_int = FFERRTAG!(b'I', b'N', b'D', b'A'); +pub const AVERROR_MUXER_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'M', b'U', b'X'); +pub const AVERROR_OPTION_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'O', b'P', b'T'); +pub const AVERROR_PATCHWELCOME: c_int = FFERRTAG!(b'P', b'A', b'W', b'E'); +pub const AVERROR_PROTOCOL_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'P', b'R', b'O'); + +pub const AVERROR_STREAM_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'S', b'T', b'R'); + +pub const AVERROR_BUG2: c_int = FFERRTAG!(b'B', b'U', b'G', b' '); +pub const AVERROR_UNKNOWN: c_int = FFERRTAG!(b'U', b'N', b'K', b'N'); + +pub const AVERROR_HTTP_BAD_REQUEST: c_int = FFERRTAG!(0xF8, b'4', b'0', b'0'); +pub const AVERROR_HTTP_UNAUTHORIZED: c_int = FFERRTAG!(0xF8, b'4', b'0', b'1'); +pub const AVERROR_HTTP_FORBIDDEN: c_int = FFERRTAG!(0xF8, b'4', b'0', b'3'); +pub const AVERROR_HTTP_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'4', b'0', b'4'); +pub const AVERROR_HTTP_TOO_MANY_REQUESTS: c_int = FFERRTAG!(0xF8, b'4', b'2', b'9'); +pub const AVERROR_HTTP_OTHER_4XX: c_int = FFERRTAG!(0xF8, b'4', b'X', b'X'); +pub const AVERROR_HTTP_SERVER_ERROR: c_int = FFERRTAG!(0xF8, b'5', b'X', b'X'); + +#[inline(always)] +pub unsafe fn av_make_error_string( + errbuf: *mut c_char, + errbuf_size: size_t, + errnum: c_int, +) -> *mut c_char { + unsafe { + av_strerror(errnum, errbuf, errbuf_size); + } + + errbuf +} + +unsafe extern "C" { + pub fn av_strerror(errnum: c_int, errbuf: *mut c_char, errbuf_size: size_t) -> c_int; +} diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/macros.rs b/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/macros.rs new file mode 100644 index 000000000..a50636e9b --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/macros.rs @@ -0,0 +1,13 @@ +#[macro_export] +macro_rules! MKBETAG { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + ($d as isize) | (($c as isize) << 8) | (($b as isize) << 16) | (($a as isize) << 24) + }; +} + +#[macro_export] +macro_rules! MKTAG { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + ($a as isize) | (($b as isize) << 8) | (($c as isize) << 16) | (($d as isize) << 24) + }; +} diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/mod.rs b/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/mod.rs new file mode 100644 index 000000000..255964b67 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/mod.rs @@ -0,0 +1,19 @@ +#[macro_use] +mod macros; + +mod error; +pub use self::error::*; + +mod util; +pub use self::util::*; + +mod rational; +pub use self::rational::*; + +mod pixfmt; +pub use self::pixfmt::*; + +#[cfg(feature = "ffmpeg_8_0")] +mod profile; +#[cfg(feature = "ffmpeg_8_0")] +pub use self::profile::*; diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/pixfmt.rs b/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/pixfmt.rs new file mode 100644 index 000000000..bd550b7ec --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/pixfmt.rs @@ -0,0 +1,286 @@ +use crate::AVPixelFormat; +use crate::AVPixelFormat::*; + +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_RGB32: AVPixelFormat = AV_PIX_FMT_BGRA; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_RGB32_1: AVPixelFormat = AV_PIX_FMT_ABGR; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_BGR32: AVPixelFormat = AV_PIX_FMT_RGBA; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_BGR32_1: AVPixelFormat = AV_PIX_FMT_ARGB; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_0RGB32: AVPixelFormat = AV_PIX_FMT_BGR0; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_0BGR32: AVPixelFormat = AV_PIX_FMT_RGB0; + +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_GRAY16: AVPixelFormat = AV_PIX_FMT_GRAY16LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YA16: AVPixelFormat = AV_PIX_FMT_YA16LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_RGB48: AVPixelFormat = AV_PIX_FMT_RGB48LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_RGB565: AVPixelFormat = AV_PIX_FMT_RGB565LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_RGB555: AVPixelFormat = AV_PIX_FMT_RGB555LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_RGB444: AVPixelFormat = AV_PIX_FMT_RGB444LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_BGR48: AVPixelFormat = AV_PIX_FMT_BGR48LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_BGR565: AVPixelFormat = AV_PIX_FMT_BGR565LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_BGR555: AVPixelFormat = AV_PIX_FMT_BGR555LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_BGR444: AVPixelFormat = AV_PIX_FMT_BGR444LE; + +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV420P9: AVPixelFormat = AV_PIX_FMT_YUV420P9LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV422P9: AVPixelFormat = AV_PIX_FMT_YUV422P9LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV444P9: AVPixelFormat = AV_PIX_FMT_YUV444P9LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV420P10: AVPixelFormat = AV_PIX_FMT_YUV420P10LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV422P10: AVPixelFormat = AV_PIX_FMT_YUV422P10LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV440P10: AVPixelFormat = AV_PIX_FMT_YUV440P10LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV444P10: AVPixelFormat = AV_PIX_FMT_YUV444P10LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV420P12: AVPixelFormat = AV_PIX_FMT_YUV420P12LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV422P12: AVPixelFormat = AV_PIX_FMT_YUV422P12LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV440P12: AVPixelFormat = AV_PIX_FMT_YUV440P12LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV444P12: AVPixelFormat = AV_PIX_FMT_YUV444P12LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV420P14: AVPixelFormat = AV_PIX_FMT_YUV420P14LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV422P14: AVPixelFormat = AV_PIX_FMT_YUV422P14LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV444P14: AVPixelFormat = AV_PIX_FMT_YUV444P14LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV420P16: AVPixelFormat = AV_PIX_FMT_YUV420P16LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV422P16: AVPixelFormat = AV_PIX_FMT_YUV422P16LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUV444P16: AVPixelFormat = AV_PIX_FMT_YUV444P16LE; + +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_GBRP9: AVPixelFormat = AV_PIX_FMT_GBRP9LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_GBRP10: AVPixelFormat = AV_PIX_FMT_GBRP10LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_GBRP12: AVPixelFormat = AV_PIX_FMT_GBRP12LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_GBRP14: AVPixelFormat = AV_PIX_FMT_GBRP14LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_GBRP16: AVPixelFormat = AV_PIX_FMT_GBRP16LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_GBRAP16: AVPixelFormat = AV_PIX_FMT_GBRAP16LE; + +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_BAYER_BGGR16: AVPixelFormat = AV_PIX_FMT_BAYER_BGGR16LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_BAYER_RGGB16: AVPixelFormat = AV_PIX_FMT_BAYER_RGGB16LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_BAYER_GBRG16: AVPixelFormat = AV_PIX_FMT_BAYER_GBRG16LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_BAYER_GRBG16: AVPixelFormat = AV_PIX_FMT_BAYER_GRBG16LE; + +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUVA420P9: AVPixelFormat = AV_PIX_FMT_YUVA420P9LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUVA422P9: AVPixelFormat = AV_PIX_FMT_YUVA422P9LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUVA444P9: AVPixelFormat = AV_PIX_FMT_YUVA444P9LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUVA420P10: AVPixelFormat = AV_PIX_FMT_YUVA420P10LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUVA422P10: AVPixelFormat = AV_PIX_FMT_YUVA422P10LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUVA444P10: AVPixelFormat = AV_PIX_FMT_YUVA444P10LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUVA420P16: AVPixelFormat = AV_PIX_FMT_YUVA420P16LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUVA422P16: AVPixelFormat = AV_PIX_FMT_YUVA422P16LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_YUVA444P16: AVPixelFormat = AV_PIX_FMT_YUVA444P16LE; + +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_XYZ12: AVPixelFormat = AV_PIX_FMT_XYZ12LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_NV20: AVPixelFormat = AV_PIX_FMT_NV20LE; +#[cfg(target_endian = "little")] +pub const AV_PIX_FMT_AYUV64: AVPixelFormat = AV_PIX_FMT_AYUV64LE; + +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_RGB32: AVPixelFormat = AV_PIX_FMT_ARGB; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_RGB32_1: AVPixelFormat = AV_PIX_FMT_RGBA; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_BGR32: AVPixelFormat = AV_PIX_FMT_ABGR; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_BGR32_1: AVPixelFormat = AV_PIX_FMT_BGRA; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_0RGB32: AVPixelFormat = AV_PIX_FMT_0RGB; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_0BGR32: AVPixelFormat = AV_PIX_FMT_0BGR; + +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_GRAY16: AVPixelFormat = AV_PIX_FMT_GRAY16BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YA16: AVPixelFormat = AV_PIX_FMT_YA16BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_RGB48: AVPixelFormat = AV_PIX_FMT_RGB48BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_RGB565: AVPixelFormat = AV_PIX_FMT_RGB565BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_RGB555: AVPixelFormat = AV_PIX_FMT_RGB555BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_RGB444: AVPixelFormat = AV_PIX_FMT_RGB444BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_BGR48: AVPixelFormat = AV_PIX_FMT_BGR48BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_BGR565: AVPixelFormat = AV_PIX_FMT_BGR565BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_BGR555: AVPixelFormat = AV_PIX_FMT_BGR555BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_BGR444: AVPixelFormat = AV_PIX_FMT_BGR444BE; + +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV420P9: AVPixelFormat = AV_PIX_FMT_YUV420P9BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV422P9: AVPixelFormat = AV_PIX_FMT_YUV422P9BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV444P9: AVPixelFormat = AV_PIX_FMT_YUV444P9BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV420P10: AVPixelFormat = AV_PIX_FMT_YUV420P10BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV422P10: AVPixelFormat = AV_PIX_FMT_YUV422P10BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV440P10: AVPixelFormat = AV_PIX_FMT_YUV440P10BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV444P10: AVPixelFormat = AV_PIX_FMT_YUV444P10BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV420P12: AVPixelFormat = AV_PIX_FMT_YUV420P12BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV422P12: AVPixelFormat = AV_PIX_FMT_YUV422P12BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV440P12: AVPixelFormat = AV_PIX_FMT_YUV440P12BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV444P12: AVPixelFormat = AV_PIX_FMT_YUV444P12BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV420P14: AVPixelFormat = AV_PIX_FMT_YUV420P14BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV422P14: AVPixelFormat = AV_PIX_FMT_YUV422P14BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV444P14: AVPixelFormat = AV_PIX_FMT_YUV444P14BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV420P16: AVPixelFormat = AV_PIX_FMT_YUV420P16BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV422P16: AVPixelFormat = AV_PIX_FMT_YUV422P16BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUV444P16: AVPixelFormat = AV_PIX_FMT_YUV444P16BE; + +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_GBRP9: AVPixelFormat = AV_PIX_FMT_GBRP9BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_GBRP10: AVPixelFormat = AV_PIX_FMT_GBRP10BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_GBRP12: AVPixelFormat = AV_PIX_FMT_GBRP12BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_GBRP14: AVPixelFormat = AV_PIX_FMT_GBRP14BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_GBRP16: AVPixelFormat = AV_PIX_FMT_GBRP16BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_GBRAP16: AVPixelFormat = AV_PIX_FMT_GBRAP16BE; + +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_BAYER_BGGR16: AVPixelFormat = AV_PIX_FMT_BAYER_BGGR16BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_BAYER_RGGB16: AVPixelFormat = AV_PIX_FMT_BAYER_RGGB16BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_BAYER_GBRG16: AVPixelFormat = AV_PIX_FMT_BAYER_GBRG16BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_BAYER_GRBG16: AVPixelFormat = AV_PIX_FMT_BAYER_GRBG16BE; + +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUVA420P9: AVPixelFormat = AV_PIX_FMT_YUVA420P9BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUVA422P9: AVPixelFormat = AV_PIX_FMT_YUVA422P9BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUVA444P9: AVPixelFormat = AV_PIX_FMT_YUVA444P9BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUVA420P10: AVPixelFormat = AV_PIX_FMT_YUVA420P10BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUVA422P10: AVPixelFormat = AV_PIX_FMT_YUVA422P10BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUVA444P10: AVPixelFormat = AV_PIX_FMT_YUVA444P10BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUVA420P16: AVPixelFormat = AV_PIX_FMT_YUVA420P16BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUVA422P16: AVPixelFormat = AV_PIX_FMT_YUVA422P16BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_YUVA444P16: AVPixelFormat = AV_PIX_FMT_YUVA444P16BE; + +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_XYZ12: AVPixelFormat = AV_PIX_FMT_XYZ12BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_NV20: AVPixelFormat = AV_PIX_FMT_NV20BE; +#[cfg(target_endian = "big")] +pub const AV_PIX_FMT_AYUV64: AVPixelFormat = AV_PIX_FMT_AYUV64BE; + +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "little"))] +pub const AV_PIX_FMT_V30X: AVPixelFormat = AV_PIX_FMT_V30XLE; +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "big"))] +pub const AV_PIX_FMT_V30X: AVPixelFormat = AV_PIX_FMT_V30XBE; + +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "little"))] +pub const AV_PIX_FMT_RGBF16: AVPixelFormat = AV_PIX_FMT_RGBF16LE; +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "big"))] +pub const AV_PIX_FMT_RGBF16: AVPixelFormat = AV_PIX_FMT_RGBF16BE; + +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "little"))] +pub const AV_PIX_FMT_RGB96: AVPixelFormat = AV_PIX_FMT_RGB96LE; +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "big"))] +pub const AV_PIX_FMT_RGB96: AVPixelFormat = AV_PIX_FMT_RGB96BE; + +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "little"))] +pub const AV_PIX_FMT_RGBA128: AVPixelFormat = AV_PIX_FMT_RGBA128LE; +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "big"))] +pub const AV_PIX_FMT_RGBA128: AVPixelFormat = AV_PIX_FMT_RGBA128BE; + +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "little"))] +pub const AV_PIX_FMT_Y216: AVPixelFormat = AV_PIX_FMT_Y216LE; +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "big"))] +pub const AV_PIX_FMT_Y216: AVPixelFormat = AV_PIX_FMT_Y216BE; + +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "little"))] +pub const AV_PIX_FMT_XV48: AVPixelFormat = AV_PIX_FMT_XV48LE; +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "big"))] +pub const AV_PIX_FMT_XV48: AVPixelFormat = AV_PIX_FMT_XV48BE; + +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "little"))] +pub const AV_PIX_FMT_YUV444P10MSB: AVPixelFormat = AV_PIX_FMT_YUV444P10MSBLE; +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "big"))] +pub const AV_PIX_FMT_YUV444P10MSB: AVPixelFormat = AV_PIX_FMT_YUV444P10MSBBE; + +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "little"))] +pub const AV_PIX_FMT_YUV444P12MSB: AVPixelFormat = AV_PIX_FMT_YUV444P12MSBLE; +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "big"))] +pub const AV_PIX_FMT_YUV444P12MSB: AVPixelFormat = AV_PIX_FMT_YUV444P12MSBBE; + +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "little"))] +pub const AV_PIX_FMT_GBRP10MSB: AVPixelFormat = AV_PIX_FMT_GBRP10MSBLE; +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "big"))] +pub const AV_PIX_FMT_GBRP10MSB: AVPixelFormat = AV_PIX_FMT_GBRP10MSBBE; + +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "little"))] +pub const AV_PIX_FMT_GBRP12MSB: AVPixelFormat = AV_PIX_FMT_GBRP12MSBLE; +#[cfg(all(feature = "ffmpeg_8_0", target_endian = "big"))] +pub const AV_PIX_FMT_GBRP12MSB: AVPixelFormat = AV_PIX_FMT_GBRP12MSBBE; diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/profile.rs b/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/profile.rs new file mode 100644 index 000000000..a121f0c85 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/profile.rs @@ -0,0 +1,78 @@ +use crate::*; + +pub const FF_PROFILE_AAC_ELD: i32 = AV_PROFILE_AAC_ELD; +pub const FF_PROFILE_AAC_HE_V2: i32 = AV_PROFILE_AAC_HE_V2; +pub const FF_PROFILE_AAC_HE: i32 = AV_PROFILE_AAC_HE; +pub const FF_PROFILE_AAC_LD: i32 = AV_PROFILE_AAC_LD; +pub const FF_PROFILE_AAC_LOW: i32 = AV_PROFILE_AAC_LOW; +pub const FF_PROFILE_AAC_LTP: i32 = AV_PROFILE_AAC_LTP; +pub const FF_PROFILE_AAC_MAIN: i32 = AV_PROFILE_AAC_MAIN; +pub const FF_PROFILE_AAC_SSR: i32 = AV_PROFILE_AAC_SSR; +pub const FF_PROFILE_DTS_96_24: i32 = AV_PROFILE_DTS_96_24; +pub const FF_PROFILE_DTS_ES: i32 = AV_PROFILE_DTS_ES; +pub const FF_PROFILE_DTS_EXPRESS: i32 = AV_PROFILE_DTS_EXPRESS; +pub const FF_PROFILE_DTS_HD_HRA: i32 = AV_PROFILE_DTS_HD_HRA; +pub const FF_PROFILE_DTS_HD_MA: i32 = AV_PROFILE_DTS_HD_MA; +pub const FF_PROFILE_DTS: i32 = AV_PROFILE_DTS; +pub const FF_PROFILE_H264_BASELINE: i32 = AV_PROFILE_H264_BASELINE; +pub const FF_PROFILE_H264_CAVLC_444: i32 = AV_PROFILE_H264_CAVLC_444; +pub const FF_PROFILE_H264_CONSTRAINED_BASELINE: i32 = AV_PROFILE_H264_CONSTRAINED_BASELINE; +pub const FF_PROFILE_H264_CONSTRAINED: i32 = AV_PROFILE_H264_CONSTRAINED; +pub const FF_PROFILE_H264_EXTENDED: i32 = AV_PROFILE_H264_EXTENDED; +pub const FF_PROFILE_H264_HIGH_10_INTRA: i32 = AV_PROFILE_H264_HIGH_10_INTRA; +pub const FF_PROFILE_H264_HIGH_10: i32 = AV_PROFILE_H264_HIGH_10; +pub const FF_PROFILE_H264_HIGH_422_INTRA: i32 = AV_PROFILE_H264_HIGH_422_INTRA; +pub const FF_PROFILE_H264_HIGH_422: i32 = AV_PROFILE_H264_HIGH_422; +pub const FF_PROFILE_H264_HIGH_444_INTRA: i32 = AV_PROFILE_H264_HIGH_444_INTRA; +pub const FF_PROFILE_H264_HIGH_444_PREDICTIVE: i32 = AV_PROFILE_H264_HIGH_444_PREDICTIVE; +pub const FF_PROFILE_H264_HIGH_444: i32 = AV_PROFILE_H264_HIGH_444; +pub const FF_PROFILE_H264_HIGH: i32 = AV_PROFILE_H264_HIGH; +pub const FF_PROFILE_H264_INTRA: i32 = AV_PROFILE_H264_INTRA; +pub const FF_PROFILE_H264_MAIN: i32 = AV_PROFILE_H264_MAIN; +pub const FF_PROFILE_HEVC_MAIN_10: i32 = AV_PROFILE_HEVC_MAIN_10; +pub const FF_PROFILE_HEVC_MAIN_STILL_PICTURE: i32 = AV_PROFILE_HEVC_MAIN_STILL_PICTURE; +pub const FF_PROFILE_HEVC_MAIN: i32 = AV_PROFILE_HEVC_MAIN; +pub const FF_PROFILE_HEVC_REXT: i32 = AV_PROFILE_HEVC_REXT; +pub const FF_PROFILE_JPEG2000_CSTREAM_NO_RESTRICTION: i32 = + AV_PROFILE_JPEG2000_CSTREAM_NO_RESTRICTION; +pub const FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_0: i32 = + AV_PROFILE_JPEG2000_CSTREAM_RESTRICTION_0; +pub const FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_1: i32 = + AV_PROFILE_JPEG2000_CSTREAM_RESTRICTION_1; +pub const FF_PROFILE_JPEG2000_DCINEMA_2K: i32 = AV_PROFILE_JPEG2000_DCINEMA_2K; +pub const FF_PROFILE_JPEG2000_DCINEMA_4K: i32 = AV_PROFILE_JPEG2000_DCINEMA_4K; +pub const FF_PROFILE_MPEG2_422: i32 = AV_PROFILE_MPEG2_422; +pub const FF_PROFILE_MPEG2_AAC_HE: i32 = AV_PROFILE_MPEG2_AAC_HE; +pub const FF_PROFILE_MPEG2_AAC_LOW: i32 = AV_PROFILE_MPEG2_AAC_LOW; +pub const FF_PROFILE_MPEG2_HIGH: i32 = AV_PROFILE_MPEG2_HIGH; +pub const FF_PROFILE_MPEG2_MAIN: i32 = AV_PROFILE_MPEG2_MAIN; +pub const FF_PROFILE_MPEG2_SIMPLE: i32 = AV_PROFILE_MPEG2_SIMPLE; +pub const FF_PROFILE_MPEG2_SNR_SCALABLE: i32 = AV_PROFILE_MPEG2_SNR_SCALABLE; +pub const FF_PROFILE_MPEG2_SS: i32 = AV_PROFILE_MPEG2_SS; +pub const FF_PROFILE_MPEG4_ADVANCED_CODING: i32 = AV_PROFILE_MPEG4_ADVANCED_CODING; +pub const FF_PROFILE_MPEG4_ADVANCED_CORE: i32 = AV_PROFILE_MPEG4_ADVANCED_CORE; +pub const FF_PROFILE_MPEG4_ADVANCED_REAL_TIME: i32 = AV_PROFILE_MPEG4_ADVANCED_REAL_TIME; +pub const FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE: i32 = + AV_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE; +pub const FF_PROFILE_MPEG4_ADVANCED_SIMPLE: i32 = AV_PROFILE_MPEG4_ADVANCED_SIMPLE; +pub const FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE: i32 = AV_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE; +pub const FF_PROFILE_MPEG4_CORE_SCALABLE: i32 = AV_PROFILE_MPEG4_CORE_SCALABLE; +pub const FF_PROFILE_MPEG4_CORE: i32 = AV_PROFILE_MPEG4_CORE; +pub const FF_PROFILE_MPEG4_HYBRID: i32 = AV_PROFILE_MPEG4_HYBRID; +pub const FF_PROFILE_MPEG4_MAIN: i32 = AV_PROFILE_MPEG4_MAIN; +pub const FF_PROFILE_MPEG4_N_BIT: i32 = AV_PROFILE_MPEG4_N_BIT; +pub const FF_PROFILE_MPEG4_SCALABLE_TEXTURE: i32 = AV_PROFILE_MPEG4_SCALABLE_TEXTURE; +pub const FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION: i32 = AV_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION; +pub const FF_PROFILE_MPEG4_SIMPLE_SCALABLE: i32 = AV_PROFILE_MPEG4_SIMPLE_SCALABLE; +pub const FF_PROFILE_MPEG4_SIMPLE_STUDIO: i32 = AV_PROFILE_MPEG4_SIMPLE_STUDIO; +pub const FF_PROFILE_MPEG4_SIMPLE: i32 = AV_PROFILE_MPEG4_SIMPLE; +pub const FF_PROFILE_RESERVED: i32 = AV_PROFILE_RESERVED; +pub const FF_PROFILE_UNKNOWN: i32 = AV_PROFILE_UNKNOWN; +pub const FF_PROFILE_VC1_ADVANCED: i32 = AV_PROFILE_VC1_ADVANCED; +pub const FF_PROFILE_VC1_COMPLEX: i32 = AV_PROFILE_VC1_COMPLEX; +pub const FF_PROFILE_VC1_MAIN: i32 = AV_PROFILE_VC1_MAIN; +pub const FF_PROFILE_VC1_SIMPLE: i32 = AV_PROFILE_VC1_SIMPLE; +pub const FF_PROFILE_VP9_0: i32 = AV_PROFILE_VP9_0; +pub const FF_PROFILE_VP9_1: i32 = AV_PROFILE_VP9_1; +pub const FF_PROFILE_VP9_2: i32 = AV_PROFILE_VP9_2; +pub const FF_PROFILE_VP9_3: i32 = AV_PROFILE_VP9_3; diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/rational.rs b/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/rational.rs new file mode 100644 index 000000000..2f9c2a0d5 --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/rational.rs @@ -0,0 +1,35 @@ +use crate::AVRational; +use libc::{c_double, c_int}; + +#[inline(always)] +pub unsafe fn av_make_q(num: c_int, den: c_int) -> AVRational { + AVRational { num, den } +} + +#[inline(always)] +pub unsafe fn av_cmp_q(a: AVRational, b: AVRational) -> c_int { + let tmp = i64::from(a.num) * i64::from(b.den) - i64::from(b.num) * i64::from(a.den); + + if tmp != 0 { + (((tmp ^ i64::from(a.den) ^ i64::from(b.den)) >> 63) | 1) as c_int + } else if b.den != 0 && a.den != 0 { + 0 + } else if a.num != 0 && b.num != 0 { + ((i64::from(a.num) >> 31) - (i64::from(b.num) >> 31)) as c_int + } else { + c_int::MIN + } +} + +#[inline(always)] +pub unsafe fn av_q2d(a: AVRational) -> c_double { + f64::from(a.num) / f64::from(a.den) +} + +#[inline(always)] +pub unsafe fn av_inv_q(q: AVRational) -> AVRational { + AVRational { + num: q.den, + den: q.num, + } +} diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/util.rs b/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/util.rs new file mode 100644 index 000000000..60c135eaa --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/src/avutil/util.rs @@ -0,0 +1,8 @@ +use crate::{AV_TIME_BASE, AVRational}; +use libc::c_int; + +pub const AV_NOPTS_VALUE: i64 = 0x8000000000000000u64 as i64; +pub const AV_TIME_BASE_Q: AVRational = AVRational { + num: 1, + den: AV_TIME_BASE as c_int, +}; diff --git a/native/opennow-streamer/vendor/ffmpeg-sys-next/src/lib.rs b/native/opennow-streamer/vendor/ffmpeg-sys-next/src/lib.rs new file mode 100644 index 000000000..945b4820a --- /dev/null +++ b/native/opennow-streamer/vendor/ffmpeg-sys-next/src/lib.rs @@ -0,0 +1,21 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(clippy::approx_constant)] +#![allow(clippy::missing_safety_doc)] +#![allow(clippy::redundant_static_lifetimes)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::type_complexity)] +#![allow(clippy::ptr_offset_with_cast)] +#![allow(clippy::useless_transmute)] +#![allow(unpredictable_function_pointer_comparisons)] +#![allow(unnecessary_transmutes)] +#![allow(suspicious_runtime_symbol_definitions)] + +extern crate libc; + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); + +#[macro_use] +mod avutil; +pub use avutil::*; diff --git a/native/opennow-streamer/vendor/gstreamer-vulkan-windows/1.28.3/OPENNOW-PATCH.txt b/native/opennow-streamer/vendor/gstreamer-vulkan-windows/1.28.3/OPENNOW-PATCH.txt deleted file mode 100644 index 48d2a680d..000000000 --- a/native/opennow-streamer/vendor/gstreamer-vulkan-windows/1.28.3/OPENNOW-PATCH.txt +++ /dev/null @@ -1 +0,0 @@ -Patched gstvkwindow_win32: VkSurface on internal GSTVULKAN hwnd (not Electron parent). diff --git a/native/opennow-streamer/vendor/gstreamer-vulkan-windows/1.28.3/bin/gstvulkan-1.0-0.dll b/native/opennow-streamer/vendor/gstreamer-vulkan-windows/1.28.3/bin/gstvulkan-1.0-0.dll deleted file mode 100644 index 542872401..000000000 Binary files a/native/opennow-streamer/vendor/gstreamer-vulkan-windows/1.28.3/bin/gstvulkan-1.0-0.dll and /dev/null differ diff --git a/native/opennow-streamer/vendor/gstreamer-vulkan-windows/1.28.3/lib/gstreamer-1.0/gstvulkan.dll b/native/opennow-streamer/vendor/gstreamer-vulkan-windows/1.28.3/lib/gstreamer-1.0/gstvulkan.dll deleted file mode 100644 index 097b856a1..000000000 Binary files a/native/opennow-streamer/vendor/gstreamer-vulkan-windows/1.28.3/lib/gstreamer-1.0/gstvulkan.dll and /dev/null differ diff --git a/native/opennow-streamer/vendor/gstreamer-vulkan-windows/README.md b/native/opennow-streamer/vendor/gstreamer-vulkan-windows/README.md deleted file mode 100644 index a7dc26e69..000000000 --- a/native/opennow-streamer/vendor/gstreamer-vulkan-windows/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Windows GStreamer Vulkan plugins - -Official GStreamer Windows packages disable the Vulkan plugin in Cerbero -(`disable_plugin('vulkan', ...)` for Linux/Windows binary builds). - -OpenNOW vendors a matching `gstvulkan` build so the experimental Windows -Vulkan video backend can load `vulkansink` / `vulkanh264dec` / `vulkanh265dec`. - -Artifacts under `1.28.3/` target GStreamer 1.28.3 MSVC x86_64. - -## OpenNOW Win32 embed patch - -`gstvkwindow_win32.c` is patched so `vkCreateWin32SurfaceKHR` targets the -`GSTVULKAN` child hwnd (not the Electron/Chromium parent overlay hwnd). -Stock GStreamer presents onto the parent when `set_window_handle` is used, -which stays black under DirectComposition hole-punch. With this patch, -VideoOverlay parenting works: GSTVULKAN is a visible child of the Internal -surface and the swapchain presents there (no floating top-level window). diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/concrt140.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/concrt140.dll deleted file mode 100644 index 830dfaeaf..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/concrt140.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gio-2.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gio-2.0-0.dll deleted file mode 100644 index 56235522e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gio-2.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/glib-2.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/glib-2.0-0.dll deleted file mode 100644 index a9e79cd53..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/glib-2.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gmodule-2.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gmodule-2.0-0.dll deleted file mode 100644 index f9712b7cd..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gmodule-2.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gobject-2.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gobject-2.0-0.dll deleted file mode 100644 index 33f81a469..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gobject-2.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer-1.0-0.dll deleted file mode 100644 index 66afb1858..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/OPENNOW-GSTREAMER-RUNTIME.txt b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/OPENNOW-GSTREAMER-RUNTIME.txt deleted file mode 100644 index 3135dca61..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/OPENNOW-GSTREAMER-RUNTIME.txt +++ /dev/null @@ -1,7 +0,0 @@ -OpenNOW private GStreamer runtime bundle -Source: C:\Program Files\gstreamer\1.0\msvc_x86_64 -Generated: 2026-06-30T13:34:35.902Z -Platform: win32 -Scope: native streamer child process only - -This directory is loaded only for the native streamer child process. Keep the private layout intact. diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/FLAC-8.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/FLAC-8.dll deleted file mode 100644 index 95227040b..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/FLAC-8.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/SvtAv1Enc.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/SvtAv1Enc.dll deleted file mode 100644 index 9dd3d0cfd..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/SvtAv1Enc.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/SvtJpegxs.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/SvtJpegxs.dll deleted file mode 100644 index bea4c0fee..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/SvtJpegxs.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/accesskit-c-0.17.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/accesskit-c-0.17.dll deleted file mode 100644 index bed220e35..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/accesskit-c-0.17.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/ass-9.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/ass-9.dll deleted file mode 100644 index 0fd9a5ceb..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/ass-9.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/avcodec-61.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/avcodec-61.dll deleted file mode 100644 index c949370bf..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/avcodec-61.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/avfilter-10.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/avfilter-10.dll deleted file mode 100644 index f98956b98..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/avfilter-10.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/avformat-61.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/avformat-61.dll deleted file mode 100644 index 95cf742b2..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/avformat-61.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/avutil-59.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/avutil-59.dll deleted file mode 100644 index c113530a2..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/avutil-59.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/bz2.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/bz2.dll deleted file mode 100644 index d16161f30..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/bz2.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/cairo-2.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/cairo-2.dll deleted file mode 100644 index 044112338..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/cairo-2.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/cairo-gobject-2.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/cairo-gobject-2.dll deleted file mode 100644 index 600f8f053..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/cairo-gobject-2.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/cairo-script-interpreter-2.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/cairo-script-interpreter-2.dll deleted file mode 100644 index b850224af..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/cairo-script-interpreter-2.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/concrt140.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/concrt140.dll deleted file mode 100644 index 830dfaeaf..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/concrt140.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/dav1d.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/dav1d.dll deleted file mode 100644 index 90618b088..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/dav1d.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/dca-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/dca-0.dll deleted file mode 100644 index bffffe9fa..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/dca-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/dv-4.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/dv-4.dll deleted file mode 100644 index 95c0114d4..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/dv-4.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/dvdnav-4.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/dvdnav-4.dll deleted file mode 100644 index ccecadc00..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/dvdnav-4.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/dvdread-8.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/dvdread-8.dll deleted file mode 100644 index 935a9c546..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/dvdread-8.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/epoxy-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/epoxy-0.dll deleted file mode 100644 index 7d4b5aab6..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/epoxy-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/ffi-7.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/ffi-7.dll deleted file mode 100644 index c443a4ac3..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/ffi-7.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/fmt.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/fmt.dll deleted file mode 100644 index eb77ff122..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/fmt.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/fontconfig-1.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/fontconfig-1.dll deleted file mode 100644 index 614b988fb..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/fontconfig-1.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/freetype-6.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/freetype-6.dll deleted file mode 100644 index 8323309db..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/freetype-6.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/fribidi-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/fribidi-0.dll deleted file mode 100644 index a831cbaeb..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/fribidi-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/g-ir-annotation-tool b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/g-ir-annotation-tool deleted file mode 100644 index e6b73a389..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/g-ir-annotation-tool +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/env C:/Users/nirbheek/AppData/Local/Python/pythoncore-3.9-64/python.exe -# -*- Mode: Python -*- -# GObject-Introspection - a framework for introspecting GObject libraries -# Copyright (C) 2008 Johan Dahlin -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301, USA. -# - -import os -import sys -import sysconfig -import builtins - - -debug = os.getenv('GI_SCANNER_DEBUG') -if debug: - if 'pydevd' in debug.split(','): - # http://pydev.org/manual_adv_remote_debugger.html - pydevdpath = os.getenv('PYDEVDPATH', None) - if pydevdpath is not None and os.path.isdir(pydevdpath): - sys.path.insert(0, pydevdpath) - import pydevd - pydevd.settrace() - else: - def on_exception(exctype, value, tb): - print("Caught exception: %r %r" % (exctype, value)) - import pdb - pdb.pm() - sys.excepthook = on_exception - -# Detect and set datadir, pylibdir, etc as applicable -# Similar to the method used in gdbus-codegen -filedir = os.path.dirname(__file__) - -# Try using relative paths first so that the installation prefix is relocatable -datadir = os.path.abspath(os.path.join(filedir, '..', 'share')) -# Fallback to hard-coded paths if the relocatable paths are wrong -if not os.path.isdir(os.path.join(datadir, 'gir-1.0')): - datadir = "C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64/share" - -builtins.__dict__['DATADIR'] = datadir - -gir_dir = os.path.abspath(os.path.join(filedir, '..', 'share', 'gir-1.0')) -# Fallback to hard-coded paths if the relocatable paths are wrong -if not os.path.isdir(gir_dir): - gir_dir = "C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64/share/gir-1.0" - -builtins.__dict__['GIR_DIR'] = gir_dir - -# Again, relative paths first so that the installation prefix is relocatable -pylibdir = os.path.abspath(os.path.join(filedir, '..', 'lib', 'gobject-introspection')) - -# EXT_SUFFIX for py3 SO for py2 -py_mod_suffix = sysconfig.get_config_var('EXT_SUFFIX') or sysconfig.get_config_var('SO') - -if not os.path.isfile(os.path.join(pylibdir, 'giscanner', '_giscanner' + py_mod_suffix)): - # Running uninstalled? - builddir = os.getenv('UNINSTALLED_INTROSPECTION_BUILDDIR', None) - if builddir is not None: - # Autotools, most likely - builddir = os.path.abspath(builddir) - # For _giscanner.so - sys.path.insert(0, os.path.join(builddir, '.libs')) - srcdir = os.getenv('UNINSTALLED_INTROSPECTION_SRCDIR', None) - if srcdir: - # For the giscanner python files - pylibdir = srcdir - elif os.path.isdir(os.path.join(filedir, '..', 'giscanner')): - # We're running uninstalled inside meson - builddir = os.path.abspath(os.path.join(filedir, '..')) - pylibdir = builddir - - if 'GI_GIR_PATH' not in os.environ: - os.environ['GI_GIR_PATH'] = os.path.join(filedir, os.pardir, 'gir') - - gdump_path = os.path.join(builddir, 'giscanner', 'gdump.c') - if os.path.isfile(gdump_path): - builtins.__dict__['GDUMP_PATH'] = gdump_path - else: - # Okay, we're not running uninstalled and the prefix is not - # relocatable. Use hard-coded libdir. - pylibdir = os.path.join('C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64/lib', 'gobject-introspection') - -sys.path.insert(0, pylibdir) - -from giscanner.utils import dll_dirs -dll_dirs = dll_dirs() -dll_dirs.add_dll_dirs(['gio-2.0']) - -def get_rspfile_args(rspfile): - ''' - Response files are useful on Windows where there is a command-line character - limit of 8191 because when passing sources as arguments to glib-mkenums this - limit can be exceeded in large codebases. - - There is no specification for response files and each tool that supports it - generally writes them out in slightly different ways, but some sources are: - https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-response-files - https://docs.microsoft.com/en-us/windows/desktop/midl/the-response-file-command - ''' - import shlex - if not os.path.isfile(rspfile): - sys.exit('Response file {!r} does not exist'.format(rspfile)) - try: - with open(rspfile, 'r') as f: - cmdline = f.read() - except OSError as e: - sys.exit('Response file {!r} could not be read: {}' - .format(rspfile, e.strerror)) - return shlex.split(cmdline) - - -# Support reading an rspfile of the form @filename which contains the args -# to be parsed -if sys.argv[-1].startswith('@'): - args = sys.argv[0:-1] + get_rspfile_args(sys.argv[-1][1:]) -else: - args = sys.argv - -from giscanner.annotationmain import annotation_main -sys.exit(annotation_main(args)) diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/g-ir-compiler.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/g-ir-compiler.exe deleted file mode 100644 index 39bbc175e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/g-ir-compiler.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/g-ir-generate.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/g-ir-generate.exe deleted file mode 100644 index 5e046b3c9..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/g-ir-generate.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/g-ir-inspect.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/g-ir-inspect.exe deleted file mode 100644 index 718fcab38..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/g-ir-inspect.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/g-ir-scanner b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/g-ir-scanner deleted file mode 100644 index ed58d9e1c..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/g-ir-scanner +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/env C:/Users/nirbheek/AppData/Local/Python/pythoncore-3.9-64/python.exe -# -*- Mode: Python -*- -# GObject-Introspection - a framework for introspecting GObject libraries -# Copyright (C) 2008 Johan Dahlin -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301, USA. -# - -import os -import sys -import sysconfig -import builtins - - -debug = os.getenv('GI_SCANNER_DEBUG') -if debug: - if 'pydevd' in debug.split(','): - # http://pydev.org/manual_adv_remote_debugger.html - pydevdpath = os.getenv('PYDEVDPATH', None) - if pydevdpath is not None and os.path.isdir(pydevdpath): - sys.path.insert(0, pydevdpath) - import pydevd - pydevd.settrace() - else: - def on_exception(exctype, value, tb): - print("Caught exception: %r %r" % (exctype, value)) - import pdb - pdb.pm() - sys.excepthook = on_exception - -# Detect and set datadir, pylibdir, etc as applicable -# Similar to the method used in gdbus-codegen -filedir = os.path.dirname(__file__) - -# Try using relative paths first so that the installation prefix is relocatable -datadir = os.path.abspath(os.path.join(filedir, '..', 'share')) -# Fallback to hard-coded paths if the relocatable paths are wrong -if not os.path.isdir(os.path.join(datadir, 'gir-1.0')): - datadir = "C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64/share" - -builtins.__dict__['DATADIR'] = datadir - -gir_dir = os.path.abspath(os.path.join(filedir, '..', 'share', 'gir-1.0')) -# Fallback to hard-coded paths if the relocatable paths are wrong -if not os.path.isdir(gir_dir): - gir_dir = "C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64/share/gir-1.0" - -builtins.__dict__['GIR_DIR'] = gir_dir - -# Again, relative paths first so that the installation prefix is relocatable -pylibdir = os.path.abspath(os.path.join(filedir, '..', 'lib', 'gobject-introspection')) - -# EXT_SUFFIX for py3 SO for py2 -py_mod_suffix = sysconfig.get_config_var('EXT_SUFFIX') or sysconfig.get_config_var('SO') - -if not os.path.isfile(os.path.join(pylibdir, 'giscanner', '_giscanner' + py_mod_suffix)): - # Running uninstalled? - builddir = os.getenv('UNINSTALLED_INTROSPECTION_BUILDDIR', None) - if builddir is not None: - # Autotools, most likely - builddir = os.path.abspath(builddir) - # For _giscanner.so - sys.path.insert(0, os.path.join(builddir, '.libs')) - srcdir = os.getenv('UNINSTALLED_INTROSPECTION_SRCDIR', None) - if srcdir: - # For the giscanner python files - pylibdir = srcdir - elif os.path.isdir(os.path.join(filedir, '..', 'giscanner')): - # We're running uninstalled inside meson - builddir = os.path.abspath(os.path.join(filedir, '..')) - pylibdir = builddir - - if 'GI_GIR_PATH' not in os.environ: - os.environ['GI_GIR_PATH'] = os.path.join(filedir, os.pardir, 'gir') - - gdump_path = os.path.join(builddir, 'giscanner', 'gdump.c') - if os.path.isfile(gdump_path): - builtins.__dict__['GDUMP_PATH'] = gdump_path - else: - # Okay, we're not running uninstalled and the prefix is not - # relocatable. Use hard-coded libdir. - pylibdir = os.path.join('C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64/lib', 'gobject-introspection') - -sys.path.insert(0, pylibdir) - -from giscanner.utils import dll_dirs -dll_dirs = dll_dirs() -dll_dirs.add_dll_dirs(['gio-2.0']) - -def get_rspfile_args(rspfile): - ''' - Response files are useful on Windows where there is a command-line character - limit of 8191 because when passing sources as arguments to glib-mkenums this - limit can be exceeded in large codebases. - - There is no specification for response files and each tool that supports it - generally writes them out in slightly different ways, but some sources are: - https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-response-files - https://docs.microsoft.com/en-us/windows/desktop/midl/the-response-file-command - ''' - import shlex - if not os.path.isfile(rspfile): - sys.exit('Response file {!r} does not exist'.format(rspfile)) - try: - with open(rspfile, 'r') as f: - cmdline = f.read() - except OSError as e: - sys.exit('Response file {!r} could not be read: {}' - .format(rspfile, e.strerror)) - return shlex.split(cmdline) - - -# Support reading an rspfile of the form @filename which contains the args -# to be parsed -if sys.argv[-1].startswith('@'): - args = sys.argv[0:-1] + get_rspfile_args(sys.argv[-1][1:]) -else: - args = sys.argv - -from giscanner.scannermain import scanner_main -sys.exit(scanner_main(args)) diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gdbus-codegen b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gdbus-codegen deleted file mode 100644 index b41ed6b37..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gdbus-codegen +++ /dev/null @@ -1,57 +0,0 @@ -#!C:\projects\repos\cerbero.git\1.28\build\build-tools\bin\python.exe - -# GDBus - GLib D-Bus Library -# -# Copyright (C) 2008-2011 Red Hat, Inc. -# -# SPDX-License-Identifier: LGPL-2.1-or-later -# -# 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 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General -# Public License along with this library; if not, see . -# -# Author: David Zeuthen - - -import os -import sys - -srcdir = os.getenv('UNINSTALLED_GLIB_SRCDIR', None) -filedir = os.path.dirname(__file__) - -if srcdir is not None: - path = os.path.join(srcdir, 'gio', 'gdbus-2.0') -elif os.path.basename(filedir) == 'bin': - # Make the prefix containing gdbus-codegen 'relocatable' at runtime by - # adding /some/prefix/bin/../share/glib-2.0 to the python path - path = os.path.join(filedir, '..', 'share', 'glib-2.0') -else: - # Assume that the modules we need are in the current directory and add the - # parent directory to the python path. - path = os.path.join(filedir, '..') - -# Canonicalize, then do further testing -path = os.path.abspath(path) - -# If the above path detection failed, use the hard-coded datadir. This can -# happen when, for instance, bindir and datadir are not in the same prefix or -# on Windows where we cannot make any guarantees about the directory structure. -# -# In these cases our installation cannot be relocatable, but at least we should -# be able to find the codegen module. -if not os.path.isfile(os.path.join(path, 'codegen', 'codegen_main.py')): - path = os.path.join('C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64/share', 'glib-2.0') - -sys.path.insert(0, path) -from codegen import codegen_main - -sys.exit(codegen_main.codegen_main()) diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gdbus.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gdbus.exe deleted file mode 100644 index 30163f69b..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gdbus.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gdk-pixbuf-csource.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gdk-pixbuf-csource.exe deleted file mode 100644 index b87483411..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gdk-pixbuf-csource.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gdk-pixbuf-query-loaders.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gdk-pixbuf-query-loaders.exe deleted file mode 100644 index 1407281d8..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gdk-pixbuf-query-loaders.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gdk_pixbuf-2.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gdk_pixbuf-2.0-0.dll deleted file mode 100644 index fa787363c..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gdk_pixbuf-2.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/ges-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/ges-1.0-0.dll deleted file mode 100644 index 7a3f44e87..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/ges-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/ges-launch-1.0.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/ges-launch-1.0.exe deleted file mode 100644 index ee2b8e9a8..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/ges-launch-1.0.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gio-2.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gio-2.0-0.dll deleted file mode 100644 index 56235522e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gio-2.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gio-querymodules.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gio-querymodules.exe deleted file mode 100644 index ebc9a14cf..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gio-querymodules.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/girepository-1.0-1.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/girepository-1.0-1.dll deleted file mode 100644 index ada1ff718..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/girepository-1.0-1.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-2.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-2.0-0.dll deleted file mode 100644 index a9e79cd53..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-2.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-compile-resources.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-compile-resources.exe deleted file mode 100644 index 003d72a31..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-compile-resources.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-compile-schemas.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-compile-schemas.exe deleted file mode 100644 index 5bfbd6396..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-compile-schemas.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-genmarshal b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-genmarshal deleted file mode 100644 index bc3fe55ac..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-genmarshal +++ /dev/null @@ -1,1080 +0,0 @@ -#!C:\projects\repos\cerbero.git\1.28\build\build-tools\bin\python.exe - -# pylint: disable=too-many-lines, missing-docstring, invalid-name - -# This file is part of GLib -# -# 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 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, see . - -import argparse -import os -import re -import sys - -VERSION_STR = '''glib-genmarshal version 2.82.4 -glib-genmarshal comes with ABSOLUTELY NO WARRANTY. -You may redistribute copies of glib-genmarshal under the terms of -the GNU General Public License which can be found in the -GLib source package. Sources, examples and contact -information are available at http://www.gtk.org''' - -GETTERS_STR = '''#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */''' - -DEPRECATED_MSG_STR = 'The token "{}" is deprecated; use "{}" instead' - -VA_ARG_STR = \ - ' arg{:d} = ({:s}) va_arg (args_copy, {:s});' -STATIC_CHECK_STR = \ - '(param_types[{:d}] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0 && ' -BOX_TYPED_STR = \ - ' arg{idx:d} = {box_func} (param_types[{idx:d}] & ~G_SIGNAL_TYPE_STATIC_SCOPE, arg{idx:d});' -BOX_UNTYPED_STR = \ - ' arg{idx:d} = {box_func} (arg{idx:d});' -UNBOX_TYPED_STR = \ - ' {unbox_func} (param_types[{idx:d}] & ~G_SIGNAL_TYPE_STATIC_SCOPE, arg{idx:d});' -UNBOX_UNTYPED_STR = \ - ' {unbox_func} (arg{idx:d});' - -STD_PREFIX = 'g_cclosure_marshal' - -# These are part of our ABI; keep this in sync with gmarshal.h -GOBJECT_MARSHALLERS = { - 'g_cclosure_marshal_VOID__VOID', - 'g_cclosure_marshal_VOID__BOOLEAN', - 'g_cclosure_marshal_VOID__CHAR', - 'g_cclosure_marshal_VOID__UCHAR', - 'g_cclosure_marshal_VOID__INT', - 'g_cclosure_marshal_VOID__UINT', - 'g_cclosure_marshal_VOID__LONG', - 'g_cclosure_marshal_VOID__ULONG', - 'g_cclosure_marshal_VOID__ENUM', - 'g_cclosure_marshal_VOID__FLAGS', - 'g_cclosure_marshal_VOID__FLOAT', - 'g_cclosure_marshal_VOID__DOUBLE', - 'g_cclosure_marshal_VOID__STRING', - 'g_cclosure_marshal_VOID__PARAM', - 'g_cclosure_marshal_VOID__BOXED', - 'g_cclosure_marshal_VOID__POINTER', - 'g_cclosure_marshal_VOID__OBJECT', - 'g_cclosure_marshal_VOID__VARIANT', - 'g_cclosure_marshal_VOID__UINT_POINTER', - 'g_cclosure_marshal_BOOLEAN__FLAGS', - 'g_cclosure_marshal_STRING__OBJECT_POINTER', - 'g_cclosure_marshal_BOOLEAN__BOXED_BOXED', -} - - -# pylint: disable=too-few-public-methods -class Color: - '''ANSI Terminal colors''' - GREEN = '\033[1;32m' - BLUE = '\033[1;34m' - YELLOW = '\033[1;33m' - RED = '\033[1;31m' - END = '\033[0m' - - -def print_color(msg, color=Color.END, prefix='MESSAGE'): - '''Print a string with a color prefix''' - if os.isatty(sys.stderr.fileno()): - real_prefix = '{start}{prefix}{end}'.format(start=color, prefix=prefix, end=Color.END) - else: - real_prefix = prefix - sys.stderr.write('{prefix}: {msg}\n'.format(prefix=real_prefix, msg=msg)) - - -def print_error(msg): - '''Print an error, and terminate''' - print_color(msg, color=Color.RED, prefix='ERROR') - sys.exit(1) - - -def print_warning(msg, fatal=False): - '''Print a warning, and optionally terminate''' - if fatal: - color = Color.RED - prefix = 'ERROR' - else: - color = Color.YELLOW - prefix = 'WARNING' - print_color(msg, color, prefix) - if fatal: - sys.exit(1) - - -def print_info(msg): - '''Print a message''' - print_color(msg, color=Color.GREEN, prefix='INFO') - - -def generate_licensing_comment(outfile): - outfile.write('/* This file is generated by glib-genmarshal, do not ' - 'modify it. This code is licensed under the same license as ' - 'the containing project. Note that it links to GLib, so ' - 'must comply with the LGPL linking clauses. */\n') - - -def generate_header_preamble(outfile, prefix='', std_includes=True, use_pragma=False): - '''Generate the preamble for the marshallers header file''' - generate_licensing_comment(outfile) - - if use_pragma: - outfile.write('#pragma once\n') - outfile.write('\n') - else: - outfile.write('#ifndef __{}_MARSHAL_H__\n'.format(prefix.upper())) - outfile.write('#define __{}_MARSHAL_H__\n'.format(prefix.upper())) - outfile.write('\n') - # Maintain compatibility with the old C-based tool - if std_includes: - outfile.write('#include \n') - outfile.write('\n') - - outfile.write('G_BEGIN_DECLS\n') - outfile.write('\n') - - -def generate_header_postamble(outfile, prefix='', use_pragma=False): - '''Generate the postamble for the marshallers header file''' - outfile.write('\n') - outfile.write('G_END_DECLS\n') - - if not use_pragma: - outfile.write('\n') - outfile.write('#endif /* __{}_MARSHAL_H__ */\n'.format(prefix.upper())) - - -def generate_body_preamble(outfile, std_includes=True, include_headers=None, cpp_defines=None, cpp_undefines=None): - '''Generate the preamble for the marshallers source file''' - generate_licensing_comment(outfile) - - for header in (include_headers or []): - outfile.write('#include "{}"\n'.format(header)) - if include_headers: - outfile.write('\n') - - for define in (cpp_defines or []): - s = define.split('=') - symbol = s[0] - value = s[1] if len(s) > 1 else '1' - outfile.write('#define {} {}\n'.format(symbol, value)) - if cpp_defines: - outfile.write('\n') - - for undefine in (cpp_undefines or []): - outfile.write('#undef {}\n'.format(undefine)) - if cpp_undefines: - outfile.write('\n') - - if std_includes: - outfile.write('#include \n') - outfile.write('\n') - - outfile.write(GETTERS_STR) - outfile.write('\n\n') - - -# Marshaller arguments, as a dictionary where the key is the token used in -# the source file, and the value is another dictionary with the following -# keys: -# -# - signal: the token used in the marshaller prototype (mandatory) -# - ctype: the C type for the marshaller argument (mandatory) -# - getter: the function used to retrieve the argument from the GValue -# array when invoking the callback (optional) -# - promoted: the C type used by va_arg() to retrieve the argument from -# the va_list when invoking the callback (optional, only used when -# generating va_list marshallers) -# - box: an array of two elements, containing the boxing and unboxing -# functions for the given type (optional, only used when generating -# va_list marshallers) -# - static-check: a boolean value, if the given type should perform -# a static type check before boxing or unboxing the argument (optional, -# only used when generating va_list marshallers) -# - takes-type: a boolean value, if the boxing and unboxing functions -# for the given type require the type (optional, only used when -# generating va_list marshallers) -# - deprecated: whether the token has been deprecated (optional) -# - replaced-by: the token used to replace a deprecated token (optional, -# only used if deprecated is True) -IN_ARGS = { - 'VOID': { - 'signal': 'VOID', - 'ctype': 'void', - }, - 'BOOLEAN': { - 'signal': 'BOOLEAN', - 'ctype': 'gboolean', - 'getter': 'g_marshal_value_peek_boolean', - }, - 'CHAR': { - 'signal': 'CHAR', - 'ctype': 'gchar', - 'promoted': 'gint', - 'getter': 'g_marshal_value_peek_char', - }, - 'UCHAR': { - 'signal': 'UCHAR', - 'ctype': 'guchar', - 'promoted': 'guint', - 'getter': 'g_marshal_value_peek_uchar', - }, - 'INT': { - 'signal': 'INT', - 'ctype': 'gint', - 'getter': 'g_marshal_value_peek_int', - }, - 'UINT': { - 'signal': 'UINT', - 'ctype': 'guint', - 'getter': 'g_marshal_value_peek_uint', - }, - 'LONG': { - 'signal': 'LONG', - 'ctype': 'glong', - 'getter': 'g_marshal_value_peek_long', - }, - 'ULONG': { - 'signal': 'ULONG', - 'ctype': 'gulong', - 'getter': 'g_marshal_value_peek_ulong', - }, - 'INT64': { - 'signal': 'INT64', - 'ctype': 'gint64', - 'getter': 'g_marshal_value_peek_int64', - }, - 'UINT64': { - 'signal': 'UINT64', - 'ctype': 'guint64', - 'getter': 'g_marshal_value_peek_uint64', - }, - 'ENUM': { - 'signal': 'ENUM', - 'ctype': 'gint', - 'getter': 'g_marshal_value_peek_enum', - }, - 'FLAGS': { - 'signal': 'FLAGS', - 'ctype': 'guint', - 'getter': 'g_marshal_value_peek_flags', - }, - 'FLOAT': { - 'signal': 'FLOAT', - 'ctype': 'gfloat', - 'promoted': 'gdouble', - 'getter': 'g_marshal_value_peek_float', - }, - 'DOUBLE': { - 'signal': 'DOUBLE', - 'ctype': 'gdouble', - 'getter': 'g_marshal_value_peek_double', - }, - 'STRING': { - 'signal': 'STRING', - 'ctype': 'gpointer', - 'getter': 'g_marshal_value_peek_string', - 'box': ['g_strdup', 'g_free'], - 'static-check': True, - }, - 'PARAM': { - 'signal': 'PARAM', - 'ctype': 'gpointer', - 'getter': 'g_marshal_value_peek_param', - 'box': ['g_param_spec_ref', 'g_param_spec_unref'], - 'static-check': True, - }, - 'BOXED': { - 'signal': 'BOXED', - 'ctype': 'gpointer', - 'getter': 'g_marshal_value_peek_boxed', - 'box': ['g_boxed_copy', 'g_boxed_free'], - 'static-check': True, - 'takes-type': True, - }, - 'POINTER': { - 'signal': 'POINTER', - 'ctype': 'gpointer', - 'getter': 'g_marshal_value_peek_pointer', - }, - 'OBJECT': { - 'signal': 'OBJECT', - 'ctype': 'gpointer', - 'getter': 'g_marshal_value_peek_object', - 'box': ['g_object_ref', 'g_object_unref'], - }, - 'VARIANT': { - 'signal': 'VARIANT', - 'ctype': 'gpointer', - 'getter': 'g_marshal_value_peek_variant', - 'box': ['g_variant_ref_sink', 'g_variant_unref'], - 'static-check': True, - 'takes-type': False, - }, - - # Deprecated tokens - 'NONE': { - 'signal': 'VOID', - 'ctype': 'void', - 'deprecated': True, - 'replaced_by': 'VOID' - }, - 'BOOL': { - 'signal': 'BOOLEAN', - 'ctype': 'gboolean', - 'getter': 'g_marshal_value_peek_boolean', - 'deprecated': True, - 'replaced_by': 'BOOLEAN' - } -} - - -# Marshaller return values, as a dictionary where the key is the token used -# in the source file, and the value is another dictionary with the following -# keys: -# -# - signal: the token used in the marshaller prototype (mandatory) -# - ctype: the C type for the marshaller argument (mandatory) -# - setter: the function used to set the return value of the callback -# into a GValue (optional) -# - deprecated: whether the token has been deprecated (optional) -# - replaced-by: the token used to replace a deprecated token (optional, -# only used if deprecated is True) -OUT_ARGS = { - 'VOID': { - 'signal': 'VOID', - 'ctype': 'void', - }, - 'BOOLEAN': { - 'signal': 'BOOLEAN', - 'ctype': 'gboolean', - 'setter': 'g_value_set_boolean', - }, - 'CHAR': { - 'signal': 'CHAR', - 'ctype': 'gchar', - 'setter': 'g_value_set_char', - }, - 'UCHAR': { - 'signal': 'UCHAR', - 'ctype': 'guchar', - 'setter': 'g_value_set_uchar', - }, - 'INT': { - 'signal': 'INT', - 'ctype': 'gint', - 'setter': 'g_value_set_int', - }, - 'UINT': { - 'signal': 'UINT', - 'ctype': 'guint', - 'setter': 'g_value_set_uint', - }, - 'LONG': { - 'signal': 'LONG', - 'ctype': 'glong', - 'setter': 'g_value_set_long', - }, - 'ULONG': { - 'signal': 'ULONG', - 'ctype': 'gulong', - 'setter': 'g_value_set_ulong', - }, - 'INT64': { - 'signal': 'INT64', - 'ctype': 'gint64', - 'setter': 'g_value_set_int64', - }, - 'UINT64': { - 'signal': 'UINT64', - 'ctype': 'guint64', - 'setter': 'g_value_set_uint64', - }, - 'ENUM': { - 'signal': 'ENUM', - 'ctype': 'gint', - 'setter': 'g_value_set_enum', - }, - 'FLAGS': { - 'signal': 'FLAGS', - 'ctype': 'guint', - 'setter': 'g_value_set_flags', - }, - 'FLOAT': { - 'signal': 'FLOAT', - 'ctype': 'gfloat', - 'setter': 'g_value_set_float', - }, - 'DOUBLE': { - 'signal': 'DOUBLE', - 'ctype': 'gdouble', - 'setter': 'g_value_set_double', - }, - 'STRING': { - 'signal': 'STRING', - 'ctype': 'gchar*', - 'setter': 'g_value_take_string', - }, - 'PARAM': { - 'signal': 'PARAM', - 'ctype': 'GParamSpec*', - 'setter': 'g_value_take_param', - }, - 'BOXED': { - 'signal': 'BOXED', - 'ctype': 'gpointer', - 'setter': 'g_value_take_boxed', - }, - 'POINTER': { - 'signal': 'POINTER', - 'ctype': 'gpointer', - 'setter': 'g_value_set_pointer', - }, - 'OBJECT': { - 'signal': 'OBJECT', - 'ctype': 'GObject*', - 'setter': 'g_value_take_object', - }, - 'VARIANT': { - 'signal': 'VARIANT', - 'ctype': 'GVariant*', - 'setter': 'g_value_take_variant', - }, - - # Deprecated tokens - 'NONE': { - 'signal': 'VOID', - 'ctype': 'void', - 'setter': None, - 'deprecated': True, - 'replaced_by': 'VOID', - }, - 'BOOL': { - 'signal': 'BOOLEAN', - 'ctype': 'gboolean', - 'setter': 'g_value_set_boolean', - 'deprecated': True, - 'replaced_by': 'BOOLEAN', - }, -} - - -def check_args(retval, params, fatal_warnings=False): - '''Check the @retval and @params tokens for invalid and deprecated symbols.''' - if retval not in OUT_ARGS: - print_error('Unknown return value type "{}"'.format(retval)) - - if OUT_ARGS[retval].get('deprecated', False): - replaced_by = OUT_ARGS[retval]['replaced_by'] - print_warning(DEPRECATED_MSG_STR.format(retval, replaced_by), fatal_warnings) - - for param in params: - if param not in IN_ARGS: - print_error('Unknown parameter type "{}"'.format(param)) - else: - if IN_ARGS[param].get('deprecated', False): - replaced_by = IN_ARGS[param]['replaced_by'] - print_warning(DEPRECATED_MSG_STR.format(param, replaced_by), fatal_warnings) - - -def indent(text, level=0, fill=' '): - '''Indent @text by @level columns, using the @fill character''' - return ''.join([fill for x in range(level)]) + text - - -# pylint: disable=too-few-public-methods -class Visibility: - '''Symbol visibility options''' - NONE = 0 - INTERNAL = 1 - EXTERN = 2 - - -def generate_marshaller_name(prefix, retval, params, replace_deprecated=True): - '''Generate a marshaller name for the given @prefix, @retval, and @params. - If @replace_deprecated is True, the generated name will replace deprecated - tokens.''' - if replace_deprecated: - real_retval = OUT_ARGS[retval]['signal'] - real_params = [] - for param in params: - real_params.append(IN_ARGS[param]['signal']) - else: - real_retval = retval - real_params = params - return '{prefix}_{retval}__{args}'.format(prefix=prefix, - retval=real_retval, - args='_'.join(real_params)) - - -def generate_prototype(retval, params, - prefix='g_cclosure_user_marshal', - visibility=Visibility.NONE, - va_marshal=False): - '''Generate a marshaller declaration with the given @visibility. If @va_marshal - is True, the marshaller will use variadic arguments in place of a GValue array.''' - signature = [] - - if visibility == Visibility.INTERNAL: - signature += ['G_GNUC_INTERNAL'] - elif visibility == Visibility.EXTERN: - signature += ['extern'] - - function_name = generate_marshaller_name(prefix, retval, params) - - if not va_marshal: - signature += ['void ' + function_name + ' (GClosure *closure,'] - width = len('void ') + len(function_name) + 2 - - signature += [indent('GValue *return_value,', level=width, fill=' ')] - signature += [indent('guint n_param_values,', level=width, fill=' ')] - signature += [indent('const GValue *param_values,', level=width, fill=' ')] - signature += [indent('gpointer invocation_hint,', level=width, fill=' ')] - signature += [indent('gpointer marshal_data);', level=width, fill=' ')] - else: - signature += ['void ' + function_name + 'v (GClosure *closure,'] - width = len('void ') + len(function_name) + 3 - - signature += [indent('GValue *return_value,', level=width, fill=' ')] - signature += [indent('gpointer instance,', level=width, fill=' ')] - signature += [indent('va_list args,', level=width, fill=' ')] - signature += [indent('gpointer marshal_data,', level=width, fill=' ')] - signature += [indent('int n_params,', level=width, fill=' ')] - signature += [indent('GType *param_types);', level=width, fill=' ')] - - return signature - - -# pylint: disable=too-many-statements, too-many-locals, too-many-branches -def generate_body(retval, params, prefix, va_marshal=False): - '''Generate a marshaller definition. If @va_marshal is True, the marshaller - will use va_list and variadic arguments in place of a GValue array.''' - retval_setter = OUT_ARGS[retval].get('setter', None) - # If there's no return value then we can mark the retval argument as unused - # and get a minor optimisation, as well as avoid a compiler warning - if not retval_setter: - unused = ' G_GNUC_UNUSED' - else: - unused = '' - - body = ['void'] - - function_name = generate_marshaller_name(prefix, retval, params) - - if not va_marshal: - body += [function_name + ' (GClosure *closure,'] - width = len(function_name) + 2 - - body += [indent('GValue *return_value{},'.format(unused), level=width, fill=' ')] - body += [indent('guint n_param_values,', level=width, fill=' ')] - body += [indent('const GValue *param_values,', level=width, fill=' ')] - body += [indent('gpointer invocation_hint G_GNUC_UNUSED,', level=width, fill=' ')] - body += [indent('gpointer marshal_data)', level=width, fill=' ')] - else: - body += [function_name + 'v (GClosure *closure,'] - width = len(function_name) + 3 - - body += [indent('GValue *return_value{},'.format(unused), level=width, fill=' ')] - body += [indent('gpointer instance,', level=width, fill=' ')] - body += [indent('va_list args,', level=width, fill=' ')] - body += [indent('gpointer marshal_data,', level=width, fill=' ')] - body += [indent('int n_params,', level=width, fill=' ')] - body += [indent('GType *param_types)', level=width, fill=' ')] - - # Filter the arguments that have a getter - get_args = [x for x in params if IN_ARGS[x].get('getter', None) is not None] - - body += ['{'] - - # Generate the type of the marshaller function - typedef_marshal = generate_marshaller_name('GMarshalFunc', retval, params) - - typedef = ' typedef {ctype} (*{func_name}) ('.format(ctype=OUT_ARGS[retval]['ctype'], - func_name=typedef_marshal) - pad = len(typedef) - typedef += 'gpointer data1,' - body += [typedef] - - for idx, in_arg in enumerate(get_args): - body += [indent('{} arg{:d},'.format(IN_ARGS[in_arg]['ctype'], idx + 1), level=pad)] - - body += [indent('gpointer data2);', level=pad)] - - # Variable declarations - body += [' GCClosure *cc = (GCClosure *) closure;'] - body += [' gpointer data1, data2;'] - body += [' {} callback;'.format(typedef_marshal)] - - if retval_setter: - body += [' {} v_return;'.format(OUT_ARGS[retval]['ctype'])] - - if va_marshal: - for idx, arg in enumerate(get_args): - body += [' {} arg{:d};'.format(IN_ARGS[arg]['ctype'], idx)] - - if get_args: - body += [' va_list args_copy;'] - body += [''] - - body += [' va_copy (args_copy, args);'] - - for idx, arg in enumerate(get_args): - ctype = IN_ARGS[arg]['ctype'] - promoted_ctype = IN_ARGS[arg].get('promoted', ctype) - body += [VA_ARG_STR.format(idx, ctype, promoted_ctype)] - if IN_ARGS[arg].get('box', None): - box_func = IN_ARGS[arg]['box'][0] - if IN_ARGS[arg].get('static-check', False): - static_check = STATIC_CHECK_STR.format(idx) - else: - static_check = '' - arg_check = 'arg{:d} != NULL'.format(idx) - body += [' if ({}{})'.format(static_check, arg_check)] - if IN_ARGS[arg].get('takes-type', False): - body += [BOX_TYPED_STR.format(idx=idx, box_func=box_func)] - else: - body += [BOX_UNTYPED_STR.format(idx=idx, box_func=box_func)] - - body += [' va_end (args_copy);'] - - body += [''] - - # Preconditions check - if retval_setter: - body += [' g_return_if_fail (return_value != NULL);'] - - if not va_marshal: - body += [' g_return_if_fail (n_param_values == {:d});'.format(len(get_args) + 1)] - - body += [''] - - # Marshal instance, data, and callback set up - body += [' if (G_CCLOSURE_SWAP_DATA (closure))'] - body += [' {'] - body += [' data1 = closure->data;'] - if va_marshal: - body += [' data2 = instance;'] - else: - body += [' data2 = g_value_peek_pointer (param_values + 0);'] - body += [' }'] - body += [' else'] - body += [' {'] - if va_marshal: - body += [' data1 = instance;'] - else: - body += [' data1 = g_value_peek_pointer (param_values + 0);'] - body += [' data2 = closure->data;'] - body += [' }'] - # pylint: disable=line-too-long - body += [' callback = ({}) (marshal_data ? marshal_data : cc->callback);'.format(typedef_marshal)] - body += [''] - - # Marshal callback action - if retval_setter: - callback = ' {} callback ('.format(' v_return =') - else: - callback = ' callback (' - - pad = len(callback) - body += [callback + 'data1,'] - - if va_marshal: - for idx, arg in enumerate(get_args): - body += [indent('arg{:d},'.format(idx), level=pad)] - else: - for idx, arg in enumerate(get_args): - arg_getter = IN_ARGS[arg]['getter'] - body += [indent('{} (param_values + {:d}),'.format(arg_getter, idx + 1), level=pad)] - - body += [indent('data2);', level=pad)] - - if va_marshal: - boxed_args = [x for x in get_args if IN_ARGS[x].get('box', None) is not None] - if not boxed_args: - body += [''] - else: - for idx, arg in enumerate(get_args): - if not IN_ARGS[arg].get('box', None): - continue - unbox_func = IN_ARGS[arg]['box'][1] - if IN_ARGS[arg].get('static-check', False): - static_check = STATIC_CHECK_STR.format(idx) - else: - static_check = '' - arg_check = 'arg{:d} != NULL'.format(idx) - body += [' if ({}{})'.format(static_check, arg_check)] - if IN_ARGS[arg].get('takes-type', False): - body += [UNBOX_TYPED_STR.format(idx=idx, unbox_func=unbox_func)] - else: - body += [UNBOX_UNTYPED_STR.format(idx=idx, unbox_func=unbox_func)] - - if retval_setter: - body += [''] - body += [' {} (return_value, v_return);'.format(retval_setter)] - - body += ['}'] - - return body - - -def generate_marshaller_alias(outfile, marshaller, real_marshaller, - include_va=False, - source_location=None): - '''Generate an alias between @marshaller and @real_marshaller, including - an optional alias for va_list marshallers''' - if source_location: - outfile.write('/* {} */\n'.format(source_location)) - - outfile.write('#define {}\t{}\n'.format(marshaller, real_marshaller)) - - if include_va: - outfile.write('#define {}v\t{}v\n'.format(marshaller, real_marshaller)) - - outfile.write('\n') - - -def generate_marshallers_header(outfile, retval, params, - prefix='g_cclosure_user_marshal', - internal=False, - include_va=False, source_location=None): - '''Generate a declaration for a marshaller function, to be used in the header, - with the given @retval, @params, and @prefix. An optional va_list marshaller - for the same arguments is also generated. The generated buffer is written to - the @outfile stream object.''' - if source_location: - outfile.write('/* {} */\n'.format(source_location)) - - if internal: - visibility = Visibility.INTERNAL - else: - visibility = Visibility.EXTERN - - signature = generate_prototype(retval, params, prefix, visibility, False) - if include_va: - signature += generate_prototype(retval, params, prefix, visibility, True) - signature += [''] - - outfile.write('\n'.join(signature)) - outfile.write('\n') - - -def generate_marshallers_body(outfile, retval, params, - prefix='g_cclosure_user_marshal', - include_prototype=True, - internal=False, - include_va=False, source_location=None): - '''Generate a definition for a marshaller function, to be used in the source, - with the given @retval, @params, and @prefix. An optional va_list marshaller - for the same arguments is also generated. The generated buffer is written to - the @outfile stream object.''' - if source_location: - outfile.write('/* {} */\n'.format(source_location)) - - if include_prototype: - # Declaration visibility - if internal: - decl_visibility = Visibility.INTERNAL - else: - decl_visibility = Visibility.EXTERN - proto = ['/* Prototype for -Wmissing-prototypes */'] - # Add C++ guards in case somebody compiles the generated code - # with a C++ compiler - proto += ['G_BEGIN_DECLS'] - proto += generate_prototype(retval, params, prefix, decl_visibility, False) - proto += ['G_END_DECLS'] - outfile.write('\n'.join(proto)) - outfile.write('\n') - - body = generate_body(retval, params, prefix, False) - outfile.write('\n'.join(body)) - outfile.write('\n\n') - - if include_va: - if include_prototype: - # Declaration visibility - if internal: - decl_visibility = Visibility.INTERNAL - else: - decl_visibility = Visibility.EXTERN - proto = ['/* Prototype for -Wmissing-prototypes */'] - # Add C++ guards here as well - proto += ['G_BEGIN_DECLS'] - proto += generate_prototype(retval, params, prefix, decl_visibility, True) - proto += ['G_END_DECLS'] - outfile.write('\n'.join(proto)) - outfile.write('\n') - - body = generate_body(retval, params, prefix, True) - outfile.write('\n'.join(body)) - outfile.write('\n\n') - - -def parse_args(): - arg_parser = argparse.ArgumentParser(description='Generate signal marshallers for GObject') - arg_parser.add_argument('--prefix', metavar='STRING', - default='g_cclosure_user_marshal', - help='Specify marshaller prefix') - arg_parser.add_argument('--output', metavar='FILE', - type=argparse.FileType('w'), - default=sys.stdout, - help='Write output into the specified file') - arg_parser.add_argument('--skip-source', - action='store_true', - help='Skip source location comments') - arg_parser.add_argument('--internal', - action='store_true', - help='Mark generated functions as internal') - arg_parser.add_argument('--valist-marshallers', - action='store_true', - help='Generate va_list marshallers') - arg_parser.add_argument('-v', '--version', - action='store_true', - dest='show_version', - help='Print version information, and exit') - arg_parser.add_argument('--g-fatal-warnings', - action='store_true', - dest='fatal_warnings', - help='Make warnings fatal') - arg_parser.add_argument('--include-header', metavar='HEADER', nargs='?', - action='append', - dest='include_headers', - help='Include the specified header in the body') - arg_parser.add_argument('--pragma-once', - action='store_true', - help='Use "pragma once" as the inclusion guard') - arg_parser.add_argument('-D', - action='append', - dest='cpp_defines', - default=[], - help='Pre-processor define') - arg_parser.add_argument('-U', - action='append', - dest='cpp_undefines', - default=[], - help='Pre-processor undefine') - arg_parser.add_argument('files', metavar='FILE', nargs='*', - type=argparse.FileType('r'), - help='Files with lists of marshallers to generate, ' + - 'or "-" for standard input') - arg_parser.add_argument('--prototypes', - action='store_true', - help='Generate the marshallers prototype in the C code') - arg_parser.add_argument('--header', - action='store_true', - help='Generate C headers') - arg_parser.add_argument('--body', - action='store_true', - help='Generate C code') - - group = arg_parser.add_mutually_exclusive_group() - group.add_argument('--stdinc', - action='store_true', - dest='stdinc', default=True, - help='Include standard marshallers') - group.add_argument('--nostdinc', - action='store_false', - dest='stdinc', default=True, - help='Use standard marshallers') - - group = arg_parser.add_mutually_exclusive_group() - group.add_argument('--quiet', - action='store_true', - help='Only print warnings and errors') - group.add_argument('--verbose', - action='store_true', - help='Be verbose, and include debugging information') - - args = arg_parser.parse_args() - - if args.show_version: - print(VERSION_STR) - sys.exit(0) - - return args - - -def generate(args): - # Backward compatibility hack; some projects use both arguments to - # generate the marshallers prototype in the C source, even though - # it's not really a supported use case. We keep this behaviour by - # forcing the --prototypes and --body arguments instead. We make this - # warning non-fatal even with --g-fatal-warnings, as it's a deprecation - compatibility_mode = False - if args.header and args.body: - print_warning('Using --header and --body at the same time is deprecated; ' + - 'use --body --prototypes instead', False) - args.prototypes = True - args.header = False - compatibility_mode = True - - if args.header: - generate_header_preamble(args.output, - prefix=args.prefix, - std_includes=args.stdinc, - use_pragma=args.pragma_once) - elif args.body: - generate_body_preamble(args.output, - std_includes=args.stdinc, - include_headers=args.include_headers, - cpp_defines=args.cpp_defines, - cpp_undefines=args.cpp_undefines) - - seen_marshallers = set() - - for infile in args.files: - if not args.quiet: - print_info('Reading {}...'.format(infile.name)) - - line_count = 0 - for line in infile: - line_count += 1 - - if line == '\n' or line.startswith('#'): - continue - - matches = re.match(r'^([A-Z0-9]+)\s?:\s?([A-Z0-9,\s]+)$', line.strip()) - if not matches or len(matches.groups()) != 2: - print_warning('Invalid entry: "{}"'.format(line.strip()), args.fatal_warnings) - continue - - if not args.skip_source: - location = '{} ({}:{:d})'.format(line.strip(), infile.name, line_count) - else: - location = None - - retval = matches.group(1).strip() - params = [x.strip() for x in matches.group(2).split(',')] - check_args(retval, params, args.fatal_warnings) - - raw_marshaller = generate_marshaller_name(args.prefix, retval, params, False) - if raw_marshaller in seen_marshallers: - if args.verbose: - print_info('Skipping repeated marshaller {}'.format(line.strip())) - continue - - if args.header: - if args.verbose: - print_info('Generating declaration for {}'.format(line.strip())) - generate_std_alias = False - if args.stdinc: - std_marshaller = generate_marshaller_name(STD_PREFIX, retval, params) - if std_marshaller in GOBJECT_MARSHALLERS: - if args.verbose: - print_info('Skipping default marshaller {}'.format(line.strip())) - generate_std_alias = True - - marshaller = generate_marshaller_name(args.prefix, retval, params) - if generate_std_alias: - generate_marshaller_alias(args.output, marshaller, std_marshaller, - source_location=location, - include_va=args.valist_marshallers) - else: - generate_marshallers_header(args.output, retval, params, - prefix=args.prefix, - internal=args.internal, - include_va=args.valist_marshallers, - source_location=location) - # If the marshaller is defined using a deprecated token, we want to maintain - # compatibility and generate an alias for the old name pointing to the new - # one - if marshaller != raw_marshaller: - if args.verbose: - print_info('Generating alias for deprecated tokens') - generate_marshaller_alias(args.output, raw_marshaller, marshaller, - include_va=args.valist_marshallers) - elif args.body: - if args.verbose: - print_info('Generating definition for {}'.format(line.strip())) - generate_std_alias = False - if args.stdinc: - std_marshaller = generate_marshaller_name(STD_PREFIX, retval, params) - if std_marshaller in GOBJECT_MARSHALLERS: - if args.verbose: - print_info('Skipping default marshaller {}'.format(line.strip())) - generate_std_alias = True - marshaller = generate_marshaller_name(args.prefix, retval, params) - if generate_std_alias: - # We need to generate the alias if we are in compatibility mode - if compatibility_mode: - generate_marshaller_alias(args.output, marshaller, std_marshaller, - source_location=location, - include_va=args.valist_marshallers) - else: - generate_marshallers_body(args.output, retval, params, - prefix=args.prefix, - internal=args.internal, - include_prototype=args.prototypes, - include_va=args.valist_marshallers, - source_location=location) - if compatibility_mode and marshaller != raw_marshaller: - if args.verbose: - print_info('Generating alias for deprecated tokens') - generate_marshaller_alias(args.output, raw_marshaller, marshaller, - include_va=args.valist_marshallers) - - seen_marshallers.add(raw_marshaller) - - if args.header: - generate_header_postamble(args.output, prefix=args.prefix, use_pragma=args.pragma_once) - - -if __name__ == '__main__': - args = parse_args() - - with args.output: - generate(args) diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-gettextize b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-gettextize deleted file mode 100644 index 9dc6f5d9b..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-gettextize +++ /dev/null @@ -1,189 +0,0 @@ -#! /bin/sh -# -# Copyright (C) 1995-1998, 2000, 2001 Free Software Foundation, Inc. -# -# SPDX-License-Identifier: GPL-2.0-or-later -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see . -# - -# - Modified in October 2001 by jacob berkman to -# work with glib's Makefile.in.in and po2tbl.sed.in, to not copy in -# intl/, and to not add ChangeLog entries to po/ChangeLog - -# This file is meant for authors or maintainers which want to -# internationalize their package with the help of GNU gettext. For -# further information how to use it consult the GNU gettext manual. - -echo=echo -progname=$0 -force=0 -configstatus=0 -origdir=`pwd` -usage="\ -Usage: glib-gettextize [OPTION]... [package-dir] - --help print this help and exit - --version print version information and exit - -c, --copy copy files instead of making symlinks - -f, --force force writing of new files even if old exist -Report bugs to https://gitlab.gnome.org/GNOME/glib/issues/new." -package=glib -version=2.82.4 -try_ln_s=: - -# Directory where the sources are stored. -prefix=C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64 -case `uname` in -MINGW32*) - prefix="`dirname $0`/.." - ;; -esac - -datarootdir=C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64/share -datadir=C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64/share - -gettext_dir=$datadir/glib-2.0/gettext - -while test $# -gt 0; do - case "$1" in - -c | --copy | --c* ) - shift - try_ln_s=false ;; - -f | --force | --f* ) - shift - force=1 ;; - -r | --run | --r* ) - shift - configstatus=1 ;; - --help | --h* ) - $echo "$usage"; exit 0 ;; - --version | --v* ) - echo "$progname (GNU $package) $version" - $echo "Copyright (C) 1995-1998, 2000, 2001 Free Software Foundation, Inc. -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - $echo "Written by" "Ulrich Drepper" - exit 0 ;; - -- ) # Stop option processing - shift; break ;; - -* ) - $echo "glib-gettextize: unknown option $1" - $echo "Try \`glib-gettextize --help' for more information."; exit 1 ;; - * ) - break ;; - esac -done - -if test $# -gt 1; then - $echo "$usage" - exit 1 -fi - -# Fill in the command line options value. -if test $# -eq 1; then - srcdir=$1 - if cd "$srcdir"; then - srcdir=`pwd` - else - $echo "Cannot change directory to \`$srcdir'" - exit 1 - fi -else - srcdir=$origdir -fi - -test -f configure.in || test -f configure.ac || { - $echo "Missing configure.in or configure.ac, please cd to your package first." - exit 1 -} - -configure_in=NONE -if test -f configure.in; then - configure_in=configure.in -else - if test -f configure.ac; then - configure_in=configure.ac - fi -fi -# Check in which directory config.rpath, mkinstalldirs etc. belong. -auxdir=`cat "$configure_in" | grep '^AC_CONFIG_AUX_DIR' | sed -n -e 's/AC_CONFIG_AUX_DIR(\([^()]*\))/\1/p' | sed -e 's/^\[\(.*\)\]$/\1/' | sed -e 1q` -if test -n "$auxdir"; then - auxdir="$auxdir/" -fi - -if test -f po/Makefile.in.in && test $force -eq 0; then - $echo "\ -po/Makefile.in.in exists: use option -f if you really want to delete it." - exit 1 -fi - -test -d po || { - $echo "Creating po/ subdirectory" - mkdir po || { - $echo "failed to create po/ subdirectory" - exit 1 - } -} - -# For simplicity we changed to the gettext source directory. -cd $gettext_dir || { - $echo "gettext source directory '${gettext_dir}' doesn't exist" - exit 1 -} - -# Now copy all files. Take care for the destination directories. -for file in *; do - case $file in - intl | po) - ;; - mkinstalldirs) - rm -f "$srcdir/$auxdir$file" - ($try_ln_s && ln -s $gettext_dir/$file "$srcdir/$auxdir$file" && $echo "Symlinking file $file") 2>/dev/null || - { $echo "Copying file $file"; cp $file "$srcdir/$auxdir$file"; } - ;; - *) - rm -f "$srcdir/$file" - ($try_ln_s && ln -s $gettext_dir/$file "$srcdir/$file" && $echo "Symlinking file $file") 2>/dev/null || - { $echo "Copying file $file"; cp $file "$srcdir/$file"; } - ;; - esac -done - -# Copy files to po/ subdirectory. -cd po -for file in *; do - rm -f "$srcdir/po/$file" - ($try_ln_s && ln -s $gettext_dir/po/$file "$srcdir/po/$file" && $echo "Symlinking file po/$file") 2>/dev/null || - { $echo "Copying file po/$file"; cp $file "$srcdir/po/$file"; } -done -if test -f "$srcdir/po/cat-id-tbl.c"; then - $echo "Removing po/cat-id-tbl.c" - rm -f "$srcdir/po/cat-id-tbl.c" -fi -if test -f "$srcdir/po/stamp-cat-id"; then - $echo "Removing po/stamp-cat-id" - rm -f "$srcdir/po/stamp-cat-id" -fi - -echo -echo "Please add the files" -echo " codeset.m4 gettext.m4 glibc21.m4 iconv.m4 isc-posix.m4 lcmessage.m4" -echo " progtest.m4" -echo "from the $datadir/aclocal directory to your autoconf macro directory" -echo "or directly to your aclocal.m4 file." -echo "You will also need config.guess and config.sub, which you can get from" -echo "ftp://ftp.gnu.org/pub/gnu/config/." -echo - -exit 0 diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-mkenums b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-mkenums deleted file mode 100644 index 825003f1d..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/glib-mkenums +++ /dev/null @@ -1,816 +0,0 @@ -#!C:\projects\repos\cerbero.git\1.28\build\build-tools\bin\python.exe - -# If the code below looks horrible and unpythonic, do not panic. -# -# It is. -# -# This is a manual conversion from the original Perl script to -# Python. Improvements are welcome. -# -from __future__ import print_function, unicode_literals - -import argparse -import os -import re -import sys -import tempfile -import io -import errno -import codecs -import locale - -# Non-english locale systems might complain to unrecognized character -sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='utf-8') - -VERSION_STR = '''glib-mkenums version 2.82.4 -glib-mkenums comes with ABSOLUTELY NO WARRANTY. -You may redistribute copies of glib-mkenums under the terms of -the GNU General Public License which can be found in the -GLib source package. Sources, examples and contact -information are available at http://www.gtk.org''' - -# pylint: disable=too-few-public-methods -class Color: - '''ANSI Terminal colors''' - GREEN = '\033[1;32m' - BLUE = '\033[1;34m' - YELLOW = '\033[1;33m' - RED = '\033[1;31m' - END = '\033[0m' - - -def print_color(msg, color=Color.END, prefix='MESSAGE'): - '''Print a string with a color prefix''' - if os.isatty(sys.stderr.fileno()): - real_prefix = '{start}{prefix}{end}'.format(start=color, prefix=prefix, end=Color.END) - else: - real_prefix = prefix - print('{prefix}: {msg}'.format(prefix=real_prefix, msg=msg), file=sys.stderr) - - -def print_error(msg): - '''Print an error, and terminate''' - print_color(msg, color=Color.RED, prefix='ERROR') - sys.exit(1) - - -def print_warning(msg, fatal=False): - '''Print a warning, and optionally terminate''' - if fatal: - color = Color.RED - prefix = 'ERROR' - else: - color = Color.YELLOW - prefix = 'WARNING' - print_color(msg, color, prefix) - if fatal: - sys.exit(1) - - -def print_info(msg): - '''Print a message''' - print_color(msg, color=Color.GREEN, prefix='INFO') - - -def get_rspfile_args(rspfile): - ''' - Response files are useful on Windows where there is a command-line character - limit of 8191 because when passing sources as arguments to glib-mkenums this - limit can be exceeded in large codebases. - - There is no specification for response files and each tool that supports it - generally writes them out in slightly different ways, but some sources are: - https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-response-files - https://docs.microsoft.com/en-us/windows/desktop/midl/the-response-file-command - ''' - import shlex - if not os.path.isfile(rspfile): - sys.exit('Response file {!r} does not exist'.format(rspfile)) - try: - with open(rspfile, 'r') as f: - cmdline = f.read() - except OSError as e: - sys.exit('Response file {!r} could not be read: {}' - .format(rspfile, e.strerror)) - return shlex.split(cmdline) - - -def write_output(output): - global output_stream - print(output, file=output_stream) - - -# Python 2 defaults to ASCII in case stdout is redirected. -# This should make it match Python 3, which uses the locale encoding. -if sys.stdout.encoding is None: - output_stream = codecs.getwriter( - locale.getpreferredencoding())(sys.stdout) -else: - output_stream = sys.stdout - - -# Some source files aren't UTF-8 and the old perl version didn't care. -# Replace invalid data with a replacement character to keep things working. -# https://bugzilla.gnome.org/show_bug.cgi?id=785113#c20 -def replace_and_warn(err): - # 7 characters of context either side of the offending character - print_warning('UnicodeWarning: {} at {} ({})'.format( - err.reason, err.start, - err.object[err.start - 7:err.end + 7])) - return ('?', err.end) - -codecs.register_error('replace_and_warn', replace_and_warn) - - -# glib-mkenums.py -# Information about the current enumeration -flags = None # Is enumeration a bitmask? -option_underscore_name = '' # Overridden underscore variant of the enum name - # for example to fix the cases we don't get the - # mixed-case -> underscorized transform right. -option_lowercase_name = '' # DEPRECATED. A lower case name to use as part - # of the *_get_type() function, instead of the - # one that we guess. For instance, when an enum - # uses abnormal capitalization and we can not - # guess where to put the underscores. -option_since = '' # User provided version info for the enum. -seenbitshift = 0 # Have we seen bitshift operators? -seenprivate = False # Have we seen a private option? -enum_prefix = None # Prefix for this enumeration -enumname = '' # Name for this enumeration -enumshort = '' # $enumname without prefix -enumname_prefix = '' # prefix of $enumname -enumindex = 0 # Global enum counter -firstenum = 1 # Is this the first enumeration per file? -entries = [] # [ name, val ] for each entry -c_namespace = {} # C symbols namespace. - -output = '' # Filename to write result into - -def parse_trigraph(opts): - result = {} - for opt in re.findall(r'(?:[^\s,"]|"(?:\\.|[^"])*")+', opts): - opt = re.sub(r'^\s*', '', opt) - opt = re.sub(r'\s*$', '', opt) - m = re.search(r'(\w+)(?:=(.+))?', opt) - assert m is not None - groups = m.groups() - key = groups[0] - if len(groups) > 1: - val = groups[1] - else: - val = 1 - result[key] = val.strip('"') if val is not None else None - return result - -def parse_entries(file, file_name): - global entries, enumindex, enumname, seenbitshift, seenprivate, flags - looking_for_name = False - - while True: - line = file.readline() - if not line: - break - - line = line.strip() - - # read lines until we have no open comments - while re.search(r'/\*([^*]|\*(?!/))*$', line): - line += file.readline() - - # strip comments w/o options - line = re.sub(r'''/\*(?!<) - ([^*]+|\*(?!/))* - \*/''', '', line, flags=re.X) - - line = line.rstrip() - - # skip empty lines - if len(line.strip()) == 0: - continue - - if looking_for_name: - m = re.match(r'\s*(\w+)', line) - if m: - enumname = m.group(1) - return True - - # Handle include files - m = re.match(r'\#include\s*<([^>]*)>', line) - if m: - newfilename = os.path.join("..", m.group(1)) - newfile = io.open(newfilename, encoding="utf-8", - errors="replace_and_warn") - - if not parse_entries(newfile, newfilename): - return False - else: - continue - - m = re.match(r'\s*\}\s*(\w+)', line) - if m: - enumname = m.group(1) - enumindex += 1 - return 1 - - m = re.match(r'\s*\}', line) - if m: - enumindex += 1 - looking_for_name = True - continue - - m = re.match(r'''\s* - (\w+)\s* # name - (\s+[A-Z]+_(?:AVAILABLE|DEPRECATED)_ENUMERATOR_IN_[0-9_]+(?:_FOR\s*\(\s*\w+\s*\))?\s*)? # availability - (?:=( # value - \s*'[^']*'\s* # char - | # OR - \s*\w+\s*\(.*\)\s* # macro with multiple args - | # OR - (?:[^,/]|/(?!\*))* # anything but a comma or comment - ))?,?\s* - (?:/\*< # options - (([^*]|\*(?!/))*) - >\s*\*/)?,? - \s*$''', line, flags=re.X) - if m: - groups = m.groups() - name = groups[0] - availability = None - value = None - options = None - if len(groups) > 1: - availability = groups[1] - if len(groups) > 2: - value = groups[2] - if len(groups) > 3: - options = groups[3] - if flags is None and value is not None and '<<' in value: - seenbitshift = 1 - - if options is not None: - options = parse_trigraph(options) - if 'skip' not in options: - entries.append((name, value, seenprivate, options.get('nick'))) - else: - entries.append((name, value, seenprivate)) - else: - m = re.match(r'''\s* - /\*< (([^*]|\*(?!/))*) >\s*\*/ - \s*$''', line, flags=re.X) - if m: - options = m.groups()[0] - if options is not None: - options = parse_trigraph(options) - if 'private' in options: - seenprivate = True - continue - if 'public' in options: - seenprivate = False - continue - if re.match(r's*\#', line): - pass - else: - print_warning('Failed to parse "{}" in {}'.format(line, file_name)) - return False - -help_epilog = '''Production text substitutions: - \u0040EnumName\u0040 PrefixTheXEnum - \u0040enum_name\u0040 prefix_the_xenum - \u0040ENUMNAME\u0040 PREFIX_THE_XENUM - \u0040ENUMSHORT\u0040 THE_XENUM - \u0040ENUMPREFIX\u0040 PREFIX - \u0040enumsince\u0040 the user-provided since value given - \u0040VALUENAME\u0040 PREFIX_THE_XVALUE - \u0040valuenick\u0040 the-xvalue - \u0040valuenum\u0040 the integer value (limited support, Since: 2.26) - \u0040type\u0040 either enum or flags - \u0040Type\u0040 either Enum or Flags - \u0040TYPE\u0040 either ENUM or FLAGS - \u0040filename\u0040 name of current input file - \u0040basename\u0040 base name of the current input file (Since: 2.22) -''' - - -# production variables: -idprefix = "" # "G", "Gtk", etc -symprefix = "" # "g", "gtk", etc, if not just lc($idprefix) -fhead = "" # output file header -fprod = "" # per input file production -ftail = "" # output file trailer -eprod = "" # per enum text (produced prior to value itarations) -vhead = "" # value header, produced before iterating over enum values -vprod = "" # value text, produced for each enum value -vtail = "" # value tail, produced after iterating over enum values -comment_tmpl = "" # comment template - -def read_template_file(file): - global idprefix, symprefix, fhead, fprod, ftail, eprod, vhead, vprod, vtail, comment_tmpl - tmpl = {'file-header': fhead, - 'file-production': fprod, - 'file-tail': ftail, - 'enumeration-production': eprod, - 'value-header': vhead, - 'value-production': vprod, - 'value-tail': vtail, - 'comment': comment_tmpl, - } - in_ = 'junk' - - ifile = io.open(file, encoding="utf-8", errors="replace_and_warn") - for line in ifile: - m = re.match(r'\/\*\*\*\s+(BEGIN|END)\s+([\w-]+)\s+\*\*\*\/', line) - if m: - if in_ == 'junk' and m.group(1) == 'BEGIN' and m.group(2) in tmpl: - in_ = m.group(2) - continue - elif in_ == m.group(2) and m.group(1) == 'END' and m.group(2) in tmpl: - in_ = 'junk' - continue - else: - sys.exit("Malformed template file " + file) - - if in_ != 'junk': - tmpl[in_] += line - - if in_ != 'junk': - sys.exit("Malformed template file " + file) - - fhead = tmpl['file-header'] - fprod = tmpl['file-production'] - ftail = tmpl['file-tail'] - eprod = tmpl['enumeration-production'] - vhead = tmpl['value-header'] - vprod = tmpl['value-production'] - vtail = tmpl['value-tail'] - comment_tmpl = tmpl['comment'] - -parser = argparse.ArgumentParser(epilog=help_epilog, - formatter_class=argparse.RawDescriptionHelpFormatter) - -parser.add_argument('--identifier-prefix', default='', dest='idprefix', - help='Identifier prefix') -parser.add_argument('--symbol-prefix', default='', dest='symprefix', - help='Symbol prefix') -parser.add_argument('--fhead', default=[], dest='fhead', action='append', - help='Output file header') -parser.add_argument('--ftail', default=[], dest='ftail', action='append', - help='Output file footer') -parser.add_argument('--fprod', default=[], dest='fprod', action='append', - help='Put out TEXT every time a new input file is being processed.') -parser.add_argument('--eprod', default=[], dest='eprod', action='append', - help='Per enum text, produced prior to value iterations') -parser.add_argument('--vhead', default=[], dest='vhead', action='append', - help='Value header, produced before iterating over enum values') -parser.add_argument('--vprod', default=[], dest='vprod', action='append', - help='Value text, produced for each enum value.') -parser.add_argument('--vtail', default=[], dest='vtail', action='append', - help='Value tail, produced after iterating over enum values') -parser.add_argument('--comments', default='', dest='comment_tmpl', - help='Comment structure') -parser.add_argument('--template', default='', dest='template', - help='Template file') -parser.add_argument('--output', default=None, dest='output') -parser.add_argument('--version', '-v', default=False, action='store_true', dest='version', - help='Print version information') -parser.add_argument('args', nargs='*', - help='One or more input files, or a single argument @rspfile_path ' - 'pointing to a file that contains the actual arguments') - -# Support reading an rspfile of the form @filename which contains the args -# to be parsed -if len(sys.argv) == 2 and sys.argv[1].startswith('@'): - args = get_rspfile_args(sys.argv[1][1:]) -else: - args = sys.argv[1:] - -options = parser.parse_args(args) - -if options.version: - print(VERSION_STR) - sys.exit(0) - -def unescape_cmdline_args(arg): - arg = arg.replace('\\n', '\n') - arg = arg.replace('\\r', '\r') - return arg.replace('\\t', '\t') - -if options.template != '': - read_template_file(options.template) - -idprefix += options.idprefix -symprefix += options.symprefix - -# This is a hack to maintain some semblance of backward compatibility with -# the old, Perl-based glib-mkenums. The old tool had an implicit ordering -# on the arguments and templates; each argument was parsed in order, and -# all the strings appended. This allowed developers to write: -# -# glib-mkenums \ -# --fhead ... \ -# --template a-template-file.c.in \ -# --ftail ... -# -# And have the fhead be prepended to the file-head stanza in the template, -# as well as the ftail be appended to the file-tail stanza in the template. -# Short of throwing away ArgumentParser and going over sys.argv[] element -# by element, we can simulate that behaviour by ensuring some ordering in -# how we build the template strings: -# -# - the head stanzas are always prepended to the template -# - the prod stanzas are always appended to the template -# - the tail stanzas are always appended to the template -# -# Within each instance of the command line argument, we append each value -# to the array in the order in which it appears on the command line. -fhead = ''.join([unescape_cmdline_args(x) for x in options.fhead]) + fhead -vhead = ''.join([unescape_cmdline_args(x) for x in options.vhead]) + vhead - -fprod += ''.join([unescape_cmdline_args(x) for x in options.fprod]) -eprod += ''.join([unescape_cmdline_args(x) for x in options.eprod]) -vprod += ''.join([unescape_cmdline_args(x) for x in options.vprod]) - -ftail = ftail + ''.join([unescape_cmdline_args(x) for x in options.ftail]) -vtail = vtail + ''.join([unescape_cmdline_args(x) for x in options.vtail]) - -if options.comment_tmpl != '': - comment_tmpl = unescape_cmdline_args(options.comment_tmpl) -elif comment_tmpl == "": - # default to C-style comments - comment_tmpl = "/* \u0040comment\u0040 */" - -output = options.output - -if output is not None: - (out_dir, out_fn) = os.path.split(options.output) - out_suffix = '_' + os.path.splitext(out_fn)[1] - if out_dir == '': - out_dir = '.' - fd, filename = tempfile.mkstemp(dir=out_dir) - os.close(fd) - tmpfile = io.open(filename, "w", encoding="utf-8") - output_stream = tmpfile -else: - tmpfile = None - -# put auto-generation comment -comment = comment_tmpl.replace('\u0040comment\u0040', - 'This file is generated by glib-mkenums, do ' - 'not modify it. This code is licensed under ' - 'the same license as the containing project. ' - 'Note that it links to GLib, so must comply ' - 'with the LGPL linking clauses.') -write_output("\n" + comment + '\n') - -def replace_specials(prod): - prod = prod.replace(r'\\a', r'\a') - prod = prod.replace(r'\\b', r'\b') - prod = prod.replace(r'\\t', r'\t') - prod = prod.replace(r'\\n', r'\n') - prod = prod.replace(r'\\f', r'\f') - prod = prod.replace(r'\\r', r'\r') - prod = prod.rstrip() - return prod - - -def warn_if_filename_basename_used(section, prod): - for substitution in ('\u0040filename\u0040', - '\u0040basename\u0040'): - if substitution in prod: - print_warning('{} used in {} section.'.format(substitution, - section)) - -if len(fhead) > 0: - prod = fhead - warn_if_filename_basename_used('file-header', prod) - prod = replace_specials(prod) - write_output(prod) - -def process_file(curfilename): - global entries, flags, seenbitshift, seenprivate, enum_prefix, c_namespace - firstenum = True - - try: - curfile = io.open(curfilename, encoding="utf-8", - errors="replace_and_warn") - except IOError as e: - if e.errno == errno.ENOENT: - print_warning('No file "{}" found.'.format(curfilename)) - return - raise - - while True: - line = curfile.readline() - if not line: - break - - line = line.strip() - - # read lines until we have no open comments - while re.search(r'/\*([^*]|\*(?!/))*$', line): - line += curfile.readline() - - # strip comments w/o options - line = re.sub(r'''/\*(?!<) - ([^*]+|\*(?!/))* - \*/''', '', line) - - # ignore forward declarations - if re.match(r'\s*typedef\s+enum.*;', line): - continue - - m = re.match(r'''\s*typedef\s+enum\s*[_A-Za-z]*[_A-Za-z0-9]*\s* - ({)?\s* - (?:/\*< - (([^*]|\*(?!/))*) - >\s*\*/)? - \s*({)?''', line, flags=re.X) - if m: - groups = m.groups() - if len(groups) >= 2 and groups[1] is not None: - options = parse_trigraph(groups[1]) - if 'skip' in options: - continue - enum_prefix = options.get('prefix', None) - flags = options.get('flags', None) - if 'flags' in options: - if flags is None: - flags = 1 - else: - flags = int(flags) - option_lowercase_name = options.get('lowercase_name', None) - option_underscore_name = options.get('underscore_name', None) - option_since = options.get('since', None) - else: - enum_prefix = None - flags = None - option_lowercase_name = None - option_underscore_name = None - option_since = None - - if option_lowercase_name is not None: - if option_underscore_name is not None: - print_warning("lowercase_name overridden with underscore_name") - option_lowercase_name = None - else: - print_warning("lowercase_name is deprecated, use underscore_name") - - # Didn't have trailing '{' look on next lines - if groups[0] is None and (len(groups) < 4 or groups[3] is None): - while True: - line = curfile.readline() - if not line: - print_error("Syntax error when looking for opening { in enum") - if re.match(r'\s*\{', line): - break - - seenbitshift = 0 - seenprivate = False - entries = [] - - # Now parse the entries - parse_entries(curfile, curfilename) - - # figure out if this was a flags or enums enumeration - if flags is None: - flags = seenbitshift - - # Autogenerate a prefix - if enum_prefix is None: - for entry in entries: - if not entry[2] and (len(entry) < 4 or entry[3] is None): - name = entry[0] - if enum_prefix is not None: - enum_prefix = os.path.commonprefix([name, enum_prefix]) - else: - enum_prefix = name - if enum_prefix is None: - enum_prefix = "" - else: - # Trim so that it ends in an underscore - enum_prefix = re.sub(r'_[^_]*$', '_', enum_prefix) - else: - # canonicalize user defined prefixes - enum_prefix = enum_prefix.upper() - enum_prefix = enum_prefix.replace('-', '_') - enum_prefix = re.sub(r'(.*)([^_])$', r'\1\2_', enum_prefix) - - fixed_entries = [] - for e in entries: - name = e[0] - num = e[1] - private = e[2] - if len(e) < 4 or e[3] is None: - nick = re.sub(r'^' + enum_prefix, '', name) - nick = nick.replace('_', '-').lower() - e = (name, num, private, nick) - fixed_entries.append(e) - entries = fixed_entries - - # Spit out the output - if option_underscore_name is not None: - enumlong = option_underscore_name.upper() - enumsym = option_underscore_name.lower() - enumshort = re.sub(r'^[A-Z][A-Z0-9]*_', '', enumlong) - - enumname_prefix = re.sub('_' + enumshort + '$', '', enumlong) - elif symprefix == '' and idprefix == '': - # enumname is e.g. GMatchType - enspace = re.sub(r'^([A-Z][a-z]*).*$', r'\1', enumname) - - enumshort = re.sub(r'^[A-Z][a-z]*', '', enumname) - enumshort = re.sub(r'([^A-Z])([A-Z])', r'\1_\2', enumshort) - enumshort = re.sub(r'([A-Z][A-Z])([A-Z][0-9a-z])', r'\1_\2', enumshort) - enumshort = enumshort.upper() - - enumname_prefix = re.sub(r'^([A-Z][a-z]*).*$', r'\1', enumname).upper() - - enumlong = enspace.upper() + "_" + enumshort - enumsym = enspace.lower() + "_" + enumshort.lower() - - if option_lowercase_name is not None: - enumsym = option_lowercase_name - else: - enumshort = enumname - if idprefix: - enumshort = re.sub(r'^' + idprefix, '', enumshort) - else: - enumshort = re.sub(r'/^[A-Z][a-z]*', '', enumshort) - - enumshort = re.sub(r'([^A-Z])([A-Z])', r'\1_\2', enumshort) - enumshort = re.sub(r'([A-Z][A-Z])([A-Z][0-9a-z])', r'\1_\2', enumshort) - enumshort = enumshort.upper() - - if symprefix: - enumname_prefix = symprefix.upper() - else: - enumname_prefix = idprefix.upper() - - enumlong = enumname_prefix + "_" + enumshort - enumsym = enumlong.lower() - - if option_since is not None: - enumsince = option_since - else: - enumsince = "" - - if firstenum: - firstenum = False - - if len(fprod) > 0: - prod = fprod - base = os.path.basename(curfilename) - - prod = prod.replace('\u0040filename\u0040', curfilename) - prod = prod.replace('\u0040basename\u0040', base) - prod = replace_specials(prod) - - write_output(prod) - - if len(eprod) > 0: - prod = eprod - - prod = prod.replace('\u0040enum_name\u0040', enumsym) - prod = prod.replace('\u0040EnumName\u0040', enumname) - prod = prod.replace('\u0040ENUMSHORT\u0040', enumshort) - prod = prod.replace('\u0040ENUMNAME\u0040', enumlong) - prod = prod.replace('\u0040ENUMPREFIX\u0040', enumname_prefix) - prod = prod.replace('\u0040enumsince\u0040', enumsince) - if flags: - prod = prod.replace('\u0040type\u0040', 'flags') - else: - prod = prod.replace('\u0040type\u0040', 'enum') - if flags: - prod = prod.replace('\u0040Type\u0040', 'Flags') - else: - prod = prod.replace('\u0040Type\u0040', 'Enum') - if flags: - prod = prod.replace('\u0040TYPE\u0040', 'FLAGS') - else: - prod = prod.replace('\u0040TYPE\u0040', 'ENUM') - prod = replace_specials(prod) - write_output(prod) - - if len(vhead) > 0: - prod = vhead - prod = prod.replace('\u0040enum_name\u0040', enumsym) - prod = prod.replace('\u0040EnumName\u0040', enumname) - prod = prod.replace('\u0040ENUMSHORT\u0040', enumshort) - prod = prod.replace('\u0040ENUMNAME\u0040', enumlong) - prod = prod.replace('\u0040ENUMPREFIX\u0040', enumname_prefix) - prod = prod.replace('\u0040enumsince\u0040', enumsince) - if flags: - prod = prod.replace('\u0040type\u0040', 'flags') - else: - prod = prod.replace('\u0040type\u0040', 'enum') - if flags: - prod = prod.replace('\u0040Type\u0040', 'Flags') - else: - prod = prod.replace('\u0040Type\u0040', 'Enum') - if flags: - prod = prod.replace('\u0040TYPE\u0040', 'FLAGS') - else: - prod = prod.replace('\u0040TYPE\u0040', 'ENUM') - prod = replace_specials(prod) - write_output(prod) - - if len(vprod) > 0: - prod = vprod - next_num = 0 - - prod = replace_specials(prod) - for name, num, private, nick in entries: - tmp_prod = prod - - if '\u0040valuenum\u0040' in prod: - # only attempt to eval the value if it is requested - # this prevents us from throwing errors otherwise - if num is not None: - # use sandboxed evaluation as a reasonable - # approximation to C constant folding - inum = eval(num, {}, c_namespace) - - # Support character literals - if isinstance(inum, str) and len(inum) == 1: - inum = ord(inum) - - # make sure it parsed to an integer - if not isinstance(inum, int): - sys.exit("Unable to parse enum value '%s'" % num) - num = inum - else: - num = next_num - - c_namespace[name] = num - tmp_prod = tmp_prod.replace('\u0040valuenum\u0040', str(num)) - next_num = int(num) + 1 - - if private: - continue - - tmp_prod = tmp_prod.replace('\u0040VALUENAME\u0040', name) - tmp_prod = tmp_prod.replace('\u0040valuenick\u0040', nick) - if flags: - tmp_prod = tmp_prod.replace('\u0040type\u0040', 'flags') - else: - tmp_prod = tmp_prod.replace('\u0040type\u0040', 'enum') - if flags: - tmp_prod = tmp_prod.replace('\u0040Type\u0040', 'Flags') - else: - tmp_prod = tmp_prod.replace('\u0040Type\u0040', 'Enum') - if flags: - tmp_prod = tmp_prod.replace('\u0040TYPE\u0040', 'FLAGS') - else: - tmp_prod = tmp_prod.replace('\u0040TYPE\u0040', 'ENUM') - tmp_prod = tmp_prod.rstrip() - - write_output(tmp_prod) - - if len(vtail) > 0: - prod = vtail - prod = prod.replace('\u0040enum_name\u0040', enumsym) - prod = prod.replace('\u0040EnumName\u0040', enumname) - prod = prod.replace('\u0040ENUMSHORT\u0040', enumshort) - prod = prod.replace('\u0040ENUMNAME\u0040', enumlong) - prod = prod.replace('\u0040ENUMPREFIX\u0040', enumname_prefix) - prod = prod.replace('\u0040enumsince\u0040', enumsince) - if flags: - prod = prod.replace('\u0040type\u0040', 'flags') - else: - prod = prod.replace('\u0040type\u0040', 'enum') - if flags: - prod = prod.replace('\u0040Type\u0040', 'Flags') - else: - prod = prod.replace('\u0040Type\u0040', 'Enum') - if flags: - prod = prod.replace('\u0040TYPE\u0040', 'FLAGS') - else: - prod = prod.replace('\u0040TYPE\u0040', 'ENUM') - prod = replace_specials(prod) - write_output(prod) - -for fname in sorted(options.args): - process_file(fname) - -if len(ftail) > 0: - prod = ftail - warn_if_filename_basename_used('file-tail', prod) - prod = replace_specials(prod) - write_output(prod) - -# put auto-generation comment -comment = comment_tmpl -comment = comment.replace('\u0040comment\u0040', 'Generated data ends here') -write_output("\n" + comment + "\n") - -if tmpfile is not None: - tmpfilename = tmpfile.name - tmpfile.close() - - try: - os.unlink(options.output) - except OSError as error: - if error.errno != errno.ENOENT: - raise error - - os.rename(tmpfilename, options.output) diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gmodule-2.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gmodule-2.0-0.dll deleted file mode 100644 index f9712b7cd..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gmodule-2.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gobject-2.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gobject-2.0-0.dll deleted file mode 100644 index 33f81a469..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gobject-2.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/graphene-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/graphene-1.0-0.dll deleted file mode 100644 index 88b49fbda..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/graphene-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gresource.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gresource.exe deleted file mode 100644 index fa5efb09f..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gresource.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gsettings.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gsettings.exe deleted file mode 100644 index fe48af7da..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gsettings.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gspawn-win64-helper-console.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gspawn-win64-helper-console.exe deleted file mode 100644 index b8ae06f03..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gspawn-win64-helper-console.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gspawn-win64-helper.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gspawn-win64-helper.exe deleted file mode 100644 index b872dcebf..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gspawn-win64-helper.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-device-monitor-1.0.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-device-monitor-1.0.exe deleted file mode 100644 index 7351b80ea..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-device-monitor-1.0.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-discoverer-1.0.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-discoverer-1.0.exe deleted file mode 100644 index 6edd577d5..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-discoverer-1.0.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-dots-viewer.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-dots-viewer.exe deleted file mode 100644 index 9dedde707..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-dots-viewer.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-inspect-1.0.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-inspect-1.0.exe deleted file mode 100644 index ecf5887be..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-inspect-1.0.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-launch-1.0.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-launch-1.0.exe deleted file mode 100644 index a2cb81edc..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-launch-1.0.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-play-1.0.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-play-1.0.exe deleted file mode 100644 index 7a18dd03f..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-play-1.0.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-shell b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-shell deleted file mode 100644 index 347bc9fa7..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-shell +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -export GSTREAMER_ROOT="C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64" -export PATH="${GSTREAMER_ROOT}/bin${PATH:+:$PATH}" -export LD_LIBRARY_PATH="${GSTREAMER_ROOT}/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" -export PKG_CONFIG_PATH="${GSTREAMER_ROOT}/lib/pkgconfig:${GSTREAMER_ROOT}/share/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" -export XDG_DATA_DIRS="${GSTREAMER_ROOT}/share${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}" -export XDG_CONFIG_DIRS="${GSTREAMER_ROOT}/etc/xdg${XDG_CONFIG_DIRS:+:$XDG_CONFIG_DIRS}" -export GST_REGISTRY_1_0="${HOME}/.cache/gstreamer-1.0/gstreamer-cerbero-registry" -export GST_PLUGIN_SCANNER_1_0="${GSTREAMER_ROOT}/libexec/gstreamer-1.0/gst-plugin-scanner" -export GST_PLUGIN_PATH_1_0="${GSTREAMER_ROOT}/lib/gstreamer-1.0" -export GST_PLUGIN_SYSTEM_PATH_1_0="${GSTREAMER_ROOT}/lib/gstreamer-1.0" -export PYTHONPATH="${GSTREAMER_ROOT}\Lib/site-packages${PYTHONPATH:+:$PYTHONPATH}" -export CFLAGS="-I${GSTREAMER_ROOT}/include ${CFLAGS}" -export CXXFLAGS="-I${GSTREAMER_ROOT}/include ${CXXFLAGS}" -export CPPFLAGS="-I${GSTREAMER_ROOT}/include ${CPPFLAGS}" -export LDFLAGS="-L${GSTREAMER_ROOT}/lib ${LDFLAGS}" -export GIO_EXTRA_MODULES="${GSTREAMER_ROOT}/lib/gio/modules" -export GI_TYPELIB_PATH="${GSTREAMER_ROOT}/lib/girepository-1.0" - - -$SHELL "$@" diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-typefind-1.0.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-typefind-1.0.exe deleted file mode 100644 index 0c16b9a2b..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-typefind-1.0.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-validate-1.0.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-validate-1.0.exe deleted file mode 100644 index e3ba43ebb..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-validate-1.0.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-validate-launcher b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-validate-launcher deleted file mode 100644 index 0267c71e3..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-validate-launcher +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) 2014,Thibault Saunier -# -# This program 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 2.1 of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this program; if not, write to the -# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -# Boston, MA 02110-1301, USA. - -import os -import subprocess -import sys - -LIBDIR = r'C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64/lib' -BUILDDIR = r'C:\projects\repos\cerbero.git\1.28\build\sources\msvc_x86_64\gst-devtools-1.0-1.28.3\b\validate\tools' -SRCDIR = r'C:\projects\repos\cerbero.git\1.28\build\sources\msvc_x86_64\gst-devtools-1.0-1.28.3\validate\tools' - - -def _add_gst_launcher_path(): - f = os.path.abspath(__file__) - if f.startswith(BUILDDIR): - # Make sure to have the configured config.py in the python path - sys.path.insert(0, os.path.abspath(os.path.join(BUILDDIR, ".."))) - root = os.path.abspath(os.path.join(SRCDIR, "../")) - else: - root = os.path.join(LIBDIR, 'gst-validate-launcher', 'python') - - sys.path.insert(0, root) - return os.path.join(root, "launcher") - - -if "__main__" == __name__: - libsdir = _add_gst_launcher_path() - from launcher.main import main - run_profile = os.environ.get('GST_VALIDATE_LAUNCHER_PROFILING', False) - if run_profile: - import cProfile - prof = cProfile.Profile() - try: - res = prof.runcall(main, libsdir) - finally: - prof.dump_stats('gst-validate-launcher-runstats') - exit(res) - - exit(main(libsdir)) diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-validate-media-check-1.0.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-validate-media-check-1.0.exe deleted file mode 100644 index 3e0b15675..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-validate-media-check-1.0.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-validate-rtsp-server-1.0.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-validate-rtsp-server-1.0.exe deleted file mode 100644 index fdd76fa99..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-validate-rtsp-server-1.0.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-validate-transcoding-1.0.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-validate-transcoding-1.0.exe deleted file mode 100644 index 8a4088e9c..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gst-validate-transcoding-1.0.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstadaptivedemux-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstadaptivedemux-1.0-0.dll deleted file mode 100644 index 6ac5942e3..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstadaptivedemux-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstallocators-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstallocators-1.0-0.dll deleted file mode 100644 index 273487df6..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstallocators-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstanalytics-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstanalytics-1.0-0.dll deleted file mode 100644 index 23aa739e0..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstanalytics-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstapp-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstapp-1.0-0.dll deleted file mode 100644 index 1393c4247..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstapp-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstaudio-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstaudio-1.0-0.dll deleted file mode 100644 index c204b1a32..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstaudio-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstbadaudio-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstbadaudio-1.0-0.dll deleted file mode 100644 index f6969c535..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstbadaudio-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstbase-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstbase-1.0-0.dll deleted file mode 100644 index f1c2eb367..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstbase-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstbasecamerabinsrc-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstbasecamerabinsrc-1.0-0.dll deleted file mode 100644 index 887e3dd7e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstbasecamerabinsrc-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstcheck-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstcheck-1.0-0.dll deleted file mode 100644 index 22a046586..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstcheck-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstcodecparsers-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstcodecparsers-1.0-0.dll deleted file mode 100644 index 3a22dee1f..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstcodecparsers-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstcodecs-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstcodecs-1.0-0.dll deleted file mode 100644 index a767b8270..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstcodecs-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstcontroller-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstcontroller-1.0-0.dll deleted file mode 100644 index 5f2a5ac30..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstcontroller-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstcuda-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstcuda-1.0-0.dll deleted file mode 100644 index 9fd1f6acd..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstcuda-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstd3d11-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstd3d11-1.0-0.dll deleted file mode 100644 index 2311aee58..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstd3d11-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstd3d12-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstd3d12-1.0-0.dll deleted file mode 100644 index 81bb65469..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstd3d12-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstd3dshader-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstd3dshader-1.0-0.dll deleted file mode 100644 index 0576eaca8..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstd3dshader-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstdxva-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstdxva-1.0-0.dll deleted file mode 100644 index 016beed43..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstdxva-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstfft-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstfft-1.0-0.dll deleted file mode 100644 index 6ab13b9cf..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstfft-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstgl-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstgl-1.0-0.dll deleted file mode 100644 index 5bc437dd4..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstgl-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstinsertbin-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstinsertbin-1.0-0.dll deleted file mode 100644 index c1e6e1939..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstinsertbin-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstisoff-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstisoff-1.0-0.dll deleted file mode 100644 index 71b16a085..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstisoff-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstmpegts-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstmpegts-1.0-0.dll deleted file mode 100644 index cfdddb325..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstmpegts-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstmse-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstmse-1.0-0.dll deleted file mode 100644 index 484f5d249..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstmse-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstnet-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstnet-1.0-0.dll deleted file mode 100644 index 1082e1e4a..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstnet-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstpbutils-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstpbutils-1.0-0.dll deleted file mode 100644 index 4e6d938cd..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstpbutils-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstphotography-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstphotography-1.0-0.dll deleted file mode 100644 index f6f7a7f0e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstphotography-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstplay-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstplay-1.0-0.dll deleted file mode 100644 index e970d5fb1..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstplay-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstplayer-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstplayer-1.0-0.dll deleted file mode 100644 index 7dea461f3..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstplayer-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstreamer-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstreamer-1.0-0.dll deleted file mode 100644 index 66afb1858..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstreamer-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstriff-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstriff-1.0-0.dll deleted file mode 100644 index 806f9bef4..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstriff-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstrtp-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstrtp-1.0-0.dll deleted file mode 100644 index a55dd77e5..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstrtp-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstrtsp-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstrtsp-1.0-0.dll deleted file mode 100644 index f06a71924..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstrtsp-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstrtspserver-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstrtspserver-1.0-0.dll deleted file mode 100644 index e4e57589b..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstrtspserver-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstsctp-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstsctp-1.0-0.dll deleted file mode 100644 index af7691c83..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstsctp-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstsdp-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstsdp-1.0-0.dll deleted file mode 100644 index bea49d060..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstsdp-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gsttag-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gsttag-1.0-0.dll deleted file mode 100644 index 2588224af..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gsttag-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gsttranscoder-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gsttranscoder-1.0-0.dll deleted file mode 100644 index 864ff64fe..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gsttranscoder-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gsturidownloader-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gsturidownloader-1.0-0.dll deleted file mode 100644 index 425290fb6..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gsturidownloader-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstvalidate-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstvalidate-1.0-0.dll deleted file mode 100644 index 4ebcf3356..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstvalidate-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstvideo-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstvideo-1.0-0.dll deleted file mode 100644 index a10e1d149..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstvideo-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstwebrtc-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstwebrtc-1.0-0.dll deleted file mode 100644 index 4f80f3fb8..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstwebrtc-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstwebrtcnice-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstwebrtcnice-1.0-0.dll deleted file mode 100644 index de461882e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstwebrtcnice-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstwinrt-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstwinrt-1.0-0.dll deleted file mode 100644 index fa0a2b56d..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gstwinrt-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gthread-2.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gthread-2.0-0.dll deleted file mode 100644 index e13a20a88..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gthread-2.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gtk-4-1.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gtk-4-1.dll deleted file mode 100644 index c3fd428f2..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/gtk-4-1.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/harfbuzz-cairo.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/harfbuzz-cairo.dll deleted file mode 100644 index 66aa54cc7..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/harfbuzz-cairo.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/harfbuzz-gobject.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/harfbuzz-gobject.dll deleted file mode 100644 index 8104b7f8e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/harfbuzz-gobject.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/harfbuzz-subset.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/harfbuzz-subset.dll deleted file mode 100644 index 834b8f14a..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/harfbuzz-subset.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/harfbuzz.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/harfbuzz.dll deleted file mode 100644 index 0d1243b68..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/harfbuzz.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/iconv-2.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/iconv-2.dll deleted file mode 100644 index 9053a75a7..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/iconv-2.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/intl-8.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/intl-8.dll deleted file mode 100644 index d37f3a60f..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/intl-8.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/jpeg8.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/jpeg8.dll deleted file mode 100644 index 7a7bfab18..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/jpeg8.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/json-glib-1.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/json-glib-1.0-0.dll deleted file mode 100644 index 1efa5409e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/json-glib-1.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/json-glib-format.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/json-glib-format.exe deleted file mode 100644 index 0cf0b1027..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/json-glib-format.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/json-glib-validate.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/json-glib-validate.exe deleted file mode 100644 index 33d567da6..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/json-glib-validate.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/lcevc_dec_api.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/lcevc_dec_api.dll deleted file mode 100644 index 6cd67a1e7..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/lcevc_dec_api.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/lcevc_dec_legacy.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/lcevc_dec_legacy.dll deleted file mode 100644 index 6277a45f4..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/lcevc_dec_legacy.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/lcevc_dec_pipeline_cpu.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/lcevc_dec_pipeline_cpu.dll deleted file mode 100644 index d2daeeb8a..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/lcevc_dec_pipeline_cpu.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/lcevc_dec_pipeline_legacy.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/lcevc_dec_pipeline_legacy.dll deleted file mode 100644 index 83d64911b..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/lcevc_dec_pipeline_legacy.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libcrypto-3-x64.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libcrypto-3-x64.dll deleted file mode 100644 index 59688b42c..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libcrypto-3-x64.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libcurl.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libcurl.dll deleted file mode 100644 index 8193459cb..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libcurl.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libexpat.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libexpat.dll deleted file mode 100644 index 5e0ae1374..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libexpat.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libgcc_s_seh-1.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libgcc_s_seh-1.dll deleted file mode 100644 index ddf0e38ff..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libgcc_s_seh-1.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libmpg123-1.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libmpg123-1.dll deleted file mode 100644 index 51c3a9e56..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libmpg123-1.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libpng16-config b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libpng16-config deleted file mode 100644 index 0068564c1..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/bin/libpng16-config +++ /dev/null @@ -1,127 +0,0 @@ -#! /bin/sh - -# libpng-config -# provides configuration info for libpng. - -# Copyright (C) 2002, 2004, 2006, 2007 Glenn Randers-Pehrson - -# This code is released under the libpng license. -# For conditions of distribution and use, see the disclaimer -# and license in png.h - -# Modeled after libxml-config. - -version="1.6.56" -prefix="C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64" -exec_prefix="C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64" -libdir="C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64/lib" -includedir="C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64/include/libpng16" -libs="-lpng16" -all_libs="-lpng16 -lz -lm" -I_opts="-I${includedir}" -L_opts="-L${libdir}" -R_opts="" -cppflags="" -ccopts="" -ldopts="" - -usage() -{ - cat < - - - Set hintslight to hintstyle - - - - hintslight - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/10-scale-bitmap-fonts.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/10-scale-bitmap-fonts.conf deleted file mode 100644 index 0c3a2efc3..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/10-scale-bitmap-fonts.conf +++ /dev/null @@ -1,83 +0,0 @@ - - - - Bitmap scaling - - - - false - - - - pixelsize - pixelsize - - - - - - - false - - - false - - - true - - - - - pixelsizefixupfactor - 1.2 - - - pixelsizefixupfactor - 0.8 - - - - - - - true - - - 1.0 - - - - - - false - - - 1.0 - - - - matrix - - pixelsizefixupfactor 0 - 0 pixelsizefixupfactor - - - - - - size - pixelsizefixupfactor - - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/10-sub-pixel-none.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/10-sub-pixel-none.conf deleted file mode 100644 index 1fb6c98af..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/10-sub-pixel-none.conf +++ /dev/null @@ -1,15 +0,0 @@ - - - - Disable sub-pixel rendering - - - - none - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/10-yes-antialias.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/10-yes-antialias.conf deleted file mode 100644 index 4451f6ed1..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/10-yes-antialias.conf +++ /dev/null @@ -1,8 +0,0 @@ - - - - Enable antialiasing - - true - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/11-lcdfilter-default.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/11-lcdfilter-default.conf deleted file mode 100644 index 602559783..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/11-lcdfilter-default.conf +++ /dev/null @@ -1,17 +0,0 @@ - - - - Use lcddefault as default for LCD filter - - - - - lcddefault - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/20-unhint-small-vera.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/20-unhint-small-vera.conf deleted file mode 100644 index e4e9c33cb..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/20-unhint-small-vera.conf +++ /dev/null @@ -1,49 +0,0 @@ - - - - Disable hinting for Bitstream Vera fonts when the size is less than 8ppem - - - - - Bitstream Vera Sans - - - 7.5 - - - false - - - - - - Bitstream Vera Serif - - - 7.5 - - - false - - - - - - Bitstream Vera Sans Mono - - - 7.5 - - - false - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/30-metric-aliases.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/30-metric-aliases.conf deleted file mode 100644 index edf4ef852..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/30-metric-aliases.conf +++ /dev/null @@ -1,658 +0,0 @@ - - - - Set substitutions for similar/metric-compatible families - - - - - - - - Helvetica LT Std - - Helvetica - - - - - Nimbus Sans L - - Helvetica - - - - - Nimbus Sans - - Helvetica - - - - - TeX Gyre Heros - - Helvetica - - - - - Nimbus Sans Narrow - - Helvetica Narrow - - - - - TeX Gyre Heros Cn - - Helvetica Narrow - - - - - Nimbus Roman No9 L - - Times - - - - - Nimbus Roman - - Times - - - - - TeX Gyre Termes - - Times - - - - - Courier Std - - Courier - - - - - Nimbus Mono L - - Courier - - - - - Nimbus Mono - - Courier - - - - - Nimbus Mono PS - - Courier - - - - - TeX Gyre Cursor - - Courier - - - - - Avant Garde - - ITC Avant Garde Gothic - - - - - URW Gothic L - - ITC Avant Garde Gothic - - - - - URW Gothic - - ITC Avant Garde Gothic - - - - - TeX Gyre Adventor - - ITC Avant Garde Gothic - - - - - Bookman - - ITC Bookman - - - - - URW Bookman L - - ITC Bookman - - - - - Bookman URW - - ITC Bookman - - - - - URW Bookman - - ITC Bookman - - - - - TeX Gyre Bonum - - ITC Bookman - - - - - Bookman Old Style - - ITC Bookman - - - - - Zapf Chancery - - ITC Zapf Chancery - - - - - URW Chancery L - - ITC Zapf Chancery - - - - - Chancery URW - - ITC Zapf Chancery - - - - - Z003 - - ITC Zapf Chancery - - - - - TeX Gyre Chorus - - ITC Zapf Chancery - - - - - URW Palladio L - - Palatino - - - - - Palladio URW - - Palatino - - - - - P052 - - Palatino - - - - - TeX Gyre Pagella - - Palatino - - - - - Palatino Linotype - - Palatino - - - - - Century Schoolbook L - - New Century Schoolbook - - - - - Century SchoolBook URW - - New Century Schoolbook - - - - - C059 - - New Century Schoolbook - - - - - TeX Gyre Schola - - New Century Schoolbook - - - - - Century Schoolbook - - New Century Schoolbook - - - - - - Arimo - - Arial - - - - - Liberation Sans - - Arial - - - - - Liberation Sans Narrow - - Arial Narrow - - - - - Albany - - Arial - - - - - Albany AMT - - Arial - - - - - Tinos - - Times New Roman - - - - - Liberation Serif - - Times New Roman - - - - - Thorndale - - Times New Roman - - - - - Thorndale AMT - - Times New Roman - - - - - Cousine - - Courier New - - - - - Liberation Mono - - Courier New - - - - - Cumberland - - Courier New - - - - - Cumberland AMT - - Courier New - - - - - Gelasio - - Georgia - - - - - Caladea - - Cambria - - - - - Carlito - - Calibri - - - - - SymbolNeu - - Symbol - - - - - - - - Helvetica - - Arial - - - - - Helvetica Narrow - - Arial Narrow - - - - - Times - - Times New Roman - - - - - Courier - - Courier New - - - - - - Arial - - Helvetica - - - - - Arial Narrow - - Helvetica Narrow - - - - - Times New Roman - - Times - - - - - Courier New - - Courier - - - - - - - - Helvetica - - Helvetica LT Std - - - - - Helvetica - - TeX Gyre Heros - - - - - Helvetica Narrow - - TeX Gyre Heros Cn - - - - - Times - - TeX Gyre Termes - - - - - Courier - - TeX Gyre Cursor - - - - - Courier - - Courier Std - - - - - ITC Avant Garde Gothic - - TeX Gyre Adventor - - - - - ITC Bookman - - Bookman Old Style - TeX Gyre Bonum - - - - - ITC Zapf Chancery - - TeX Gyre Chorus - - - - - Palatino - - Palatino Linotype - TeX Gyre Pagella - - - - - New Century Schoolbook - - Century Schoolbook - TeX Gyre Schola - - - - - - Arial - - Arimo - Liberation Sans - Albany - Albany AMT - - - - - Arial Narrow - - Liberation Sans Narrow - - - - - Times New Roman - - Tinos - Liberation Serif - Thorndale - Thorndale AMT - - - - - Courier New - - Cousine - Liberation Mono - Cumberland - Cumberland AMT - - - - - Georgia - - Gelasio - - - - - Cambria - - Caladea - - - - - Calibri - - Carlito - - - - - Symbol - - SymbolNeu - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/40-nonlatin.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/40-nonlatin.conf deleted file mode 100644 index f8d96ce81..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/40-nonlatin.conf +++ /dev/null @@ -1,332 +0,0 @@ - - - - Set substitutions for non-Latin fonts - - - - - Nazli - serif - - - Lotoos - serif - - - Mitra - serif - - - Ferdosi - serif - - - Badr - serif - - - Zar - serif - - - Titr - serif - - - Jadid - serif - - - Kochi Mincho - serif - - - AR PL SungtiL GB - serif - - - AR PL Mingti2L Big5 - serif - - - MS 明朝 - serif - - - NanumMyeongjo - serif - - - UnBatang - serif - - - Baekmuk Batang - serif - - - MgOpen Canonica - serif - - - Sazanami Mincho - serif - - - AR PL ZenKai Uni - serif - - - ZYSong18030 - serif - - - FreeSerif - serif - - - SimSun - serif - - - - Arshia - sans-serif - - - Elham - sans-serif - - - Farnaz - sans-serif - - - Nasim - sans-serif - - - Sina - sans-serif - - - Roya - sans-serif - - - Koodak - sans-serif - - - Terafik - sans-serif - - - Kochi Gothic - sans-serif - - - AR PL KaitiM GB - sans-serif - - - AR PL KaitiM Big5 - sans-serif - - - MS ゴシック - sans-serif - - - NanumGothic - sans-serif - - - UnDotum - sans-serif - - - Baekmuk Dotum - sans-serif - - - MgOpen Modata - sans-serif - - - Sazanami Gothic - sans-serif - - - AR PL ShanHeiSun Uni - sans-serif - - - ZYSong18030 - sans-serif - - - FreeSans - sans-serif - - - - NSimSun - monospace - - - ZYSong18030 - monospace - - - NanumGothicCoding - monospace - - - FreeMono - monospace - - - - - Homa - fantasy - - - Kamran - fantasy - - - Fantezi - fantasy - - - Tabassom - fantasy - - - - - IranNastaliq - cursive - - - Nafees Nastaleeq - cursive - - - - - Noto Sans Arabic UI - system-ui - - - Noto Sans Bengali UI - system-ui - - - Noto Sans Devanagari UI - system-ui - - - Noto Sans Gujarati UI - system-ui - - - Noto Sans Gurmukhi UI - system-ui - - - Noto Sans Kannada UI - system-ui - - - Noto Sans Khmer UI - system-ui - - - Noto Sans Lao UI - system-ui - - - Noto Sans Malayalam UI - system-ui - - - Noto Sans Myanmar UI - system-ui - - - Noto Sans Oriya UI - system-ui - - - Noto Sans Sinhala UI - system-ui - - - Noto Sans Tamil UI - system-ui - - - Noto Sans Telugu UI - system-ui - - - Noto Sans Thai UI - system-ui - - - Leelawadee UI - system-ui - - - Nirmala UI - system-ui - - - Yu Gothic UI - system-ui - - - Meiryo UI - system-ui - - - MS UI Gothic - system-ui - - - Khmer UI - system-ui - - - Lao UI - system-ui - - - Microsoft JhengHei UI - system-ui - - - Microsoft YaHei UI - system-ui - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/45-generic.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/45-generic.conf deleted file mode 100644 index 5c1bd36b5..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/45-generic.conf +++ /dev/null @@ -1,136 +0,0 @@ - - - - Set substitutions for emoji/math fonts - - - - - - - - Noto Color Emoji - emoji - - - Apple Color Emoji - emoji - - - Segoe UI Emoji - emoji - - - Twitter Color Emoji - emoji - - - EmojiOne Mozilla - emoji - - - - Emoji Two - emoji - - - JoyPixels - emoji - - - Emoji One - emoji - - - - Noto Emoji - emoji - - - Android Emoji - emoji - - - - - - emoji - - - und-zsye - - - - - - und-zsye - - - emoji - - - - - emoji - - - - - - - - - XITS Math - math - - - STIX Two Math - math - - - Cambria Math - math - - - Latin Modern Math - math - - - Minion Math - math - - - Lucida Math - math - - - Asana Math - math - - - - - - math - - - und-zmth - - - - - - und-zmth - - - math - - - - - math - - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/45-latin.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/45-latin.conf deleted file mode 100644 index 53158c767..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/45-latin.conf +++ /dev/null @@ -1,309 +0,0 @@ - - - - Set substitutions for Latin fonts - - - - - Bitstream Vera Serif - serif - - - Cambria - serif - - - Constantia - serif - - - DejaVu Serif - serif - - - Elephant - serif - - - Garamond - serif - - - Georgia - serif - - - Liberation Serif - serif - - - Luxi Serif - serif - - - MS Serif - serif - - - Nimbus Roman No9 L - serif - - - Nimbus Roman - serif - - - Palatino Linotype - serif - - - Thorndale AMT - serif - - - Thorndale - serif - - - Times New Roman - serif - - - Times - serif - - - - Albany AMT - sans-serif - - - Albany - sans-serif - - - Arial Unicode MS - sans-serif - - - Arial - sans-serif - - - Bitstream Vera Sans - sans-serif - - - Britannic - sans-serif - - - Calibri - sans-serif - - - Candara - sans-serif - - - Century Gothic - sans-serif - - - Corbel - sans-serif - - - DejaVu Sans - sans-serif - - - Helvetica LT Std - sans-serif - - - Helvetica - sans-serif - - - Haettenschweiler - sans-serif - - - Liberation Sans - sans-serif - - - MS Sans Serif - sans-serif - - - Nimbus Sans L - sans-serif - - - Nimbus Sans - sans-serif - - - Luxi Sans - sans-serif - - - Tahoma - sans-serif - - - Trebuchet MS - sans-serif - - - Twentieth Century - sans-serif - - - Verdana - sans-serif - - - - Andale Mono - monospace - - - Bitstream Vera Sans Mono - monospace - - - Consolas - monospace - - - Courier New - monospace - - - Courier Std - monospace - - - Courier - monospace - - - Cumberland AMT - monospace - - - Cumberland - monospace - - - DejaVu Sans Mono - monospace - - - Fixedsys - monospace - - - Inconsolata - monospace - - - Liberation Mono - monospace - - - Luxi Mono - monospace - - - Nimbus Mono L - monospace - - - Nimbus Mono - monospace - - - Nimbus Mono PS - monospace - - - Terminal - monospace - - - - Bauhaus Std - fantasy - - - Cooper Std - fantasy - - - Copperplate Gothic Std - fantasy - - - Impact - fantasy - - - - Comic Sans MS - cursive - - - ITC Zapf Chancery Std - cursive - - - Zapfino - cursive - - - - Adwaita Sans - system-ui - - - Cantarell - system-ui - - - Noto Sans UI - system-ui - - - Segoe UI - system-ui - - - Segoe UI Historic - system-ui - - - Segoe UI Symbol - system-ui - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/48-spacing.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/48-spacing.conf deleted file mode 100644 index 6df5c1176..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/48-spacing.conf +++ /dev/null @@ -1,16 +0,0 @@ - - - - Add mono to the family when spacing is 100 - - - - 100 - - - monospace - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/49-sansserif.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/49-sansserif.conf deleted file mode 100644 index 6cc3a1c49..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/49-sansserif.conf +++ /dev/null @@ -1,22 +0,0 @@ - - - - Add sans-serif to the family when no generic name - - - - sans-serif - - - serif - - - monospace - - - sans-serif - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/50-user.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/50-user.conf deleted file mode 100644 index d019f4d4e..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/50-user.conf +++ /dev/null @@ -1,16 +0,0 @@ - - - - Load per-user customization files - - fontconfig/conf.d - fontconfig/fonts.conf - - ~/.fonts.conf.d - ~/.fonts.conf - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/51-local.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/51-local.conf deleted file mode 100644 index 82e3c1b2f..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/51-local.conf +++ /dev/null @@ -1,7 +0,0 @@ - - - - Load local customization file - - local.conf - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/60-generic.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/60-generic.conf deleted file mode 100644 index 783150771..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/60-generic.conf +++ /dev/null @@ -1,64 +0,0 @@ - - - - Set preferable fonts for emoji/math fonts - - - - - - - - und-zsye - - - true - - - false - - - true - - - - - - emoji - - - Noto Color Emoji - Apple Color Emoji - Segoe UI Emoji - Twitter Color Emoji - EmojiOne Mozilla - - Emoji Two - JoyPixels - Emoji One - - Noto Emoji - Android Emoji - - - - - - - math - - XITS Math - STIX Two Math - Cambria Math - Latin Modern Math - Minion Math - Lucida Math - Asana Math - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/60-latin.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/60-latin.conf deleted file mode 100644 index ae3be3c73..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/60-latin.conf +++ /dev/null @@ -1,89 +0,0 @@ - - - - Set preferable fonts for Latin - - serif - - Noto Serif - DejaVu Serif - Times New Roman - Thorndale AMT - Luxi Serif - Nimbus Roman No9 L - Nimbus Roman - Times - - - - sans-serif - - Noto Sans - DejaVu Sans - Verdana - Arial - Albany AMT - Luxi Sans - Nimbus Sans L - Nimbus Sans - Helvetica - Lucida Sans Unicode - BPG Glaho International - Tahoma - - - - monospace - - Noto Sans Mono - DejaVu Sans Mono - Inconsolata - Andale Mono - Courier New - Cumberland AMT - Luxi Mono - Nimbus Mono L - Nimbus Mono - Nimbus Mono PS - Courier - - - - - fantasy - - Impact - Copperplate Gothic Std - Cooper Std - Bauhaus Std - - - - - cursive - - ITC Zapf Chancery Std - Zapfino - Comic Sans MS - - - - - system-ui - - Adwaita Sans - Cantarell - Noto Sans UI - Segoe UI - Segoe UI Historic - Segoe UI Symbol - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/65-fonts-persian.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/65-fonts-persian.conf deleted file mode 100644 index 47da1bb09..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/65-fonts-persian.conf +++ /dev/null @@ -1,418 +0,0 @@ - - - - - - - - - - Nesf - Nesf2 - - - Nesf2 - Persian_sansserif_default - - - - - - Nazanin - Nazli - - - Lotus - Lotoos - - - Yaqut - Yaghoot - - - Yaghut - Yaghoot - - - Traffic - Terafik - - - Ferdowsi - Ferdosi - - - Fantezy - Fantezi - - - - - - - - Jadid - Persian_title - - - Titr - Persian_title - - - - - Kamran - - Persian_fantasy - Homa - - - - Homa - - Persian_fantasy - Kamran - - - - Fantezi - Persian_fantasy - - - Tabassom - Persian_fantasy - - - - - Arshia - Persian_square - - - Nasim - Persian_square - - - Elham - - Persian_square - Farnaz - - - - Farnaz - - Persian_square - Elham - - - - Sina - Persian_square - - - - - - - Persian_title - - Titr - Jadid - Persian_serif - - - - - - Persian_fantasy - - Homa - Kamran - Fantezi - Tabassom - Persian_square - - - - - - Persian_square - - Arshia - Elham - Farnaz - Nasim - Sina - Persian_serif - - - - - - - - Elham - - - farsiweb - - - - - - Homa - - - farsiweb - - - - - - Koodak - - - farsiweb - - - - - - Nazli - - - farsiweb - - - - - - Roya - - - farsiweb - - - - - - Terafik - - - farsiweb - - - - - - Titr - - - farsiweb - - - - - - - - - - TURNED-OFF - - - farsiweb - - - - roman - - - - roman - - - - - matrix - 1-0.2 - 01 - - - - - - oblique - - - - - - - - - farsiweb - - - false - - - false - - - false - - - - - - - - - serif - - Nazli - Lotoos - Mitra - Ferdosi - Badr - Zar - - - - - - sans-serif - - Roya - Koodak - Terafik - - - - - - monospace - - - Terafik - - - - - - fantasy - - Homa - Kamran - Fantezi - Tabassom - - - - - - cursive - - IranNastaliq - Nafees Nastaleeq - - - - - - - - - serif - - - 200 - - - 24 - - - Titr - - - - - - - sans-serif - - - 200 - - - 24 - - - Titr - - - - - - - Persian_sansserif_default - - - 200 - - - 24 - - - Titr - - - - - - - - - Persian_sansserif_default - - - Roya - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/65-nonlatin.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/65-nonlatin.conf deleted file mode 100644 index 3e5d1c7d8..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/65-nonlatin.conf +++ /dev/null @@ -1,240 +0,0 @@ - - - - Set preferable fonts for non-Latin - - serif - - Artsounk - BPG UTF8 M - Kinnari - Norasi - Frank Ruehl - Dror - JG LaoTimes - Saysettha Unicode - Pigiarniq - B Davat - B Compset - Kacst-Qr - Urdu Nastaliq Unicode - Raghindi - Mukti Narrow - malayalam - Sampige - padmaa - Hapax Berbère - MS Mincho - SimSun - PMingLiu - WenQuanYi Zen Hei - WenQuanYi Bitmap Song - AR PL ShanHeiSun Uni - AR PL New Sung - ZYSong18030 - HanyiSong - Hiragino Mincho ProN - Songti SC - Songti TC - SimSong - MgOpen Canonica - Sazanami Mincho - IPAMonaMincho - IPAMincho - Kochi Mincho - AR PL SungtiL GB - AR PL Mingti2L Big5 - AR PL Zenkai Uni - MS 明朝 - ZYSong18030 - NanumMyeongjo - UnBatang - Baekmuk Batang - AppleMyungjo - KacstQura - Frank Ruehl CLM - Lohit Bengali - Lohit Gujarati - Lohit Hindi - Lohit Marathi - Lohit Maithili - Lohit Kashmiri - Lohit Konkani - Lohit Nepali - Lohit Sindhi - Lohit Punjabi - Lohit Tamil - Rachana - Lohit Malayalam - Lohit Kannada - Lohit Telugu - Lohit Oriya - LKLUG - - - - sans-serif - - Nachlieli - Lucida Sans Unicode - Yudit Unicode - Kerkis - ArmNet Helvetica - Artsounk - BPG UTF8 M - Waree - Loma - Garuda - Umpush - Saysettha Unicode - JG Lao Old Arial - GF Zemen Unicode - Pigiarniq - B Davat - B Compset - Kacst-Qr - Urdu Nastaliq Unicode - Raghindi - Mukti Narrow - malayalam - Sampige - padmaa - Hapax Berbère - MS Gothic - UmePlus P Gothic - Microsoft YaHei - Microsoft JhengHei - WenQuanYi Zen Hei - WenQuanYi Bitmap Song - AR PL ShanHeiSun Uni - AR PL New Sung - Hiragino Sans - PingFang SC - PingFang TC - PingFang HK - Hiragino Sans CNS - Hiragino Sans GB - MgOpen Modata - VL Gothic - IPAMonaGothic - IPAGothic - Sazanami Gothic - Kochi Gothic - AR PL KaitiM GB - AR PL KaitiM Big5 - AR PL ShanHeiSun Uni - AR PL SungtiL GB - AR PL Mingti2L Big5 - MS ゴシック - ZYSong18030 - TSCu_Paranar - NanumGothic - UnDotum - Baekmuk Dotum - Baekmuk Gulim - Apple SD Gothic Neo - KacstQura - Lohit Bengali - Lohit Gujarati - Lohit Hindi - Lohit Marathi - Lohit Maithili - Lohit Kashmiri - Lohit Konkani - Lohit Nepali - Lohit Sindhi - Lohit Punjabi - Lohit Tamil - Meera - Lohit Malayalam - Lohit Kannada - Lohit Telugu - Lohit Oriya - LKLUG - - - - monospace - - Miriam Mono - VL Gothic - IPAMonaGothic - IPAGothic - Sazanami Gothic - Kochi Gothic - AR PL KaitiM GB - MS Gothic - UmePlus Gothic - NSimSun - MingLiu - AR PL ShanHeiSun Uni - AR PL New Sung Mono - HanyiSong - AR PL SungtiL GB - AR PL Mingti2L Big5 - ZYSong18030 - NanumGothicCoding - NanumGothic - UnDotum - Baekmuk Dotum - Baekmuk Gulim - TlwgTypo - TlwgTypist - TlwgTypewriter - TlwgMono - Hasida - GF Zemen Unicode - Hapax Berbère - Lohit Bengali - Lohit Gujarati - Lohit Hindi - Lohit Marathi - Lohit Maithili - Lohit Kashmiri - Lohit Konkani - Lohit Nepali - Lohit Sindhi - Lohit Punjabi - Lohit Tamil - Meera - Lohit Malayalam - Lohit Kannada - Lohit Telugu - Lohit Oriya - LKLUG - - - - - system-ui - - Noto Sans Arabic UI - Noto Sans Bengali UI - Noto Sans Devanagari UI - Noto Sans Gujarati UI - Noto Sans Gurmukhi UI - Noto Sans Kannada UI - Noto Sans Khmer UI - Noto Sans Lao UI - Noto Sans Malayalam UI - Noto Sans Myanmar UI - Noto Sans Oriya UI - Noto Sans Sinhala UI - Noto Sans Tamil UI - Noto Sans Telugu UI - Noto Sans Thai UI - Leelawadee UI - Nirmala UI - Yu Gothic UI - Meiryo UI - MS UI Gothic - Khmer UI - Lao UI - Microsoft YaHei UI - Microsoft JhengHei UI - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/69-unifont.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/69-unifont.conf deleted file mode 100644 index 02854ff9d..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/69-unifont.conf +++ /dev/null @@ -1,28 +0,0 @@ - - - - - serif - - FreeSerif - Code2000 - Code2001 - - - - sans-serif - - FreeSans - Arial Unicode MS - Arial Unicode - Code2000 - Code2001 - - - - monospace - - FreeMono - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/80-delicious.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/80-delicious.conf deleted file mode 100644 index d20990cd3..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/80-delicious.conf +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - Delicious - - - Heavy - - - heavy - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/90-synthetic.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/90-synthetic.conf deleted file mode 100644 index dfce674bb..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/90-synthetic.conf +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - roman - - - - roman - - - - - matrix - 10.2 - 01 - - - - - - oblique - - - - false - - - - - - - - - medium - - - - bold - - - - true - - - - bold - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/README b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/README deleted file mode 100644 index fd4f5b212..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/conf.d/README +++ /dev/null @@ -1,23 +0,0 @@ -conf.d/README - -Each file in this directory is a fontconfig configuration file. Fontconfig -scans this directory, loading all files of the form [0-9][0-9]*.conf. -These files are normally installed in C:/projects/repos/cerbero.git/1.28/build/dist/msvc_x86_64/share/fontconfig/conf.avail -and then symlinked here, allowing them to be easily installed and then -enabled/disabled by adjusting the symlinks. - -The files are loaded in numeric order, the structure of the configuration -has led to the following conventions in usage: - - Files beginning with: Contain: - - 00 through 09 Font directories - 10 through 19 system rendering defaults (AA, etc) - 20 through 29 font rendering options - 30 through 39 family substitution - 40 through 49 generic identification, map family->generic - 50 through 59 alternate config file loading - 60 through 69 generic aliases, map generic->family - 70 through 79 select font (adjust which fonts are available) - 80 through 89 match target="scan" (modify scanned patterns) - 90 through 99 font synthesis diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/fonts.conf b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/fonts.conf deleted file mode 100644 index c8fdfc24e..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/fonts/fonts.conf +++ /dev/null @@ -1,103 +0,0 @@ - - - - - Default configuration file - - - - - - WINDOWSFONTDIR - WINDOWSUSERFONTDIR - - - fonts - - ~/.fonts - - - - - mono - - - monospace - - - - - - - sans serif - - - sans-serif - - - - - - - sans - - - sans-serif - - - - - - system ui - - - system-ui - - - - - conf.d - - - - LOCAL_APPDATA_FONTCONFIG_CACHE - fontconfig - - ~/.fontconfig - - - - - 30 - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/ssl/certs/ca-certificates.crt b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/ssl/certs/ca-certificates.crt deleted file mode 100644 index 9551dfd83..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/etc/ssl/certs/ca-certificates.crt +++ /dev/null @@ -1,3451 +0,0 @@ -## -## Bundle of CA Root Certificates -## -## Certificate data from Mozilla as of: Tue Aug 22 03:12:04 2023 GMT -## -## This is a bundle of X.509 certificates of public Certificate Authorities -## (CA). These were automatically extracted from Mozilla's root certificates -## file (certdata.txt). This file can be found in the mozilla source tree: -## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt -## -## It contains the certificates in PEM format and therefore -## can be directly used with curl / libcurl / php_curl, or with -## an Apache+mod_ssl webserver for SSL client authentication. -## Just configure this file as the SSLCACertificateFile. -## -## Conversion done with mk-ca-bundle.pl version 1.29. -## SHA256: 0ff137babc6a5561a9cfbe9f29558972e5b528202681b7d3803d03a3e82922bd -## - - -GlobalSign Root CA -================== ------BEGIN CERTIFICATE----- -MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx -GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds -b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV -BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD -VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa -DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc -THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb -Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP -c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX -gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF -AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj -Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG -j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH -hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC -X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== ------END CERTIFICATE----- - -Entrust.net Premium 2048 Secure Server CA -========================================= ------BEGIN CERTIFICATE----- -MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u -ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp -bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV -BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx -NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 -d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl -MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u -ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL -Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr -hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW -nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi -VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ -KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy -T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf -zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT -J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e -nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= ------END CERTIFICATE----- - -Baltimore CyberTrust Root -========================= ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE -ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li -ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC -SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs -dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME -uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB -UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C -G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 -XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr -l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI -VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB -BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh -cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 -hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa -Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H -RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp ------END CERTIFICATE----- - -Entrust Root Certification Authority -==================================== ------BEGIN CERTIFICATE----- -MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV -BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw -b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG -A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 -MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu -MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu -Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v -dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz -A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww -Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 -j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN -rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw -DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 -MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH -hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA -A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM -Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa -v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS -W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 -tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 ------END CERTIFICATE----- - -Comodo AAA Services root -======================== ------BEGIN CERTIFICATE----- -MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS -R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg -TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw -MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl -c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV -BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG -C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs -i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW -Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH -Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK -Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f -BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl -cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz -LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm -7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz -Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z -8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C -12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== ------END CERTIFICATE----- - -QuoVadis Root CA 2 -================== ------BEGIN CERTIFICATE----- -MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT -EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx -ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC -DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 -XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk -lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB -lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy -lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt -66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn -wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh -D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy -BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie -J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud -DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU -a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT -ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv -Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 -UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm -VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK -+JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW -IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 -WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X -f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II -4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 -VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u ------END CERTIFICATE----- - -QuoVadis Root CA 3 -================== ------BEGIN CERTIFICATE----- -MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT -EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx -OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC -DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg -DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij -KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K -DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv -BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp -p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 -nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX -MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM -Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz -uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT -BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj -YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 -aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB -BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD -VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 -ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE -AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV -qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s -hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z -POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 -Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp -8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC -bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu -g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p -vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr -qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= ------END CERTIFICATE----- - -Security Communication Root CA -============================== ------BEGIN CERTIFICATE----- -MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP -U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw -HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP -U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw -8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM -DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX -5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd -DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 -JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw -DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g -0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a -mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ -s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ -6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi -FL39vmwLAw== ------END CERTIFICATE----- - -XRamp Global CA Root -==================== ------BEGIN CERTIFICATE----- -MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE -BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj -dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx -HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg -U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu -IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx -foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE -zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs -AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry -xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud -EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap -oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC -AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc -/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt -qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n -nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz -8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= ------END CERTIFICATE----- - -Go Daddy Class 2 CA -=================== ------BEGIN CERTIFICATE----- -MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY -VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG -A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g -RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD -ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv -2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 -qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j -YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY -vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O -BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o -atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu -MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG -A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim -PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt -I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ -HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI -Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b -vZ8= ------END CERTIFICATE----- - -Starfield Class 2 CA -==================== ------BEGIN CERTIFICATE----- -MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc -U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg -Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo -MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG -A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG -SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY -bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ -JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm -epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN -F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF -MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f -hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo -bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g -QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs -afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM -PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl -xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD -KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 -QBFGmh95DmK/D5fs4C8fF5Q= ------END CERTIFICATE----- - -DigiCert Assured ID Root CA -=========================== ------BEGIN CERTIFICATE----- -MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw -IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx -MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL -ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO -9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy -UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW -/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy -oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf -GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF -66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq -hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc -EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn -SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i -8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe -+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== ------END CERTIFICATE----- - -DigiCert Global Root CA -======================= ------BEGIN CERTIFICATE----- -MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw -HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw -MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 -dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq -hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn -TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 -BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H -4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y -7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB -o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm -8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF -BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr -EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt -tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 -UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk -CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= ------END CERTIFICATE----- - -DigiCert High Assurance EV Root CA -================================== ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw -KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw -MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ -MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu -Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t -Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS -OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 -MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ -NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe -h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB -Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY -JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ -V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp -myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK -mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe -vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K ------END CERTIFICATE----- - -SwissSign Gold CA - G2 -====================== ------BEGIN CERTIFICATE----- -MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw -EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN -MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp -c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B -AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq -t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C -jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg -vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF -ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR -AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend -jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO -peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR -7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi -GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 -OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov -L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm -5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr -44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf -Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m -Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp -mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk -vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf -KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br -NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj -viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ ------END CERTIFICATE----- - -SwissSign Silver CA - G2 -======================== ------BEGIN CERTIFICATE----- -MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT -BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X -DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3 -aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG -9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644 -N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm -+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH -6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu -MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h -qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5 -FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs -ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc -celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X -CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB -tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 -cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P -4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F -kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L -3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx -/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa -DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP -e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu -WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ -DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub -DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u ------END CERTIFICATE----- - -SecureTrust CA -============== ------BEGIN CERTIFICATE----- -MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG -EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy -dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe -BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC -ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX -OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t -DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH -GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b -01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH -ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj -aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ -KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu -SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf -mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ -nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR -3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= ------END CERTIFICATE----- - -Secure Global CA -================ ------BEGIN CERTIFICATE----- -MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG -EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH -bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg -MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg -Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx -YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ -bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g -8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV -HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi -0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud -EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn -oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA -MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ -OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn -CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 -3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc -f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW ------END CERTIFICATE----- - -COMODO Certification Authority -============================== ------BEGIN CERTIFICATE----- -MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE -BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG -A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 -dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb -MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD -T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH -+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww -xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV -4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA -1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI -rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k -b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC -AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP -OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ -RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc -IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN -+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== ------END CERTIFICATE----- - -COMODO ECC Certification Authority -================================== ------BEGIN CERTIFICATE----- -MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC -R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE -ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix -GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR -Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X -4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni -wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG -FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA -U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= ------END CERTIFICATE----- - -Certigna -======== ------BEGIN CERTIFICATE----- -MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw -EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 -MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI -Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q -XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH -GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p -ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg -DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf -Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ -tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ -BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J -SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA -hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ -ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu -PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY -1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw -WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== ------END CERTIFICATE----- - -ePKI Root Certification Authority -================================= ------BEGIN CERTIFICATE----- -MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG -EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg -Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx -MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq -MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B -AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs -IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi -lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv -qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX -12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O -WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ -ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao -lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ -vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi -Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi -MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH -ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 -1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq -KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV -xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP -NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r -GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE -xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx -gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy -sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD -BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= ------END CERTIFICATE----- - -certSIGN ROOT CA -================ ------BEGIN CERTIFICATE----- -MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD -VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa -Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE -CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I -JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH -rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 -ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD -0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 -AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B -Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB -AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 -SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 -x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt -vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz -TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD ------END CERTIFICATE----- - -NetLock Arany (Class Gold) Főtanúsítvány -======================================== ------BEGIN CERTIFICATE----- -MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G -A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 -dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB -cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx -MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO -ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv -biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 -c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu -0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw -/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk -H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw -fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 -neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW -qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta -YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC -bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna -NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu -dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= ------END CERTIFICATE----- - -SecureSign RootCA11 -=================== ------BEGIN CERTIFICATE----- -MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi -SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS -b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw -KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 -cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL -TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO -wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq -g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP -O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA -bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX -t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh -OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r -bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ -Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 -y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 -lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= ------END CERTIFICATE----- - -Microsec e-Szigno Root CA 2009 -============================== ------BEGIN CERTIFICATE----- -MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER -MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv -c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o -dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE -BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt -U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA -fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG -0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA -pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm -1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC -AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf -QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE -FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o -lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX -I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 -tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 -yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi -LXpUq3DDfSJlgnCW ------END CERTIFICATE----- - -GlobalSign Root CA - R3 -======================= ------BEGIN CERTIFICATE----- -MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv -YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh -bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT -aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln -bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt -iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ -0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 -rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl -OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 -xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE -FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 -lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 -EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E -bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 -YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r -kpeDMdmztcpHWD9f ------END CERTIFICATE----- - -Autoridad de Certificacion Firmaprofesional CIF A62634068 -========================================================= ------BEGIN CERTIFICATE----- -MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA -BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 -MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw -QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB -NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD -Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P -B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY -7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH -ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI -plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX -MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX -LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK -bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU -vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud -EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH -DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp -cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA -bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx -ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx -51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk -R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP -T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f -Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl -osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR -crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR -saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD -KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi -6Et8Vcad+qMUu2WFbm5PEn4KPJ2V ------END CERTIFICATE----- - -Izenpe.com -========== ------BEGIN CERTIFICATE----- -MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG -EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz -MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu -QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ -03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK -ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU -+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC -PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT -OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK -F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK -0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ -0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB -leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID -AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ -SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG -NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx -MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O -BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l -Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga -kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q -hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs -g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 -aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 -nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC -ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo -Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z -WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== ------END CERTIFICATE----- - -Go Daddy Root Certificate Authority - G2 -======================================== ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT -B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu -MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 -MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 -b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G -A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq -9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD -+qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd -fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl -NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC -MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 -BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac -vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r -5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV -N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO -LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 ------END CERTIFICATE----- - -Starfield Root Certificate Authority - G2 -========================================= ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT -B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s -b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 -eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw -DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg -VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB -dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv -W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs -bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk -N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf -ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU -JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol -TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx -4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw -F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K -pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ -c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 ------END CERTIFICATE----- - -Starfield Services Root Certificate Authority - G2 -================================================== ------BEGIN CERTIFICATE----- -MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT -B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s -b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl -IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV -BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT -dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg -Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 -h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa -hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP -LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB -rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw -AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG -SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP -E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy -xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd -iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza -YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 ------END CERTIFICATE----- - -AffirmTrust Commercial -====================== ------BEGIN CERTIFICATE----- -MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS -BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw -MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly -bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb -DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV -C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 -BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww -MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV -HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG -hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi -qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv -0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh -sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= ------END CERTIFICATE----- - -AffirmTrust Networking -====================== ------BEGIN CERTIFICATE----- -MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS -BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw -MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly -bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE -Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI -dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 -/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb -h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV -HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu -UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 -12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 -WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 -/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= ------END CERTIFICATE----- - -AffirmTrust Premium -=================== ------BEGIN CERTIFICATE----- -MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS -BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy -OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy -dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A -MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn -BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV -5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs -+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd -GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R -p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI -S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 -6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 -/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo -+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv -MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg -Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC -6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S -L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK -+4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV -BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg -IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 -g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb -zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== ------END CERTIFICATE----- - -AffirmTrust Premium ECC -======================= ------BEGIN CERTIFICATE----- -MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV -BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx -MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U -cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ -N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW -BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK -BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X -57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM -eQ== ------END CERTIFICATE----- - -Certum Trusted Network CA -========================= ------BEGIN CERTIFICATE----- -MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK -ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy -MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU -ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 -MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC -l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J -J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 -fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 -cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB -Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw -DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj -jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 -mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj -Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI -03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= ------END CERTIFICATE----- - -TWCA Root Certification Authority -================================= ------BEGIN CERTIFICATE----- -MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ -VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG -EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB -IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx -QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC -oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP -4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r -y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB -BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG -9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC -mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW -QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY -T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny -Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== ------END CERTIFICATE----- - -Security Communication RootCA2 -============================== ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc -U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh -dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC -SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy -aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ -+T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R -3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV -spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K -EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 -QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB -CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj -u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk -3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q -tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 -mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 ------END CERTIFICATE----- - -Actalis Authentication Root CA -============================== ------BEGIN CERTIFICATE----- -MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM -BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE -AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky -MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz -IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 -IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ -wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa -by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 -zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f -YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 -oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l -EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 -hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 -EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 -jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY -iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt -ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI -WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 -JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx -K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ -Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC -4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo -2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz -lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem -OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 -vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== ------END CERTIFICATE----- - -Buypass Class 2 Root CA -======================= ------BEGIN CERTIFICATE----- -MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU -QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X -DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 -eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw -DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 -g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn -9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b -/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU -CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff -awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI -zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn -Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX -Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs -M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD -VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF -AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s -A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI -osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S -aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd -DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD -LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 -oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC -wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS -CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN -rJgWVqA= ------END CERTIFICATE----- - -Buypass Class 3 Root CA -======================= ------BEGIN CERTIFICATE----- -MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU -QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X -DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 -eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw -DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH -sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR -5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh -7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ -ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH -2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV -/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ -RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA -Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq -j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD -VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF -AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV -cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G -uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG -Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 -ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 -KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz -6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug -UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe -eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi -Cp/HuZc= ------END CERTIFICATE----- - -T-TeleSec GlobalRoot Class 3 -============================ ------BEGIN CERTIFICATE----- -MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM -IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU -cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx -MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz -dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD -ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK -9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU -NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF -iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W -0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA -MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr -AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb -fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT -ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h -P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml -e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== ------END CERTIFICATE----- - -D-TRUST Root Class 3 CA 2 2009 -============================== ------BEGIN CERTIFICATE----- -MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK -DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe -Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE -LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD -ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA -BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv -KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z -p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC -AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ -4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y -eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw -MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G -PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw -OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm -2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 -o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV -dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph -X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= ------END CERTIFICATE----- - -D-TRUST Root Class 3 CA 2 EV 2009 -================================= ------BEGIN CERTIFICATE----- -MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK -DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw -OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK -DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw -OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS -egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh -zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T -7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 -sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 -11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv -cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v -ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El -MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp -b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh -c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ -PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 -nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX -ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA -NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv -w9y4AyHqnxbxLFS1 ------END CERTIFICATE----- - -CA Disig Root R2 -================ ------BEGIN CERTIFICATE----- -MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw -EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp -ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx -EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp -c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC -w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia -xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 -A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S -GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV -g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa -5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE -koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A -Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i -Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u -Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM -tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV -sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je -dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 -1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx -mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 -utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 -sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg -UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV -7+ZtsH8tZ/3zbBt1RqPlShfppNcL ------END CERTIFICATE----- - -ACCVRAIZ1 -========= ------BEGIN CERTIFICATE----- -MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB -SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1 -MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH -UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC -DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM -jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0 -RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD -aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ -0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG -WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7 -8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR -5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J -9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK -Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw -Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu -Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 -VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM -Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA -QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh -AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA -YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj -AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA -IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk -aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0 -dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2 -MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI -hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E -R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN -YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49 -nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ -TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3 -sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h -I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg -Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd -3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p -EfbRD0tVNEYqi4Y7 ------END CERTIFICATE----- - -TWCA Global Root CA -=================== ------BEGIN CERTIFICATE----- -MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT -CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD -QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK -EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg -Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C -nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV -r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR -Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV -tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W -KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99 -sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p -yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn -kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI -zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC -AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g -cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn -LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M -8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg -/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg -lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP -A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m -i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8 -EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3 -zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0= ------END CERTIFICATE----- - -TeliaSonera Root CA v1 -====================== ------BEGIN CERTIFICATE----- -MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE -CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4 -MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW -VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+ -6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA -3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k -B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn -Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH -oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3 -F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ -oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7 -gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc -TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB -AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW -DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm -zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx -0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW -pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV -G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc -c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT -JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2 -qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6 -Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems -WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= ------END CERTIFICATE----- - -T-TeleSec GlobalRoot Class 2 -============================ ------BEGIN CERTIFICATE----- -MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM -IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU -cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx -MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz -dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD -ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ -SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F -vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970 -2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV -WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA -MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy -YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4 -r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf -vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR -3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN -9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg== ------END CERTIFICATE----- - -Atos TrustedRoot 2011 -===================== ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU -cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4 -MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG -A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV -hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr -54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+ -DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320 -HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR -z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R -l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ -bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB -CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h -k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh -TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9 -61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G -3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed ------END CERTIFICATE----- - -QuoVadis Root CA 1 G3 -===================== ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG -A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv -b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN -MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg -RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE -PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm -PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6 -Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN -ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l -g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV -7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX -9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f -iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg -t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI -hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC -MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3 -GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct -Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP -+V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh -3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa -wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6 -O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0 -FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV -hMJKzRwuJIczYOXD ------END CERTIFICATE----- - -QuoVadis Root CA 2 G3 -===================== ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG -A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv -b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN -MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg -RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh -ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY -NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t -oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o -MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l -V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo -L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ -sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD -6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh -lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI -hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 -AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K -pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9 -x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz -dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X -U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw -mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD -zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN -JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr -O3jtZsSOeWmD3n+M ------END CERTIFICATE----- - -QuoVadis Root CA 3 G3 -===================== ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG -A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv -b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN -MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg -RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286 -IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL -Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe -6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3 -I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U -VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7 -5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi -Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM -dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt -rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI -hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px -KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS -t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ -TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du -DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib -Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD -hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX -0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW -dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2 -PpxxVJkES/1Y+Zj0 ------END CERTIFICATE----- - -DigiCert Assured ID Root G2 -=========================== ------BEGIN CERTIFICATE----- -MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw -IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw -MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL -ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH -35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq -bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw -VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP -YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn -lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO -w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv -0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz -d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW -hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M -jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo -IhNzbM8m9Yop5w== ------END CERTIFICATE----- - -DigiCert Assured ID Root G3 -=========================== ------BEGIN CERTIFICATE----- -MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV -UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD -VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 -MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ -BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb -RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs -KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF -UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy -YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy -1vUhZscv6pZjamVFkpUBtA== ------END CERTIFICATE----- - -DigiCert Global Root G2 -======================= ------BEGIN CERTIFICATE----- -MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw -HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx -MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 -dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq -hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ -kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO -3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV -BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM -UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB -o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu -5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr -F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U -WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH -QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/ -iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl -MrY= ------END CERTIFICATE----- - -DigiCert Global Root G3 -======================= ------BEGIN CERTIFICATE----- -MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV -UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD -VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw -MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k -aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C -AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O -YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP -BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp -Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y -3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34 -VOKa5Vt8sycX ------END CERTIFICATE----- - -DigiCert Trusted Root G4 -======================== ------BEGIN CERTIFICATE----- -MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw -HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 -MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G -CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp -pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o -k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa -vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY -QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6 -MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm -mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7 -f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH -dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8 -oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud -DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD -ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY -ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr -yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy -7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah -ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN -5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb -/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa -5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK -G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP -82Z+ ------END CERTIFICATE----- - -COMODO RSA Certification Authority -================================== ------BEGIN CERTIFICATE----- -MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE -BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG -A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC -R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE -ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn -dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ -FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+ -5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG -x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX -2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL -OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3 -sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C -GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5 -WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E -FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w -DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt -rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+ -nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg -tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW -sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp -pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA -zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq -ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52 -7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I -LaZRfyHBNVOFBkpdn627G190 ------END CERTIFICATE----- - -USERTrust RSA Certification Authority -===================================== ------BEGIN CERTIFICATE----- -MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE -BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK -ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE -BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK -ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz -0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j -Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn -RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O -+T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq -/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE -Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM -lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8 -yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+ -eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd -BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF -MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW -FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ -7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ -Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM -8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi -FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi -yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c -J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw -sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx -Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9 ------END CERTIFICATE----- - -USERTrust ECC Certification Authority -===================================== ------BEGIN CERTIFICATE----- -MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC -VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU -aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC -VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU -aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2 -0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez -nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV -HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB -HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu -9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= ------END CERTIFICATE----- - -GlobalSign ECC Root CA - R5 -=========================== ------BEGIN CERTIFICATE----- -MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb -R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD -EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb -R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD -EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6 -SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS -h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd -BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx -uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7 -yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3 ------END CERTIFICATE----- - -IdenTrust Commercial Root CA 1 -============================== ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG -EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS -b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES -MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB -IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld -hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/ -mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi -1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C -XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl -3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy -NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV -WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg -xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix -uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC -AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI -hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH -6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg -ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt -ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV -YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX -feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro -kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe -2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz -Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R -cGzM7vRX+Bi6hG6H ------END CERTIFICATE----- - -IdenTrust Public Sector Root CA 1 -================================= ------BEGIN CERTIFICATE----- -MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG -EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv -ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV -UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS -b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy -P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6 -Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI -rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf -qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS -mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn -ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh -LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v -iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL -4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B -Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw -DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj -t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A -mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt -GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt -m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx -NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4 -Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI -ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC -ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ -3Wl9af0AVqW3rLatt8o+Ae+c ------END CERTIFICATE----- - -Entrust Root Certification Authority - G2 -========================================= ------BEGIN CERTIFICATE----- -MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV -BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy -bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug -b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw -HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT -DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx -OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s -eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP -/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz -HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU -s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y -TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx -AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6 -0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z -iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ -Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi -nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+ -vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO -e4pIb4tF9g== ------END CERTIFICATE----- - -Entrust Root Certification Authority - EC1 -========================================== ------BEGIN CERTIFICATE----- -MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx -FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn -YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl -ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 -IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw -FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs -LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg -dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt -IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy -AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef -9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE -FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h -vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8 -kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G ------END CERTIFICATE----- - -CFCA EV ROOT -============ ------BEGIN CERTIFICATE----- -MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE -CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB -IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw -MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD -DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV -BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD -7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN -uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW -ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7 -xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f -py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K -gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol -hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ -tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf -BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB -/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB -ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q -ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua -4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG -E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX -BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn -aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy -PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX -kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C -ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su ------END CERTIFICATE----- - -OISTE WISeKey Global Root GB CA -=============================== ------BEGIN CERTIFICATE----- -MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG -EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl -ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw -MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD -VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds -b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX -scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP -rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk -9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o -Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg -GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB -/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI -hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD -dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0 -VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui -HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic -Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= ------END CERTIFICATE----- - -SZAFIR ROOT CA2 -=============== ------BEGIN CERTIFICATE----- -MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG -A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV -BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ -BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD -VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q -qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK -DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE -2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ -ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi -ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P -AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC -AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5 -O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67 -oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul -4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6 -+/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw== ------END CERTIFICATE----- - -Certum Trusted Network CA 2 -=========================== ------BEGIN CERTIFICATE----- -MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE -BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1 -bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y -ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ -TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl -cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB -IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9 -7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o -CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b -Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p -uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130 -GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ -9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB -Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye -hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM -BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI -hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW -Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA -L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo -clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM -pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb -w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo -J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm -ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX -is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7 -zAYspsbiDrW5viSP ------END CERTIFICATE----- - -Hellenic Academic and Research Institutions RootCA 2015 -======================================================= ------BEGIN CERTIFICATE----- -MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT -BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0 -aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl -YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx -MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg -QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV -BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw -MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv -bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh -iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+ -6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd -FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr -i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F -GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2 -fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu -iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc -Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI -hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+ -D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM -d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y -d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn -82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb -davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F -Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt -J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa -JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q -p/UsQu0yrbYhnr68 ------END CERTIFICATE----- - -Hellenic Academic and Research Institutions ECC RootCA 2015 -=========================================================== ------BEGIN CERTIFICATE----- -MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0 -aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u -cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj -aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw -MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj -IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD -VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290 -Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP -dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK -Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O -BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA -GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn -dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR ------END CERTIFICATE----- - -ISRG Root X1 -============ ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE -BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD -EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG -EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT -DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r -Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1 -3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K -b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN -Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ -4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf -1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu -hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH -usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r -OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G -A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY -9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV -0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt -hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw -TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx -e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA -JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD -YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n -JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ -m+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- - -AC RAIZ FNMT-RCM -================ ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT -AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw -MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD -TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC -ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf -qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr -btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL -j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou -08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw -WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT -tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ -47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC -ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa -i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o -dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD -nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s -D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ -j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT -Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW -+YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7 -Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d -8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm -5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG -rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM= ------END CERTIFICATE----- - -Amazon Root CA 1 -================ ------BEGIN CERTIFICATE----- -MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD -VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1 -MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv -bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH -FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ -gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t -dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce -VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB -/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3 -DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM -CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy -8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa -2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2 -xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5 ------END CERTIFICATE----- - -Amazon Root CA 2 -================ ------BEGIN CERTIFICATE----- -MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD -VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1 -MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv -bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC -ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4 -kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp -N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9 -AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd -fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx -kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS -btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0 -Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN -c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+ -3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw -DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA -A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY -+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE -YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW -xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ -gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW -aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV -Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3 -KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi -JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw= ------END CERTIFICATE----- - -Amazon Root CA 3 -================ ------BEGIN CERTIFICATE----- -MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG -EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy -NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ -MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB -f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr -Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43 -rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc -eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw== ------END CERTIFICATE----- - -Amazon Root CA 4 -================ ------BEGIN CERTIFICATE----- -MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG -EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy -NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ -MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN -/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri -83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV -HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA -MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1 -AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA== ------END CERTIFICATE----- - -TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 -============================================= ------BEGIN CERTIFICATE----- -MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT -D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr -IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g -TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp -ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD -VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt -c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth -bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11 -IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8 -6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc -wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0 -3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9 -WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU -ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ -KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh -AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc -lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R -e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j -q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= ------END CERTIFICATE----- - -GDCA TrustAUTH R5 ROOT -====================== ------BEGIN CERTIFICATE----- -MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw -BgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD -DBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow -YjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ -IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B -AQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs -AlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p -OqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr -pftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ -9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ -xXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM -R6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ -D2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4 -oR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx -9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR -MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg -p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9 -H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35 -6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd -+PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ -HtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD -F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ -8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv -/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT -aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== ------END CERTIFICATE----- - -SSL.com Root Certification Authority RSA -======================================== ------BEGIN CERTIFICATE----- -MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM -BgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x -MTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw -MjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx -EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM -LmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD -ggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C -Fp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8 -P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge -oeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp -k8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z -fBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ -gUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2 -UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8 -1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s -bE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV -HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE -AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr -dIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf -ijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl -u1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq -erQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj -MxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ -vTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI -Pb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y -wKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI -WuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k= ------END CERTIFICATE----- - -SSL.com Root Certification Authority ECC -======================================== ------BEGIN CERTIFICATE----- -MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV -BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv -BgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy -MTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO -BgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv -bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA -BEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+ -8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR -hXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT -jgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW -e+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z -5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl ------END CERTIFICATE----- - -SSL.com EV Root Certification Authority RSA R2 -============================================== ------BEGIN CERTIFICATE----- -MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w -DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u -MTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy -MB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI -DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD -VQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN -BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh -hqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w -cXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO -Zw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+ -B6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh -CBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim -9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto -RHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm -JuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48 -+qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV -HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp -qJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1 -++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx -Y/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G -guDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz -OFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7 -CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq -lD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR -rwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1 -hlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX -9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== ------END CERTIFICATE----- - -SSL.com EV Root Certification Authority ECC -=========================================== ------BEGIN CERTIFICATE----- -MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV -BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy -BgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw -MjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx -EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM -LmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB -BAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy -3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O -BBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe -5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ -N+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm -m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== ------END CERTIFICATE----- - -GlobalSign Root CA - R6 -======================= ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEgMB4GA1UECxMX -R2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds -b2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9i -YWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs -U2lnbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQss -grRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1kZguSgMpE -3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxDaNc9PIrFsmbVkJq3MQbF -vuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqM -PKq0pPbzlUoSB239jLKJz9CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+ -azayOeSsJDa38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05O -WgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/hbguy -CLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4nWUx2OVvq+aWh2IMP -0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kN -b7gu3GduyYsRtYQUigAZcIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQE -AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNV -HSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN -nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0 -lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrY -BzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFym -Fe944Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr -3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB1 -0jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/T -uTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItK -oZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+t -JDfLRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= ------END CERTIFICATE----- - -OISTE WISeKey Global Root GC CA -=============================== ------BEGIN CERTIFICATE----- -MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQswCQYDVQQGEwJD -SDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEo -MCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRa -Fw00MjA1MDkwOTU4MzNaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQL -ExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh -bCBSb290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4nieUqjFqdr -VCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4Wp2OQ0jnUsYd4XxiWD1Ab -NTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd -BgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7TrYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0E -AwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk -AjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 ------END CERTIFICATE----- - -UCA Global G2 Root -================== ------BEGIN CERTIFICATE----- -MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQG -EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBHbG9iYWwgRzIgUm9vdDAeFw0x -NjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0xCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlU -cnVzdDEbMBkGA1UEAwwSVUNBIEdsb2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A -MIICCgKCAgEAxeYrb3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmT -oni9kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzmVHqUwCoV -8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/RVogvGjqNO7uCEeBHANBS -h6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDcC/Vkw85DvG1xudLeJ1uK6NjGruFZfc8o -LTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIjtm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/ -R+zvWr9LesGtOxdQXGLYD0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBe -KW4bHAyvj5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6DlNaBa -4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6iIis7nCs+dwp4wwc -OxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznPO6Q0ibd5Ei9Hxeepl2n8pndntd97 -8XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O -BBYEFIHEjMz15DD/pQwIX4wVZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo -5sOASD0Ee/ojL3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 -1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl1qnN3e92mI0A -Ds0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oUb3n09tDh05S60FdRvScFDcH9 -yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LVPtateJLbXDzz2K36uGt/xDYotgIVilQsnLAX -c47QN6MUPJiVAAwpBVueSUmxX8fjy88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHo -jhJi6IjMtX9Gl8CbEGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZk -bxqgDMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI+Vg7RE+x -ygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGyYiGqhkCyLmTTX8jjfhFn -RR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bXUB+K+wb1whnw0A== ------END CERTIFICATE----- - -UCA Extended Validation Root -============================ ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQG -EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9u -IFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMxMDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8G -A1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrs -iWogD4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvSsPGP2KxF -Rv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aopO2z6+I9tTcg1367r3CTu -eUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dksHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR -59mzLC52LqGj3n5qiAno8geK+LLNEOfic0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH -0mK1lTnj8/FtDw5lhIpjVMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KR -el7sFsLzKuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/TuDv -B0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41Gsx2VYVdWf6/wFlth -WG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs1+lvK9JKBZP8nm9rZ/+I8U6laUpS -NwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQDfwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS -3H5aBZ8eNJr34RQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL -BQADggIBADaNl8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR -ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQVBcZEhrxH9cM -aVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5c6sq1WnIeJEmMX3ixzDx/BR4 -dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb -+7lsq+KePRXBOy5nAliRn+/4Qh8st2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOW -F3sGPjLtx7dCvHaj2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwi -GpWOvpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2CxR9GUeOc -GMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmxcmtpzyKEC2IPrNkZAJSi -djzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbMfjKaiJUINlK73nZfdklJrX+9ZSCyycEr -dhh2n1ax ------END CERTIFICATE----- - -Certigna Root CA -================ ------BEGIN CERTIFICATE----- -MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UE -BhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAwMiA0ODE0NjMwODEwMDAzNjEZ -MBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0xMzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjda -MFoxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYz -MDgxMDAwMzYxGTAXBgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC -DwAwggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sOty3tRQgX -stmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9MCiBtnyN6tMbaLOQdLNyz -KNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPuI9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8 -JXrJhFwLrN1CTivngqIkicuQstDuI7pmTLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16 -XdG+RCYyKfHx9WzMfgIhC59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq -4NYKpkDfePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3YzIoej -wpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWTCo/1VTp2lc5ZmIoJ -lXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1kJWumIWmbat10TWuXekG9qxf5kBdI -jzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp/ -/TBt2dzhauH8XwIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw -HQYDVR0OBBYEFBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of -1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczovL3d3d3cuY2Vy -dGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNlcnRpZ25h -LmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5kaGlteW90aXMuY29tL2Nl -cnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOIt -OoldaDgvUSILSo3L6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxP -TGRGHVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH60BGM+RFq -7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncBlA2c5uk5jR+mUYyZDDl3 -4bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdio2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd -8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS -6Cvu5zHbugRqh5jnxV/vfaci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaY -tlu3zM63Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayhjWZS -aX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw3kAP+HwV96LOPNde -E4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= ------END CERTIFICATE----- - -emSign Root CA - G1 -=================== ------BEGIN CERTIFICATE----- -MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJJTjET -MBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl -ZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgx -ODMwMDBaMGcxCzAJBgNVBAYTAklOMRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVk -aHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQzf2N4aLTN -LnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO8oG0x5ZOrRkVUkr+PHB1 -cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aqd7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHW -DV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhMtTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ -6DqS0hdW5TUaQBw+jSztOd9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrH -hQIDAQABo0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQDAgEG -MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31xPaOfG1vR2vjTnGs2 -vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjMwiI/aTvFthUvozXGaCocV685743Q -NcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6dGNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q -+Mri/Tm3R7nrft8EI6/6nAYH6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeih -U80Bv2noWgbyRQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx -iN66zB+Afko= ------END CERTIFICATE----- - -emSign ECC Root CA - G3 -======================= ------BEGIN CERTIFICATE----- -MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQGEwJJTjETMBEG -A1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg -MB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4 -MTgzMDAwWjBrMQswCQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11 -ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g -RzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0WXTsuwYc -58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xySfvalY8L1X44uT6EYGQIr -MgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuBzhccLikenEhjQjAOBgNVHQ8BAf8EBAMC -AQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+D -CBeQyh+KTOgNG3qxrdWBCUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7 -jHvrZQnD+JbNR6iC8hZVdyR+EhCVBCyj ------END CERTIFICATE----- - -emSign Root CA - C1 -=================== ------BEGIN CERTIFICATE----- -MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMx -EzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNp -Z24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UE -BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQD -ExNlbVNpZ24gUm9vdCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+up -ufGZBczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZHdPIWoU/ -Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH3DspVpNqs8FqOp099cGX -OFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvHGPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4V -I5b2P/AgNBbeCsbEBEV5f6f9vtKppa+cxSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleooms -lMuoaJuvimUnzYnu3Yy1aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+ -XJGFehiqTbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD -ggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87/kOXSTKZEhVb3xEp -/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4kqNPEjE2NuLe/gDEo2APJ62gsIq1 -NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrGYQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9 -wC68AivTxEDkigcxHpvOJpkT+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQ -BmIMMMAVSKeoWXzhriKi4gp6D/piq1JM4fHfyr6DDUI= ------END CERTIFICATE----- - -emSign ECC Root CA - C3 -======================= ------BEGIN CERTIFICATE----- -MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQGEwJVUzETMBEG -A1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxIDAeBgNVBAMTF2VtU2lnbiBF -Q0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UE -BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQD -ExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd -6bciMK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4OjavtisIGJAnB9 -SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0OBBYEFPtaSNCAIEDyqOkA -B2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gA -MGUCMQC02C8Cif22TGK6Q04ThHK1rt0c3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwU -ZOR8loMRnLDRWmFLpg9J0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== ------END CERTIFICATE----- - -Hongkong Post Root CA 3 -======================= ------BEGIN CERTIFICATE----- -MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQELBQAwbzELMAkG -A1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJSG9uZyBLb25nMRYwFAYDVQQK -Ew1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25na29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2 -MDMwMjI5NDZaFw00MjA2MDMwMjI5NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtv -bmcxEjAQBgNVBAcTCUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMX -SG9uZ2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz -iNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFOdem1p+/l6TWZ5Mwc50tf -jTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mIVoBc+L0sPOFMV4i707mV78vH9toxdCim -5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOe -sL4jpNrcyCse2m5FHomY2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj -0mRiikKYvLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+TtbNe/ -JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZbx39ri1UbSsUgYT2u -y1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+l2oBlKN8W4UdKjk60FSh0Tlxnf0h -+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YKTE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsG -xVd7GYYKecsAyVKvQv83j+GjHno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwID -AQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e -i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEwDQYJKoZIhvcN -AQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG7BJ8dNVI0lkUmcDrudHr9Egw -W62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCkMpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWld -y8joRTnU+kLBEUx3XZL7av9YROXrgZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov -+BS5gLNdTaqX4fnkGMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDc -eqFS3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJmOzj/2ZQw -9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+l6mc1X5VTMbeRRAc6uk7 -nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6cJfTzPV4e0hz5sy229zdcxsshTrD3mUcY -hcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB -60PZ2Pierc+xYw5F9KBaLJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fq -dBb9HxEGmpv0 ------END CERTIFICATE----- - -Entrust Root Certification Authority - G4 -========================================= ------BEGIN CERTIFICATE----- -MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAwgb4xCzAJBgNV -BAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3Qu -bmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1 -dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1 -dGhvcml0eSAtIEc0MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYT -AlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 -L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhv -cml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhv -cml0eSAtIEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3D -umSXbcr3DbVZwbPLqGgZ2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV -3imz/f3ET+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j5pds -8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAMC1rlLAHGVK/XqsEQ -e9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73TDtTUXm6Hnmo9RR3RXRv06QqsYJn7 -ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNXwbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5X -xNMhIWNlUpEbsZmOeX7m640A2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV -7rtNOzK+mndmnqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 -dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwlN4y6mACXi0mW -Hv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNjc0kCAwEAAaNCMEAwDwYDVR0T -AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9n -MA0GCSqGSIb3DQEBCwUAA4ICAQAS5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4Q -jbRaZIxowLByQzTSGwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht -7LGrhFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/B7NTeLUK -YvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uIAeV8KEsD+UmDfLJ/fOPt -jqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbwH5Lk6rWS02FREAutp9lfx1/cH6NcjKF+ -m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKW -RGhXxNUzzxkvFMSUHHuk2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjA -JOgc47OlIQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk5F6G -+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuYn/PIjhs4ViFqUZPT -kcpG2om3PVODLAgfi49T3f+sHw== ------END CERTIFICATE----- - -Microsoft ECC Root Certificate Authority 2017 -============================================= ------BEGIN CERTIFICATE----- -MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV -UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQgRUND -IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4 -MjMxNjA0WjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw -NAYDVQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQ -BgcqhkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZRogPZnZH6 -thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYbhGBKia/teQ87zvH2RPUB -eMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIy5lycFIM -+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlf -Xu5gKcs68tvWMoQZP3zVL8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaR -eNtUjGUBiudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= ------END CERTIFICATE----- - -Microsoft RSA Root Certificate Authority 2017 -============================================= ------BEGIN CERTIFICATE----- -MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQG -EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQg -UlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIw -NzE4MjMwMDIzWjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u -MTYwNAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcw -ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZNt9GkMml -7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0ZdDMbRnMlfl7rEqUrQ7e -S0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw7 -1VdyvD/IybLeS2v4I2wDwAW9lcfNcztmgGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+ -dkC0zVJhUXAoP8XFWvLJjEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49F -yGcohJUcaDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaGYaRS -MLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6W6IYZVcSn2i51BVr -lMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4KUGsTuqwPN1q3ErWQgR5WrlcihtnJ -0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJ -ClTUFLkqqNfs+avNJVgyeY+QW5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYw -DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC -NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZCLgLNFgVZJ8og -6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OCgMNPOsduET/m4xaRhPtthH80 -dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk -+ONVFT24bcMKpBLBaYVu32TxU5nhSnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex -/2kskZGT4d9Mozd2TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDy -AmH3pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGRxpl/j8nW -ZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiAppGWSZI1b7rCoucL5mxAyE -7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKT -c0QWbej09+CVgI+WXTik9KveCjCHk9hNAHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D -5KbvtwEwXlGjefVwaaZBRA+GsCyRxj3qrg+E ------END CERTIFICATE----- - -e-Szigno Root CA 2017 -===================== ------BEGIN CERTIFICATE----- -MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNVBAYTAkhVMREw -DwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUt -MjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJvb3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZa -Fw00MjA4MjIxMjA3MDZaMHExCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UE -CgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3pp -Z25vIFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtvxie+RJCx -s1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+HWyx7xf58etqjYzBhMA8G -A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSHERUI0arBeAyxr87GyZDv -vzAEwDAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEA -tVfd14pVCzbhhkT61NlojbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxO -svxyqltZ+efcMQ== ------END CERTIFICATE----- - -certSIGN Root CA G2 -=================== ------BEGIN CERTIFICATE----- -MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlJPMRQw -EgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjAeFw0xNzAy -MDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJBgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lH -TiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP -ADCCAgoCggIBAMDFdRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05 -N0IwvlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZuIt4Imfk -abBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhpn+Sc8CnTXPnGFiWeI8Mg -wT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKscpc/I1mbySKEwQdPzH/iV8oScLumZfNp -dWO9lfsbl83kqK/20U6o2YpxJM02PbyWxPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91Qqh -ngLjYl/rNUssuHLoPj1PrCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732 -jcZZroiFDsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fxDTvf -95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgyLcsUDFDYg2WD7rlc -z8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6CeWRgKRM+o/1Pcmqr4tTluCRVLERL -iohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud -DgQWBBSCIS1mxteg4BXrzkwJd8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOB -ywaK8SJJ6ejqkX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC -b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQlqiCA2ClV9+BB -/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0OJD7uNGzcgbJceaBxXntC6Z5 -8hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+cNywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5 -BiKDUyUM/FHE5r7iOZULJK2v0ZXkltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklW -atKcsWMy5WHgUyIOpwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tU -Sxfj03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZkPuXaTH4M -NMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE1LlSVHJ7liXMvGnjSG4N -0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MXQRBdJ3NghVdJIgc= ------END CERTIFICATE----- - -Trustwave Global Certification Authority -======================================== ------BEGIN CERTIFICATE----- -MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV -UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2 -ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u -IEF1dGhvcml0eTAeFw0xNzA4MjMxOTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJV -UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2 -ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u -IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALldUShLPDeS0YLOvR29 -zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0XznswuvCAAJWX/NKSqIk4cXGIDtiLK0thAf -LdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4Bq -stTnoApTAbqOl5F2brz81Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9o -WN0EACyW80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotPJqX+ -OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1lRtzuzWniTY+HKE40 -Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfwhI0Vcnyh78zyiGG69Gm7DIwLdVcE -uE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm -+9jaJXLE9gCxInm943xZYkqcBW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqj -ifLJS3tBEW1ntwiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud -EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1UdDwEB/wQEAwIB -BjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W0OhUKDtkLSGm+J1WE2pIPU/H -PinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfeuyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0H -ZJDmHvUqoai7PF35owgLEQzxPy0QlG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla -4gt5kNdXElE1GYhBaCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5R -vbbEsLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPTMaCm/zjd -zyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qequ5AvzSxnI9O4fKSTx+O -856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxhVicGaeVyQYHTtgGJoC86cnn+OjC/QezH -Yj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu -3R3y4G5OBVixwJAWKqQ9EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP -29FpHOTKyeC2nOnOcXHebD8WpHk= ------END CERTIFICATE----- - -Trustwave Global ECC P256 Certification Authority -================================================= ------BEGIN CERTIFICATE----- -MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYDVQQGEwJVUzER -MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI -b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYD -VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy -dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1 -NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABH77bOYj -43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoNFWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqm -P62jQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt -0UrrdaVKEJmzsaGLSvcwCgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjz -RM4q3wghDDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 ------END CERTIFICATE----- - -Trustwave Global ECC P384 Certification Authority -================================================= ------BEGIN CERTIFICATE----- -MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYDVQQGEwJVUzER -MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI -b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYD -VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy -dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4 -NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuBBAAiA2IABGvaDXU1CDFH -Ba5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJj9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr -/TklZvFe/oyujUF5nQlgziip04pt89ZF1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNV -HQ8BAf8EBQMDBwYAMB0GA1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNn -ADBkAjA3AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsCMGcl -CrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVuSw== ------END CERTIFICATE----- - -NAVER Global Root Certification Authority -========================================= ------BEGIN CERTIFICATE----- -MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEMBQAwaTELMAkG -A1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRGT1JNIENvcnAuMTIwMAYDVQQD -DClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4 -NDJaFw0zNzA4MTgyMzU5NTlaMGkxCzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVT -UyBQTEFURk9STSBDb3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVAiQqrDZBb -UGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH38dq6SZeWYp34+hInDEW -+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lEHoSTGEq0n+USZGnQJoViAbbJAh2+g1G7 -XNr4rRVqmfeSVPc0W+m/6imBEtRTkZazkVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2 -aacp+yPOiNgSnABIqKYPszuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4 -Yb8ObtoqvC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHfnZ3z -VHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaGYQ5fG8Ir4ozVu53B -A0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo0es+nPxdGoMuK8u180SdOqcXYZai -cdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3aCJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejy -YhbLgGvtPe31HzClrkvJE+2KAQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNV -HQ4EFgQU0p+I36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB -Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoNqo0hV4/GPnrK -21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatjcu3cvuzHV+YwIHHW1xDBE1UB -jCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bx -hYTeodoS76TiEJd6eN4MUZeoIUCLhr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTg -E34h5prCy8VCZLQelHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTH -D8z7p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8piKCk5XQ -A76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLRLBT/DShycpWbXgnbiUSY -qqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oG -I/hGoiLtk/bdmuYqh7GYVPEi92tF4+KOdh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmg -kpzNNIaRkPpkUZ3+/uul9XXeifdy ------END CERTIFICATE----- - -AC RAIZ FNMT-RCM SERVIDORES SEGUROS -=================================== ------BEGIN CERTIFICATE----- -MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQswCQYDVQQGEwJF -UzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgwFgYDVQRhDA9WQVRFUy1RMjgy -NjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1SQ00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4 -MTIyMDA5MzczM1oXDTQzMTIyMDA5MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQt -UkNNMQ4wDAYDVQQLDAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNB -QyBSQUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuBBAAiA2IA -BPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LHsbI6GA60XYyzZl2hNPk2 -LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oKUm8BA06Oi6NCMEAwDwYDVR0TAQH/BAUw -AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqG -SM49BAMDA2kAMGYCMQCuSuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoD -zBOQn5ICMQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJyv+c= ------END CERTIFICATE----- - -GlobalSign Root R46 -=================== ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUAMEYxCzAJBgNV -BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJv -b3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAX -BgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08Es -CVeJOaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQGvGIFAha/ -r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud316HCkD7rRlr+/fKYIje -2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo0q3v84RLHIf8E6M6cqJaESvWJ3En7YEt -bWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSEy132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvj -K8Cd+RTyG/FWaha/LIWFzXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD4 -12lPFzYE+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCNI/on -ccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzsx2sZy/N78CsHpdls -eVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqaByFrgY/bxFn63iLABJzjqls2k+g9 -vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYD -VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEM -BQADggIBAHx47PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg -JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti2kM3S+LGteWy -gxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIkpnnpHs6i58FZFZ8d4kuaPp92 -CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRFFRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZm -OUdkLG5NrmJ7v2B0GbhWrJKsFjLtrWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qq -JZ4d16GLuc1CLgSkZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwye -qiv5u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP4vkYxboz -nxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6N3ec592kD3ZDZopD8p/7 -DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3vouXsXgxT7PntgMTzlSdriVZzH81Xwj3 -QEUxeCp6 ------END CERTIFICATE----- - -GlobalSign Root E46 -=================== ------BEGIN CERTIFICATE----- -MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYxCzAJBgNVBAYT -AkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3Qg -RTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNV -BAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcq -hkjOPQIBBgUrgQQAIgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkB -jtjqR+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGddyXqBPCCj -QjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQxCpCPtsad0kRL -gLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZk -vLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+ -CAezNIm8BZ/3Hobui3A= ------END CERTIFICATE----- - -GLOBALTRUST 2020 -================ ------BEGIN CERTIFICATE----- -MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCQVQx -IzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVT -VCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYxMDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAh -BgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAy -MDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWi -D59bRatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9ZYybNpyrO -VPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3QWPKzv9pj2gOlTblzLmM -CcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPwyJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCm -fecqQjuCgGOlYx8ZzHyyZqjC0203b+J+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKA -A1GqtH6qRNdDYfOiaxaJSaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9OR -JitHHmkHr96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj04KlG -DfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9MedKZssCz3AwyIDMvU -clOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIwq7ejMZdnrY8XD2zHc+0klGvIg5rQ -mjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUw -AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1Ud -IwQYMBaAFNwuH9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA -VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJCXtzoRlgHNQIw -4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd6IwPS3BD0IL/qMy/pJTAvoe9 -iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS -8cE54+X1+NZK3TTN+2/BT+MAi1bikvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2 -HcqtbepBEX4tdJP7wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxS -vTOBTI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6CMUO+1918 -oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn4rnvyOL2NSl6dPrFf4IF -YqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+IaFvowdlxfv1k7/9nR4hYJS8+hge9+6jl -gqispdNpQ80xiEmEU5LAsTkbOYMBMMTyqfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== ------END CERTIFICATE----- - -ANF Secure Server Root CA -========================= ------BEGIN CERTIFICATE----- -MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNVBAUTCUc2MzI4 -NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lv -bjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNVBAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3Qg -Q0EwHhcNMTkwOTA0MTAwMDM4WhcNMzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEw -MQswCQYDVQQGEwJFUzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQw -EgYDVQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9vdCBDQTCC -AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCjcqQZAZ2cC4Ffc0m6p6zz -BE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9qyGFOtibBTI3/TO80sh9l2Ll49a2pcbnv -T1gdpd50IJeh7WhM3pIXS7yr/2WanvtH2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcv -B2VSAKduyK9o7PQUlrZXH1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXse -zx76W0OLzc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyRp1RM -VwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQzW7i1o0TJrH93PB0j -7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/SiOL9V8BY9KHcyi1Swr1+KuCLH5z -JTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJnLNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe -8TZBAQIvfXOn3kLMTOmJDVb3n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVO -Hj1tyRRM4y5Bu8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj -o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAOBgNVHQ8BAf8E -BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEATh65isagmD9uw2nAalxJ -UqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzx -j6ptBZNscsdW699QIyjlRRA96Gejrw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDt -dD+4E5UGUcjohybKpFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM -5gf0vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjqOknkJjCb -5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ/zo1PqVUSlJZS2Db7v54 -EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ92zg/LFis6ELhDtjTO0wugumDLmsx2d1H -hk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGy -g77FGr8H6lnco4g175x2MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3 -r5+qPeoott7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= ------END CERTIFICATE----- - -Certum EC-384 CA -================ ------BEGIN CERTIFICATE----- -MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQswCQYDVQQGEwJQ -TDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2 -MDcyNDU0WhcNNDMwMzI2MDcyNDU0WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERh -dGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx -GTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATEKI6rGFtq -vm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7TmFy8as10CW4kjPMIRBSqn -iBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68KjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD -VR0OBBYEFI0GZnQkdjrzife81r1HfS+8EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNo -ADBlAjADVS2m5hjEfO/JUG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0 -QoSZ/6vnnvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= ------END CERTIFICATE----- - -Certum Trusted Root CA -====================== ------BEGIN CERTIFICATE----- -MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6MQswCQYDVQQG -EwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0g -Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0Ew -HhcNMTgwMzE2MTIxMDEzWhcNNDMwMzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMY -QXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZn0EGze2jusDbCSzBfN8p -fktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/qp1x4EaTByIVcJdPTsuclzxFUl6s1wB52 -HO8AU5853BSlLCIls3Jy/I2z5T4IHhQqNwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2 -fJmItdUDmj0VDT06qKhF8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGt -g/BKEiJ3HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGamqi4 -NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi7VdNIuJGmj8PkTQk -fVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSFytKAQd8FqKPVhJBPC/PgP5sZ0jeJ -P/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0PqafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSY -njYJdmZm/Bo/6khUHL4wvYBQv3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHK -HRzQ+8S1h9E6Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 -vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQADggIBAEii1QAL -LtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4WxmB82M+w85bj/UvXgF2Ez8s -ALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvozMrnadyHncI013nR03e4qllY/p0m+jiGPp2K -h2RX5Rc64vmNueMzeMGQ2Ljdt4NR5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8 -CYyqOhNf6DR5UMEQGfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA -4kZf5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq0Uc9Nneo -WWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj -6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTMqJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmT -OPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck -bxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb ------END CERTIFICATE----- - -TunTrust Root CA -================ ------BEGIN CERTIFICATE----- -MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQELBQAwYTELMAkG -A1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUgQ2VydGlmaWNhdGlvbiBFbGVj -dHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJvb3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQw -NDI2MDg1NzU2WjBhMQswCQYDVQQGEwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBD -ZXJ0aWZpY2F0aW9uIEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIw -DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZn56eY+hz -2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd2JQDoOw05TDENX37Jk0b -bjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgFVwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7 -NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZGoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAd -gjH8KcwAWJeRTIAAHDOFli/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViW -VSHbhlnUr8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2eY8f -Tpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIbMlEsPvLfe/ZdeikZ -juXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISgjwBUFfyRbVinljvrS5YnzWuioYas -DXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwS -VXAkPcvCFDVDXSdOvsC9qnyW5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI -04Y+oXNZtPdEITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 -90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+zxiD2BkewhpMl -0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYuQEkHDVneixCwSQXi/5E/S7fd -Ao74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRY -YdZ2vyJ/0Adqp2RT8JeNnYA/u8EH22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJp -adbGNjHh/PqAulxPxOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65x -xBzndFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5Xc0yGYuP -jCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7bnV2UqL1g52KAdoGDDIzM -MEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQCvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9z -ZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZHu/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3r -AZ3r2OvEhJn7wAzMMujjd9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= ------END CERTIFICATE----- - -HARICA TLS RSA Root CA 2021 -=========================== ------BEGIN CERTIFICATE----- -MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQG -EwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u -cyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUz -OFoXDTQ1MDIxMzEwNTUzN1owbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRl -bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNB -IFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569lmwVnlskN -JLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE4VGC/6zStGndLuwRo0Xu -a2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uva9of08WRiFukiZLRgeaMOVig1mlDqa2Y -Ulhu2wr7a89o+uOkXjpFc5gH6l8Cct4MpbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K -5FrZx40d/JiZ+yykgmvwKh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEv -dmn8kN3bLW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcYAuUR -0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqBAGMUuTNe3QvboEUH -GjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYqE613TBoYm5EPWNgGVMWX+Ko/IIqm -haZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHrW2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQ -CPxrvrNQKlr9qEgYRtaQQJKQCoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8G -A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE -AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAUX15QvWiWkKQU -EapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3f5Z2EMVGpdAgS1D0NTsY9FVq -QRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxajaH6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxD -QpSbIPDRzbLrLFPCU3hKTwSUQZqPJzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcR -j88YxeMn/ibvBZ3PzzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5 -vZStjBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0/L5H9MG0 -qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pTBGIBnfHAT+7hOtSLIBD6 -Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79aPib8qXPMThcFarmlwDB31qlpzmq6YR/ -PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YWxw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnn -kf3/W9b3raYvAwtt41dU63ZTGI0RmLo= ------END CERTIFICATE----- - -HARICA TLS ECC Root CA 2021 -=========================== ------BEGIN CERTIFICATE----- -MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQswCQYDVQQGEwJH -UjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD -QTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoX -DTQ1MDIxMzExMDEwOVowbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWlj -IGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJv -b3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7KKrxcm1l -AEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9YSTHMmE5gEYd103KUkE+b -ECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW -0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAi -rcJRQO9gcS3ujwLEXQNwSaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/Qw -CZ61IygNnxS2PFOiTAZpffpskcYqSUXm7LcT4Tps ------END CERTIFICATE----- - -Autoridad de Certificacion Firmaprofesional CIF A62634068 -========================================================= ------BEGIN CERTIFICATE----- -MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCRVMxQjBA -BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 -MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIw -QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB -NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD -Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P -B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY -7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH -ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI -plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX -MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX -LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK -bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU -vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1Ud -DgQWBBRlzeurNR4APn7VdMActHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4w -gZswgZgGBFUdIAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j -b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABCAG8AbgBhAG4A -bwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAwADEANzAOBgNVHQ8BAf8EBAMC -AQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9miWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL -4QjbEwj4KKE1soCzC1HA01aajTNFSa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDb -LIpgD7dvlAceHabJhfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1il -I45PVf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZEEAEeiGaP -cjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV1aUsIC+nmCjuRfzxuIgA -LI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2tCsvMo2ebKHTEm9caPARYpoKdrcd7b/+A -lun4jWq9GJAd/0kakFI3ky88Al2CdgtR5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH -9IBk9W6VULgRfhVwOEqwf9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpf -NIbnYrX9ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNKGbqE -ZycPvEJdvSRUDewdcAZfpLz6IHxV ------END CERTIFICATE----- - -vTrus ECC Root CA -================= ------BEGIN CERTIFICATE----- -MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMwRzELMAkGA1UE -BhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBS -b290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDczMTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAa -BgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYw -EAYHKoZIzj0CAQYFK4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+c -ToL0v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUde4BdS49n -TPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIwV53dVvHH4+m4SVBrm2nDb+zDfSXkV5UT -QJtS0zvzQBm8JsctBp61ezaf9SXUY2sAAjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQL -YgmRWAD5Tfs0aNoJrSEGGJTO ------END CERTIFICATE----- - -vTrus Root CA -============= ------BEGIN CERTIFICATE----- -MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQELBQAwQzELMAkG -A1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xFjAUBgNVBAMTDXZUcnVzIFJv -b3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMxMDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoG -A1UEChMTaVRydXNDaGluYSBDby4sTHRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZots -SKYcIrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykUAyyNJJrI -ZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+GrPSbcKvdmaVayqwlHeF -XgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z98Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KA -YPxMvDVTAWqXcoKv8R1w6Jz1717CbMdHflqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70 -kLJrxLT5ZOrpGgrIDajtJ8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2 -AXPKBlim0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZNpGvu -/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQUqqzApVg+QxMaPnu -1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHWOXSuTEGC2/KmSNGzm/MzqvOmwMVO -9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMBAAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYg -scasGrz2iTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOC -AgEAKbqSSaet8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd -nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1jbhd47F18iMjr -jld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvMKar5CKXiNxTKsbhm7xqC5PD4 -8acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIivTDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJn -xDHO2zTlJQNgJXtxmOTAGytfdELSS8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554Wg -icEFOwE30z9J4nfrI8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4 -sEb9b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNBUvupLnKW -nyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1PTi07NEPhmg4NpGaXutIc -SkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929vensBxXVsFy6K2ir40zSbofitzmdHxghm+H -l3s= ------END CERTIFICATE----- - -ISRG Root X2 -============ ------BEGIN CERTIFICATE----- -MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQswCQYDVQQGEwJV -UzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElT -UkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVT -MSkwJwYDVQQKEyBJbnRlcm5ldCBTZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNS -RyBSb290IFgyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0H -ttwW+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9ItgKbppb -d9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZIzj0EAwMDaAAwZQIwe3lORlCEwkSHRhtF -cP9Ymd70/aTSVaYgLXTWNLxBo1BfASdWtL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5 -U6VR5CmD1/iQMVtCnwr1/q4AaOeMSQ+2b1tbFfLn ------END CERTIFICATE----- - -HiPKI Root CA - G1 -================== ------BEGIN CERTIFICATE----- -MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQG -EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xGzAZBgNVBAMMEkhpUEtJ -IFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRaFw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYT -AlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kg -Um9vdCBDQSAtIEcxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0 -o9QwqNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twvVcg3Px+k -wJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6lZgRZq2XNdZ1AYDgr/SE -YYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnzQs7ZngyzsHeXZJzA9KMuH5UHsBffMNsA -GJZMoYFL3QRtU6M9/Aes1MU3guvklQgZKILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfd -hSi8MEyr48KxRURHH+CKFgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj -1jOXTyFjHluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDry+K4 -9a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ/W3c1pzAtH2lsN0/ -Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgMa/aOEmem8rJY5AIJEzypuxC00jBF -8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYD -VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQD -AgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi -7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqcSE5XCV0vrPSl -tJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6FzaZsT0pPBWGTMpWmWSBUdGSquE -wx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9TcXzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07Q -JNBAsNB1CI69aO4I1258EHBGG3zgiLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv -5wiZqAxeJoBF1PhoL5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+Gpz -jLrFNe85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wrkkVbbiVg -hUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+vhV4nYWBSipX3tUZQ9rb -yltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQUYDksswBVLuT1sw5XxJFBAJw/6KXf6vb/ -yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== ------END CERTIFICATE----- - -GlobalSign ECC Root CA - R4 -=========================== ------BEGIN CERTIFICATE----- -MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYDVQQLExtHbG9i -YWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds -b2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgwMTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9i -YWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds -b2JhbFNpZ24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkW -ymOxuYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNVHQ8BAf8E -BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/+wpu+74zyTyjhNUwCgYI -KoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147bmF0774BxL4YSFlhgjICICadVGNA3jdg -UM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm ------END CERTIFICATE----- - -GTS Root R1 -=========== ------BEGIN CERTIFICATE----- -MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV -UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg -UjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE -ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0G -CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM -f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7raKb0 -xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnWr4+w -B7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXW -nOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk -9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zq -kUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92wO1A -K/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om3xPX -V2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDW -cfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T -AQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQAD -ggIBAJ+qQibbC5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe -QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuyh6f88/qBVRRi -ClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM47HLwEXWdyzRSjeZ2axfG34ar -J45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8JZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYci -NuaCp+0KueIHoI17eko8cdLiA6EfMgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5me -LMFrUKTX5hgUvYU/Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJF -fbdT6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ0E6yove+ -7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm2tIMPNuzjsmhDYAPexZ3 -FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bbbP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3 -gm3c ------END CERTIFICATE----- - -GTS Root R2 -=========== ------BEGIN CERTIFICATE----- -MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV -UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg -UjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE -ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0G -CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv -CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY6Dlo7JUl -e3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAuMC6C/Pq8tBcKSOWIm8Wb -a96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS -+LFjKBC4swm4VndAoiaYecb+3yXuPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7M -kogwTZq9TwtImoS1mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJG -r61K8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RWIr9q -S34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKaG73VululycslaVNV -J1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCqgc7dGtxRcw1PcOnlthYhGXmy5okL -dWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T -AQH/BAUwAwEB/zAdBgNVHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQAD -ggIBAB/Kzt3HvqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 -0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyCB19m3H0Q/gxh -swWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2uNmSRXbBoGOqKYcl3qJfEycel -/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMgyALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVn -jWQye+mew4K6Ki3pHrTgSAai/GevHyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y5 -9PYjJbigapordwj6xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M -7YNRTOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924SgJPFI/2R8 -0L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV7LXTWtiBmelDGDfrs7vR -WGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjW -HYbL ------END CERTIFICATE----- - -GTS Root R3 -=========== ------BEGIN CERTIFICATE----- -MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi -MCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMw -HhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ -R29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjO -PQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout -736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24CejQjBA -MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP0/Eq -Er24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azT -L818+FsuVbu/3ZL3pAzcMeGiAjEA/JdmZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV -11RZt+cRLInUue4X ------END CERTIFICATE----- - -GTS Root R4 -=========== ------BEGIN CERTIFICATE----- -MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi -MCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQw -HhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ -R29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjO -PQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu -hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqjQjBA -MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV2Py1 -PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/C -r8deVl5c1RxYIigL9zC2L7F8AjEA8GE8p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh -4rsUecrNIdSUtUlD ------END CERTIFICATE----- - -Telia Root CA v2 -================ ------BEGIN CERTIFICATE----- -MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQxCzAJBgNVBAYT -AkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2 -MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQK -DBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZI -hvcNAQEBBQADggIPADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ7 -6zBqAMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9vVYiQJ3q -9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9lRdU2HhE8Qx3FZLgmEKn -pNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTODn3WhUidhOPFZPY5Q4L15POdslv5e2QJl -tI5c0BE0312/UqeBAMN/mUWZFdUXyApT7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW -5olWK8jjfN7j/4nlNW4o6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNr -RBH0pUPCTEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6WT0E -BXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63RDolUK5X6wK0dmBR4 -M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZIpEYslOqodmJHixBTB0hXbOKSTbau -BcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGjYzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7W -xy+G2CQ5MB0GA1UdDgQWBBRyrOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ -8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi0f6X+J8wfBj5 -tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMMA8iZGok1GTzTyVR8qPAs5m4H -eW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBSSRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+C -y748fdHif64W1lZYudogsYMVoe+KTTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygC -QMez2P2ccGrGKMOF6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15 -h2Er3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMtTy3EHD70 -sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pTVmBds9hCG1xLEooc6+t9 -xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAWysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQ -raVplI/owd8k+BsHMYeB2F326CjYSlKArBPuUBQemMc= ------END CERTIFICATE----- - -D-TRUST BR Root CA 1 2020 -========================= ------BEGIN CERTIFICATE----- -MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE -RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0EgMSAy -MDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNV -BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAG -ByqGSM49AgEGBSuBBAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7 -dPYSzuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0QVK5buXu -QqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/VbNafAkl1bK6CKBrqx9t -MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu -bmV0L2NybC9kLXRydXN0X2JyX3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj -dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP -PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD -AwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFWwKrY7RjEsK70Pvom -AjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHVdWNbFJWcHwHP2NVypw87 ------END CERTIFICATE----- - -D-TRUST EV Root CA 1 2020 -========================= ------BEGIN CERTIFICATE----- -MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE -RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0EgMSAy -MDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNV -BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAG -ByqGSM49AgEGBSuBBAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8 -ZRCC/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rDwpdhQntJ -raOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3OqQo5FD4pPfsazK2/umL -MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu -bmV0L2NybC9kLXRydXN0X2V2X3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj -dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP -PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD -AwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CAy/m0sRtW9XLS/BnR -AjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJbgfM0agPnIjhQW+0ZT0MW ------END CERTIFICATE----- - -DigiCert TLS ECC P384 Root G5 -============================= ------BEGIN CERTIFICATE----- -MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV -UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURpZ2lDZXJ0IFRMUyBFQ0MgUDM4 -NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMx -FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQg -Um9vdCBHNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1Tzvd -lHJS7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp0zVozptj -n4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICISB4CIfBFqMA4GA1UdDwEB -/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQCJao1H5+z8blUD2Wds -Jk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQLgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIx -AJSdYsiJvRmEFOml+wG4DXZDjC5Ty3zfDBeWUA== ------END CERTIFICATE----- - -DigiCert TLS RSA4096 Root G5 -============================ ------BEGIN CERTIFICATE----- -MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBNMQswCQYDVQQG -EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0 -MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcNNDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJV -UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2 -IFJvb3QgRzUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS8 -7IE+ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG02C+JFvuU -AT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgpwgscONyfMXdcvyej/Ces -tyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZMpG2T6T867jp8nVid9E6P/DsjyG244gXa -zOvswzH016cpVIDPRFtMbzCe88zdH5RDnU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnV -DdXifBBiqmvwPXbzP6PosMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9q -TXeXAaDxZre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cdLvvy -z6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvXKyY//SovcfXWJL5/ -MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNeXoVPzthwiHvOAbWWl9fNff2C+MIk -wcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPLtgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4E -FgQUUTMc7TZArxfTJc1paPKvTiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8w -DQYJKoZIhvcNAQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw -GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7HPNtQOa27PShN -lnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLFO4uJ+DQtpBflF+aZfTCIITfN -MBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQREtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/ -u4cnYiWB39yhL/btp/96j1EuMPikAdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9G -OUrYU9DzLjtxpdRv/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh -47a+p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilwMUc/dNAU -FvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WFqUITVuwhd4GTWgzqltlJ -yqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCKovfepEWFJqgejF0pW8hL2JpqA15w8oVP -bEtoL8pU9ozaMv7Da4M/OMZ+ ------END CERTIFICATE----- - -Certainly Root R1 -================= ------BEGIN CERTIFICATE----- -MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE -BhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2VydGFpbmx5IFJvb3QgUjEwHhcN -MjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2Vy -dGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIP -ADCCAgoCggIBANA21B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O -5MQTvqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbedaFySpvXl -8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b01C7jcvk2xusVtyWMOvwl -DbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGI -XsXwClTNSaa/ApzSRKft43jvRl5tcdF5cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkN -KPl6I7ENPT2a/Z2B7yyQwHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQ -AjeZjOVJ6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA2Cnb -rlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyHWyf5QBGenDPBt+U1 -VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMReiFPCyEQtkA6qyI6BJyLm4SGcprS -p6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBTgqj8ljZ9EXME66C6ud0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAsz -HQNTVfSVcOQrPbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d -8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi1wrykXprOQ4v -MMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrdrRT90+7iIgXr0PK3aBLXWopB -GsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9ditaY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+ -gjwN/KUD+nsa2UUeYNrEjvn8K8l7lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgH -JBu6haEaBQmAupVjyTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7 -fpYnKx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLyyCwzk5Iw -x06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5nwXARPbv0+Em34yaXOp/S -X3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6OV+KmalBWQewLK8= ------END CERTIFICATE----- - -Certainly Root E1 -================= ------BEGIN CERTIFICATE----- -MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQswCQYDVQQGEwJV -UzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBFMTAeFw0yMTA0 -MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlu -bHkxGjAYBgNVBAMTEUNlcnRhaW5seSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4 -fxzf7flHh4axpMCK+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9 -YBk2QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8EBAMCAQYw -DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4hevIIgcwCgYIKoZIzj0E -AwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozmut6Dacpps6kFtZaSF4fC0urQe87YQVt8 -rgIwRt7qy12a7DLCZRawTDBcMPPaTnOGBtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR ------END CERTIFICATE----- - -Security Communication RootCA3 -============================== ------BEGIN CERTIFICATE----- -MIIFfzCCA2egAwIBAgIJAOF8N0D9G/5nMA0GCSqGSIb3DQEBDAUAMF0xCzAJBgNVBAYTAkpQMSUw -IwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScwJQYDVQQDEx5TZWN1cml0eSBD -b21tdW5pY2F0aW9uIFJvb3RDQTMwHhcNMTYwNjE2MDYxNzE2WhcNMzgwMTE4MDYxNzE2WjBdMQsw -CQYDVQQGEwJKUDElMCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UE -AxMeU2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A -MIICCgKCAgEA48lySfcw3gl8qUCBWNO0Ot26YQ+TUG5pPDXC7ltzkBtnTCHsXzW7OT4rCmDvu20r -hvtxosis5FaU+cmvsXLUIKx00rgVrVH+hXShuRD+BYD5UpOzQD11EKzAlrenfna84xtSGc4RHwsE -NPXY9Wk8d/Nk9A2qhd7gCVAEF5aEt8iKvE1y/By7z/MGTfmfZPd+pmaGNXHIEYBMwXFAWB6+oHP2 -/D5Q4eAvJj1+XCO1eXDe+uDRpdYMQXF79+qMHIjH7Iv10S9VlkZ8WjtYO/u62C21Jdp6Ts9EriGm -npjKIG58u4iFW/vAEGK78vknR+/RiTlDxN/e4UG/VHMgly1s2vPUB6PmudhvrvyMGS7TZ2crldtY -XLVqAvO4g160a75BflcJdURQVc1aEWEhCmHCqYj9E7wtiS/NYeCVvsq1e+F7NGcLH7YMx3weGVPK -p7FKFSBWFHA9K4IsD50VHUeAR/94mQ4xr28+j+2GaR57GIgUssL8gjMunEst+3A7caoreyYn8xrC -3PsXuKHqy6C0rtOUfnrQq8PsOC0RLoi/1D+tEjtCrI8Cbn3M0V9hvqG8OmpI6iZVIhZdXw3/JzOf -GAN0iltSIEdrRU0id4xVJ/CvHozJgyJUt5rQT9nO/NkuHJYosQLTA70lUhw0Zk8jq/R3gpYd0Vcw -CBEF/VfR2ccCAwEAAaNCMEAwHQYDVR0OBBYEFGQUfPxYchamCik0FW8qy7z8r6irMA4GA1UdDwEB -/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4ICAQDcAiMI4u8hOscNtybS -YpOnpSNyByCCYN8Y11StaSWSntkUz5m5UoHPrmyKO1o5yGwBQ8IibQLwYs1OY0PAFNr0Y/Dq9HHu -Tofjcan0yVflLl8cebsjqodEV+m9NU1Bu0soo5iyG9kLFwfl9+qd9XbXv8S2gVj/yP9kaWJ5rW4O -H3/uHWnlt3Jxs/6lATWUVCvAUm2PVcTJ0rjLyjQIUYWg9by0F1jqClx6vWPGOi//lkkZhOpn2ASx -YfQAW0q3nHE3GYV5v4GwxxMOdnE+OoAGrgYWp421wsTL/0ClXI2lyTrtcoHKXJg80jQDdwj98ClZ -XSEIx2C/pHF7uNkegr4Jr2VvKKu/S7XuPghHJ6APbw+LP6yVGPO5DtxnVW5inkYO0QR4ynKudtml -+LLfiAlhi+8kTtFZP1rUPcmTPCtk9YENFpb3ksP+MW/oKjJ0DvRMmEoYDjBU1cXrvMUVnuiZIesn -KwkK2/HmcBhWuwzkvvnoEKQTkrgc4NtnHVMDpCKn3F2SEDzq//wbEBrD2NCcnWXL0CsnMQMeNuE9 -dnUM/0Umud1RvCPHX9jYhxBAEg09ODfnRDwYwFMJZI//1ZqmfHAuc1Uh6N//g7kdPjIe1qZ9LPFm -6Vwdp6POXiUyK+OVrCoHzrQoeIY8LaadTdJ0MN1kURXbg4NR16/9M51NZg== ------END CERTIFICATE----- - -Security Communication ECC RootCA1 -================================== ------BEGIN CERTIFICATE----- -MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYTAkpQMSUwIwYD -VQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYDVQQDEyJTZWN1cml0eSBDb21t -dW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYxNjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTEL -MAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNV -BAMTIlNlY3VyaXR5IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+CnnfdldB9sELLo -5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpKULGjQjBAMB0GA1UdDgQW -BBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAK -BggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3L -snNdo4gIxwwCMQDAqy0Obe0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70e -N9k= ------END CERTIFICATE----- - -BJCA Global Root CA1 -==================== ------BEGIN CERTIFICATE----- -MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQG -EwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJK -Q0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAzMTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkG -A1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQD -DBRCSkNBIEdsb2JhbCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFm -CL3ZxRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZspDyRhyS -sTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O558dnJCNPYwpj9mZ9S1Wn -P3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgRat7GGPZHOiJBhyL8xIkoVNiMpTAK+BcW -yqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRj -eulumijWML3mG90Vr4TqnMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNn -MoH1V6XKV0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/pj+b -OT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZOz2nxbkRs1CTqjSSh -GL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXnjSXWgXSHRtQpdaJCbPdzied9v3pK -H9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMB -AAGjQjBAMB0GA1UdDgQWBBTF7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4 -YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3KliawLwQ8hOnThJ -dMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u+2D2/VnGKhs/I0qUJDAnyIm8 -60Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuh -TaRjAv04l5U/BXCga99igUOLtFkNSoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW -4AB+dAb/OMRyHdOoP2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmp -GQrI+pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRzznfSxqxx -4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9eVzYH6Eze9mCUAyTF6ps -3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4S -SPfSKcOYKMryMguTjClPPGAyzQWWYezyr/6zcCwupvI= ------END CERTIFICATE----- - -BJCA Global Root CA2 -==================== ------BEGIN CERTIFICATE----- -MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQswCQYDVQQGEwJD -TjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJKQ0Eg -R2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgyMVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UE -BhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRC -SkNBIEdsb2JhbCBSb290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jl -SR9BIgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK++kpRuDCK -/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJKsVF/BvDRgh9Obl+rg/xI -1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8 -W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8g -UXOQwKhbYdDFUDn9hf7B43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w== ------END CERTIFICATE----- - -Sectigo Public Server Authentication Root E46 -============================================= ------BEGIN CERTIFICATE----- -MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQswCQYDVQQGEwJH -QjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBTZXJ2 -ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5 -WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0 -aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUr -gQQAIgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccCWvkEN/U0 -NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+6xnOQ6OjQjBAMB0GA1Ud -DgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB -/zAKBggqhkjOPQQDAwNnADBkAjAn7qRaqCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RH -lAFWovgzJQxC36oCMB3q4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21U -SAGKcw== ------END CERTIFICATE----- - -Sectigo Public Server Authentication Root R46 -============================================= ------BEGIN CERTIFICATE----- -MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBfMQswCQYDVQQG -EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT -ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1 -OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T -ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3 -DQEBAQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDaef0rty2k -1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnzSDBh+oF8HqcIStw+Kxwf -GExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xfiOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMP -FF1bFOdLvt30yNoDN9HWOaEhUTCDsG3XME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vu -ZDCQOc2TZYEhMbUjUDM3IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5Qaz -Yw6A3OASVYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgESJ/A -wSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu+Zd4KKTIRJLpfSYF -plhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt8uaZFURww3y8nDnAtOFr94MlI1fZ -EoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+LHaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW -6aWWrL3DkJiy4Pmi1KZHQ3xtzwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWI -IUkwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c -mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQYKlJfp/imTYp -E0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52gDY9hAaLMyZlbcp+nv4fjFg4 -exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZAFv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M -0ejf5lG5Nkc/kLnHvALcWxxPDkjBJYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI -84HxZmduTILA7rpXDhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9m -pFuiTdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5dHn5Hrwd -Vw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65LvKRRFHQV80MNNVIIb/b -E/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmm -J1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAYQqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL ------END CERTIFICATE----- - -SSL.com TLS RSA Root CA 2022 -============================ ------BEGIN CERTIFICATE----- -MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQG -EwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBSU0Eg -Um9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloXDTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMC -VVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJv -b3QgQ0EgMjAyMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u -9nTPL3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OYt6/wNr/y -7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0insS657Lb85/bRi3pZ7Qcac -oOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3PnxEX4MN8/HdIGkWCVDi1FW24IBydm5M -R7d1VVm0U3TZlMZBrViKMWYPHqIbKUBOL9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDG -D6C1vBdOSHtRwvzpXGk3R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEW -TO6Af77wdr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS+YCk -8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYSd66UNHsef8JmAOSq -g+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoGAtUjHBPW6dvbxrB6y3snm/vg1UYk -7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2fgTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1Ud -EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsu -N+7jhHonLs0ZNbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt -hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsMQtfhWsSWTVTN -j8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvfR4iyrT7gJ4eLSYwfqUdYe5by -iB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJDPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjU -o3KUQyxi4U5cMj29TH0ZR6LDSeeWP4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqo -ENjwuSfr98t67wVylrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7Egkaib -MOlqbLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2wAgDHbICi -vRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3qr5nsLFR+jM4uElZI7xc7 -P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sjiMho6/4UIyYOf8kpIEFR3N+2ivEC+5BB0 -9+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= ------END CERTIFICATE----- - -SSL.com TLS ECC Root CA 2022 -============================ ------BEGIN CERTIFICATE----- -MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV -UzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBFQ0MgUm9v -dCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMx -GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3Qg -Q0EgMjAyMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWy -JGYmacCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFNSeR7T5v1 -5wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSJjy+j6CugFFR7 -81a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NWuCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGG -MAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w -7deedWo1dlJF4AIxAMeNb0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5 -Zn6g6g== ------END CERTIFICATE----- - -Atos TrustedRoot Root CA ECC TLS 2021 -===================================== ------BEGIN CERTIFICATE----- -MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4wLAYDVQQDDCVB -dG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQswCQYD -VQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3Mg -VHJ1c3RlZFJvb3QgUm9vdCBDQSBFQ0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYT -AkRFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6K -DP/XtXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4AjJn8ZQS -b+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2KCXWfeBmmnoJsmo7jjPX -NtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIwW5kp85wxtolrbNa9d+F851F+ -uDrNozZffPc8dz7kUK2o59JZDCaOMDtuCCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGY -a3cpetskz2VAv9LcjBHo9H1/IISpQuQo ------END CERTIFICATE----- - -Atos TrustedRoot Root CA RSA TLS 2021 -===================================== ------BEGIN CERTIFICATE----- -MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBMMS4wLAYDVQQD -DCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQsw -CQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0 -b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNV -BAYTAkRFMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BB -l01Z4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYvYe+W/CBG -vevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZkmGbzSoXfduP9LVq6hdK -ZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDsGY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt -0xU6kGpn8bRrZtkh68rZYnxGEFzedUlnnkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVK -PNe0OwANwI8f4UDErmwh3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMY -sluMWuPD0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzygeBY -Br3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8ANSbhqRAvNncTFd+ -rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezBc6eUWsuSZIKmAMFwoW4sKeFYV+xa -fJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lIpw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQUdEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0G -CSqGSIb3DQEBDAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS -4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPso0UvFJ/1TCpl -Q3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJqM7F78PRreBrAwA0JrRUITWX -AdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuywxfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9G -slA9hGCZcbUztVdF5kJHdWoOsAgMrr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2Vkt -afcxBPTy+av5EzH4AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9q -TFsR0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuYo7Ey7Nmj -1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5dDTedk+SKlOxJTnbPP/l -PqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcEoji2jbDwN/zIIX8/syQbPYtuzE2wFg2W -HYMfRsCbvUOZ58SWLs5fyQ== ------END CERTIFICATE----- diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gio/modules/giolibproxy.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gio/modules/giolibproxy.dll deleted file mode 100644 index f348693df..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gio/modules/giolibproxy.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gio/modules/gioopenssl.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gio/modules/gioopenssl.dll deleted file mode 100644 index ca4c70fe4..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gio/modules/gioopenssl.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsta52dec.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsta52dec.dll deleted file mode 100644 index 56f8143d7..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsta52dec.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaccurip.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaccurip.dll deleted file mode 100644 index 9279d0825..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaccurip.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstadaptivedemux2.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstadaptivedemux2.dll deleted file mode 100644 index fc9471412..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstadaptivedemux2.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstadder.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstadder.dll deleted file mode 100644 index ce1e34804..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstadder.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstadpcmdec.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstadpcmdec.dll deleted file mode 100644 index 52660069b..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstadpcmdec.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstadpcmenc.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstadpcmenc.dll deleted file mode 100644 index d7d20bd7d..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstadpcmenc.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaes.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaes.dll deleted file mode 100644 index 95c0c7230..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaes.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaiff.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaiff.dll deleted file mode 100644 index af096de7b..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaiff.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstalaw.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstalaw.dll deleted file mode 100644 index b7d82e831..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstalaw.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstalpha.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstalpha.dll deleted file mode 100644 index 32a67ebb5..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstalpha.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstalphacolor.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstalphacolor.dll deleted file mode 100644 index c66cd8546..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstalphacolor.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstamfcodec.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstamfcodec.dll deleted file mode 100644 index 2b00cba76..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstamfcodec.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstamrnb.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstamrnb.dll deleted file mode 100644 index c82a22128..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstamrnb.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstamrwbdec.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstamrwbdec.dll deleted file mode 100644 index b4eb803c8..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstamrwbdec.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstanalyticsoverlay.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstanalyticsoverlay.dll deleted file mode 100644 index 85714fcef..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstanalyticsoverlay.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstapetag.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstapetag.dll deleted file mode 100644 index d2c8b9213..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstapetag.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstapp.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstapp.dll deleted file mode 100644 index 47ce4bde6..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstapp.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstasf.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstasf.dll deleted file mode 100644 index bcc0ba007..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstasf.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstasfmux.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstasfmux.dll deleted file mode 100644 index 8b7aa0d18..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstasfmux.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstasio.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstasio.dll deleted file mode 100644 index 5b9e0581b..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstasio.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstassrender.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstassrender.dll deleted file mode 100644 index 207a122d1..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstassrender.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiobuffersplit.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiobuffersplit.dll deleted file mode 100644 index cddfbd300..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiobuffersplit.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudioconvert.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudioconvert.dll deleted file mode 100644 index ef0ad8f85..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudioconvert.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiofx.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiofx.dll deleted file mode 100644 index d8b96bd76..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiofx.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiofxbad.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiofxbad.dll deleted file mode 100644 index afc595e91..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiofxbad.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiolatency.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiolatency.dll deleted file mode 100644 index b7e99c861..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiolatency.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiomixer.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiomixer.dll deleted file mode 100644 index 96a4cd146..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiomixer.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiomixmatrix.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiomixmatrix.dll deleted file mode 100644 index 59201861a..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiomixmatrix.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudioparsers.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudioparsers.dll deleted file mode 100644 index 6157b31b1..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudioparsers.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiorate.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiorate.dll deleted file mode 100644 index 79beef0c7..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiorate.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudioresample.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudioresample.dll deleted file mode 100644 index 3f2dd37a7..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudioresample.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiotestsrc.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiotestsrc.dll deleted file mode 100644 index 83135e18f..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiotestsrc.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiovisualizers.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiovisualizers.dll deleted file mode 100644 index 3f96b340c..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaudiovisualizers.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstauparse.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstauparse.dll deleted file mode 100644 index 9260fc8d5..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstauparse.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstautoconvert.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstautoconvert.dll deleted file mode 100644 index 0988e2b29..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstautoconvert.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstautodetect.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstautodetect.dll deleted file mode 100644 index 0cb2b3425..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstautodetect.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstavi.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstavi.dll deleted file mode 100644 index e179a8d35..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstavi.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaws.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaws.dll deleted file mode 100644 index bbf50cc84..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstaws.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstbayer.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstbayer.dll deleted file mode 100644 index 2b46908ef..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstbayer.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstburn.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstburn.dll deleted file mode 100644 index 68d3a13fa..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstburn.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstbz2.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstbz2.dll deleted file mode 100644 index e7e8e1757..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstbz2.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcairo.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcairo.dll deleted file mode 100644 index d7bafe440..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcairo.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcamerabin.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcamerabin.dll deleted file mode 100644 index 5144c1858..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcamerabin.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcdg.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcdg.dll deleted file mode 100644 index abc9d9e86..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcdg.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstclaxon.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstclaxon.dll deleted file mode 100644 index 32cb88cc6..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstclaxon.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstclosedcaption.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstclosedcaption.dll deleted file mode 100644 index 431739792..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstclosedcaption.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcodecalpha.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcodecalpha.dll deleted file mode 100644 index 28c616ec3..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcodecalpha.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcodectimestamper.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcodectimestamper.dll deleted file mode 100644 index f352e7106..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcodectimestamper.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcoloreffects.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcoloreffects.dll deleted file mode 100644 index fa480f6ad..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcoloreffects.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcompositor.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcompositor.dll deleted file mode 100644 index c46f422ba..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcompositor.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcoreelements.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcoreelements.dll deleted file mode 100644 index 1802d5631..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcoreelements.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcoretracers.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcoretracers.dll deleted file mode 100644 index a6e3ac676..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcoretracers.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcurl.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcurl.dll deleted file mode 100644 index 38bbc20e7..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcurl.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcutter.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcutter.dll deleted file mode 100644 index 3f881d934..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstcutter.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstd3d.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstd3d.dll deleted file mode 100644 index 312764312..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstd3d.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstd3d11.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstd3d11.dll deleted file mode 100644 index 6a1c00a27..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstd3d11.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstd3d12.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstd3d12.dll deleted file mode 100644 index a192ebfa7..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstd3d12.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdash.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdash.dll deleted file mode 100644 index 9e152f9bc..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdash.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdav1d.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdav1d.dll deleted file mode 100644 index 0e88f96f7..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdav1d.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdebug.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdebug.dll deleted file mode 100644 index e2f1a7545..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdebug.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdebugutilsbad.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdebugutilsbad.dll deleted file mode 100644 index 6a664162b..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdebugutilsbad.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdecklink.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdecklink.dll deleted file mode 100644 index befc423f5..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdecklink.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdeinterlace.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdeinterlace.dll deleted file mode 100644 index c9a56efde..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdeinterlace.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdemucs.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdemucs.dll deleted file mode 100644 index fe4d85c9c..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdemucs.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdirectshow.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdirectshow.dll deleted file mode 100644 index 09a2ad222..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdirectshow.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdirectsound.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdirectsound.dll deleted file mode 100644 index 5767cb631..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdirectsound.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdirectsoundsrc.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdirectsoundsrc.dll deleted file mode 100644 index 2b89e91a6..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdirectsoundsrc.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdtls.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdtls.dll deleted file mode 100644 index 75893711d..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdtls.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdtmf.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdtmf.dll deleted file mode 100644 index 5cafa25f9..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdtmf.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdtsdec.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdtsdec.dll deleted file mode 100644 index 6d1155420..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdtsdec.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdv.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdv.dll deleted file mode 100644 index 32f8c61d1..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdv.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvbsubenc.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvbsubenc.dll deleted file mode 100644 index 55a893db5..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvbsubenc.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvbsuboverlay.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvbsuboverlay.dll deleted file mode 100644 index 9ecb5ae5c..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvbsuboverlay.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvdlpcmdec.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvdlpcmdec.dll deleted file mode 100644 index 36fb93c1a..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvdlpcmdec.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvdread.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvdread.dll deleted file mode 100644 index a7d18edff..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvdread.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvdspu.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvdspu.dll deleted file mode 100644 index 10cb9829f..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvdspu.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvdsub.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvdsub.dll deleted file mode 100644 index c4bb74344..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdvdsub.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdwrite.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdwrite.dll deleted file mode 100644 index 0c2247566..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstdwrite.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsteffectv.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsteffectv.dll deleted file mode 100644 index b4fbc2350..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsteffectv.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstelevenlabs.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstelevenlabs.dll deleted file mode 100644 index 0d95a678b..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstelevenlabs.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstencoding.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstencoding.dll deleted file mode 100644 index 635c84ce8..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstencoding.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstequalizer.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstequalizer.dll deleted file mode 100644 index 2d0a59172..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstequalizer.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstfallbackswitch.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstfallbackswitch.dll deleted file mode 100644 index 76cb21f82..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstfallbackswitch.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstffv1.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstffv1.dll deleted file mode 100644 index 7dcad6261..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstffv1.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstfieldanalysis.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstfieldanalysis.dll deleted file mode 100644 index e9a65cc20..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstfieldanalysis.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstflac.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstflac.dll deleted file mode 100644 index ad616a6d4..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstflac.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstflv.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstflv.dll deleted file mode 100644 index 381f2e2d9..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstflv.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstflxdec.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstflxdec.dll deleted file mode 100644 index a86d747d5..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstflxdec.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstfreeverb.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstfreeverb.dll deleted file mode 100644 index 2c7f2ec51..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstfreeverb.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstfrei0r.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstfrei0r.dll deleted file mode 100644 index 4cc8db4f8..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstfrei0r.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgaudieffects.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgaudieffects.dll deleted file mode 100644 index 9e0d542bd..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgaudieffects.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgdkpixbuf.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgdkpixbuf.dll deleted file mode 100644 index 16d488382..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgdkpixbuf.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgdp.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgdp.dll deleted file mode 100644 index 487813af3..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgdp.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgeometrictransform.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgeometrictransform.dll deleted file mode 100644 index c5e06c016..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgeometrictransform.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstges.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstges.dll deleted file mode 100644 index 673e0c074..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstges.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgif.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgif.dll deleted file mode 100644 index fba7011cb..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgif.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgio.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgio.dll deleted file mode 100644 index beccad521..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgio.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgoom.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgoom.dll deleted file mode 100644 index 284483bcd..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgoom.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgoom2k1.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgoom2k1.dll deleted file mode 100644 index 2c7a9f0de..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgoom2k1.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgopbuffer.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgopbuffer.dll deleted file mode 100644 index 018151490..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgopbuffer.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgtk4.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgtk4.dll deleted file mode 100644 index 09086caa7..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstgtk4.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsthls.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsthls.dll deleted file mode 100644 index 94a3a37a4..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsthls.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsthlsmultivariantsink.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsthlsmultivariantsink.dll deleted file mode 100644 index a65a2dd27..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsthlsmultivariantsink.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsthlssink3.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsthlssink3.dll deleted file mode 100644 index 9f6636013..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsthlssink3.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsthsv.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsthsv.dll deleted file mode 100644 index eac6704e3..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsthsv.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsticecast.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsticecast.dll deleted file mode 100644 index a52fd7125..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsticecast.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsticydemux.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsticydemux.dll deleted file mode 100644 index a68b9e822..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsticydemux.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstid3demux.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstid3demux.dll deleted file mode 100644 index 6f8c4318c..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstid3demux.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstid3tag.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstid3tag.dll deleted file mode 100644 index 5ce38cf2b..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstid3tag.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstimagefreeze.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstimagefreeze.dll deleted file mode 100644 index 91f1f433c..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstimagefreeze.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstinsertbin.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstinsertbin.dll deleted file mode 100644 index c8cdc7427..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstinsertbin.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstinter.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstinter.dll deleted file mode 100644 index 959db4a00..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstinter.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstinterlace.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstinterlace.dll deleted file mode 100644 index 8d26fa701..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstinterlace.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstinterleave.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstinterleave.dll deleted file mode 100644 index dd80a53fb..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstinterleave.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstipcpipeline.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstipcpipeline.dll deleted file mode 100644 index c4f38ffe0..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstipcpipeline.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstisobmff.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstisobmff.dll deleted file mode 100644 index 7ab299655..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstisobmff.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstisomp4.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstisomp4.dll deleted file mode 100644 index 6ae077514..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstisomp4.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstivfparse.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstivfparse.dll deleted file mode 100644 index ba5983ec3..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstivfparse.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstivtc.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstivtc.dll deleted file mode 100644 index cfd09cefe..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstivtc.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstjack.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstjack.dll deleted file mode 100644 index d1a0e9705..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstjack.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstjpeg.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstjpeg.dll deleted file mode 100644 index a68709c9e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstjpeg.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstjpegformat.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstjpegformat.dll deleted file mode 100644 index 516ffa1c6..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstjpegformat.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstjson.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstjson.dll deleted file mode 100644 index d15db93d6..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstjson.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstladspa.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstladspa.dll deleted file mode 100644 index 06c01d195..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstladspa.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlame.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlame.dll deleted file mode 100644 index a0c0ab0ea..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlame.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlcevcdecoder.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlcevcdecoder.dll deleted file mode 100644 index f33a18a8a..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlcevcdecoder.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlegacyrawparse.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlegacyrawparse.dll deleted file mode 100644 index c85f14c9d..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlegacyrawparse.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlevel.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlevel.dll deleted file mode 100644 index ad69fac2b..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlevel.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlewton.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlewton.dll deleted file mode 100644 index a28c7d249..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlewton.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlibav.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlibav.dll deleted file mode 100644 index 10f7cd2bb..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlibav.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlivesync.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlivesync.dll deleted file mode 100644 index ac97d2387..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstlivesync.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmatroska.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmatroska.dll deleted file mode 100644 index 7cd8cb841..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmatroska.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmediafoundation.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmediafoundation.dll deleted file mode 100644 index e8bfee4a9..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmediafoundation.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmidi.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmidi.dll deleted file mode 100644 index 8db2c5c37..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmidi.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpegpsdemux.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpegpsdemux.dll deleted file mode 100644 index e68572021..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpegpsdemux.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpegpsmux.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpegpsmux.dll deleted file mode 100644 index 3fb929d4d..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpegpsmux.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpegtsdemux.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpegtsdemux.dll deleted file mode 100644 index 8fbc69064..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpegtsdemux.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpegtslive.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpegtslive.dll deleted file mode 100644 index e544637bd..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpegtslive.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpegtsmux.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpegtsmux.dll deleted file mode 100644 index 0bd1d4874..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpegtsmux.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpg123.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpg123.dll deleted file mode 100644 index 8da3ad136..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmpg123.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmse.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmse.dll deleted file mode 100644 index e0500b7b4..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmse.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmulaw.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmulaw.dll deleted file mode 100644 index 336752161..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmulaw.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmultifile.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmultifile.dll deleted file mode 100644 index 27b23a115..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmultifile.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmultipart.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmultipart.dll deleted file mode 100644 index bcdd9618d..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmultipart.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmxf.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmxf.dll deleted file mode 100644 index 5b785c02a..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstmxf.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstndi.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstndi.dll deleted file mode 100644 index c994b0a59..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstndi.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstnetsim.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstnetsim.dll deleted file mode 100644 index 1161ae9b4..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstnetsim.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstnice.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstnice.dll deleted file mode 100644 index 728403147..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstnice.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstnle.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstnle.dll deleted file mode 100644 index 018f55481..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstnle.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstnvcodec.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstnvcodec.dll deleted file mode 100644 index 155b0d808..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstnvcodec.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstogg.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstogg.dll deleted file mode 100644 index ed2dc9742..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstogg.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstopengl.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstopengl.dll deleted file mode 100644 index f62ec2e45..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstopengl.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstopenh264.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstopenh264.dll deleted file mode 100644 index 27ce5d3a2..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstopenh264.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstopenjpeg.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstopenjpeg.dll deleted file mode 100644 index 9b8126d72..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstopenjpeg.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstopus.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstopus.dll deleted file mode 100644 index 7a2051205..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstopus.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstopusparse.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstopusparse.dll deleted file mode 100644 index e12237366..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstopusparse.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstoriginalbuffer.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstoriginalbuffer.dll deleted file mode 100644 index 61f8ead36..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstoriginalbuffer.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstoverlaycomposition.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstoverlaycomposition.dll deleted file mode 100644 index 05821d373..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstoverlaycomposition.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpango.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpango.dll deleted file mode 100644 index ddfb532f9..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpango.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpbtypes.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpbtypes.dll deleted file mode 100644 index ba4f6371f..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpbtypes.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpcapparse.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpcapparse.dll deleted file mode 100644 index d2092e0fd..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpcapparse.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstplayback.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstplayback.dll deleted file mode 100644 index 70a5b9309..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstplayback.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpng.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpng.dll deleted file mode 100644 index f7cd8ae8e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpng.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpnm.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpnm.dll deleted file mode 100644 index 8728b4125..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpnm.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstproxy.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstproxy.dll deleted file mode 100644 index 3e9539205..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstproxy.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpython.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpython.dll deleted file mode 100644 index 58afce20a..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstpython.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstqroverlay.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstqroverlay.dll deleted file mode 100644 index ee849f272..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstqroverlay.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstqsv.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstqsv.dll deleted file mode 100644 index 554cd2054..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstqsv.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstquinn.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstquinn.dll deleted file mode 100644 index f89a4576d..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstquinn.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstraptorq.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstraptorq.dll deleted file mode 100644 index bc538755c..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstraptorq.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrav1e.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrav1e.dll deleted file mode 100644 index 3741cfb50..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrav1e.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrawparse.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrawparse.dll deleted file mode 100644 index 804fedb09..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrawparse.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrealmedia.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrealmedia.dll deleted file mode 100644 index 71871f074..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrealmedia.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstregex.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstregex.dll deleted file mode 100644 index 66273d2bf..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstregex.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstremovesilence.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstremovesilence.dll deleted file mode 100644 index 246bb3e5e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstremovesilence.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstreplaygain.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstreplaygain.dll deleted file mode 100644 index e60c5cdbd..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstreplaygain.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstreqwest.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstreqwest.dll deleted file mode 100644 index 2a0182eee..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstreqwest.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstresindvd.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstresindvd.dll deleted file mode 100644 index 4a69a9f47..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstresindvd.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrfbsrc.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrfbsrc.dll deleted file mode 100644 index 0bb36a6c2..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrfbsrc.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrist.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrist.dll deleted file mode 100644 index e65172e9c..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrist.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsanalytics.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsanalytics.dll deleted file mode 100644 index 16e06fd3b..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsanalytics.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsaudiofx.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsaudiofx.dll deleted file mode 100644 index b70ee4263..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsaudiofx.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsaudioparsers.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsaudioparsers.dll deleted file mode 100644 index 0f92b4a0a..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsaudioparsers.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsclosedcaption.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsclosedcaption.dll deleted file mode 100644 index 748fdeabf..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsclosedcaption.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsinter.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsinter.dll deleted file mode 100644 index 04a8068c0..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsinter.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsonvif.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsonvif.dll deleted file mode 100644 index 91523ee61..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsonvif.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrspng.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrspng.dll deleted file mode 100644 index cbf4a143b..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrspng.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsrtp.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsrtp.dll deleted file mode 100644 index 71c9d0564..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsrtp.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsrtsp.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsrtsp.dll deleted file mode 100644 index 2ad63642c..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsrtsp.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrstracers.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrstracers.dll deleted file mode 100644 index a8520c1f3..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrstracers.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsvg.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsvg.dll deleted file mode 100644 index 3b28d819b..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsvg.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsvideofx.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsvideofx.dll deleted file mode 100644 index cb10e0c42..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrsvideofx.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrswebrtc.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrswebrtc.dll deleted file mode 100644 index 4ed5830a0..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrswebrtc.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtmp.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtmp.dll deleted file mode 100644 index 4284c1354..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtmp.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtmp2.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtmp2.dll deleted file mode 100644 index ec8cca100..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtmp2.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtp.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtp.dll deleted file mode 100644 index e706b9e72..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtp.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtpmanager.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtpmanager.dll deleted file mode 100644 index d43f1eb9a..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtpmanager.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtpmanagerbad.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtpmanagerbad.dll deleted file mode 100644 index 089f75fa8..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtpmanagerbad.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtponvif.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtponvif.dll deleted file mode 100644 index 3fcd146c7..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtponvif.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtsp.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtsp.dll deleted file mode 100644 index 73d847477..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtsp.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtspclientsink.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtspclientsink.dll deleted file mode 100644 index 268dd3853..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstrtspclientsink.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsbc.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsbc.dll deleted file mode 100644 index 276be1fb8..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsbc.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsctp.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsctp.dll deleted file mode 100644 index afbac24a3..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsctp.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsdpelem.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsdpelem.dll deleted file mode 100644 index 6568e4a5e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsdpelem.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsegmentclip.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsegmentclip.dll deleted file mode 100644 index 189c18a43..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsegmentclip.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstshapewipe.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstshapewipe.dll deleted file mode 100644 index f096d2ab3..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstshapewipe.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsiren.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsiren.dll deleted file mode 100644 index 1b9ddee88..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsiren.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsmooth.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsmooth.dll deleted file mode 100644 index b98ad8835..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsmooth.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsmoothstreaming.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsmoothstreaming.dll deleted file mode 100644 index 54d921b9e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsmoothstreaming.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsmpte.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsmpte.dll deleted file mode 100644 index 8800a7779..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsmpte.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsoundtouch.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsoundtouch.dll deleted file mode 100644 index 05aacba61..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsoundtouch.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsoup.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsoup.dll deleted file mode 100644 index 3edfd63b7..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsoup.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstspandsp.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstspandsp.dll deleted file mode 100644 index 160f5b7bb..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstspandsp.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstspectrum.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstspectrum.dll deleted file mode 100644 index 190a39313..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstspectrum.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstspeechmatics.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstspeechmatics.dll deleted file mode 100644 index 08879d7e0..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstspeechmatics.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstspeed.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstspeed.dll deleted file mode 100644 index e97009f3e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstspeed.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstspeex.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstspeex.dll deleted file mode 100644 index 7e8bdef65..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstspeex.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsrt.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsrt.dll deleted file mode 100644 index 7d0f61142..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsrt.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsrtp.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsrtp.dll deleted file mode 100644 index c8adbd37d..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsrtp.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gststreamgrouper.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gststreamgrouper.dll deleted file mode 100644 index 9b92949c8..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gststreamgrouper.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsubenc.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsubenc.dll deleted file mode 100644 index e78d0f454..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsubenc.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsubparse.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsubparse.dll deleted file mode 100644 index 70825b328..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsubparse.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsvtav1.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsvtav1.dll deleted file mode 100644 index 8cd564b34..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsvtav1.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsvtjpegxs.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsvtjpegxs.dll deleted file mode 100644 index ee4518a97..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstsvtjpegxs.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstswitchbin.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstswitchbin.dll deleted file mode 100644 index adbcf6ef5..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstswitchbin.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttaglib.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttaglib.dll deleted file mode 100644 index 27906c1ff..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttaglib.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttcp.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttcp.dll deleted file mode 100644 index 7a24d5655..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttcp.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttensordecoders.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttensordecoders.dll deleted file mode 100644 index 99aa09cc5..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttensordecoders.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttextahead.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttextahead.dll deleted file mode 100644 index 1b136d380..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttextahead.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttextwrap.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttextwrap.dll deleted file mode 100644 index 8d9fcd0a4..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttextwrap.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttheora.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttheora.dll deleted file mode 100644 index 556c18fc0..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttheora.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstthreadshare.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstthreadshare.dll deleted file mode 100644 index 1ddfa58bd..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstthreadshare.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttimecode.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttimecode.dll deleted file mode 100644 index f4ae7a456..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttimecode.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttogglerecord.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttogglerecord.dll deleted file mode 100644 index ad95bc478..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttogglerecord.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttranscode.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttranscode.dll deleted file mode 100644 index fe481c7f7..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttranscode.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttypefindfunctions.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttypefindfunctions.dll deleted file mode 100644 index 848b00da5..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsttypefindfunctions.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstudp.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstudp.dll deleted file mode 100644 index 562a170c9..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstudp.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsturiplaylistbin.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsturiplaylistbin.dll deleted file mode 100644 index 4f1ac143e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsturiplaylistbin.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideobox.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideobox.dll deleted file mode 100644 index d525fbe3a..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideobox.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideoconvertscale.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideoconvertscale.dll deleted file mode 100644 index dce21665e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideoconvertscale.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideocrop.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideocrop.dll deleted file mode 100644 index fdf32f8b6..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideocrop.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideofilter.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideofilter.dll deleted file mode 100644 index 6d303ed4c..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideofilter.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideofiltersbad.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideofiltersbad.dll deleted file mode 100644 index cd37ef7e4..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideofiltersbad.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideoframe_audiolevel.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideoframe_audiolevel.dll deleted file mode 100644 index 16e06e468..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideoframe_audiolevel.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideomixer.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideomixer.dll deleted file mode 100644 index a2973a50c..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideomixer.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideoparsersbad.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideoparsersbad.dll deleted file mode 100644 index 2d2ca9713..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideoparsersbad.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideorate.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideorate.dll deleted file mode 100644 index df5f884d0..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideorate.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideosignal.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideosignal.dll deleted file mode 100644 index 55fe45ef9..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideosignal.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideotestsrc.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideotestsrc.dll deleted file mode 100644 index 3ef458028..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvideotestsrc.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvoaacenc.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvoaacenc.dll deleted file mode 100644 index 36fe55096..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvoaacenc.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvolume.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvolume.dll deleted file mode 100644 index 07bf135d3..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvolume.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvorbis.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvorbis.dll deleted file mode 100644 index 19c8f8115..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvorbis.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvpx.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvpx.dll deleted file mode 100644 index 96d842b7a..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstvpx.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwasapi.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwasapi.dll deleted file mode 100644 index fcc2e6ef4..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwasapi.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwasapi2.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwasapi2.dll deleted file mode 100644 index d280ca52d..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwasapi2.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwavenc.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwavenc.dll deleted file mode 100644 index 7c5e9b2cb..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwavenc.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwavpack.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwavpack.dll deleted file mode 100644 index 705af2ba6..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwavpack.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwavparse.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwavparse.dll deleted file mode 100644 index 14e6c7c74..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwavparse.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwebrtc.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwebrtc.dll deleted file mode 100644 index a0cf7227a..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwebrtc.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwebrtcdsp.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwebrtcdsp.dll deleted file mode 100644 index 4943eee5c..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwebrtcdsp.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwebrtchttp.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwebrtchttp.dll deleted file mode 100644 index 4480b8aaf..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwebrtchttp.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwebview2.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwebview2.dll deleted file mode 100644 index 16f77aaa7..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwebview2.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwic.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwic.dll deleted file mode 100644 index 917a716ee..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwic.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwin32ipc.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwin32ipc.dll deleted file mode 100644 index 363639f95..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwin32ipc.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwinks.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwinks.dll deleted file mode 100644 index 4dcee3ade..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwinks.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwinscreencap.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwinscreencap.dll deleted file mode 100644 index 2d5c4d897..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstwinscreencap.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstx264.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstx264.dll deleted file mode 100644 index 286a318ee..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstx264.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstx265.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstx265.dll deleted file mode 100644 index c5558224a..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstx265.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstxingmux.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstxingmux.dll deleted file mode 100644 index 32f436056..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstxingmux.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsty4m.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsty4m.dll deleted file mode 100644 index 8e7c1e621..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gsty4m.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstzbar.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstzbar.dll deleted file mode 100644 index cec58449e..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/gstzbar.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/include/gst/d3d11/gstd3d11config.h b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/include/gst/d3d11/gstd3d11config.h deleted file mode 100644 index b8d917865..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/include/gst/d3d11/gstd3d11config.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -G_BEGIN_DECLS - -#define GST_D3D11_WINAPI_ONLY_APP 0 -#define GST_D3D11_WINAPI_APP 1 - -G_END_DECLS diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/include/gst/gl/gstglconfig.h b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/include/gst/gl/gstglconfig.h deleted file mode 100644 index 3872f9b9a..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/include/gst/gl/gstglconfig.h +++ /dev/null @@ -1,49 +0,0 @@ -/* gstglconfig.h - */ - -#ifndef __GST_GL_CONFIG_H__ -#define __GST_GL_CONFIG_H__ - -#include - -G_BEGIN_DECLS - - -#define GST_GL_HAVE_OPENGL 1 -#define GST_GL_HAVE_GLES2 0 -#define GST_GL_HAVE_GLES3 0 -#define GST_GL_HAVE_GLES3EXT3_H 0 - -#define GST_GL_HAVE_WINDOW_X11 0 -#define GST_GL_HAVE_WINDOW_COCOA 0 -#define GST_GL_HAVE_WINDOW_WIN32 1 -#define GST_GL_HAVE_WINDOW_WINRT 0 -#define GST_GL_HAVE_WINDOW_WAYLAND 0 -#define GST_GL_HAVE_WINDOW_ANDROID 0 -#define GST_GL_HAVE_WINDOW_DISPMANX 0 -#define GST_GL_HAVE_WINDOW_EAGL 0 -#define GST_GL_HAVE_WINDOW_VIV_FB 0 -#define GST_GL_HAVE_WINDOW_GBM 0 - -#define GST_GL_HAVE_PLATFORM_EGL 0 -#define GST_GL_HAVE_PLATFORM_GLX 0 -#define GST_GL_HAVE_PLATFORM_WGL 1 -#define GST_GL_HAVE_PLATFORM_CGL 0 -#define GST_GL_HAVE_PLATFORM_EAGL 0 - -#define GST_GL_HAVE_DMABUF 0 -#define GST_GL_HAVE_VIV_DIRECTVIV 0 - -#define GST_GL_HAVE_GLEGLIMAGEOES 1 -#define GST_GL_HAVE_GLCHAR 1 -#define GST_GL_HAVE_GLSIZEIPTR 1 -#define GST_GL_HAVE_GLINTPTR 1 -#define GST_GL_HAVE_GLSYNC 1 -#define GST_GL_HAVE_GLUINT64 1 -#define GST_GL_HAVE_GLINT64 1 -#define GST_GL_HAVE_EGLATTRIB 0 -#define GST_GL_HAVE_EGLUINT64KHR 0 - -G_END_DECLS - -#endif /* __GST_GL_CONFIG_H__ */ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstaws.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstaws.pc deleted file mode 100644 index 3d883264f..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstaws.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstaws -Description: GStreamer Amazon Web Services plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstaws -Cflags: -Libs.private: -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lbcrypt -ladvapi32 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gobject-2.0, glib-2.0, gmodule-2.0, openssl - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstburn.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstburn.pc deleted file mode 100644 index c6f9b087d..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstburn.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstburn -Description: GStreamer Burn plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstburn -Cflags: -Libs.private: -lgstanalytics-1.0 -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lbcrypt -ladvapi32 -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-video-1.0, gstreamer-analytics-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstcdg.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstcdg.pc deleted file mode 100644 index cb104100d..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstcdg.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstcdg -Description: GStreamer CDG codec Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstcdg -Cflags: -Libs.private: -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-video-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstclaxon.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstclaxon.pc deleted file mode 100644 index 155df58bd..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstclaxon.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstclaxon -Description: GStreamer Claxon FLAC Decoder Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstclaxon -Cflags: -Libs.private: -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-audio-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstdav1d.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstdav1d.pc deleted file mode 100644 index 8c06bbfa9..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstdav1d.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstdav1d -Description: GStreamer dav1d AV1 decoder Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstdav1d -Cflags: -Libs.private: -ldav1d -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-video-1.0, gobject-2.0, glib-2.0, gmodule-2.0, dav1d - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstdemucs.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstdemucs.pc deleted file mode 100644 index 94f3df756..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstdemucs.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstdemucs -Description: GStreamer Demucs Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstdemucs -Cflags: -Libs.private: -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lbcrypt -ladvapi32 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-audio-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstelevenlabs.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstelevenlabs.pc deleted file mode 100644 index 1228bcdf8..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstelevenlabs.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstelevenlabs -Description: GStreamer ElevenLabs plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstelevenlabs -Cflags: -Libs.private: -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lbcrypt -ladvapi32 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-audio-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstfallbackswitch.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstfallbackswitch.pc deleted file mode 100644 index 58fe8cf6f..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstfallbackswitch.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstfallbackswitch -Description: GStreamer Fallback Switcher and Source Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstfallbackswitch -Cflags: -Libs.private: -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-audio-1.0, gstreamer-video-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstffv1.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstffv1.pc deleted file mode 100644 index b1aa6defe..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstffv1.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstffv1 -Description: GStreamer FFV1 Decoder Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstffv1 -Cflags: -Libs.private: -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-video-1.0, gobject-2.0, glib-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstgif.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstgif.pc deleted file mode 100644 index cd88164d5..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstgif.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstgif -Description: GStreamer GIF plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstgif -Cflags: -Libs.private: -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-video-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstgopbuffer.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstgopbuffer.pc deleted file mode 100644 index b0739a245..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstgopbuffer.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstgopbuffer -Description: Store complete groups of pictures at a time -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstgopbuffer -Cflags: -Libs.private: -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-audio-1.0, gstreamer-video-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstgtk4.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstgtk4.pc deleted file mode 100644 index 20a02a6d7..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstgtk4.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstgtk4 -Description: GStreamer GTK 4 sink element -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstgtk4 -Cflags: -Libs.private: -lgstgl-1.0 -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgtk-4 -lpangowin32-1.0 -lpangocairo-1.0 -lpango-1.0 -lharfbuzz -lgdk_pixbuf-2.0 -lcairo-gobject -lcairo -lgraphene-1.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgtk-4 -lpangowin32-1.0 -lpangocairo-1.0 -lpango-1.0 -lharfbuzz -lgdk_pixbuf-2.0 -lcairo-gobject -lcairo -lgraphene-1.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgraphene-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgtk-4 -lpangowin32-1.0 -lpangocairo-1.0 -lpango-1.0 -lharfbuzz -lgdk_pixbuf-2.0 -lcairo-gobject -lcairo -lgraphene-1.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lpango-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lharfbuzz -lgdk_pixbuf-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lcairo-gobject -lcairo -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-video-1.0, gtk4, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsthlsmultivariantsink.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsthlsmultivariantsink.pc deleted file mode 100644 index e88e3f41e..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsthlsmultivariantsink.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gsthlsmultivariantsink -Description: GStreamer HLS (HTTP Live Streaming) multi-variant sink Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgsthlsmultivariantsink -Cflags: -Libs.private: -lgstpbutils-1.0 -lgstvideo-1.0 -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsthlssink3.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsthlssink3.pc deleted file mode 100644 index bb3b226ed..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsthlssink3.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gsthlssink3 -Description: GStreamer HLS (HTTP Live Streaming) Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgsthlssink3 -Cflags: -Libs.private: -lgstapp-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsthsv.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsthsv.pc deleted file mode 100644 index c540c12cc..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsthsv.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gsthsv -Description: GStreamer plugin with HSV manipulation elements -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgsthsv -Cflags: -Libs.private: -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-video-1.0, gstreamer-audio-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsticecast.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsticecast.pc deleted file mode 100644 index 84b36d3b7..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsticecast.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gsticecast -Description: GStreamer Icecast Sink Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgsticecast -Cflags: -Libs.private: -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lbcrypt -ladvapi32 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstisobmff.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstisobmff.pc deleted file mode 100644 index 4c08f512a..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstisobmff.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstisobmff -Description: GStreamer ISO Base Media File Format (MP4) Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstisobmff -Cflags: -Libs.private: -lgsttag-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstpbutils-1.0 -lgstvideo-1.0 -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-audio-1.0, gstreamer-video-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstjson.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstjson.pc deleted file mode 100644 index b3d01c74f..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstjson.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstjson -Description: GStreamer JSON Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstjson -Cflags: -Libs.private: -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstlewton.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstlewton.pc deleted file mode 100644 index dafb2d65e..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstlewton.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstlewton -Description: GStreamer lewton Vorbis Decoder Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstlewton -Cflags: -Libs.private: -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-audio-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstlivesync.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstlivesync.pc deleted file mode 100644 index 03f9b4658..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstlivesync.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstlivesync -Description: Livesync Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstlivesync -Cflags: -Libs.private: -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-audio-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstmpegtslive.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstmpegtslive.pc deleted file mode 100644 index 41df90db0..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstmpegtslive.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstmpegtslive -Description: GStreamer MPEG-TS Live sources -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstmpegtslive -Cflags: -Libs.private: -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstndi.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstndi.pc deleted file mode 100644 index d16226280..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstndi.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstndi -Description: GStreamer NewTek NDI Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstndi -Cflags: -Libs.private: -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-audio-1.0, gstreamer-video-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstoriginalbuffer.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstoriginalbuffer.pc deleted file mode 100644 index 0426be761..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstoriginalbuffer.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstoriginalbuffer -Description: GStreamer Origin buffer meta Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstoriginalbuffer -Cflags: -Libs.private: -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstquinn.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstquinn.pc deleted file mode 100644 index d5e9229de..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstquinn.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstquinn -Description: GStreamer Plugin for QUIC -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstquinn -Cflags: -Libs.private: -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lbcrypt -ladvapi32 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gobject-2.0, glib-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstraptorq.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstraptorq.pc deleted file mode 100644 index 93ed49053..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstraptorq.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstraptorq -Description: GStreamer RaptorQ FEC Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstraptorq -Cflags: -Libs.private: -lgstrtp-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-rtp-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrav1e.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrav1e.pc deleted file mode 100644 index 03d7a0419..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrav1e.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstrav1e -Description: GStreamer rav1e AV1 Encoder Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstrav1e -Cflags: -Libs.private: -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-video-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstregex.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstregex.pc deleted file mode 100644 index 1c311847a..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstregex.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstregex -Description: GStreamer Regular Expression Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstregex -Cflags: -Libs.private: -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstreqwest.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstreqwest.pc deleted file mode 100644 index 90b9b8306..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstreqwest.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstreqwest -Description: GStreamer reqwest HTTP Source Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstreqwest -Cflags: -Libs.private: -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lbcrypt -ladvapi32 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsanalytics.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsanalytics.pc deleted file mode 100644 index cf4b956b1..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsanalytics.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstrsanalytics -Description: GStreamer Rust Analytics Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstrsanalytics -Cflags: -Libs.private: -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstanalytics-1.0 -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gobject-2.0, glib-2.0, gmodule-2.0, gstreamer-analytics-1.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsaudiofx.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsaudiofx.pc deleted file mode 100644 index 1cdca409b..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsaudiofx.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstrsaudiofx -Description: GStreamer Rust Audio Effects Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstrsaudiofx -Cflags: -Libs.private: -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-audio-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsaudioparsers.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsaudioparsers.pc deleted file mode 100644 index 8e507bc4e..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsaudioparsers.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstrsaudioparsers -Description: GStreamer Rust Audio Parsers Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstrsaudioparsers -Cflags: -Libs.private: -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-audio-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsclosedcaption.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsclosedcaption.pc deleted file mode 100644 index 717002645..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsclosedcaption.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstrsclosedcaption -Description: GStreamer Rust Closed Caption Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstrsclosedcaption -Cflags: -Libs.private: -lpangocairo-1.0 -lpango-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lharfbuzz -lcairo -lcairo-gobject -lcairo -lgobject-2.0 -lglib-2.0 -lintl -lpango-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lharfbuzz -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-video-1.0, gobject-2.0, glib-2.0, gmodule-2.0, pango, pangocairo, cairo-gobject - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsinter.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsinter.pc deleted file mode 100644 index e81fbe388..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsinter.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstrsinter -Description: GStreamer Inter Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstrsinter -Cflags: -Libs.private: -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstapp-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsonvif.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsonvif.pc deleted file mode 100644 index bbb266024..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsonvif.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstrsonvif -Description: GStreamer Rust ONVIF Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstrsonvif -Cflags: -Libs.private: -lpangocairo-1.0 -lpango-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lharfbuzz -lcairo -lcairo-gobject -lcairo -lgobject-2.0 -lglib-2.0 -lintl -lpango-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lharfbuzz -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstrtp-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gobject-2.0, glib-2.0, gmodule-2.0, pango, pangocairo - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrspng.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrspng.pc deleted file mode 100644 index d824c8415..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrspng.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstrspng -Description: GStreamer Rust PNG encoder/decoder -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstrspng -Cflags: -Libs.private: -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-video-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsrtp.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsrtp.pc deleted file mode 100644 index d7be3a15c..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsrtp.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstrsrtp -Description: GStreamer Rust RTP Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstrsrtp -Cflags: -Libs.private: -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstnet-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstrtp-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-rtp-1.0, gstreamer-net-1.0, gstreamer-video-1.0 gobject-2.0, glib-2.0, gmodule-2.0, gio-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsrtsp.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsrtsp.pc deleted file mode 100644 index 42e8f1818..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsrtsp.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstrsrtsp -Description: GStreamer RTSP Client Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstrsrtsp -Cflags: -Libs.private: -lgstpbutils-1.0 -lgstvideo-1.0 -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstapp-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstnet-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-net-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrstracers.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrstracers.pc deleted file mode 100644 index f5674318a..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrstracers.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstrstracers -Description: GStreamer Rust tracers plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstrstracers -Cflags: -Libs.private: -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsvideofx.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsvideofx.pc deleted file mode 100644 index 77048a43a..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrsvideofx.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstrsvideofx -Description: GStreamer Rust Video Effects Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstrsvideofx -Cflags: -Libs.private: -lcairo-gobject -lcairo -lgobject-2.0 -lglib-2.0 -lintl -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gstreamer-video-1.0, gobject-2.0, glib-2.0, cairo-gobject - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrswebrtc.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrswebrtc.pc deleted file mode 100644 index 525a2f524..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstrswebrtc.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstrswebrtc -Description: GStreamer plugin for high level WebRTC elements and a simple signaling server -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstrswebrtc -Cflags: -Libs.private: -lgstnet-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstpbutils-1.0 -lgstvideo-1.0 -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstwebrtc-1.0 -lgstsdp-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstsdp-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstapp-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstrtp-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lbcrypt -ladvapi32 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-rtp-1.0 >= 1.20, gstreamer-webrtc-1.0 >= 1.20, gstreamer-1.0 >= 1.20, gstreamer-app-1.0 >= 1.20, gstreamer-video-1.0 >= 1.20, gstreamer-sdp-1.0 >= 1.20, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstspeechmatics.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstspeechmatics.pc deleted file mode 100644 index c991cd528..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstspeechmatics.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstspeechmatics -Description: GStreamer Speechmatics plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstspeechmatics -Cflags: -Libs.private: -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lbcrypt -ladvapi32 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gststreamgrouper.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gststreamgrouper.pc deleted file mode 100644 index 4cba88faf..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gststreamgrouper.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gststreamgrouper -Description: Filter element that makes all the incoming streams share a group-id -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgststreamgrouper -Cflags: -Libs.private: -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsttextahead.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsttextahead.pc deleted file mode 100644 index 67836656d..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsttextahead.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gsttextahead -Description: GStreamer Plugin for displaying upcoming text buffers ahead of time -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgsttextahead -Cflags: -Libs.private: -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsttextwrap.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsttextwrap.pc deleted file mode 100644 index f2bc6a06a..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsttextwrap.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gsttextwrap -Description: GStreamer Text Wrap Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgsttextwrap -Cflags: -Libs.private: -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstthreadshare.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstthreadshare.pc deleted file mode 100644 index 9c208580e..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstthreadshare.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstthreadshare -Description: GStreamer Threadshare Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstthreadshare -Cflags: -Libs.private: -lgstnet-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-net-1.0, gstreamer-rtp-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsttogglerecord.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsttogglerecord.pc deleted file mode 100644 index 5b37fed7e..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsttogglerecord.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gsttogglerecord -Description: GStreamer Toggle Record Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgsttogglerecord -Cflags: -Libs.private: -lgstvideo-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-audio-1.0, gstreamer-video-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsturiplaylistbin.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsturiplaylistbin.pc deleted file mode 100644 index de5d9ced1..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gsturiplaylistbin.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gsturiplaylistbin -Description: GStreamer Playlist Playback Plugin -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgsturiplaylistbin -Cflags: -Libs.private: -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gobject-2.0, glib-2.0, gmodule-2.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstwebrtchttp.pc b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstwebrtchttp.pc deleted file mode 100644 index 6bc030959..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/lib/gstreamer-1.0/pkgconfig/gstwebrtchttp.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=${pcfiledir}/../../.. -exec_prefix=${prefix} -libdir=${prefix}/lib -includedir=${prefix}/include - -Name: gstwebrtchttp -Description: GStreamer WebRTC Plugin for WebRTC HTTP protocols (WHIP/WHEP) -Version: 0.15.2 -Libs: -L${libdir}/gstreamer-1.0 -lgstwebrtchttp -Cflags: -Libs.private: -lgstwebrtc-1.0 -lgstsdp-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgstsdp-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lbcrypt -ladvapi32 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -lgobject-2.0 -lglib-2.0 -lintl -llegacy_stdio_definitions -lkernel32 -lntdll -luserenv -lws2_32 -ldbghelp -Requires.private: gstrsworkspace, gstreamer-1.0, gstreamer-base-1.0, gobject-2.0, glib-2.0, gstreamer-sdp-1.0, gstreamer-webrtc-1.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/libexec/gstreamer-1.0/gst-plugin-scanner.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/libexec/gstreamer-1.0/gst-plugin-scanner.exe deleted file mode 100644 index 3dc07a298..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/libexec/gstreamer-1.0/gst-plugin-scanner.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/libexec/gstreamer-1.0/gst-ptp-helper.exe b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/libexec/gstreamer-1.0/gst-ptp-helper.exe deleted file mode 100644 index 9194b1603..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/libexec/gstreamer-1.0/gst-ptp-helper.exe and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/gschema.dtd b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/gschema.dtd deleted file mode 100644 index 9d7482db7..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/gschema.dtd +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/gschemas.compiled b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/gschemas.compiled deleted file mode 100644 index b369f2b28..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/gschemas.compiled and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.Demo4.gschema.xml b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.Demo4.gschema.xml deleted file mode 100644 index 3eaa6e8b4..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.Demo4.gschema.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - 'red' - - - (-1, -1) - - - false - - - false - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.gtk4.Inspector.gschema.xml b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.gtk4.Inspector.gschema.xml deleted file mode 100644 index 28fa5dd6e..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.gtk4.Inspector.gschema.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - false - Insert debug nodes - - If this setting is true, the recorder will insert debug nodes - into the recording. - - - - false - Record events - - If this setting is true, the recorder will include events - in the recording. - - - - false - Highlight sequences - - If this setting is true, the recorder will highlight events - that are part of an event sequence. - - - - false - Set the recorder to dark - - If this setting is true, the recorder will display render nodes - on a dark background. - - - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.gtk4.Settings.ColorChooser.gschema.xml b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.gtk4.Settings.ColorChooser.gschema.xml deleted file mode 100644 index bedc7030b..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.gtk4.Settings.ColorChooser.gschema.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - [] - Custom colors - - An array of custom colors to show in the color chooser. Each color is - specified as a tuple of four doubles, specifying RGBA values between - 0 and 1. - - - - (false,1.0,1.0,1.0,1.0) - The selected color - - The selected color, described as a tuple whose first member is a - boolean that is true if a color was selected, and the remaining - four members are four doubles, specifying RGBA values between - 0 and 1. - - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.gtk4.Settings.Debug.gschema.xml b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.gtk4.Settings.Debug.gschema.xml deleted file mode 100644 index 89428d0c0..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.gtk4.Settings.Debug.gschema.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - true - Enable inspector keybinding - - If this setting is true, GTK lets the user open an interactive - debugging window with a keybinding. The default shortcuts for - the keybinding are Control-Shift-I and Control-Shift-D. - - - - true - Inspector warning - - If this setting is true, GTK shows a warning before letting - the user use the interactive debugger. - - - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.gtk4.Settings.EmojiChooser.gschema.xml b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.gtk4.Settings.EmojiChooser.gschema.xml deleted file mode 100644 index 28c0a62c0..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.gtk4.Settings.EmojiChooser.gschema.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - [] - Recently used Emoji - - An array of Emoji definitions to show in the Emoji chooser. Each Emoji is - specified as an array of codepoints, name and keywords. The extra - integer after this pair is the code of the Fitzpatrick modifier to use in - place of a modifier placeholder (0 or 0x1F3FB) in the codepoint array. - - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.gtk4.Settings.FileChooser.gschema.xml b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.gtk4.Settings.FileChooser.gschema.xml deleted file mode 100644 index f1f0e054c..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/glib-2.0/schemas/org.gtk.gtk4.Settings.FileChooser.gschema.xml +++ /dev/null @@ -1,186 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 'path-bar' - Location mode - - Controls whether the file chooser shows just a path bar, or a visible entry - for the filename as well, for the benefit of typing-oriented users. The - possible values for these modes are "path-bar" and "filename-entry". - - - - false - Show hidden files - - Controls whether the file chooser shows hidden files or not. - - - - true - Show folders first - - If set to true, then folders are shown before files in the list. - - - - false - Expand folders - This key is deprecated; do not use it. - - - true - Show file sizes - - Controls whether the file chooser shows a column with file sizes. - - - - true - Show file types - - Controls whether the file chooser shows a column with file types. - - - - 'name' - Sort column - - Can be one of "name", "modified", or "size". It controls - which of the columns in the file chooser is used for sorting - the list of files. - - - - 'ascending' - Sort order - - Can be one of the strings "ascending" or "descending". - - - - (-1, -1) - Window position - - This key is ignored. - - - - (-1, -1) - Window size - - The size (width, height) of the GtkFileChooserDialog's window, in pixels. - - - - 'recent' - Startup mode - - Either "recent" or "cwd"; controls whether the file chooser - starts up showing the list of recently-used files, or the - contents of the current working directory. - - - - -1 - Sidebar width - - Width in pixels of the file chooser's places sidebar. - - - - '24h' - Time format - - Whether the time is shown in 24h or 12h format. - - - - 'regular' - Date format - - The amount of detail to show in the Modified column. - - - - 'category' - Type format - - Different ways to show the 'Type' column information. - Example outputs for a video mp4 file: - 'mime' -> 'video/mp4' - 'description' -> 'MPEG-4 video' - 'category' -> 'Video' - - - - 'list' - View type - - Whether the files are shown in a list or in a grid. - - - - - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/adaptive_video_framerate.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/adaptive_video_framerate.scenario deleted file mode 100644 index a3043af08..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/adaptive_video_framerate.scenario +++ /dev/null @@ -1,5 +0,0 @@ -description, duration=15.0 -set-restriction, playback-time=5.0, restriction-caps="video/x-raw,framerate=(fraction)5/1" -set-restriction, playback-time=10.0, restriction-caps="video/x-raw,framerate=(fraction)30/1" -eos, playback-time=15.0 -stop, playback-time=15.0 diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/adaptive_video_framerate_size.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/adaptive_video_framerate_size.scenario deleted file mode 100644 index d5cf5963a..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/adaptive_video_framerate_size.scenario +++ /dev/null @@ -1,7 +0,0 @@ -description, duration=25.0 -set-restriction, playback-time=5.0, restriction-caps="video/x-raw,framerate=(fraction)5/1" -set-restriction, playback-time=10.0, restriction-caps="video/x-raw,height=20,width=20,framerate=(fraction)5/1" -set-restriction, playback-time=15.0, restriction-caps="video/x-raw,height=20,width=20,framerate=(fraction)30/1" -set-restriction, playback-time=20.0, restriction-caps="video/x-raw,height=720,width=1280,framerate=(fraction)30/1" -eos, playback-time=25.0 -stop, playback-time=25.0 diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/adaptive_video_size.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/adaptive_video_size.scenario deleted file mode 100644 index c3b5d2ef9..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/adaptive_video_size.scenario +++ /dev/null @@ -1,5 +0,0 @@ -description, duration=15.0 -set-restriction, playback-time=5.0, restriction-caps="video/x-raw,height=480,width=854" -set-restriction, playback-time=10.0, restriction-caps="video/x-raw,height=720,width=1280" -eos, playback-time=15.0 -stop, playback-time=15.0 diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/alternate_fast_backward_forward.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/alternate_fast_backward_forward.scenario deleted file mode 100644 index 59138982e..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/alternate_fast_backward_forward.scenario +++ /dev/null @@ -1,14 +0,0 @@ -description, duration=55.0, min-media-duration=470.0, seek=true, reverse-playback=true -include,location=includes/default-seek-flags.scenario -seek, name=backward-seek, playback-time=0.0, rate=-1.0, start=0.0, stop=310.0, flags="$(default_flags)" -seek, name=forward-seek, playback-time=305.0, rate=1.0, start=305.0, flags="$(default_flags)" -seek, name=Fast-forward-seek, playback-time=310.0, rate=2.0, start=310.0, flags="$(default_flags)" -seek, name=Fast-backward-seek, playback-time=320.0, rate=-2.0, start=0.0, stop=320.0, flags="$(default_flags)" -seek, name=Fast-forward-seek, playback-time=310.0, rate=4.0, start=310.0, flags="$(default_flags)" -seek, name=Fast-backward-seek, playback-time=330.0, rate=-4.0, start=0.0, stop=330.0, flags="$(default_flags)" -seek, name=Fast-forward-seek, playback-time=310.0, rate=8.0, start=310.0, flags="$(default_flags)" -seek, name=Fast-backward-seek, playback-time=350.0, rate=-8.0, start=0.0, stop=350.0, flags="$(default_flags)" -seek, name=Fast-forward-seek, playback-time=310.0, rate=16.0, start=310.0, flags="$(default_flags)" -seek, name=Fast-backward-seek, playback-time=390.0, rate=-16.0, start=0.0, stop=390.0, flags="$(default_flags)" -seek, name=Fast-forward-seek, playback-time=310.0, rate=32.0, start=310.0, flags="$(default_flags)" -seek, name=Fast-backward-seek, playback-time=470.0, rate=-32.0, start=310.0, stop=470.0, flags="$(default_flags)" diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/change_state_intensive.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/change_state_intensive.scenario deleted file mode 100644 index 042d6fbc1..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/change_state_intensive.scenario +++ /dev/null @@ -1,8 +0,0 @@ -description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times", need-clock-sync=true, min-media-duration=1.0, live_content_compatible=True, handles-states=true, ignore-eos=true - -foreach, i=[0, 40], - actions = { - "set-state, state=playing", - "set-state, state=null", - } -stop; diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/disable_subtitle_track_while_paused.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/disable_subtitle_track_while_paused.scenario deleted file mode 100644 index 3c679c501..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/disable_subtitle_track_while_paused.scenario +++ /dev/null @@ -1,6 +0,0 @@ -description, summary="Disable subtitle track while pipeline is PAUSED", min-subtitle-track=2, duration=5.0, handles-states=true, needs_preroll=true -pause; -switch-track, name="Disable subtitle", type=text, disable=true -wait, duration=0.5 -play; -stop, playback-time=2.0 diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/fast_backward.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/fast_backward.scenario deleted file mode 100644 index f16072d50..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/fast_backward.scenario +++ /dev/null @@ -1,9 +0,0 @@ -description, duration=30.0, minfo-media-duration=310.0, seek=true, reverse-playback=true, need-clock-sync=true, min-media-duration=310.0, ignore-eos=true -include,location=includes/default-seek-flags.scenario -seek, name=Fast-backward-seek, playback-time=0.0, rate=-2.0, start=0.0, stop=310.0, flags="$(default_flags)" -seek, name=Fast-backward-seek, playback-time=300.0, rate=-4.0, start=0.0, stop=300.0, flags="$(default_flags)" -seek, name=Fast-backward-seek, playback-time=280.0, rate=-8.0, start=0.0, stop=280.0, flags="$(default_flags)" -seek, name=Fast-backward-seek, playback-time=240.0, rate=-16.0, start=0.0, stop=240.0, flags="$(default_flags)" -seek, name=Fast-backward-seek, playback-time=160.0, rate=-32.0, start=0.0, stop=160.0, flags="$(default_flags)" -wait, message-type=eos -stop \ No newline at end of file diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/fast_forward.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/fast_forward.scenario deleted file mode 100644 index 89855a609..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/fast_forward.scenario +++ /dev/null @@ -1,8 +0,0 @@ -description, duration=25.0, seek=true, need-clock-sync=true, min-media-duration=5.0, ignore-eos=true -include,location=includes/default-seek-flags.scenario -seek, name=Fast-forward-seek, playback-time=0.0, rate=2.0, start=0.0, flags="$(default_flags)" -seek, name=Fast-forward-seek, playback-time="min(10.0, $(duration) * 0.0625)", rate=4.0, start=0.0, flags="$(default_flags)" -seek, name=Fast-forward-seek, playback-time="min(20.0, $(duration) * 0.125)", rate=8.0, start=0.0, flags="$(default_flags)" -seek, name=Fast-forward-seek, playback-time="min(40.0, $(duration) * 0.25)", rate=16.0, start=0.0, flags="$(default_flags)" -seek, name=Fast-forward-seek, playback-time="min(80.0, $(duration) * 0.50)", rate=32.0, start=0.0, flags="$(default_flags)" -stop, playback-time="min($(duration) - 0.3, 160.0)", on-message="eos" diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/force_key_unit.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/force_key_unit.scenario deleted file mode 100644 index 2a9c8394d..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/force_key_unit.scenario +++ /dev/null @@ -1,4 +0,0 @@ -description, duration=2.0 -video-request-key-unit, playback-time=1.0, direction=upstream, running_time=-1.0, all-header=true, count=1 -eos, playback-time=2.0 -stop, playback-time=2.0 diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/force_rtsp2.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/force_rtsp2.scenario deleted file mode 100644 index 0d957b6d2..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/force_rtsp2.scenario +++ /dev/null @@ -1 +0,0 @@ -set-property, target-element-factory-name="rtspsrc", property-name=default-rtsp-version, property-value=(string)"2-0" diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/pause_resume.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/pause_resume.scenario deleted file mode 100644 index 27bfc1090..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/pause_resume.scenario +++ /dev/null @@ -1,6 +0,0 @@ -description, duration=14.0, min-media-duration=7.0 -pause, name=First-pause, playback-time=1.0, duration=1.0 -pause, name=Second-pause, playback-time=3.0, duration=5.0 -pause, name=Third-pause, playback-time=5.0, duration=1.0 -eos, name=Done-testing, playback-time=7.0 -stop, playback-time=7.0 diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/play_15s.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/play_15s.scenario deleted file mode 100644 index af86cb35f..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/play_15s.scenario +++ /dev/null @@ -1,3 +0,0 @@ -description, duration=15.0 -eos, playback-time=15.0 -stop, playback-time=15.0 diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/play_5s.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/play_5s.scenario deleted file mode 100644 index 40186e8f0..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/play_5s.scenario +++ /dev/null @@ -1,3 +0,0 @@ -description, duration=5.0 -eos, playback-time=5.0 -stop, playback-time=5.0 diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/reverse_playback.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/reverse_playback.scenario deleted file mode 100644 index 90e02cdce..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/reverse_playback.scenario +++ /dev/null @@ -1,3 +0,0 @@ -description, seek=true, reverse-playback=true -include,location=includes/default-seek-flags.scenario -seek, name=Reverse-seek, playback-time=0.0, rate=-1.0, start="max($(duration) - 15.0, 0.0)", stop="$(duration)", flags="$(default_flags)" diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/scrub_backward_seeking.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/scrub_backward_seeking.scenario deleted file mode 100644 index 3a8ff4784..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/scrub_backward_seeking.scenario +++ /dev/null @@ -1,8 +0,0 @@ -description, seek=true, handles-states=true, needs_preroll=true -include,location=includes/default-seek-flags.scenario -pause, playback-time=0.0 -seek, playback-time=0.0, start="$(duration) - 0.5", flags="$(default_flags)" -seek, playback-time=0.0, start=position-0.1, repeat="min(10, ($(duration) - 0.6))/0.1", flags="$(default_flags)" -play, playback-time=0.0 -stop, playback-time=1.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/scrub_backward_seeking_full.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/scrub_backward_seeking_full.scenario deleted file mode 100644 index 7cb1f7abe..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/scrub_backward_seeking_full.scenario +++ /dev/null @@ -1,8 +0,0 @@ -description, seek=true, handles-states=true, needs_preroll=true -include,location=includes/default-seek-flags.scenario -pause, playback-time=0.0 -seek, playback-time=0.0, start="$(duration) - 0.5", flags="$(default_flags)" -seek, playback-time=0.0, start=position-0.1, repeat="($(duration) - 0.6)/0.1", flags="$(default_flags)" -play, playback-time=0.0 -stop, playback-time=1.0 - diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/scrub_forward_seeking.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/scrub_forward_seeking.scenario deleted file mode 100644 index 814dce4fe..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/scrub_forward_seeking.scenario +++ /dev/null @@ -1,6 +0,0 @@ -description, seek=true, handles-states=true, needs_preroll=true -include,location=includes/default-seek-flags.scenario -pause, playback-time=0.0 -seek, playback-time=0.0, start=position+0.1, repeat="min(10, ($(duration) - 0.5) / 0.1)", flags="$(default_flags)" -play, playback-time=0.0 -stop, playback-time=1.0 diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/scrub_forward_seeking_full.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/scrub_forward_seeking_full.scenario deleted file mode 100644 index d83c8b1e9..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/scrub_forward_seeking_full.scenario +++ /dev/null @@ -1,6 +0,0 @@ -description, seek=true, handles-states=true, needs_preroll=true -include,location=includes/default-seek-flags.scenario -pause, playback-time=0.0 -seek, playback-time=0.0, start=position+0.1, repeat="($(duration) - 0.5)/0.1", flags="$(default_flags)" -play, playback-time=0.0 -stop, playback-time=1.0 diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/seek_backward.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/seek_backward.scenario deleted file mode 100644 index 66c9cd3dd..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/seek_backward.scenario +++ /dev/null @@ -1,6 +0,0 @@ -description, seek=true, duration=30, need-clock-sync=true, ignore-eos=true -include,location=includes/default-seek-flags.scenario -seek, name=Backward-seek, playback-time="min(5.0, ($(duration) / 4))", rate=1.0, start=0.0, flags="$(default_flags)" -seek, name=Backward-seek, playback-time="min(10.0, 2*($(duration) / 4))", rate=1.0, start="min(5.0, $(duration) / 4)", flags="$(default_flags)" -seek, name=Backward-seek, playback-time="min(15.0, 3*($(duration) / 4))", rate=1.0, start="min(10.0, 2*($(duration) / 4))", flags="$(default_flags)" -stop, playback-time="min(15.0, 3*($(duration) / 4))" diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/seek_forward.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/seek_forward.scenario deleted file mode 100644 index 9949e4149..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/seek_forward.scenario +++ /dev/null @@ -1,6 +0,0 @@ -description, seek=true, duration=20, need-clock-sync=true, ignore-eos=true -include,location=includes/default-seek-flags.scenario -seek, name=First-forward-seek, playback-time="min(5.0, ($(duration)/8))", start="min(10, 2*($(duration)/8))", flags="$(default_flags)" -seek, name=Second-forward-seek, playback-time="min(15.0, 3*($(duration)/8))", start="min(20, 4*($(duration)/8))", flags="$(default_flags)" -seek, name=Third-forward-seek, playback-time="min(25, 5*($(duration)/8))", start="min(30.0, 6*($(duration)/8))", flags="$(default_flags)" -stop, playback-time="min($(duration) - 1, 35)", on-message=eos \ No newline at end of file diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/seek_forward_backward.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/seek_forward_backward.scenario deleted file mode 100644 index 4b669aff7..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/seek_forward_backward.scenario +++ /dev/null @@ -1,10 +0,0 @@ -description, seek=true, duration=40, min-media-duration=45.0 -include,location=includes/default-seek-flags.scenario -seek, name=Forward-seek, playback-time=0.0, rate=1.0, start=5.0, flags="$(default_flags)" -seek, name=Backward-seek, playback-time=10.0, rate=1.0, start=0.0, flags="$(default_flags)" -seek, name=Backward-seek, playback-time=5.0, rate=1.0, start=25.0, stop=-1, flags="$(default_flags)" -seek, name=Backward-seek, playback-time=30.0, rate=1.0, start=0.0, flags="$(default_flags)" -seek, name=Forward-seek, playback-time=5.0, rate=1.0, start=15.0, flags="$(default_flags)" -seek, name=Forward-seek, playback-time=20.0, rate=1.0, start=35.0, flags="$(default_flags)" -seek, name=Backward-seek, playback-time=40.0, rate=1.0, start=25.0, flags="$(default_flags)" -seek, name=Last-backward-seek, playback-time=30.0, rate=1.0, start=5.0, stop=10.0, flags="$(default_flags)" diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/seek_with_stop.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/seek_with_stop.scenario deleted file mode 100644 index b4b7e3f60..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/seek_with_stop.scenario +++ /dev/null @@ -1,3 +0,0 @@ -description, seek=true, duration=5.0, need_clock_sync=true, min-media-duration=2 -include,location=includes/default-seek-flags.scenario -seek, playback-time=1.0, start=0.0, stop="min(5.0, duration-1.0)", flags="$(default_flags)" diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/simple_seeks.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/simple_seeks.scenario deleted file mode 100644 index ca41f6ca2..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/simple_seeks.scenario +++ /dev/null @@ -1,5 +0,0 @@ -description, seek=true, duration=5.0 -include,location=includes/default-seek-flags.scenario -seek, playback-time=1.0, rate=1.0, start=2.0, flags="$(default_flags)" -seek, playback-time=3.0, rate=1.0, start=0.0, flags="$(default_flags)" -seek, playback-time=1.0, rate=1.0, start=2.0, stop=3.0, flags="$(default_flags)" diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/switch_audio_track.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/switch_audio_track.scenario deleted file mode 100644 index b1a968b66..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/switch_audio_track.scenario +++ /dev/null @@ -1,3 +0,0 @@ -description, summary="Change audio track at 5 second to the second audio track", min-audio-track=2, duration=10.0, min-media-duration=5.1 -switch-track, name=Next-audio-track, playback-time=5.0, type=audio, index=(string)+1 -stop, playback-time=10.0 diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/switch_audio_track_while_paused.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/switch_audio_track_while_paused.scenario deleted file mode 100644 index fd4c36249..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/switch_audio_track_while_paused.scenario +++ /dev/null @@ -1,11 +0,0 @@ -description, summary="Change audio track while pipeline is paused", min-audio-track=2, duration=6.0, need-clock-sync=true, needs_preroll=true -pause, playback-time=1.0; - -# Wait so that humans can see the pipeline is paused -wait, duration=0.5 -switch-track, name=Next-audio-track, type=audio, index=(string)+1 - -# Wait so that humans can see the pipeline is paused -wait, duration=0.5 -play; -stop, playback-time=5.0 diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/switch_subtitle_track.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/switch_subtitle_track.scenario deleted file mode 100644 index 216e7ce91..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/switch_subtitle_track.scenario +++ /dev/null @@ -1,3 +0,0 @@ -description, summary="Change subtitle track at 1 second while playing back", min-subtitle-track=2, duration=5.0, need-clock-sync=true -switch-track, playback-time=1.0, type=text, index=(string)+1 -stop, playback-time=5.0 diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/switch_subtitle_track_while_paused.scenario b/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/switch_subtitle_track_while_paused.scenario deleted file mode 100644 index 611914256..000000000 --- a/opennow-stable/native/opennow-streamer/bin/win32-x64/gstreamer/share/gstreamer-1.0/validate/scenarios/switch_subtitle_track_while_paused.scenario +++ /dev/null @@ -1,7 +0,0 @@ -description, summary="Change subtitle track while pipeline is PAUSED", min-subtitle-track=2, duration=5.0, handles-states=true, need-clock-sync=true, needs_preroll=true -pause; -wait, duration=0.5 -switch-track, type=text, index=(string)+1 -wait, duration=0.5 -play; -stop, playback-time=5.0 diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/gthread-2.0-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/gthread-2.0-0.dll deleted file mode 100644 index e13a20a88..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/gthread-2.0-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/intl-8.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/intl-8.dll deleted file mode 100644 index d37f3a60f..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/intl-8.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/msvcp140.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/msvcp140.dll deleted file mode 100644 index 5153fb087..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/msvcp140.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/msvcp140_1.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/msvcp140_1.dll deleted file mode 100644 index fe6169ee5..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/msvcp140_1.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/msvcp140_2.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/msvcp140_2.dll deleted file mode 100644 index 967be8237..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/msvcp140_2.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/msvcp140_atomic_wait.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/msvcp140_atomic_wait.dll deleted file mode 100644 index 01f8e9a36..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/msvcp140_atomic_wait.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/msvcp140_codecvt_ids.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/msvcp140_codecvt_ids.dll deleted file mode 100644 index 63214b8a8..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/msvcp140_codecvt_ids.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/orc-0.4-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/orc-0.4-0.dll deleted file mode 100644 index 5270f9f69..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/orc-0.4-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/pcre2-8-0.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/pcre2-8-0.dll deleted file mode 100644 index 092953e23..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/pcre2-8-0.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/vcruntime140.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/vcruntime140.dll deleted file mode 100644 index c2f509d20..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/vcruntime140.dll and /dev/null differ diff --git a/opennow-stable/native/opennow-streamer/bin/win32-x64/vcruntime140_1.dll b/opennow-stable/native/opennow-streamer/bin/win32-x64/vcruntime140_1.dll deleted file mode 100644 index 64cd24630..000000000 Binary files a/opennow-stable/native/opennow-streamer/bin/win32-x64/vcruntime140_1.dll and /dev/null differ diff --git a/opennow-stable/package.json b/opennow-stable/package.json index 954c4d572..1cae405dd 100644 --- a/opennow-stable/package.json +++ b/opennow-stable/package.json @@ -26,7 +26,7 @@ "preview": "electron-vite preview", "dist": "npm run build && npm run native:build && cross-env CSC_IDENTITY_AUTO_DISCOVERY=false electron-builder", "dist:signed": "npm run build && npm run native:build && electron-builder", - "native:check": "cargo check --manifest-path ../native/opennow-streamer/Cargo.toml", + "native:check": "cargo check --manifest-path ../native/opennow-streamer/Cargo.toml --workspace", "native:build": "node scripts/build-native-streamer.mjs", "lint": "oxlint src", "locales:check": "node scripts/check-translations.mjs", @@ -113,6 +113,10 @@ "package.json" ], "extraResources": [ + { + "from": "../THIRD_PARTY_NOTICES", + "to": "THIRD_PARTY_NOTICES" + }, { "from": "../native/opennow-streamer/bin", "to": "native/opennow-streamer", @@ -174,27 +178,6 @@ "category": "Game", "maintainer": "zortos293 ", "artifactName": "OpenNOW-v${version}-linux-${arch}.${ext}" - }, - "deb": { - "depends": [ - "libgstreamer1.0-0", - "libgstreamer-plugins-base1.0-0", - "gstreamer1.0-tools", - "gstreamer1.0-libav", - "gstreamer1.0-plugins-base", - "gstreamer1.0-plugins-good", - "gstreamer1.0-plugins-bad", - "gstreamer1.0-plugins-ugly", - "gstreamer1.0-nice", - "gstreamer1.0-vaapi", - "gstreamer1.0-gl", - "gstreamer1.0-x", - "gstreamer1.0-alsa", - "libva2", - "libva-drm2", - "libvulkan1", - "mesa-vulkan-drivers" - ] } } } diff --git a/opennow-stable/scripts/build-native-streamer-config.mjs b/opennow-stable/scripts/build-native-streamer-config.mjs new file mode 100644 index 000000000..e8177f306 --- /dev/null +++ b/opennow-stable/scripts/build-native-streamer-config.mjs @@ -0,0 +1,27 @@ +export function nativeStreamerCargoArgs({ + manifestPath, + nativeTarget, + platformKey, + enableLinuxVaapi = false, + enableLinuxFfmpeg = true, +}) { + const args = [ + "build", + "--locked", + "--release", + "--package", + "opennow-streamer", + "--manifest-path", + manifestPath, + ]; + if (platformKey.startsWith("linux-")) { + const features = []; + if (enableLinuxVaapi) features.push("linux-vaapi"); + if (enableLinuxFfmpeg) features.push("linux-ffmpeg-bundled"); + if (features.length > 0) args.push("--features", features.join(",")); + } + if (nativeTarget) { + args.push("--target", nativeTarget); + } + return args; +} diff --git a/opennow-stable/scripts/build-native-streamer-config.test.mjs b/opennow-stable/scripts/build-native-streamer-config.test.mjs new file mode 100644 index 000000000..4548c240b --- /dev/null +++ b/opennow-stable/scripts/build-native-streamer-config.test.mjs @@ -0,0 +1,89 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import { nativeStreamerCargoArgs } from "./build-native-streamer-config.mjs"; + +const common = [ + "build", + "--locked", + "--release", + "--package", + "opennow-streamer", + "--manifest-path", + "/workspace/Cargo.toml", +]; + +test("production Linux build bundles FFmpeg for both architectures", () => { + for (const [platformKey, nativeTarget] of [ + ["linux-x64", "x86_64-unknown-linux-gnu"], + ["linux-arm64", "aarch64-unknown-linux-gnu"], + ]) { + assert.deepEqual( + nativeStreamerCargoArgs({ + manifestPath: "/workspace/Cargo.toml", + nativeTarget, + platformKey, + }), + [...common, "--features", "linux-ffmpeg-bundled", "--target", nativeTarget], + ); + } +}); + +test("non-Linux production build snapshot does not enable Linux VA-API", () => { + assert.deepEqual( + nativeStreamerCargoArgs({ + manifestPath: "/workspace/Cargo.toml", + nativeTarget: "x86_64-pc-windows-msvc", + platformKey: "win32-x64", + }), + [...common, "--target", "x86_64-pc-windows-msvc"], + ); +}); + +test("host Linux production build bundles FFmpeg without a target", () => { + assert.deepEqual( + nativeStreamerCargoArgs({ + manifestPath: "/workspace/Cargo.toml", + nativeTarget: "", + platformKey: "linux-x64", + }), + [...common, "--features", "linux-ffmpeg-bundled"], + ); +}); + +test("Linux production build can explicitly enable VA-API", () => { + assert.deepEqual( + nativeStreamerCargoArgs({ + manifestPath: "/workspace/Cargo.toml", + nativeTarget: "", + platformKey: "linux-x64", + enableLinuxVaapi: true, + }), + [...common, "--features", "linux-vaapi,linux-ffmpeg-bundled"], + ); +}); + +test("Linux production build can explicitly disable FFmpeg", () => { + assert.deepEqual( + nativeStreamerCargoArgs({ + manifestPath: "/workspace/Cargo.toml", + nativeTarget: "", + platformKey: "linux-x64", + enableLinuxFfmpeg: false, + }), + common, + ); +}); + +test("Linux production build can disable every optional decoder", () => { + assert.deepEqual( + nativeStreamerCargoArgs({ + manifestPath: "/workspace/Cargo.toml", + nativeTarget: "", + platformKey: "linux-x64", + enableLinuxVaapi: false, + enableLinuxFfmpeg: false, + }), + common, + ); +}); diff --git a/opennow-stable/scripts/build-native-streamer.mjs b/opennow-stable/scripts/build-native-streamer.mjs index cf19c93ff..0058a0a72 100644 --- a/opennow-stable/scripts/build-native-streamer.mjs +++ b/opennow-stable/scripts/build-native-streamer.mjs @@ -1,533 +1,172 @@ -import { copyFileSync, chmodSync, existsSync, mkdirSync, readFileSync, statSync } from "node:fs"; -import { delimiter, dirname, join, resolve } from "node:path"; +import { + chmodSync, + copyFileSync, + existsSync, + mkdirSync, + readFileSync, + renameSync, + rmSync, +} from "node:fs"; +import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { spawnSync } from "node:child_process"; -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); +import { nativeStreamerCargoArgs } from "./build-native-streamer-config.mjs"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); const packageRoot = resolve(__dirname, ".."); const repoRoot = resolve(packageRoot, ".."); -const crateRoot = join(repoRoot, "native", "opennow-streamer"); -const manifestPath = join(crateRoot, "Cargo.toml"); -const protocolSourcePath = join(crateRoot, "src", "protocol.rs"); +const workspaceRoot = join(repoRoot, "native", "opennow-streamer"); +const manifestPath = join(workspaceRoot, "Cargo.toml"); +const protocolSourcePath = join( + workspaceRoot, + "crates", + "opennow-streamer-protocol", + "src", + "lib.rs", +); const appProtocolSourcePath = join(packageRoot, "src", "shared", "nativeStreamer.ts"); -const exeName = process.platform === "win32" ? "opennow-streamer.exe" : "opennow-streamer"; -const verifyCommandId = "verify"; -const nativeStreamerProtocolVersion = readVerifiedNativeStreamerProtocolVersion(); const nativeTarget = process.env.OPENNOW_NATIVE_STREAMER_TARGET?.trim() || ""; -const platformKey = process.env.OPENNOW_NATIVE_STREAMER_PLATFORM_KEY?.trim() || `${process.platform}-${process.arch}`; -const targetReleaseDir = nativeTarget - ? join(crateRoot, "target", nativeTarget, "release") - : join(crateRoot, "target", "release"); -const builtBinary = join(targetReleaseDir, exeName); -const packageBinaryDir = join(crateRoot, "bin"); -const packageBinary = join(packageBinaryDir, exeName); -const packagePlatformBinaryDir = join(packageBinaryDir, platformKey); -const packagePlatformBinary = join(packagePlatformBinaryDir, exeName); - -function hasFeature(features, feature) { - return features - .split(/[,\s]+/) - .map((value) => value.trim().toLowerCase()) - .filter(Boolean) - .includes(feature); -} - -function readProtocolVersion(sourcePath, pattern, label) { - const source = readFileSync(sourcePath, "utf8"); - const match = source.match(pattern); - if (!match) { - throw new Error(`Unable to read ${label} protocol version from ${sourcePath}`); - } +const platformKey = process.env.OPENNOW_NATIVE_STREAMER_PLATFORM_KEY?.trim() + || `${process.platform}-${process.arch}`; +// Production Linux media libraries are statically bundled. VA-API remains an +// opt-in developer backend because linking host libva would make the binary +// distro-dependent; Vulkan Video and NVDEC cover the packaged GPU paths. +const enableLinuxVaapi = process.env.OPENNOW_NATIVE_LINUX_VAAPI === "1"; +const enableLinuxFfmpeg = process.env.OPENNOW_NATIVE_LINUX_FFMPEG !== "0"; +const exeName = platformKey.startsWith("win32-") ? "opennow-streamer.exe" : "opennow-streamer"; +const releaseDir = nativeTarget + ? join(workspaceRoot, "target", nativeTarget, "release") + : join(workspaceRoot, "target", "release"); +const builtBinary = join(releaseDir, exeName); +const binRoot = join(workspaceRoot, "bin"); +const platformBinary = join(binRoot, platformKey, exeName); +rmSync(join(binRoot, exeName), { force: true }); + +function readVersion(path, pattern, label) { + const match = readFileSync(path, "utf8").match(pattern); + if (!match) throw new Error(`Unable to read ${label} protocol version from ${path}`); return Number.parseInt(match[1], 10); } -function readVerifiedNativeStreamerProtocolVersion() { - const appProtocolVersion = readProtocolVersion( - appProtocolSourcePath, - /export\s+const\s+NATIVE_STREAMER_PROTOCOL_VERSION\s*=\s*(\d+)\s*;/, - "app", - ); - const nativeProtocolVersion = readProtocolVersion( - protocolSourcePath, - /pub\s+const\s+PROTOCOL_VERSION\s*:\s*u64\s*=\s*(\d+)\s*;/, - "native", - ); - - if (appProtocolVersion !== nativeProtocolVersion) { - throw new Error( - `Native streamer protocol mismatch: app sends ${appProtocolVersion} from ${appProtocolSourcePath}, ` - + `native expects ${nativeProtocolVersion} from ${protocolSourcePath}.`, - ); - } - - return appProtocolVersion; -} - -function isWindowsBuild() { - return process.platform === "win32" || /windows-msvc$/i.test(nativeTarget); -} - -function isDarwinBuild() { - return process.platform === "darwin" || /apple-darwin$/i.test(nativeTarget); -} - -function shouldBundlePrivateGstreamerRuntime(nativeFeatures) { - if (!hasFeature(nativeFeatures, "gstreamer")) { - return false; - } - if (!isWindowsBuild() && !isDarwinBuild()) { - return false; - } - - const override = process.env.OPENNOW_BUNDLE_GSTREAMER_RUNTIME?.trim(); - if (override === "0") { - return false; - } - if (override === "1") { - return true; - } - return true; -} - -function prependEnvPath(env, directory) { - const pathKey = Object.keys(env).find((key) => key.toLowerCase() === "path") || "PATH"; - env[pathKey] = env[pathKey] ? `${directory}${delimiter}${env[pathKey]}` : directory; -} - -function appendEnvValue(env, key, value) { - env[key] = env[key]?.trim() ? `${env[key]} ${value}` : value; -} - -function configureDarwinLinkerPadding(env, nativeFeatures) { - if (!isDarwinBuild() || !shouldBundlePrivateGstreamerRuntime(nativeFeatures)) { - return; - } - appendEnvValue(env, "RUSTFLAGS", "-C link-arg=-Wl,-headerpad_max_install_names"); -} - -function brewPrefix() { - const result = spawnSync("brew", ["--prefix"], { encoding: "utf8" }); - return result.status === 0 ? result.stdout.trim() || null : null; -} - -function brewPrefixForPackage(packageName) { - const result = spawnSync("brew", ["--prefix", packageName], { encoding: "utf8" }); - return result.status === 0 ? result.stdout.trim() || null : null; -} - -function configuredCandidate(root, source) { - return root ? { root, source } : null; -} - -function existingConfiguredCandidates(candidates) { - return candidates.filter(Boolean); -} - -function formatCandidateSources(candidates) { - return candidates.map((candidate) => candidate.source).join(", ") || "none"; -} - -function configureGstreamerPluginDiscovery(env, sdkRoot) { - const pluginDir = join(sdkRoot, "lib", "gstreamer-1.0"); - const scanner = join( - sdkRoot, - "libexec", - "gstreamer-1.0", - process.platform === "win32" ? "gst-plugin-scanner.exe" : "gst-plugin-scanner", - ); - - if (isExistingDirectory(pluginDir)) { - env.GST_PLUGIN_PATH = pluginDir; - env.GST_PLUGIN_PATH_1_0 = pluginDir; - env.GST_PLUGIN_SYSTEM_PATH = pluginDir; - env.GST_PLUGIN_SYSTEM_PATH_1_0 = pluginDir; - } - if (isExistingFile(scanner)) { - env.GST_PLUGIN_SCANNER = scanner; - env.GST_PLUGIN_SCANNER_1_0 = scanner; - } - env.GST_REGISTRY_REUSE_PLUGIN_SCANNER = "no"; -} - -function configureGstreamerSdk(env) { - if (process.platform === "win32") { - const candidates = existingConfiguredCandidates([ - configuredCandidate(env.GSTREAMER_1_0_ROOT_MSVC_X86_64, "GSTREAMER_1_0_ROOT_MSVC_X86_64"), - configuredCandidate("C:\\Program Files\\gstreamer\\1.0\\msvc_x86_64", "default Program Files"), - configuredCandidate("C:\\gstreamer\\1.0\\msvc_x86_64", "default C drive"), - ]); - const sdk = candidates - .map((candidate) => { - const pkgConfigFile = join(candidate.root, "lib", "pkgconfig", "gstreamer-1.0.pc"); - const pkgConfigBinary = ["pkg-config.exe", "pkgconf.exe"] - .map((name) => join(candidate.root, "bin", name)) - .find((path) => existsSync(path)); - return { ...candidate, pkgConfigBinary, pkgConfigFile }; - }) - .find((candidate) => candidate.pkgConfigBinary && existsSync(candidate.pkgConfigFile)); - if (!sdk) { - console.warn( - [ - "GStreamer SDK was not found automatically; relying on the current PKG_CONFIG environment.", - `Checked ${candidates.length} candidate source(s): ${formatCandidateSources(candidates)}.`, - "Expected relative files: bin/pkg-config.exe or bin/pkgconf.exe, and lib/pkgconfig/gstreamer-1.0.pc.", - ].join(" "), - ); - return null; - } - const pkgConfigDir = join(sdk.root, "lib", "pkgconfig"); - env.PKG_CONFIG = sdk.pkgConfigBinary; - env.PKG_CONFIG_PATH = env.PKG_CONFIG_PATH ? `${pkgConfigDir}${delimiter}${env.PKG_CONFIG_PATH}` : pkgConfigDir; - prependEnvPath(env, join(sdk.root, "bin")); - // The Windows MSI supports a custom INSTALLDIR, but a native executable outside - // the SDK cannot reliably infer that relocated plugin directory from its own path. - configureGstreamerPluginDiscovery(env, sdk.root); - console.log(`Configured GStreamer SDK from ${sdk.source}.`); - console.log("Configured pkg-config executable for GStreamer SDK."); - return sdk.root; - } - - if (process.platform === "darwin") { - const homebrewRoot = brewPrefix(); - const homebrewGStreamerRoot = brewPrefixForPackage("gstreamer"); - const candidates = existingConfiguredCandidates([ - configuredCandidate(env.GSTREAMER_1_0_ROOT_MACOS, "GSTREAMER_1_0_ROOT_MACOS"), - configuredCandidate("/Library/Frameworks/GStreamer.framework/Versions/1.0", "GStreamer framework version 1.0"), - configuredCandidate("/Library/Frameworks/GStreamer.framework/Versions/Current", "GStreamer framework current"), - configuredCandidate(homebrewGStreamerRoot, "Homebrew gstreamer prefix"), - configuredCandidate(homebrewRoot && join(homebrewRoot, "opt", "gstreamer"), "Homebrew opt gstreamer"), - configuredCandidate(homebrewRoot, "Homebrew prefix"), - configuredCandidate("/opt/homebrew", "default Homebrew Apple Silicon prefix"), - configuredCandidate("/usr/local", "default Homebrew Intel prefix"), - ]); - const sdk = candidates.find((candidate) => - existsSync(join(candidate.root, "lib", "pkgconfig", "gstreamer-1.0.pc")) - && existsSync(join(candidate.root, "lib", "libgstreamer-1.0.dylib")), - ); - if (!sdk) { - console.warn( - [ - "GStreamer macOS SDK was not found automatically; relying on the current PKG_CONFIG environment.", - `Checked ${candidates.length} candidate source(s): ${formatCandidateSources(candidates)}.`, - "Expected relative files: lib/pkgconfig/gstreamer-1.0.pc and lib/libgstreamer-1.0.dylib.", - ].join(" "), - ); - return null; - } - const sdkRoot = sdk.root; - const pkgConfigDir = join(sdkRoot, "lib", "pkgconfig"); - env.GSTREAMER_1_0_ROOT_MACOS = sdkRoot; - env.PKG_CONFIG_PATH = env.PKG_CONFIG_PATH ? `${pkgConfigDir}${delimiter}${env.PKG_CONFIG_PATH}` : pkgConfigDir; - prependEnvPath(env, join(sdkRoot, "bin")); - env.DYLD_LIBRARY_PATH = env.DYLD_LIBRARY_PATH ? `${join(sdkRoot, "lib")}${delimiter}${env.DYLD_LIBRARY_PATH}` : join(sdkRoot, "lib"); - env.DYLD_FALLBACK_LIBRARY_PATH = env.DYLD_FALLBACK_LIBRARY_PATH ? `${join(sdkRoot, "lib")}${delimiter}${env.DYLD_FALLBACK_LIBRARY_PATH}` : join(sdkRoot, "lib"); - if (/apple-darwin$/.test(nativeTarget)) { - env.PKG_CONFIG_ALLOW_CROSS = "1"; - env.PKG_CONFIG_SYSROOT_DIR = env.PKG_CONFIG_SYSROOT_DIR || "/"; - } - console.log(`Configured GStreamer SDK from ${sdk.source}.`); - return sdkRoot; - } - - return null; -} - -function bundleGstreamerRuntime(sdkRoot, nativeFeatures) { - if (!shouldBundlePrivateGstreamerRuntime(nativeFeatures)) { - return false; - } - - const args = [ - join(__dirname, "bundle-gstreamer-runtime.mjs"), - "--dest", - join(packagePlatformBinaryDir, "gstreamer"), - ]; - - if (sdkRoot) { - args.push("--sdk-root", sdkRoot); - } - args.push("--binary", packagePlatformBinary); - - const result = spawnSync(process.execPath, args, { - cwd: packageRoot, - stdio: "inherit", - env: process.env, - }); - - if (result.status !== 0) { - process.exit(result.status ?? 1); - } - - if (process.platform === "win32") { - injectWindowsVulkanPlugins(join(packagePlatformBinaryDir, "gstreamer")); - } - - return true; -} - -function injectWindowsVulkanPlugins(runtimeRoot) { - const result = spawnSync( - process.execPath, - [join(__dirname, "inject-gstreamer-vulkan-windows.mjs"), "--dest", runtimeRoot], - { - cwd: packageRoot, - stdio: "inherit", - env: process.env, - }, +const appProtocolVersion = readVersion( + appProtocolSourcePath, + /export\s+const\s+NATIVE_STREAMER_PROTOCOL_VERSION\s*=\s*(\d+)\s*;/, + "app", +); +const nativeProtocolVersion = readVersion( + protocolSourcePath, + /pub\s+const\s+PROTOCOL_VERSION\s*:\s*u64\s*=\s*(\d+)\s*;/, + "native", +); +if (appProtocolVersion !== nativeProtocolVersion) { + throw new Error( + `Native streamer protocol mismatch: app sends ${appProtocolVersion}, native expects ${nativeProtocolVersion}.`, ); - if (result.status !== 0) { - process.exit(result.status ?? 1); - } } -function isExistingFile(path) { - try { - return existsSync(path) && statSync(path).isFile(); - } catch { - return false; - } -} +const cargoArgs = nativeStreamerCargoArgs({ + manifestPath, + nativeTarget, + platformKey, + enableLinuxVaapi, + enableLinuxFfmpeg, +}); -function isExistingDirectory(path) { +const cargoEnvironment = { + ...process.env, + ...(platformKey.startsWith("linux-") + ? { + // cc-rs would otherwise add a dynamic libstdc++ for OpenH264. The + // executable build script links the same runtime statically. + CXXSTDLIB: "", + } + : {}), +}; + +const build = spawnSync("cargo", cargoArgs, { + cwd: workspaceRoot, + stdio: "inherit", + env: cargoEnvironment, +}); +if (build.status !== 0) process.exit(build.status ?? 1); +if (!existsSync(builtBinary)) throw new Error(`Native streamer build missing: ${builtBinary}`); + +mkdirSync(dirname(platformBinary), { recursive: true }); +if (process.platform === "linux" && platformKey.startsWith("linux-")) { + // A running ELF cannot be truncated in place (ETXTBSY). Stage the new + // executable beside it and atomically replace the directory entry so an + // active session can finish on the old inode while the next one uses this + // build. + const stagedBinary = `${platformBinary}.${process.pid}.tmp`; + rmSync(stagedBinary, { force: true }); try { - return existsSync(path) && statSync(path).isDirectory(); - } catch { - return false; - } -} - -function buildBundledGstreamerEnv(baseEnv, binaryPath) { - const env = { SystemRoot: baseEnv.SystemRoot, WINDIR: baseEnv.WINDIR }; - const runtimeRoot = join(dirname(binaryPath), "gstreamer"); - const binDir = join(runtimeRoot, "bin"); - const libDir = join(runtimeRoot, "lib"); - const pluginDir = join(libDir, "gstreamer-1.0"); - const scanner = join(runtimeRoot, "libexec", "gstreamer-1.0", process.platform === "win32" ? "gst-plugin-scanner.exe" : "gst-plugin-scanner"); - const gioModulesDir = join(libDir, "gio", "modules"); - - if (!isExistingDirectory(runtimeRoot)) { - throw new Error(`Bundled GStreamer runtime was not found next to ${binaryPath}`); - } - if (process.platform === "win32") prependEnvPath(env, dirname(binaryPath)); - if (isExistingDirectory(binDir)) prependEnvPath(env, binDir); - if (isExistingDirectory(pluginDir)) { - env.GST_PLUGIN_PATH = pluginDir; - env.GST_PLUGIN_PATH_1_0 = pluginDir; - env.GST_PLUGIN_SYSTEM_PATH = pluginDir; - env.GST_PLUGIN_SYSTEM_PATH_1_0 = pluginDir; - } - if (isExistingFile(scanner)) { - env.GST_PLUGIN_SCANNER = scanner; - env.GST_PLUGIN_SCANNER_1_0 = scanner; - } - env.GST_REGISTRY_REUSE_PLUGIN_SCANNER = "no"; - if (isExistingDirectory(gioModulesDir)) { - env.GIO_MODULE_DIR = gioModulesDir; - env.GIO_EXTRA_MODULES = gioModulesDir; - } - if (process.platform === "linux" && isExistingDirectory(libDir)) { - env.LD_LIBRARY_PATH = env.LD_LIBRARY_PATH ? `${libDir}${delimiter}${env.LD_LIBRARY_PATH}` : libDir; - } - if (process.platform === "darwin" && isExistingDirectory(libDir)) { - env.DYLD_LIBRARY_PATH = env.DYLD_LIBRARY_PATH ? `${libDir}${delimiter}${env.DYLD_LIBRARY_PATH}` : libDir; - env.DYLD_FALLBACK_LIBRARY_PATH = env.DYLD_FALLBACK_LIBRARY_PATH ? `${libDir}${delimiter}${env.DYLD_FALLBACK_LIBRARY_PATH}` : libDir; - } - if (process.platform === "win32" && isExistingDirectory(libDir)) { - prependEnvPath(env, libDir); - } - return env; -} - -function parseNativeStreamerResponse(stdout) { - const messages = []; - for (const rawLine of stdout.split(/\r?\n/)) { - const line = rawLine.trim(); - if (!line) { - continue; - } - - try { - messages.push(JSON.parse(line)); - } catch { - console.error(`Native streamer verification returned invalid JSON: ${line}`); - process.exit(1); - } - } - - const response = messages.find((message) => message?.id === verifyCommandId); - if (!response) { - console.error( - `Native streamer verification did not return a response to ${verifyCommandId}: ${JSON.stringify(messages)}`, - ); - process.exit(1); - } - - return response; -} - -function verifyGstreamerBinary(binaryPath, env) { - const result = spawnSync(binaryPath, { - input: `${JSON.stringify({ id: verifyCommandId, type: "hello", protocolVersion: nativeStreamerProtocolVersion })}\n`, + copyFileSync(builtBinary, stagedBinary); + chmodSync(stagedBinary, 0o755); + renameSync(stagedBinary, platformBinary); + } finally { + rmSync(stagedBinary, { force: true }); + } +} else { + copyFileSync(builtBinary, platformBinary); + if (!platformKey.startsWith("win32-")) { + chmodSync(platformBinary, 0o755); + } +} + +const hostPlatformKey = `${process.platform}-${process.arch}`; +if (!nativeTarget || platformKey === hostPlatformKey) { + const input = [ + JSON.stringify({ id: "verify", type: "hello", protocolVersion: nativeProtocolVersion }), + JSON.stringify({ + id: "verify-start", + type: "start", + context: { + session: { + sessionId: "build-verification", + serverIp: "127.0.0.1", + iceServers: [], + }, + settings: { codec: "H264" }, + shortcuts: {}, + }, + }), + JSON.stringify({ id: "stop", type: "stop", reason: "build verification" }), + "", + ].join("\n"); + const verify = spawnSync(platformBinary, [], { + cwd: packageRoot, encoding: "utf8", env: { - ...env, - OPENNOW_NATIVE_STREAMER_BACKEND: "gstreamer", + ...process.env, + ...(process.platform === "darwin" ? {} : { OPENNOW_NATIVE_VIDEO_BACKEND: "software" }), + SDL_AUDIODRIVER: "dummy", + SDL_VIDEODRIVER: "dummy", }, + input, + timeout: 15_000, }); - - if (result.status !== 0) { - console.error(result.stderr || result.stdout); - console.error(`Native streamer verification failed for ${binaryPath}`); - process.exit(result.status ?? 1); - } - - const response = parseNativeStreamerResponse(result.stdout); - if (response.type === "error") { - console.error( - `Native streamer verification failed: ${response.code ?? "error"}${response.message ? `: ${response.message}` : ""}`, - ); - process.exit(1); - } - - const capabilities = response.capabilities; - if ( - response.type !== "ready" || - capabilities?.backend !== "gstreamer" || - capabilities?.supportsOfferAnswer !== true || - capabilities?.supportsInput !== true - ) { - console.error( - `Native streamer verification expected a GStreamer backend, got: ${JSON.stringify( - capabilities, - )}`, - ); - process.exit(1); - } - - if (!Array.isArray(capabilities.videoBackends) || capabilities.videoBackends.length === 0) { - console.error( - `Native streamer verification expected video backend capabilities, got: ${JSON.stringify( - capabilities, - )}`, - ); - process.exit(1); - } - - const availableVideoBackends = capabilities.videoBackends - .filter((backend) => backend?.available) - .map((backend) => { - const codecs = Array.isArray(backend.codecs) - ? backend.codecs.filter((codec) => codec.available).map((codec) => codec.codec).join("/") - : ""; - return `${backend.backend}${codecs ? `(${codecs})` : ""}`; - }); - - if (availableVideoBackends.length === 0) { - console.error( - `Native streamer verification found no usable video backend: ${JSON.stringify( - capabilities.videoBackends, - )}`, + if (verify.status !== 0) { + const detail = verify.stderr || verify.stdout || verify.error?.message || "no process output"; + throw new Error( + `Native streamer verification failed (status=${verify.status}, signal=${verify.signal}): ${detail}`, ); - process.exit(1); } - - console.log(`Verified native streamer GStreamer capabilities: ${availableVideoBackends.join(", ")}.`); -} - -function verifyBundledWindowsLoader(binaryPath, baseEnv) { - const result = spawnSync(binaryPath, { - cwd: dirname(binaryPath), - input: `${JSON.stringify({ id: verifyCommandId, type: "hello", protocolVersion: nativeStreamerProtocolVersion })}\n`, - encoding: "utf8", - env: { - SystemRoot: baseEnv.SystemRoot, - WINDIR: baseEnv.WINDIR, - PATH: dirname(binaryPath), - OPENNOW_NATIVE_STREAMER_BACKEND: "gstreamer", - }, - }); - if (result.status !== 0) { - console.error(result.stderr || result.stdout); - console.error("Bundled native streamer could not start using only DLLs next to its executable."); - process.exit(result.status ?? 1); - } - parseNativeStreamerResponse(result.stdout); - console.log("Verified native streamer Windows loader dependency closure."); -} - -function verifyBundledWindowsVulkanPlugin(binaryPath, env) { - const gstInspect = join(dirname(binaryPath), "gstreamer", "bin", "gst-inspect-1.0.exe"); - const result = spawnSync(gstInspect, ["vulkanupload"], { - encoding: "utf8", - env, - }); - if (result.status !== 0) { - console.error(result.stderr || result.stdout); - console.error("Bundled GStreamer Vulkan plugin failed to load."); - process.exit(result.status ?? 1); - } - console.log("Verified bundled GStreamer Vulkan plugin and loader."); -} - -const cargoArgs = ["build", "--release", "--manifest-path", manifestPath]; -if (nativeTarget) { - cargoArgs.push("--target", nativeTarget); -} -const nativeFeatures = process.env.OPENNOW_NATIVE_STREAMER_FEATURES?.trim() || "gstreamer"; -if (nativeFeatures && nativeFeatures.toLowerCase() !== "none") { - cargoArgs.push("--features", nativeFeatures); -} -console.log( - nativeFeatures.toLowerCase() === "none" - ? "Building native streamer without optional features." - : `Building native streamer with features: ${nativeFeatures}`, -); - -const buildEnv = { ...process.env }; -let gstreamerSdkRoot = null; -if (hasFeature(nativeFeatures, "gstreamer")) { - gstreamerSdkRoot = configureGstreamerSdk(buildEnv); -} -configureDarwinLinkerPadding(buildEnv, nativeFeatures); - -const cargoCommand = process.platform === "win32" ? "cargo.exe" : "cargo"; -const result = spawnSync(cargoCommand, cargoArgs, { - cwd: repoRoot, - stdio: "inherit", - env: buildEnv, -}); - -if (result.status !== 0) { - process.exit(result.status ?? 1); -} - -if (!existsSync(builtBinary)) { - console.error(`Native streamer build did not produce ${builtBinary}`); - process.exit(1); -} - -mkdirSync(packageBinaryDir, { recursive: true }); -mkdirSync(packagePlatformBinaryDir, { recursive: true }); -copyFileSync(builtBinary, packageBinary); -copyFileSync(builtBinary, packagePlatformBinary); - -if (process.platform !== "win32") { - chmodSync(packageBinary, 0o755); - chmodSync(packagePlatformBinary, 0o755); -} - -if (hasFeature(nativeFeatures, "gstreamer")) { - verifyGstreamerBinary(packageBinary, buildEnv); - if (bundleGstreamerRuntime(gstreamerSdkRoot, nativeFeatures)) { - const bundledEnv = buildBundledGstreamerEnv(buildEnv, packagePlatformBinary); - if (process.platform === "win32") { - verifyBundledWindowsLoader(packagePlatformBinary, buildEnv); - verifyBundledWindowsVulkanPlugin(packagePlatformBinary, bundledEnv); - } - verifyGstreamerBinary(packagePlatformBinary, bundledEnv); + const messages = verify.stdout + .split(/\r?\n/) + .filter(Boolean) + .map((line) => JSON.parse(line)); + const ready = messages.find((message) => message.id === "verify" && message.type === "ready"); + const stopped = messages.find((message) => message.id === "stop" && message.type === "ok"); + const started = messages.find((message) => message.id === "verify-start" && message.type === "ok"); + const capabilitiesComplete = ready?.capabilities?.supportsOfferAnswer === true + && ready.capabilities.supportsVideoDecode === true + && ready.capabilities.supportsVideoPresent === true + && ready.capabilities.supportsAudioDecode === true + && ready.capabilities.supportsAudioOutput === true; + if (!capabilitiesComplete || !started || !stopped) { + throw new Error(`Native streamer verification returned an incomplete handshake: ${verify.stdout}`); } } -console.log(`Copied native streamer to ${packageBinary}`); -console.log(`Copied native streamer to ${packagePlatformBinary}`); +console.log(`Built native streamer v2: ${platformBinary}`); diff --git a/opennow-stable/scripts/build-patched-gstreamer-d3d11.ps1 b/opennow-stable/scripts/build-patched-gstreamer-d3d11.ps1 deleted file mode 100644 index abee94a9b..000000000 --- a/opennow-stable/scripts/build-patched-gstreamer-d3d11.ps1 +++ /dev/null @@ -1,91 +0,0 @@ -param( - [Parameter(Mandatory = $true)] - [string] $GStreamerRoot, - [Parameter(Mandatory = $true)] - [string] $Version -) - -$ErrorActionPreference = "Stop" -$patch = Resolve-Path (Join-Path $PSScriptRoot "..\..\native\gstreamer-patches\0001-d3d11-enable-tearing-vrr.patch") -$workRoot = Join-Path ([System.IO.Path]::GetTempPath()) "opennow-gstreamer-$Version" -$archive = Join-Path $workRoot "gstreamer-$Version.tar.gz" -$sourceRoot = Join-Path $workRoot "gstreamer-$Version" -$buildRoot = Join-Path $workRoot "build" -$sourceUrl = "https://gitlab.freedesktop.org/gstreamer/gstreamer/-/archive/$Version/gstreamer-$Version.tar.gz" -$sourceMirrorUrl = "https://github.com/GStreamer/gstreamer/archive/refs/tags/$Version.tar.gz" - -Remove-Item -Recurse -Force $workRoot -ErrorAction SilentlyContinue -New-Item -ItemType Directory -Force -Path $workRoot | Out-Null - -& curl.exe --fail --location --retry 5 --retry-all-errors --output $archive $sourceUrl -if ($LASTEXITCODE -ne 0) { - & curl.exe --fail --location --retry 5 --retry-all-errors --output $archive $sourceMirrorUrl - if ($LASTEXITCODE -ne 0) { - throw "Failed to download GStreamer $Version source." - } -} - -& tar.exe -xzf $archive -C $workRoot -if ($LASTEXITCODE -ne 0) { - throw "Failed to extract GStreamer $Version source." -} - -& git.exe -C $sourceRoot apply --check $patch -if ($LASTEXITCODE -ne 0) { - throw "OpenNOW D3D11 tearing patch does not apply to GStreamer $Version." -} -& git.exe -C $sourceRoot apply $patch -if ($LASTEXITCODE -ne 0) { - throw "Failed to apply OpenNOW D3D11 tearing patch." -} - -python -m pip install --disable-pip-version-check --quiet meson ninja -if ($LASTEXITCODE -ne 0) { - throw "Failed to install Meson and Ninja." -} - -$env:PKG_CONFIG_PATH = "$(Join-Path $GStreamerRoot "lib\pkgconfig");$env:PKG_CONFIG_PATH" -$env:PATH = "$(Join-Path $GStreamerRoot "bin");$env:PATH" -$badPluginsSource = Join-Path $sourceRoot "subprojects\gst-plugins-bad" - -meson setup $buildRoot $badPluginsSource ` - --buildtype=release ` - --vsenv ` - -Dauto_features=disabled ` - -Dd3d11=enabled ` - -Dtests=disabled ` - -Dexamples=disabled ` - -Dtools=disabled ` - -Dintrospection=disabled ` - -Dgpl=disabled -if ($LASTEXITCODE -ne 0) { - throw "Failed to configure the patched GStreamer D3D11 plugin." -} - -meson compile -C $buildRoot gstd3d11 -if ($LASTEXITCODE -ne 0) { - throw "Failed to compile the patched GStreamer D3D11 plugin." -} - -$plugin = Get-ChildItem -Path $buildRoot -Filter "gstd3d11.dll" -Recurse | - Select-Object -First 1 -if (-not $plugin) { - throw "Patched gstd3d11.dll was not produced." -} - -$pluginDestination = Join-Path $GStreamerRoot "lib\gstreamer-1.0\gstd3d11.dll" -Copy-Item -Force $plugin.FullName $pluginDestination - -$d3d11Library = Get-ChildItem -Path $buildRoot -Filter "gstd3d11-1.0-0.dll" -Recurse | - Select-Object -First 1 -if ($d3d11Library) { - Copy-Item -Force $d3d11Library.FullName (Join-Path $GStreamerRoot "bin\gstd3d11-1.0-0.dll") -} - -$gstInspect = Join-Path $GStreamerRoot "bin\gst-inspect-1.0.exe" -& $gstInspect d3d11videosink -if ($LASTEXITCODE -ne 0) { - throw "Patched GStreamer D3D11 plugin failed its gst-inspect smoke check." -} - -Write-Host "Installed patched GStreamer D3D11 plugin: $pluginDestination" diff --git a/opennow-stable/scripts/bundle-gstreamer-runtime.mjs b/opennow-stable/scripts/bundle-gstreamer-runtime.mjs deleted file mode 100644 index 174cc4615..000000000 --- a/opennow-stable/scripts/bundle-gstreamer-runtime.mjs +++ /dev/null @@ -1,390 +0,0 @@ -import { - chmodSync, - copyFileSync, - cpSync, - existsSync, - mkdirSync, - readdirSync, - readFileSync, - rmSync, - statSync, - writeFileSync, -} from "node:fs"; -import { basename, delimiter, dirname, extname, join, relative, resolve } from "node:path"; -import { fileURLToPath } from "node:url"; -import { spawnSync } from "node:child_process"; -import { collectBundledPeDependencies } from "./windows-pe-imports.mjs"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); -const packageRoot = resolve(__dirname, ".."); - -function parseArgs(argv) { - const parsed = new Map(); - for (let index = 0; index < argv.length; index += 1) { - const value = argv[index]; - if (!value.startsWith("--")) continue; - const key = value.slice(2); - const next = argv[index + 1]; - if (!next || next.startsWith("--")) { - parsed.set(key, "true"); - continue; - } - parsed.set(key, next); - index += 1; - } - return parsed; -} - -function isExistingFile(path) { - try { return existsSync(path) && statSync(path).isFile(); } catch { return false; } -} - -function isExistingDirectory(path) { - try { return existsSync(path) && statSync(path).isDirectory(); } catch { return false; } -} - -function run(command, args, options = {}) { - return spawnSync(command, args, { encoding: "utf8", ...options }); -} - -function commandAvailable(command) { - return run("/usr/bin/env", ["which", command]).status === 0; -} - -function brewPrefix() { - const result = run("brew", ["--prefix"]); - return result.status === 0 ? result.stdout.trim() || null : null; -} - -function copyPathIfPresent(source, destination) { - if (!existsSync(source)) return false; - const stats = statSync(source); - if (stats.isDirectory()) { - cpSync(source, destination, { - recursive: true, - force: true, - // Follow symlinks to copy actual files instead of broken links - // (Homebrew GStreamer installs some plugins as symlinks). - dereference: true, - filter: (entry) => { - const lower = entry.toLowerCase(); - return !lower.endsWith(".pdb") - && !lower.endsWith(".lib") - && !lower.endsWith(".a") - && !lower.includes(`${join("share", "doc").toLowerCase()}`); - }, - }); - return true; - } - mkdirSync(dirname(destination), { recursive: true }); - copyFileSync(source, destination); - return true; -} - -function copyMatchingFiles(sourceDir, destinationDir, pattern) { - if (!isExistingDirectory(sourceDir)) return; - mkdirSync(destinationDir, { recursive: true }); - for (const name of readdirSync(sourceDir)) { - if (pattern.test(name)) copyFileSync(join(sourceDir, name), join(destinationDir, name)); - } -} - -function windowsSdkCandidates(explicitSdkRoot) { - return [ - explicitSdkRoot, - process.env.GSTREAMER_1_0_ROOT_MSVC_X86_64, - "C:\\Program Files\\gstreamer\\1.0\\msvc_x86_64", - "C:\\gstreamer\\1.0\\msvc_x86_64", - ].filter(Boolean); -} - -function resolveWindowsSdkRoot(explicitSdkRoot) { - const sdkRoot = windowsSdkCandidates(explicitSdkRoot).find((candidate) => - isExistingFile(join(candidate, "bin", "gstreamer-1.0-0.dll")) - && isExistingDirectory(join(candidate, "lib", "gstreamer-1.0")), - ); - if (!sdkRoot) throw new Error("GStreamer MSVC x86_64 runtime was not found. Install the runtime/development MSI or pass --sdk-root."); - return sdkRoot; -} - -function macosCandidates(explicitSdkRoot) { - return [ - explicitSdkRoot, - process.env.GSTREAMER_1_0_ROOT_MACOS, - "/Library/Frameworks/GStreamer.framework/Versions/1.0", - "/Library/Frameworks/GStreamer.framework/Versions/Current", - brewPrefix(), - "/opt/homebrew", - "/usr/local", - ].filter(Boolean); -} - -function validateMacosRoot(candidate) { - return isExistingFile(join(candidate, "lib", "pkgconfig", "gstreamer-1.0.pc")) - && isExistingFile(join(candidate, "lib", "libgstreamer-1.0.dylib")) - && isExistingDirectory(join(candidate, "lib", "gstreamer-1.0")); -} - -function resolveMacosRuntimeRoot(explicitSdkRoot) { - const runtimeRoot = macosCandidates(explicitSdkRoot).find(validateMacosRoot); - if (!runtimeRoot) { - throw new Error("GStreamer macOS runtime was not found. Install the official runtime/devel .pkg packages or Homebrew packages, or pass --sdk-root."); - } - return runtimeRoot; -} - -function writeMetadata(destination, source, platform) { - writeFileSync( - join(destination, "OPENNOW-GSTREAMER-RUNTIME.txt"), - [ - "OpenNOW private GStreamer runtime bundle", - `Source: ${source}`, - `Generated: ${new Date().toISOString()}`, - `Platform: ${platform}`, - "Scope: native streamer child process only", - "", - "This directory is loaded only for the native streamer child process. Keep the private layout intact.", - "", - ].join("\n"), - ); -} - -const WINDOWS_VC_RUNTIME_DLLS = [ - "vcruntime140.dll", - "vcruntime140_1.dll", - "msvcp140.dll", - "msvcp140_1.dll", - "msvcp140_2.dll", - "msvcp140_atomic_wait.dll", - "msvcp140_codecvt_ids.dll", - "concrt140.dll", -]; - -function windowsVcRuntimeSearchDirs() { - return [ - process.env.VCToolsRedistDir ? join(process.env.VCToolsRedistDir, "x64", "Microsoft.VC143.CRT") : null, - process.env.VCToolsRedistDir ? join(process.env.VCToolsRedistDir, "x64", "Microsoft.VC142.CRT") : null, - process.env.VCToolsRedistDir ? join(process.env.VCToolsRedistDir, "x64", "Microsoft.VC141.CRT") : null, - process.env.SystemRoot ? join(process.env.SystemRoot, "System32") : null, - ...String(process.env.PATH ?? "").split(delimiter), - ].filter(Boolean); -} - -function copyWindowsLoaderDlls({ sdkRoot, destination, binary }) { - const executableDir = binary ? dirname(binary) : dirname(destination); - const sdkBin = join(sdkRoot, "bin"); - const copiedLoader = []; - const copiedVc = []; - - if (!binary) { - throw new Error("A native streamer executable is required to collect its Windows DLL dependencies."); - } - for (const source of collectBundledPeDependencies(binary, sdkBin)) { - const name = basename(source); - copyFileSync(source, join(executableDir, name)); - copiedLoader.push(name); - } - - const vcSearchDirs = windowsVcRuntimeSearchDirs(); - for (const name of WINDOWS_VC_RUNTIME_DLLS) { - const source = vcSearchDirs.map((dir) => join(dir, name)).find(isExistingFile); - if (!source) continue; - copyFileSync(source, join(executableDir, name)); - copyFileSync(source, join(destination, "bin", name)); - copiedVc.push(name); - } - - console.log(`Copied Windows loader DLLs next to native streamer: ${copiedLoader.length ? copiedLoader.join(", ") : "none"}.`); - console.log(`Copied Windows VC runtime DLLs: ${copiedVc.length ? copiedVc.join(", ") : "none found"}.`); -} - -function bundleWindowsRuntime({ sdkRoot, destination, binary }) { - const resolvedSdkRoot = resolveWindowsSdkRoot(sdkRoot); - rmSync(destination, { recursive: true, force: true }); - mkdirSync(destination, { recursive: true }); - const copied = [ - copyPathIfPresent(join(resolvedSdkRoot, "bin"), join(destination, "bin")), - copyPathIfPresent(join(resolvedSdkRoot, "lib", "gstreamer-1.0"), join(destination, "lib", "gstreamer-1.0")), - copyPathIfPresent(join(resolvedSdkRoot, "lib", "gio", "modules"), join(destination, "lib", "gio", "modules")), - copyPathIfPresent(join(resolvedSdkRoot, "libexec", "gstreamer-1.0"), join(destination, "libexec", "gstreamer-1.0")), - copyPathIfPresent(join(resolvedSdkRoot, "share", "gstreamer-1.0"), join(destination, "share", "gstreamer-1.0")), - copyPathIfPresent(join(resolvedSdkRoot, "share", "glib-2.0"), join(destination, "share", "glib-2.0")), - copyPathIfPresent(join(resolvedSdkRoot, "etc"), join(destination, "etc")), - ].filter(Boolean).length; - copyMatchingFiles(resolvedSdkRoot, destination, /^(copying|license|readme)/i); - copyWindowsLoaderDlls({ sdkRoot: resolvedSdkRoot, destination, binary }); - writeMetadata(destination, resolvedSdkRoot, "win32"); - console.log(`Bundled GStreamer runtime from ${resolvedSdkRoot} to ${destination} (${copied} paths).`); -} - -function walkFiles(root) { - if (!isExistingDirectory(root)) return []; - const out = []; - const stack = [root]; - while (stack.length > 0) { - const dir = stack.pop(); - for (const name of readdirSync(dir)) { - const path = join(dir, name); - const stats = statSync(path); - if (stats.isDirectory()) stack.push(path); - else if (stats.isFile()) out.push(path); - } - } - return out; -} - -function isMachO(path) { - try { - const buffer = readFileSync(path, { flag: "r" }); - if (buffer.length < 4) return false; - const magic = buffer.readUInt32BE(0); - return [0xfeedface, 0xfeedfacf, 0xcafebabe, 0xcafebabf, 0xbebafeca, 0xcffaedfe, 0xcefaedfe].includes(magic); - } catch { - return false; - } -} - -function dylibName(ref) { - return ref.split("/").pop(); -} - -function isPathInside(path, parent) { - const relativePath = relative(parent, path); - return relativePath === "" || (!relativePath.startsWith("..") && !relativePath.startsWith("/")); -} - -function posixPath(path) { - return path.split(/[\\/]+/).filter(Boolean).join("/"); -} - -function relocationTarget(file, destination, libDir, dep) { - const name = dylibName(dep); - if (!name) return null; - if (!isPathInside(file, destination)) return `@executable_path/gstreamer/lib/${name}`; - const relativeLibDir = posixPath(relative(dirname(file), libDir)); - return relativeLibDir ? `@loader_path/${relativeLibDir}/${name}` : `@loader_path/${name}`; -} - -function shouldRewriteDependency(dep, roots, bundledLibs) { - const name = dylibName(dep); - if (!name || !bundledLibs.has(name)) return false; - if (dep.startsWith("@rpath/") || dep.startsWith("@loader_path/") || dep.startsWith("@executable_path/")) return bundledLibs.has(name); - return roots.some((root) => dep === join(root, "lib", name) || dep.startsWith(`${root}/`) || dep.includes("GStreamer.framework")); -} - -function macosExternalRoots(sourceRoot) { - return [ - sourceRoot, - "/Library/Frameworks/GStreamer.framework/Versions/1.0", - "/Library/Frameworks/GStreamer.framework/Versions/Current", - "/Library/Frameworks/GStreamer.framework", - "/opt/homebrew", - "/usr/local", - ]; -} - -function runInstallNameTool(args, file) { - const result = run("install_name_tool", args, { stdio: "inherit" }); - if (result.status !== 0) { - throw new Error(`install_name_tool failed for ${file}: install_name_tool ${args.join(" ")}`); - } -} - -function patchMachO(file, destination, sourceRoot, libDir, bundledLibs) { - if (!isMachO(file) || !commandAvailable("otool") || !commandAvailable("install_name_tool")) return; - const output = run("otool", ["-L", file]); - if (output.status !== 0) return; - const roots = macosExternalRoots(sourceRoot); - for (const line of output.stdout.split(/\r?\n/).slice(1)) { - const dep = line.trim().split(/\s+/)[0]; - if (!dep || !shouldRewriteDependency(dep, roots, bundledLibs)) continue; - const target = relocationTarget(file, destination, libDir, dep); - if (target && target !== dep) runInstallNameTool(["-change", dep, target, file], file); - } - if (isPathInside(file, libDir) && extname(file) === ".dylib") { - runInstallNameTool(["-id", `@rpath/${dylibName(file)}`, file], file); - } -} - -function isExternalGstreamerDependency(dep, roots, bundledLibs) { - const name = dylibName(dep); - if (!name || !bundledLibs.has(name)) return false; - if (dep.startsWith("@")) return false; - return roots.some((root) => dep === join(root, "lib", name) || dep.startsWith(`${root}/`) || dep.includes("GStreamer.framework")); -} - -function validatePackagedBinaryRelocation(binary, sourceRoot, bundledLibs) { - if (!binary || !isMachO(binary) || !commandAvailable("otool")) return; - const output = run("otool", ["-L", binary]); - if (output.status !== 0) { - throw new Error(`otool -L failed for packaged native streamer: ${binary}`); - } - const roots = macosExternalRoots(sourceRoot); - const leakedDeps = output.stdout - .split(/\r?\n/) - .slice(1) - .map((line) => line.trim().split(/\s+/)[0]) - .filter((dep) => dep && isExternalGstreamerDependency(dep, roots, bundledLibs)); - if (leakedDeps.length > 0) { - throw new Error( - `Packaged native streamer still references external GStreamer dependencies after relocation: ${leakedDeps.join(", ")}`, - ); - } -} - -function bundleMacosRuntime({ sdkRoot, destination, binary }) { - const resolvedRuntimeRoot = resolveMacosRuntimeRoot(sdkRoot); - rmSync(destination, { recursive: true, force: true }); - mkdirSync(destination, { recursive: true }); - const copied = [ - copyPathIfPresent(join(resolvedRuntimeRoot, "bin"), join(destination, "bin")), - copyPathIfPresent(join(resolvedRuntimeRoot, "lib", "gstreamer-1.0"), join(destination, "lib", "gstreamer-1.0")), - copyPathIfPresent(join(resolvedRuntimeRoot, "lib", "gio", "modules"), join(destination, "lib", "gio", "modules")), - copyPathIfPresent(join(resolvedRuntimeRoot, "libexec", "gstreamer-1.0"), join(destination, "libexec", "gstreamer-1.0")), - copyPathIfPresent(join(resolvedRuntimeRoot, "share"), join(destination, "share")), - copyPathIfPresent(join(resolvedRuntimeRoot, "etc"), join(destination, "etc")), - ].filter(Boolean).length; - copyMatchingFiles(join(resolvedRuntimeRoot, "lib"), join(destination, "lib"), /\.(dylib|so)$/); - copyMatchingFiles(resolvedRuntimeRoot, destination, /^(copying|license|readme)/i); - const libDir = join(destination, "lib"); - const bundledLibs = new Set(readdirSync(libDir).filter((name) => name.endsWith(".dylib") || name.endsWith(".so"))); - for (const file of [...walkFiles(destination), binary].filter(Boolean)) { - try { chmodSync(file, statSync(file).mode | 0o200); } catch {} - patchMachO(file, destination, resolvedRuntimeRoot, libDir, bundledLibs); - } - validatePackagedBinaryRelocation(binary, resolvedRuntimeRoot, bundledLibs); - writeMetadata(destination, resolvedRuntimeRoot, "darwin"); - console.log(`Bundled GStreamer runtime from ${resolvedRuntimeRoot} to ${destination} (${copied} paths plus dylibs).`); -} - -const args = parseArgs(process.argv.slice(2)); -const destination = args.get("dest"); -if (!destination) { - console.error("Usage: node scripts/bundle-gstreamer-runtime.mjs --dest [--sdk-root ] [--binary ]"); - process.exit(1); -} - -try { - const resolvedDestination = resolve(packageRoot, destination); - if (process.platform === "win32") { - bundleWindowsRuntime({ - sdkRoot: args.get("sdk-root"), - destination: resolvedDestination, - binary: args.get("binary") ? resolve(packageRoot, args.get("binary")) : null, - }); - } else if (process.platform === "darwin") { - bundleMacosRuntime({ - sdkRoot: args.get("sdk-root"), - destination: resolvedDestination, - binary: args.get("binary") ? resolve(packageRoot, args.get("binary")) : null, - }); - } else { - throw new Error( - `Private GStreamer runtime collection is intentionally unsupported on Linux (${process.platform}). Linux builds use distro GStreamer packages because AppImage/private bundling is unreliable across glibc, libdrm/VAAPI/Vulkan, and GPU driver stacks.`, - ); - } -} catch (error) { - console.error(error instanceof Error ? error.message : String(error)); - process.exit(1); -} diff --git a/opennow-stable/scripts/dev.mjs b/opennow-stable/scripts/dev.mjs deleted file mode 100644 index 4412491be..000000000 --- a/opennow-stable/scripts/dev.mjs +++ /dev/null @@ -1,84 +0,0 @@ -import { spawn, spawnSync } from "node:child_process"; -import { dirname, join, resolve } from "node:path"; -import { fileURLToPath } from "node:url"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); -const packageRoot = resolve(__dirname, ".."); -const repoRoot = resolve(packageRoot, ".."); -const crateRoot = join(repoRoot, "native", "opennow-streamer"); -const exeName = process.platform === "win32" ? "opennow-streamer.exe" : "opennow-streamer"; -const nativeTarget = process.env.OPENNOW_NATIVE_STREAMER_TARGET?.trim() || ""; -const nativeProfile = process.env.OPENNOW_NATIVE_STREAMER_DEV_PROFILE?.trim() || "debug"; -const nativeFeatures = - process.env.OPENNOW_NATIVE_STREAMER_DEV_FEATURES?.trim() - ?? process.env.OPENNOW_NATIVE_STREAMER_FEATURES?.trim() - ?? "none"; -const targetDir = nativeTarget - ? join(crateRoot, "target", nativeTarget, nativeProfile) - : join(crateRoot, "target", nativeProfile); -const streamerBinary = join(targetDir, exeName); - -function runNativeBuild() { - if (process.env.OPENNOW_SKIP_NATIVE_STREAMER_BUILD === "1") { - console.log("Skipping native streamer build because OPENNOW_SKIP_NATIVE_STREAMER_BUILD=1."); - return; - } - - const args = [ - join(__dirname, "build-native-streamer.mjs"), - "--profile", - nativeProfile, - "--features", - nativeFeatures, - "--no-copy", - "--skip-verify", - ]; - const result = spawnSync(process.execPath, args, { - cwd: packageRoot, - stdio: "inherit", - env: process.env, - }); - - if (result.status !== 0) { - process.exit(result.status ?? 1); - } -} - -function runElectronVite() { - const child = spawn("electron-vite", ["dev"], { - cwd: packageRoot, - stdio: "inherit", - shell: process.platform === "win32", - env: { - ...process.env, - OPENNOW_NATIVE_STREAMER: process.env.OPENNOW_NATIVE_STREAMER?.trim() || streamerBinary, - }, - }); - - const forwardSignal = (signal) => { - if (!child.killed) { - child.kill(signal); - } - }; - process.once("SIGINT", forwardSignal); - process.once("SIGTERM", forwardSignal); - - child.once("exit", (code, signal) => { - process.off("SIGINT", forwardSignal); - process.off("SIGTERM", forwardSignal); - if (signal) { - process.kill(process.pid, signal); - return; - } - process.exit(code ?? 0); - }); - - child.once("error", (error) => { - console.error(`Failed to start electron-vite dev: ${error.message}`); - process.exit(1); - }); -} - -runNativeBuild(); -runElectronVite(); diff --git a/opennow-stable/scripts/inject-gstreamer-vulkan-windows.mjs b/opennow-stable/scripts/inject-gstreamer-vulkan-windows.mjs deleted file mode 100644 index 94146d122..000000000 --- a/opennow-stable/scripts/inject-gstreamer-vulkan-windows.mjs +++ /dev/null @@ -1,148 +0,0 @@ -import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs"; -import { dirname, join, resolve } from "node:path"; -import { fileURLToPath } from "node:url"; -import { spawnSync } from "node:child_process"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); -const packageRoot = resolve(__dirname, ".."); -const repoRoot = resolve(packageRoot, ".."); -const vendorRoot = join(repoRoot, "native", "opennow-streamer", "vendor", "gstreamer-vulkan-windows"); - -function parseArgs(argv) { - const parsed = new Map(); - for (let index = 0; index < argv.length; index += 1) { - const value = argv[index]; - if (!value.startsWith("--")) continue; - const key = value.slice(2); - const next = argv[index + 1]; - if (!next || next.startsWith("--")) { - parsed.set(key, "true"); - continue; - } - parsed.set(key, next); - index += 1; - } - return parsed; -} - -function isExistingFile(path) { - try { - return existsSync(path) && statSync(path).isFile(); - } catch { - return false; - } -} - -function isExistingDirectory(path) { - try { - return existsSync(path) && statSync(path).isDirectory(); - } catch { - return false; - } -} - -function readRuntimeVersion(runtimeRoot) { - const metadataPath = join(runtimeRoot, "OPENNOW-GSTREAMER-RUNTIME.txt"); - if (!isExistingFile(metadataPath)) return null; - const text = readFileSync(metadataPath, "utf8"); - const sourceLine = text.split(/\r?\n/).find((line) => line.startsWith("Source:")); - // Prefer probing the bundled gst-inspect version when available. - const inspect = join(runtimeRoot, "bin", "gst-inspect-1.0.exe"); - if (isExistingFile(inspect)) { - const result = spawnSync(inspect, ["--version"], { encoding: "utf8" }); - const match = `${result.stdout ?? ""}\n${result.stderr ?? ""}`.match(/GStreamer\s+(\d+\.\d+\.\d+)/i); - if (match) return match[1]; - } - return sourceLine ? sourceLine.slice("Source:".length).trim() : null; -} - -function listVendorVersions() { - if (!isExistingDirectory(vendorRoot)) return []; - return readdirSync(vendorRoot) - .filter((name) => /^\d+\.\d+\.\d+$/.test(name) && isExistingDirectory(join(vendorRoot, name))) - .sort((a, b) => b.localeCompare(a, undefined, { numeric: true })); -} - -function resolveVendorDir(runtimeVersion) { - const versions = listVendorVersions(); - if (versions.length === 0) return null; - if (runtimeVersion && versions.includes(runtimeVersion)) { - return join(vendorRoot, runtimeVersion); - } - // Fall back to newest vendored build; plugin ABI is usually compatible within a minor series. - if (runtimeVersion) { - const [major, minor] = runtimeVersion.split("."); - const sameSeries = versions.find((version) => version.startsWith(`${major}.${minor}.`)); - if (sameSeries) return join(vendorRoot, sameSeries); - return null; - } - return join(vendorRoot, versions[0]); -} - -function injectVulkanPlugins(runtimeRoot, vendorDir) { - const pluginSource = join(vendorDir, "lib", "gstreamer-1.0", "gstvulkan.dll"); - const librarySource = join(vendorDir, "bin", "gstvulkan-1.0-0.dll"); - const loaderSource = join(packageRoot, "node_modules", "electron", "dist", "vulkan-1.dll"); - if (!isExistingFile(pluginSource) || !isExistingFile(librarySource)) { - throw new Error(`Vendored Vulkan artifacts are incomplete under ${vendorDir}`); - } - if (!isExistingFile(loaderSource)) { - throw new Error(`Electron Vulkan loader was not found: ${loaderSource}`); - } - - const pluginDestDir = join(runtimeRoot, "lib", "gstreamer-1.0"); - const binDestDir = join(runtimeRoot, "bin"); - mkdirSync(pluginDestDir, { recursive: true }); - mkdirSync(binDestDir, { recursive: true }); - copyFileSync(pluginSource, join(pluginDestDir, "gstvulkan.dll")); - copyFileSync(librarySource, join(binDestDir, "gstvulkan-1.0-0.dll")); - copyFileSync(loaderSource, join(binDestDir, "vulkan-1.dll")); - - const metadataPath = join(runtimeRoot, "OPENNOW-GSTREAMER-RUNTIME.txt"); - if (isExistingFile(metadataPath)) { - const text = readFileSync(metadataPath, "utf8"); - if (!text.includes("Vulkan plugin: injected")) { - writeFileSync( - metadataPath, - `${text.trimEnd()}\nVulkan plugin: injected from ${vendorDir}\n`, - "utf8", - ); - } - } - - console.log(`Injected Windows GStreamer Vulkan plugins and loader into ${runtimeRoot}.`); -} - -const args = parseArgs(process.argv.slice(2)); -const destination = args.get("dest"); -if (!destination) { - console.error("Usage: node scripts/inject-gstreamer-vulkan-windows.mjs --dest "); - process.exit(1); -} - -if (process.platform !== "win32") { - console.log("Skipping Windows Vulkan plugin inject on non-Windows host."); - process.exit(0); -} - -try { - const runtimeRoot = resolve(packageRoot, destination); - if (!isExistingDirectory(runtimeRoot)) { - throw new Error(`GStreamer runtime directory was not found: ${runtimeRoot}`); - } - - const runtimeVersion = readRuntimeVersion(runtimeRoot); - const vendorDir = resolveVendorDir(runtimeVersion); - if (!vendorDir) { - throw new Error( - `No compatible vendored Windows GStreamer Vulkan plugins were found for runtime ${runtimeVersion ?? "unknown"}. ` - + `Expected artifacts under ${vendorRoot}//.`, - ); - } - - injectVulkanPlugins(runtimeRoot, vendorDir); -} catch (error) { - console.error(error instanceof Error ? error.message : String(error)); - process.exit(1); -} diff --git a/opennow-stable/scripts/run-tests.mjs b/opennow-stable/scripts/run-tests.mjs index c1a2c854b..f2efeff8a 100644 --- a/opennow-stable/scripts/run-tests.mjs +++ b/opennow-stable/scripts/run-tests.mjs @@ -73,7 +73,10 @@ async function appendGitHubSummary({ tests, output, exitCode }) { const tests = (await discoverTests("src")) .map((path) => path.split(sep).join("/")) .sort(); -tests.push("scripts/after-sign-mac.test.mjs", "scripts/windows-pe-imports.test.mjs"); +tests.push( + "scripts/after-sign-mac.test.mjs", + "scripts/build-native-streamer-config.test.mjs", +); if (tests.length === 0) { console.error("No test files found under src/**/*.test.ts"); diff --git a/opennow-stable/scripts/windows-pe-imports.mjs b/opennow-stable/scripts/windows-pe-imports.mjs deleted file mode 100644 index f00377934..000000000 --- a/opennow-stable/scripts/windows-pe-imports.mjs +++ /dev/null @@ -1,123 +0,0 @@ -import { readFileSync, readdirSync } from "node:fs"; -import { basename, join } from "node:path"; - -function checkedRead(buffer, offset, size, label) { - if (!Number.isInteger(offset) || offset < 0 || offset + size > buffer.length) { - throw new Error(`Invalid PE ${label} offset: ${offset}`); - } -} - -function readUInt16(buffer, offset, label) { - checkedRead(buffer, offset, 2, label); - return buffer.readUInt16LE(offset); -} - -function readUInt32(buffer, offset, label) { - checkedRead(buffer, offset, 4, label); - return buffer.readUInt32LE(offset); -} - -function readAsciiString(buffer, offset) { - checkedRead(buffer, offset, 1, "string"); - const end = buffer.indexOf(0, offset); - if (end < 0) { - throw new Error(`Unterminated PE import name at offset ${offset}`); - } - return buffer.toString("ascii", offset, end); -} - -export function readPeImportNames(buffer) { - if (buffer.length < 64 || buffer.toString("ascii", 0, 2) !== "MZ") { - throw new Error("File is not a PE executable"); - } - - const peOffset = readUInt32(buffer, 0x3c, "header"); - checkedRead(buffer, peOffset, 24, "signature"); - if (buffer.toString("ascii", peOffset, peOffset + 4) !== "PE\u0000\u0000") { - throw new Error("Invalid PE signature"); - } - - const sectionCount = readUInt16(buffer, peOffset + 6, "section count"); - const optionalHeaderSize = readUInt16(buffer, peOffset + 20, "optional header size"); - const optionalHeaderOffset = peOffset + 24; - const optionalHeaderMagic = readUInt16(buffer, optionalHeaderOffset, "optional header"); - const dataDirectoryOffset = optionalHeaderOffset + ( - optionalHeaderMagic === 0x10b ? 96 : optionalHeaderMagic === 0x20b ? 112 : 0 - ); - if (dataDirectoryOffset === optionalHeaderOffset) { - throw new Error(`Unsupported PE optional header: 0x${optionalHeaderMagic.toString(16)}`); - } - - checkedRead(buffer, optionalHeaderOffset, optionalHeaderSize, "optional header"); - const importTableRva = readUInt32(buffer, dataDirectoryOffset + 8, "import table"); - if (importTableRva === 0) { - return []; - } - - const sectionTableOffset = optionalHeaderOffset + optionalHeaderSize; - const sections = []; - for (let index = 0; index < sectionCount; index += 1) { - const offset = sectionTableOffset + index * 40; - checkedRead(buffer, offset, 40, "section"); - sections.push({ - virtualSize: readUInt32(buffer, offset + 8, "section virtual size"), - virtualAddress: readUInt32(buffer, offset + 12, "section virtual address"), - rawSize: readUInt32(buffer, offset + 16, "section raw size"), - rawOffset: readUInt32(buffer, offset + 20, "section raw offset"), - }); - } - - const rvaToOffset = (rva) => { - const section = sections.find(({ virtualAddress, virtualSize, rawSize }) => - rva >= virtualAddress && rva < virtualAddress + Math.max(virtualSize, rawSize), - ); - if (!section) { - throw new Error(`PE import RVA 0x${rva.toString(16)} is outside every section`); - } - const offset = section.rawOffset + rva - section.virtualAddress; - checkedRead(buffer, offset, 1, "import"); - return offset; - }; - - const imports = []; - let descriptorOffset = rvaToOffset(importTableRva); - for (;;) { - checkedRead(buffer, descriptorOffset, 20, "import descriptor"); - const fields = Array.from({ length: 5 }, (_, index) => - readUInt32(buffer, descriptorOffset + index * 4, "import descriptor"), - ); - if (fields.every((value) => value === 0)) { - break; - } - imports.push(readAsciiString(buffer, rvaToOffset(fields[3]))); - descriptorOffset += 20; - } - return imports; -} - -export function collectBundledPeDependencies(binary, dependencyDirectory) { - const available = new Map( - readdirSync(dependencyDirectory) - .filter((name) => name.toLowerCase().endsWith(".dll")) - .map((name) => [name.toLowerCase(), join(dependencyDirectory, name)]), - ); - const dependencies = new Map(); - const pending = [binary]; - - while (pending.length > 0) { - const current = pending.pop(); - for (const importedName of readPeImportNames(readFileSync(current))) { - const normalizedName = importedName.toLowerCase(); - const dependency = available.get(normalizedName); - if (!dependency || dependencies.has(normalizedName)) { - continue; - } - dependencies.set(normalizedName, dependency); - pending.push(dependency); - } - } - - return [...dependencies.values()].sort((left, right) => - basename(left).localeCompare(basename(right), "en", { sensitivity: "base" }), - ); -} diff --git a/opennow-stable/scripts/windows-pe-imports.test.mjs b/opennow-stable/scripts/windows-pe-imports.test.mjs deleted file mode 100644 index c5e1a7ff0..000000000 --- a/opennow-stable/scripts/windows-pe-imports.test.mjs +++ /dev/null @@ -1,71 +0,0 @@ -import assert from "node:assert/strict"; -import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises"; -import { tmpdir } from "node:os"; -import { join } from "node:path"; -import test from "node:test"; - -import { collectBundledPeDependencies, readPeImportNames } from "./windows-pe-imports.mjs"; - -function peFixture(importNames) { - const buffer = Buffer.alloc(0x800); - const peOffset = 0x80; - const optionalHeaderOffset = peOffset + 24; - const sectionTableOffset = optionalHeaderOffset + 0xf0; - const sectionRva = 0x1000; - const sectionOffset = 0x200; - const importTableOffset = sectionOffset; - - buffer.write("MZ", 0, "ascii"); - buffer.writeUInt32LE(peOffset, 0x3c); - buffer.write("PE\u0000\u0000", peOffset, "ascii"); - buffer.writeUInt16LE(0x8664, peOffset + 4); - buffer.writeUInt16LE(1, peOffset + 6); - buffer.writeUInt16LE(0xf0, peOffset + 20); - buffer.writeUInt16LE(0x20b, optionalHeaderOffset); - buffer.writeUInt32LE(sectionRva, optionalHeaderOffset + 112 + 8); - buffer.write(".rdata\u0000\u0000", sectionTableOffset, "ascii"); - buffer.writeUInt32LE(0x600, sectionTableOffset + 8); - buffer.writeUInt32LE(sectionRva, sectionTableOffset + 12); - buffer.writeUInt32LE(0x600, sectionTableOffset + 16); - buffer.writeUInt32LE(sectionOffset, sectionTableOffset + 20); - - let nameOffset = importTableOffset + (importNames.length + 1) * 20; - importNames.forEach((name, index) => { - buffer.writeUInt32LE(sectionRva + nameOffset - sectionOffset, importTableOffset + index * 20 + 12); - buffer.write(`${name}\u0000`, nameOffset, "ascii"); - nameOffset += Buffer.byteLength(name) + 1; - }); - return buffer; -} - -test("reads imported DLL names from a 64-bit PE image", () => { - assert.deepEqual( - readPeImportNames(peFixture(["gstvideo-1.0-0.dll", "KERNEL32.dll"])), - ["gstvideo-1.0-0.dll", "KERNEL32.dll"], - ); -}); - -test("collects only the recursive DLL closure available in the runtime", async () => { - const root = await mkdtemp(join(tmpdir(), "opennow-pe-imports-")); - const runtime = join(root, "runtime"); - const binary = join(root, "opennow-streamer.exe"); - - try { - await mkdir(runtime); - await writeFile(binary, peFixture(["gstvideo-1.0-0.dll", "KERNEL32.dll"])); - await writeFile( - join(runtime, "gstvideo-1.0-0.dll"), - peFixture(["gstreamer-1.0-0.dll", "ffi-7.dll"]), - ); - await writeFile(join(runtime, "gstreamer-1.0-0.dll"), peFixture(["glib-2.0-0.dll"])); - await writeFile(join(runtime, "glib-2.0-0.dll"), peFixture([])); - await writeFile(join(runtime, "unused.dll"), peFixture([])); - - assert.deepEqual( - collectBundledPeDependencies(binary, runtime).map((path) => path.slice(runtime.length + 1)), - ["glib-2.0-0.dll", "gstreamer-1.0-0.dll", "gstvideo-1.0-0.dll"], - ); - } finally { - await rm(root, { recursive: true, force: true }); - } -}); diff --git a/opennow-stable/src/main/escapeFullscreenGuard.ts b/opennow-stable/src/main/escapeFullscreenGuard.ts index ae704b29b..a37f7d9cf 100644 --- a/opennow-stable/src/main/escapeFullscreenGuard.ts +++ b/opennow-stable/src/main/escapeFullscreenGuard.ts @@ -1,5 +1,5 @@ export const POINTER_LOCK_ESCAPE_FULLSCREEN_GRACE_MS = 1000; -/** Match native Internal Escape-hold timing (gstreamer_platform.rs). */ +/** Match native presenter's Escape-hold timing. */ export const ESCAPE_HOLD_TO_EXIT_FULLSCREEN_MS = 1500; export interface EscapeKeyInput { diff --git a/opennow-stable/src/main/index.ts b/opennow-stable/src/main/index.ts index 7ef82389b..91bbd26ec 100644 --- a/opennow-stable/src/main/index.ts +++ b/opennow-stable/src/main/index.ts @@ -81,15 +81,27 @@ import { getReleaseHighlightsPayload, shouldShowReleaseHighlights } from "./rele import { shutdownMainTelemetry, syncMainTelemetry } from "./telemetry/posthog"; import { createMainWindow } from "./window/mainWindow"; import { resolveAppInstanceProfile } from "./appInstance"; -import { shouldDefaultLinuxShellToX11 } from "./nativeStreamer/runtime"; import { DiagnosticHistoryController, DiagnosticHistoryStore, } from "./services/diagnosticHistory"; +import { resolveLinuxWindowSystem } from "./linuxWindowSystem"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); +const linuxOzonePlatform = app.commandLine.getSwitchValue("ozone-platform") + || app.commandLine.getSwitchValue("ozone-platform-hint"); +if ( + process.platform === "linux" + && (!linuxOzonePlatform || linuxOzonePlatform === "auto") +) { + app.commandLine.appendSwitch( + "ozone-platform", + resolveLinuxWindowSystem(linuxOzonePlatform, process.env), + ); +} + const appInstanceProfile = resolveAppInstanceProfile( process.argv, app.getPath("userData"), @@ -138,16 +150,6 @@ console.log( `[Main] Video acceleration preference: decode=${bootstrapChromiumPrefs.decoderPreference}, encode=${bootstrapChromiumPrefs.encoderPreference}`, ); -const explicitLinuxOzonePlatform = app.commandLine.getSwitchValue("ozone-platform") - || app.commandLine.getSwitchValue("ozone-platform-hint") - || process.env.ELECTRON_OZONE_PLATFORM_HINT; -if (shouldDefaultLinuxShellToX11(process.platform, explicitLinuxOzonePlatform)) { - app.commandLine.appendSwitch("ozone-platform", "x11"); - console.log( - "[Main] Linux display backend: X11/XWayland (required for embedded native GStreamer video).", - ); -} - const chromiumCommandLine = buildChromiumCommandLine( bootstrapChromiumPrefs, process.platform, diff --git a/opennow-stable/src/main/ipc/sessionHandlers.ts b/opennow-stable/src/main/ipc/sessionHandlers.ts index 2faf435d6..600c68e86 100644 --- a/opennow-stable/src/main/ipc/sessionHandlers.ts +++ b/opennow-stable/src/main/ipc/sessionHandlers.ts @@ -78,12 +78,12 @@ export function registerSessionIpcHandlers(deps: SessionIpcHandlerDeps): void { const streamingBaseUrl = payload.streamingBaseUrl ?? authService.getSelectedProvider().streamingServiceUrl; - const forceNewSession = shouldForceNewSession( - payload.existingSessionStrategy, - ); const resolvedSettings = await resolveSessionCloudGsyncSettings( payload.settings, ); + const forceNewSession = + shouldForceNewSession(payload.existingSessionStrategy) || + resolvedSettings.transportMode === "nvst"; const resolvedPayload: SessionCreateRequest = { ...payload, settings: resolvedSettings, diff --git a/opennow-stable/src/main/linuxVrr.test.ts b/opennow-stable/src/main/linuxVrr.test.ts new file mode 100644 index 000000000..b7b378204 --- /dev/null +++ b/opennow-stable/src/main/linuxVrr.test.ts @@ -0,0 +1,85 @@ +/// + +import assert from "node:assert/strict"; +import test from "node:test"; + +import { + parseHyprlandVrr, + parseXrandrOutputs, + resolveLinuxVrrWindowSystem, + resolveX11Vrr, +} from "./linuxVrr"; + +test("Hyprland VRR requires compositor permission and a high-refresh display", () => { + const monitors = JSON.stringify([{ + name: "DP-2", + description: "VRR Display", + refreshRate: 165.08, + focused: true, + disabled: false, + dpmsStatus: true, + vrr: false, + }]); + const disabled = parseHyprlandVrr('{"int":0}', monitors); + const enabled = parseHyprlandVrr('{"int":1}', monitors); + + assert.equal(disabled.displayCapable, false); + assert.match(disabled.reason, /vrr-disabled/); + assert.equal(enabled.displayCapable, true); + assert.equal(enabled.active, false); + assert.equal(enabled.refreshHz, 165.08); +}); + +test("Hyprland reports VRR active only when the compositor activates it", () => { + const result = parseHyprlandVrr('{"int":2}', JSON.stringify([{ + name: "DP-1", + refreshRate: 144, + focused: true, + vrr: true, + }])); + + assert.equal(result.displayCapable, true); + assert.equal(result.active, true); +}); + +test("Hyprland content-type-only VRR is rejected until SDL can advertise game content", () => { + const result = parseHyprlandVrr('{"int":3}', JSON.stringify([{ + name: "DP-1", + refreshRate: 240, + focused: true, + vrr: false, + }])); + + assert.equal(result.displayCapable, false); + assert.match(result.reason, /content-type-required/); +}); + +test("RandR parser keeps the active mode and standard VRR property", () => { + const outputs = parseXrandrOutputs(`DP-0 connected primary 2560x1440+0+0 +\tvrr_capable: 1 + 2560x1440 165.00*+ 144.00 +HDMI-0 disconnected +`); + + assert.deepEqual(outputs, [{ + name: "DP-0", + primary: true, + refreshHz: 165, + vrrCapable: true, + }]); + assert.equal(resolveX11Vrr("DP-0 connected primary\n\tvrr_capable: 1\n", false).displayCapable, true); +}); + +test("NVIDIA X11 fallback is limited to one high-refresh display", () => { + const oneDisplay = "DP-0 connected primary\n 2560x1440 165.00*+\n"; + const twoDisplays = `${oneDisplay}HDMI-0 connected\n 1920x1080 144.00*+\n`; + + assert.equal(resolveX11Vrr(oneDisplay, true).displayCapable, true); + assert.equal(resolveX11Vrr(twoDisplays, true).displayCapable, false); +}); + +test("Linux window system resolution prefers Wayland", () => { + assert.equal(resolveLinuxVrrWindowSystem({ WAYLAND_DISPLAY: "wayland-1", DISPLAY: ":0" }), "wayland"); + assert.equal(resolveLinuxVrrWindowSystem({ DISPLAY: ":0" }), "x11"); + assert.equal(resolveLinuxVrrWindowSystem({}), "unknown"); +}); diff --git a/opennow-stable/src/main/linuxVrr.ts b/opennow-stable/src/main/linuxVrr.ts new file mode 100644 index 000000000..703410c2b --- /dev/null +++ b/opennow-stable/src/main/linuxVrr.ts @@ -0,0 +1,230 @@ +import { execFile } from "node:child_process"; + +export type LinuxVrrWindowSystem = "wayland" | "x11" | "unknown"; + +export interface LinuxVrrProbe { + platformSupported: boolean; + displayCapable: boolean; + active: boolean; + gsyncDisplay: boolean; + detection: "native" | "assumed" | "unsupported"; + windowSystem: LinuxVrrWindowSystem; + displayName?: string; + refreshHz?: number; + reason: string; +} + +interface HyprlandMonitor { + name?: unknown; + description?: unknown; + refreshRate?: unknown; + focused?: unknown; + disabled?: unknown; + dpmsStatus?: unknown; + vrr?: unknown; +} + +interface XrandrOutput { + name: string; + primary: boolean; + refreshHz?: number; + vrrCapable: boolean; +} + +function execFileText(file: string, args: string[], timeoutMs = 2_500): Promise { + return new Promise((resolve, reject) => { + execFile(file, args, { timeout: timeoutMs, windowsHide: true }, (error, stdout) => { + if (error) { + reject(error); + return; + } + resolve(stdout); + }); + }); +} + +export function resolveLinuxVrrWindowSystem( + env: NodeJS.ProcessEnv = process.env, +): LinuxVrrWindowSystem { + const sessionType = env.XDG_SESSION_TYPE?.trim().toLowerCase(); + if (sessionType === "wayland" || env.WAYLAND_DISPLAY) return "wayland"; + if (sessionType === "x11" || env.DISPLAY) return "x11"; + return "unknown"; +} + +export function parseHyprlandVrr( + optionJson: string, + monitorsJson: string, +): LinuxVrrProbe { + const option = JSON.parse(optionJson || "{}") as { int?: unknown }; + const rawMonitors = JSON.parse(monitorsJson || "[]") as HyprlandMonitor[]; + const monitors = Array.isArray(rawMonitors) + ? rawMonitors.filter((monitor) => monitor.disabled !== true && monitor.dpmsStatus !== false) + : []; + const monitor = monitors.find((candidate) => candidate.focused === true) ?? monitors[0]; + const refreshHz = typeof monitor?.refreshRate === "number" && Number.isFinite(monitor.refreshRate) + ? monitor.refreshRate + : undefined; + const displayName = [monitor?.description, monitor?.name] + .find((value): value is string => typeof value === "string" && value.trim().length > 0); + const vrrMode = typeof option.int === "number" ? option.int : 0; + // Hyprland mode 3 additionally requires the Wayland content-type protocol. + // SDL2 does not advertise game/video content, so only always-on (1) and + // fullscreen-only (2) can reliably activate VRR for this output window. + const compositorAllowsVrr = vrrMode === 1 || vrrMode === 2; + const highRefreshDisplay = refreshHz !== undefined && refreshHz > 60; + const displayCapable = compositorAllowsVrr && highRefreshDisplay; + const active = displayCapable && monitor?.vrr === true; + + let reason: string; + if (!monitor) { + reason = "hyprland-no-active-display"; + } else if (!highRefreshDisplay) { + reason = `hyprland-display-refresh-unsupported display=${displayName ?? "unknown"} refresh=${refreshHz ?? "unknown"}`; + } else if (vrrMode === 3) { + reason = `hyprland-vrr-content-type-required display=${displayName ?? "unknown"} refresh=${refreshHz?.toFixed(2) ?? "unknown"}`; + } else if (!compositorAllowsVrr) { + reason = `hyprland-vrr-disabled display=${displayName ?? "unknown"} refresh=${refreshHz?.toFixed(2) ?? "unknown"}`; + } else { + reason = `hyprland-vrr-allowed display=${displayName ?? "unknown"} refresh=${refreshHz?.toFixed(2) ?? "unknown"} active=${active}`; + } + + return { + platformSupported: true, + displayCapable, + active, + gsyncDisplay: false, + detection: "native", + windowSystem: "wayland", + displayName, + refreshHz, + reason, + }; +} + +export function parseXrandrOutputs(stdout: string): XrandrOutput[] { + const outputs: XrandrOutput[] = []; + let current: XrandrOutput | undefined; + + for (const line of stdout.split(/\r?\n/)) { + const connected = /^(\S+)\s+connected(?:\s+(primary))?\b/.exec(line); + if (connected) { + current = { + name: connected[1], + primary: connected[2] === "primary", + vrrCapable: false, + }; + outputs.push(current); + continue; + } + if (!current) continue; + + const vrr = /^\s+(?:vrr_capable|VARIABLE_REFRESH):\s*(\d+)/i.exec(line); + if (vrr) { + current.vrrCapable = Number(vrr[1]) > 0; + continue; + } + const activeMode = /^\s+\d+x\d+\s+(.+)$/.exec(line); + if (activeMode) { + for (const token of activeMode[1].trim().split(/\s+/)) { + if (!token.includes("*")) continue; + const refreshHz = Number.parseFloat(token.replace(/[^\d.]/g, "")); + if (Number.isFinite(refreshHz)) current.refreshHz = refreshHz; + } + } + } + return outputs; +} + +export function resolveX11Vrr( + stdout: string, + hasNvidiaGpu: boolean, +): LinuxVrrProbe { + const outputs = parseXrandrOutputs(stdout); + const display = outputs.find((output) => output.primary) ?? outputs[0]; + const explicitlyCapable = display?.vrrCapable === true; + // NVIDIA's Xorg driver exposes G-SYNC through NV-CONTROL rather than the + // standard RandR vrr_capable property. Match the official client's + // vrrDisplayWar only for its supported one-display, high-refresh topology. + const nvidiaAssumedCapable = hasNvidiaGpu + && outputs.length === 1 + && (display?.refreshHz ?? 0) > 60; + const displayCapable = explicitlyCapable || nvidiaAssumedCapable; + const detection = explicitlyCapable ? "native" : nvidiaAssumedCapable ? "assumed" : "unsupported"; + const reason = displayCapable + ? `x11-vrr-${explicitlyCapable ? "detected" : "nvidia-assumed"} display=${display?.name ?? "unknown"} refresh=${display?.refreshHz ?? "unknown"}` + : `x11-vrr-unavailable displays=${outputs.length} nvidia=${hasNvidiaGpu} refresh=${display?.refreshHz ?? "unknown"}`; + + return { + platformSupported: true, + displayCapable, + active: displayCapable, + gsyncDisplay: nvidiaAssumedCapable, + detection, + windowSystem: "x11", + displayName: display?.name, + refreshHz: display?.refreshHz, + reason, + }; +} + +export async function probeLinuxVrr( + env: NodeJS.ProcessEnv = process.env, +): Promise { + const windowSystem = resolveLinuxVrrWindowSystem(env); + const desktop = `${env.XDG_CURRENT_DESKTOP ?? ""} ${env.DESKTOP_SESSION ?? ""}`; + + if (windowSystem === "wayland" && /hyprland/i.test(desktop)) { + try { + const [option, monitors] = await Promise.all([ + execFileText("hyprctl", ["getoption", "misc:vrr", "-j"]), + execFileText("hyprctl", ["monitors", "-j"]), + ]); + return parseHyprlandVrr(option, monitors); + } catch (error) { + return { + platformSupported: true, + displayCapable: false, + active: false, + gsyncDisplay: false, + detection: "unsupported", + windowSystem, + reason: `hyprland-vrr-probe-failed ${error instanceof Error ? error.message : String(error)}`, + }; + } + } + + if (windowSystem === "x11") { + try { + const [xrandr, nvidia] = await Promise.all([ + execFileText("xrandr", ["--props", "--current"]), + execFileText("nvidia-smi", ["--query-gpu=name", "--format=csv,noheader"]) + .then((value) => /nvidia/i.test(value)) + .catch(() => false), + ]); + return resolveX11Vrr(xrandr, nvidia); + } catch (error) { + return { + platformSupported: true, + displayCapable: false, + active: false, + gsyncDisplay: false, + detection: "unsupported", + windowSystem, + reason: `x11-vrr-probe-failed ${error instanceof Error ? error.message : String(error)}`, + }; + } + } + + return { + platformSupported: false, + displayCapable: false, + active: false, + gsyncDisplay: false, + detection: "unsupported", + windowSystem, + reason: windowSystem === "wayland" + ? "wayland-compositor-vrr-probe-unsupported" + : "linux-window-system-unknown", + }; +} diff --git a/opennow-stable/src/main/linuxWindowSystem.test.ts b/opennow-stable/src/main/linuxWindowSystem.test.ts new file mode 100644 index 000000000..a592ed0d6 --- /dev/null +++ b/opennow-stable/src/main/linuxWindowSystem.test.ts @@ -0,0 +1,41 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import { resolveLinuxWindowSystem } from "./linuxWindowSystem"; + +test("explicit Linux Ozone platform wins over the desktop environment", () => { + assert.equal( + resolveLinuxWindowSystem("x11", { + XDG_SESSION_TYPE: "wayland", + WAYLAND_DISPLAY: "wayland-0", + }), + "x11", + ); + assert.equal(resolveLinuxWindowSystem("wayland", { DISPLAY: ":0" }), "wayland"); +}); + +test("automatic Linux window system follows a native Wayland session", () => { + assert.equal( + resolveLinuxWindowSystem("auto", { + DISPLAY: ":0", + XDG_SESSION_TYPE: "wayland", + WAYLAND_DISPLAY: "wayland-0", + }), + "wayland", + ); + assert.equal( + resolveLinuxWindowSystem(undefined, { WAYLAND_DISPLAY: "wayland-1" }), + "wayland", + ); +}); + +test("automatic Linux window system keeps X11 sessions on X11", () => { + assert.equal( + resolveLinuxWindowSystem(undefined, { + DISPLAY: ":0", + XDG_SESSION_TYPE: "x11", + }), + "x11", + ); + assert.equal(resolveLinuxWindowSystem(undefined, {}), "x11"); +}); diff --git a/opennow-stable/src/main/linuxWindowSystem.ts b/opennow-stable/src/main/linuxWindowSystem.ts new file mode 100644 index 000000000..3edf3ec07 --- /dev/null +++ b/opennow-stable/src/main/linuxWindowSystem.ts @@ -0,0 +1,23 @@ +export type LinuxWindowSystem = "x11" | "wayland"; + +export function resolveLinuxWindowSystem( + ozonePlatform: string | undefined, + env: NodeJS.ProcessEnv, +): LinuxWindowSystem { + const requested = ozonePlatform?.trim().toLowerCase(); + if (requested === "wayland") { + return "wayland"; + } + if (requested === "x11") { + return "x11"; + } + + const sessionType = env.XDG_SESSION_TYPE?.trim().toLowerCase(); + if (sessionType === "wayland" && env.WAYLAND_DISPLAY?.trim()) { + return "wayland"; + } + if (!env.DISPLAY?.trim() && env.WAYLAND_DISPLAY?.trim()) { + return "wayland"; + } + return "x11"; +} diff --git a/opennow-stable/src/main/nativeCloudGsync.ts b/opennow-stable/src/main/nativeCloudGsync.ts index d18268be5..d63e2e3c6 100644 --- a/opennow-stable/src/main/nativeCloudGsync.ts +++ b/opennow-stable/src/main/nativeCloudGsync.ts @@ -7,13 +7,14 @@ import { unsupportedNativeCloudGsyncCapabilities, type NativeCloudGsyncCapabilities, } from "@shared/cloudGsync"; +import { probeLinuxVrr } from "./linuxVrr"; interface WindowsDisplayProbe { adapters?: string[]; monitors?: string[]; } -function assumedWindowsCapabilities(reason: string): NativeCloudGsyncCapabilities { +function assumedCapabilities(reason: string): NativeCloudGsyncCapabilities { return { platformSupportsCloudGsync: true, isVrrCapableDisplay: true, @@ -21,6 +22,7 @@ function assumedWindowsCapabilities(reason: string): NativeCloudGsyncCapabilitie minimumFpsForCloudGsync: DEFAULT_MINIMUM_FPS_FOR_CLOUD_GSYNC, minimumFpsForReflexWithoutVrr: DEFAULT_MINIMUM_FPS_FOR_REFLEX_WITHOUT_VRR, detectionSource: "assumed", + windowSystem: process.platform === "win32" ? "windows" : "unknown", reason, }; } @@ -64,7 +66,24 @@ export async function getNativeCloudGsyncCapabilities( const override = normalizeCloudGsyncOverride(overrideValue); if (override === "1") { - return assumedWindowsCapabilities("OPENNOW_NATIVE_CLOUD_GSYNC=1"); + return assumedCapabilities("OPENNOW_NATIVE_CLOUD_GSYNC=1"); + } + + if (process.platform === "linux") { + const probe = await probeLinuxVrr(); + return { + platformSupportsCloudGsync: probe.platformSupported, + isVrrCapableDisplay: probe.displayCapable, + isVrrActive: probe.active, + isGsyncDisplay: probe.gsyncDisplay, + minimumFpsForCloudGsync: DEFAULT_MINIMUM_FPS_FOR_CLOUD_GSYNC, + minimumFpsForReflexWithoutVrr: DEFAULT_MINIMUM_FPS_FOR_REFLEX_WITHOUT_VRR, + detectionSource: probe.detection, + windowSystem: probe.windowSystem, + displayName: probe.displayName, + displayRefreshHz: probe.refreshHz, + reason: probe.reason, + }; } if (process.platform !== "win32") { @@ -87,7 +106,7 @@ export async function getNativeCloudGsyncCapabilities( // Node/Electron has no NVAPI/DXGI VRR binding here. Match the official client's // vrrDisplayWar behavior: on Windows with NVIDIA present, treat likely G-Sync // setups as VRR-capable when exact detection is unavailable. - return assumedWindowsCapabilities( + return assumedCapabilities( `nvidia-adapter-assumed-vrr adapters=${adapters.join(",")} monitors=${monitors.join(",") || "unknown"}`, ); } catch (error) { diff --git a/opennow-stable/src/main/nativeStreamer/capabilities.test.ts b/opennow-stable/src/main/nativeStreamer/capabilities.test.ts index 19cea38a7..672892546 100644 --- a/opennow-stable/src/main/nativeStreamer/capabilities.test.ts +++ b/opennow-stable/src/main/nativeStreamer/capabilities.test.ts @@ -53,16 +53,18 @@ test("capability selection skips unavailable preferred and platform backends", ( test("status formatting reports selected video path and codec summary", () => { const status = createNativeStreamerStatus({ protocolVersion: 4, - backend: "gstreamer", + backend: "native", supportsOfferAnswer: true, supportsRemoteIce: true, supportsLocalIce: true, supportsInput: true, + supportsVideoDecode: true, + supportsVideoPresent: true, videoBackends: [backend("vaapi", "linux")], }, { - source: "system", - bundled: false, - message: "System runtime", + source: "self-contained", + selfContained: true, + message: "Self-contained runtime", }, "auto", "linux"); assert.equal(status.activeVideoBackend?.backend, "vaapi"); diff --git a/opennow-stable/src/main/nativeStreamer/capabilities.ts b/opennow-stable/src/main/nativeStreamer/capabilities.ts index b1324b3fe..9fcfe18a8 100644 --- a/opennow-stable/src/main/nativeStreamer/capabilities.ts +++ b/opennow-stable/src/main/nativeStreamer/capabilities.ts @@ -1,11 +1,10 @@ import type { - NativeGstreamerRuntimeStatus, + NativeStreamerRuntimeStatus, NativeStreamerStatus, NativeVideoBackendCapability, NativeVideoBackendPreference, } from "@shared/gfn"; import type { NativeStreamerCapabilities } from "@shared/nativeStreamer"; -import { linuxInstallInstructions } from "./runtime"; function formatVideoBackendName(backend: string | undefined): string { switch (backend) { @@ -86,63 +85,40 @@ export function formatError(error: unknown): string { return error instanceof Error ? error.message : String(error); } -function isWindowsDllLoadFailure(error: unknown, platform: NodeJS.Platform): boolean { - const message = formatError(error); - return platform === "win32" - && (message.includes("3221225781") || message.toLowerCase().includes("0xc0000135")); -} - function formatNativeStreamerDetectionFailure( error: unknown, - runtime: NativeGstreamerRuntimeStatus | null, - platform: NodeJS.Platform, + runtime: NativeStreamerRuntimeStatus | null, ): string { - if (isWindowsDllLoadFailure(error, platform)) { - return runtime?.bundled - ? `Native streamer could not load a required DLL even though bundled GStreamer was detected at ${runtime.path}. The packaged runtime may be incomplete or blocked. ${formatError(error)}` - : `Native streamer could not load a required DLL and no bundled GStreamer runtime was detected. ${formatError(error)}`; + const message = formatError(error); + if (message.includes("3221225781") || message.toLowerCase().includes("0xc0000135")) { + const location = runtime?.path ? ` at ${runtime.path}` : ""; + return `Native streamer could not load a required library${location}. The executable may be incomplete or blocked. ${message}`; } - return `Native streamer was not detected: ${formatError(error)}`; + return `Native streamer was not detected: ${message}`; } export function createNativeStreamerStatus( capabilities: NativeStreamerCapabilities | null, - runtimeStatus: NativeGstreamerRuntimeStatus | null, + runtimeStatus: NativeStreamerRuntimeStatus | null, preferredBackend: NativeVideoBackendPreference, platform = process.platform, ): NativeStreamerStatus { const backend = capabilities?.backend; - const gstreamerAvailable = backend === "gstreamer" && capabilities?.supportsOfferAnswer === true; + const available = backend === "native" + && capabilities?.supportsOfferAnswer === true + && capabilities?.supportsVideoDecode === true + && capabilities?.supportsVideoPresent === true; const videoBackends = capabilities?.videoBackends ?? []; const activeVideoBackend = resolveActiveVideoBackend(videoBackends, preferredBackend, platform); const runtime = runtimeStatus ?? { source: "unknown", - bundled: false, - message: "GStreamer runtime has not been checked yet.", - installInstructions: linuxInstallInstructions(platform), - } satisfies NativeGstreamerRuntimeStatus; - const effectiveRuntime: NativeGstreamerRuntimeStatus = gstreamerAvailable - ? runtime.bundled - ? runtime - : { - ...runtime, - source: "system", - message: "Using system GStreamer runtime; packaged Windows/macOS builds should use the bundled runtime.", - } - : { - ...runtime, - source: runtime.bundled ? "bundled" : platform === "linux" ? "missing" : runtime.source, - message: runtime.bundled - ? "Bundled GStreamer runtime was found, but the GStreamer backend is not ready." - : platform === "linux" - ? "GStreamer is not ready. Install distro GStreamer packages so plugins match the host GPU/driver stack." - : runtime.message, - installInstructions: runtime.installInstructions ?? linuxInstallInstructions(platform), - }; + selfContained: false, + message: "Native streamer runtime has not been checked yet.", + } satisfies NativeStreamerRuntimeStatus; return { detected: true, - gstreamerAvailable, + available, supportsOfferAnswer: capabilities?.supportsOfferAnswer === true, backend, fallbackReason: capabilities?.fallbackReason, @@ -150,31 +126,28 @@ export function createNativeStreamerStatus( activeVideoBackend, codecSummary: summarizeCodecs(activeVideoBackend), zeroCopySummary: summarizeZeroCopy(activeVideoBackend), - gstreamerRuntime: effectiveRuntime, - message: gstreamerAvailable - ? `${effectiveRuntime.message} Video path: ${formatVideoBackendName(activeVideoBackend?.backend)}.` - : capabilities?.fallbackReason ?? effectiveRuntime.message, + runtime, + message: available + ? `${runtime.message} Video path: ${formatVideoBackendName(activeVideoBackend?.backend)}.` + : capabilities?.fallbackReason ?? runtime.message, }; } export function createNativeStreamerDetectionFailureStatus( error: unknown, - runtimeStatus: NativeGstreamerRuntimeStatus | null, - platform = process.platform, + runtimeStatus: NativeStreamerRuntimeStatus | null, + _platform = process.platform, ): NativeStreamerStatus { const runtime = runtimeStatus ?? { - source: platform === "linux" ? "missing" : "unknown", - bundled: false, - message: platform === "linux" - ? "GStreamer is not ready. Linux uses distro packages because private AppImage GStreamer bundling is unreliable across glibc, libdrm/VAAPI/Vulkan, and GPU driver stacks." - : "GStreamer runtime could not be checked because the native streamer did not start.", - installInstructions: linuxInstallInstructions(platform), - } satisfies NativeGstreamerRuntimeStatus; + source: "unknown", + selfContained: false, + message: "Native streamer runtime could not be checked because the executable did not start.", + } satisfies NativeStreamerRuntimeStatus; return { detected: false, - gstreamerAvailable: false, + available: false, supportsOfferAnswer: false, - gstreamerRuntime: runtime, - message: formatNativeStreamerDetectionFailure(error, runtime, platform), + runtime, + message: formatNativeStreamerDetectionFailure(error, runtime), }; } diff --git a/opennow-stable/src/main/nativeStreamer/executableDiscovery.test.ts b/opennow-stable/src/main/nativeStreamer/executableDiscovery.test.ts new file mode 100644 index 000000000..e3f3b64e6 --- /dev/null +++ b/opennow-stable/src/main/nativeStreamer/executableDiscovery.test.ts @@ -0,0 +1,46 @@ +import assert from "node:assert/strict"; +import { chmodSync, mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import test from "node:test"; + +import { resolveNativeStreamerExecutableCandidates } from "./executableDiscovery"; + +function options(root: string, configuredPath = "") { + return { + platform: "linux" as const, + arch: "x64", + resourcesPath: join(root, "resources"), + appPath: join(root, "app"), + mainDir: join(root, "app", "out", "main"), + envExecutablePath: undefined, + getConfiguredPath: () => configuredPath, + }; +} + +test("discovers the packaged self-contained executable", () => { + const root = mkdtempSync(join(tmpdir(), "opennow-native-discovery-")); + try { + const executable = join(root, "resources", "native", "opennow-streamer", "linux-x64", "opennow-streamer"); + mkdirSync(join(executable, ".."), { recursive: true }); + writeFileSync(executable, "native"); + chmodSync(executable, 0o755); + + assert.deepEqual(resolveNativeStreamerExecutableCandidates(options(root)), [executable]); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test("rejects a configured executable path that does not exist", () => { + const root = mkdtempSync(join(tmpdir(), "opennow-native-discovery-")); + try { + const missing = join(root, "missing-streamer"); + assert.throws( + () => resolveNativeStreamerExecutableCandidates(options(root, missing)), + /Configured native streamer executable was not found/, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/opennow-stable/src/main/nativeStreamer/executableDiscovery.ts b/opennow-stable/src/main/nativeStreamer/executableDiscovery.ts index 32987f8b5..c42f4421c 100644 --- a/opennow-stable/src/main/nativeStreamer/executableDiscovery.ts +++ b/opennow-stable/src/main/nativeStreamer/executableDiscovery.ts @@ -1,16 +1,10 @@ import { join, resolve } from "node:path"; import { - hasBundledRuntimeNextToExecutable, isExistingFile, - isPathInside, nativeStreamerExecutableName, nativeStreamerPlatformKey, } from "./runtime"; -import { - materializePackagedNativeStreamerCache, - type PackagedNativeStreamerCacheContext, -} from "./runtimeCache"; export interface NativeStreamerExecutableDiscoveryOptions { platform: NodeJS.Platform; @@ -18,31 +12,8 @@ export interface NativeStreamerExecutableDiscoveryOptions { resourcesPath: string; appPath: string; mainDir: string; - isPackaged: boolean; envExecutablePath: string | undefined; getConfiguredPath(): string; - cacheContext: PackagedNativeStreamerCacheContext; -} - -export function shouldIgnorePackagedExecutableOverride( - configuredPath: string, - options: Pick< - NativeStreamerExecutableDiscoveryOptions, - "resourcesPath" | "appPath" | "mainDir" | "platform" - >, -): boolean { - if (hasBundledRuntimeNextToExecutable(configuredPath)) { - return false; - } - - const packagedRoots = [ - join(options.resourcesPath, "native", "opennow-streamer"), - resolve(options.appPath, "../native/opennow-streamer"), - resolve(options.mainDir, "../../../dist-release/win-unpacked/resources/native/opennow-streamer"), - resolve(options.mainDir, "../../../dist-release/win-unpacked/resources/app.asar.unpacked/native/opennow-streamer"), - ]; - - return packagedRoots.some((root) => isPathInside(root, configuredPath, options.platform)); } export function resolveNativeStreamerExecutableCandidates( @@ -50,83 +21,35 @@ export function resolveNativeStreamerExecutableCandidates( ): string[] { const exeName = nativeStreamerExecutableName(options.platform); const platformKey = nativeStreamerPlatformKey(options.platform, options.arch); - const bundledCandidates = [ - join(options.resourcesPath, "native", "opennow-streamer", platformKey, exeName), - join(options.resourcesPath, "native", "opennow-streamer", exeName), - ]; - const candidates: string[] = []; - const addCandidate = (candidate: string | undefined): void => { - if (!candidate || !isExistingFile(candidate) || candidates.includes(candidate)) { - return; - } - candidates.push(candidate); - }; - - if (options.isPackaged) { - for (const candidate of bundledCandidates) { - if (!isExistingFile(candidate) || !hasBundledRuntimeNextToExecutable(candidate)) { - continue; - } - addCandidate( - materializePackagedNativeStreamerCache( - candidate, - platformKey, - exeName, - options.cacheContext, - ) ?? undefined, - ); - } - } - bundledCandidates.forEach(addCandidate); - if (options.isPackaged && candidates.length > 0) { - const packagedBundledCandidates = candidates.filter((candidate) => - hasBundledRuntimeNextToExecutable(candidate), - ); - return packagedBundledCandidates.length > 0 ? packagedBundledCandidates : candidates; - } - const configuredPath = options.getConfiguredPath().trim(); - if (configuredPath) { - if (isExistingFile(configuredPath)) { - if (!shouldIgnorePackagedExecutableOverride(configuredPath, options)) { - addCandidate(configuredPath); - } else { - console.warn( - "[NativeStreamer] Ignoring packaged executable override without bundled runtime:", - configuredPath, - ); - } - } else { - throw new Error(`Configured native streamer executable was not found: ${configuredPath}`); - } + if (configuredPath && !isExistingFile(configuredPath)) { + throw new Error(`Configured native streamer executable was not found: ${configuredPath}`); } - - [ + // On macOS the streamer must run from inside an .app bundle: a bundle-less process is + // refused window compositing by the WindowServer, so the video overlay never appears. + const bundledMacBinary = + options.platform === "darwin" + ? resolve( + options.mainDir, + "../../../native/opennow-streamer/bin", + platformKey, + "OpenNOWStreamer.app/Contents/MacOS", + exeName, + ) + : undefined; + const checked = [ + configuredPath || undefined, options.envExecutablePath, - ...bundledCandidates, + bundledMacBinary, + join(options.resourcesPath, "native", "opennow-streamer", platformKey, exeName), resolve(options.mainDir, "../../../native/opennow-streamer/bin", platformKey, exeName), - resolve(options.mainDir, "../../../native/opennow-streamer/bin", exeName), - resolve(options.mainDir, "../../../native/opennow-streamer/dist", platformKey, exeName), - resolve(options.mainDir, "../../../native/opennow-streamer/dist", exeName), - resolve(options.mainDir, "../../../native/opennow-streamer/target/release", platformKey, exeName), resolve(options.mainDir, "../../../native/opennow-streamer/target/release", exeName), - resolve(options.mainDir, "../../../native/opennow-streamer/target/debug", platformKey, exeName), resolve(options.mainDir, "../../../native/opennow-streamer/target/debug", exeName), resolve(options.appPath, "../native/opennow-streamer/bin", platformKey, exeName), - resolve(options.appPath, "../native/opennow-streamer/bin", exeName), - resolve(options.appPath, "../native/opennow-streamer/dist", platformKey, exeName), - resolve(options.appPath, "../native/opennow-streamer/dist", exeName), - resolve(options.appPath, "../native/opennow-streamer/target/release", platformKey, exeName), - resolve(options.appPath, "../native/opennow-streamer/target/release", exeName), - resolve(options.appPath, "../native/opennow-streamer/target/debug", platformKey, exeName), - resolve(options.appPath, "../native/opennow-streamer/target/debug", exeName), - ] - .filter((candidate): candidate is string => Boolean(candidate)) - .forEach(addCandidate); - - if (candidates.length > 0) { - return candidates; - } - - throw new Error(`Native streamer binary not found. Checked: ${candidates.join(", ")}`); + ].filter((candidate): candidate is string => Boolean(candidate)); + const candidates = checked.filter((candidate, index) => + isExistingFile(candidate) && checked.indexOf(candidate) === index, + ); + if (candidates.length > 0) return candidates; + throw new Error(`Native streamer binary not found. Checked: ${checked.join(", ")}`); } diff --git a/opennow-stable/src/main/nativeStreamer/manager.test.ts b/opennow-stable/src/main/nativeStreamer/manager.test.ts index 24810889c..1ece74d05 100644 --- a/opennow-stable/src/main/nativeStreamer/manager.test.ts +++ b/opennow-stable/src/main/nativeStreamer/manager.test.ts @@ -3,8 +3,13 @@ import type { ChildProcessWithoutNullStreams } from "node:child_process"; import { EventEmitter } from "node:events"; import test from "node:test"; +import type { + MainToRendererSignalingEvent, + NativeStreamerSessionContext, +} from "@shared/gfn"; import type { NativeStreamerCapabilities, + NativeStreamerActiveTransportCapabilities, NativeStreamerEvent, NativeStreamerResponse, } from "@shared/nativeStreamer"; @@ -37,17 +42,39 @@ interface FakeChild { interface ManagerInternals { child: ChildProcessWithoutNullStreams | null; + stdoutBuffer: string; activeSessionId: string | null; + activeTransport: "webrtc" | "nvst" | null; capabilities: NativeStreamerCapabilities | null; + activeTransportCapabilities: NativeStreamerActiveTransportCapabilities | null; + inputReady: boolean; + nativeInputOwner: "electron" | "native"; + nvstTransportReady: boolean; + nvstReadinessError: Error | null; pending: Map; request( input: NativeStreamerCommandInput, timeoutMs: number, ): Promise; installStdinErrorHandler(child: ChildProcessWithoutNullStreams): void; + handleStdout(child: ChildProcessWithoutNullStreams, chunk: string): void; handleEvent(message: NativeStreamerEvent): void; + ensureProcess(): Promise; } +test("stdout from a replaced native process cannot affect the current session", () => { + const { internals } = createManager(); + const current = createFakeChild(); + const stale = createFakeChild(); + internals.child = current.child; + + internals.handleStdout(stale.child, "stale partial output"); + assert.equal(internals.stdoutBuffer, ""); + + internals.handleStdout(current.child, "current partial output"); + assert.equal(internals.stdoutBuffer, "current partial output"); +}); + function createFakeChild(): FakeChild { const stdin = new FakeStdin(); let killed = false; @@ -68,13 +95,12 @@ function createFakeChild(): FakeChild { }; } -function createManager(): { +function createManager(emitted: MainToRendererSignalingEvent[] = []): { manager: NativeStreamerManager; internals: ManagerInternals; } { const manager = new NativeStreamerManager({ mainDir: "", - getBackendPreference: () => "auto", getVideoBackendPreference: () => "auto", getExecutablePathOverride: () => "", getCloudGsyncMode: () => "auto", @@ -83,7 +109,7 @@ function createManager(): { sendAnswer: async () => undefined, sendIceCandidate: async () => undefined, requestKeyframe: async () => undefined, - emit: () => undefined, + emit: (event) => emitted.push(event), retryWithSoftwareDecoder: () => undefined, }); return { @@ -98,7 +124,6 @@ test("Linux decoder startup timeout requests one native software retry", () => { let recoveryMessage = ""; const manager = new NativeStreamerManager({ mainDir: "", - getBackendPreference: () => "auto", getVideoBackendPreference: () => "nvdec", getExecutablePathOverride: () => "", getCloudGsyncMode: () => "auto", @@ -175,12 +200,16 @@ test("input writes tolerate a child exit race but still throw unrelated failures internals.activeSessionId = "session"; internals.capabilities = { protocolVersion: 4, - backend: "gstreamer", + backend: "native", supportsOfferAnswer: true, supportsRemoteIce: true, supportsLocalIce: true, supportsInput: true, + supportsVideoDecode: true, + supportsVideoPresent: true, }; + internals.activeTransportCapabilities = activeInputCapabilities(); + internals.inputReady = true; fake.stdin.writeImpl = () => { throw writeError("ERR_STREAM_DESTROYED"); }; @@ -200,12 +229,16 @@ test("input writes tolerate a child exit race but still throw unrelated failures internals.activeSessionId = "session"; internals.capabilities = { protocolVersion: 4, - backend: "gstreamer", + backend: "native", supportsOfferAnswer: true, supportsRemoteIce: true, supportsLocalIce: true, supportsInput: true, + supportsVideoDecode: true, + supportsVideoPresent: true, }; + internals.activeTransportCapabilities = activeInputCapabilities(); + internals.inputReady = true; assert.throws( () => manager.sendInput({ payloadBase64: "AQ==" }), @@ -214,6 +247,312 @@ test("input writes tolerate a child exit race but still throw unrelated failures assert.equal(internals.child, secondFake.child); }); +function activeInputCapabilities(): NativeStreamerActiveTransportCapabilities { + return { + supportsOfferAnswer: false, + supportsRemoteIce: false, + supportsLocalIce: false, + supportsInput: true, + supportsAudioDecode: true, + supportsAudioOutput: true, + }; +} + +test("input is suppressed until the active transport reports its channels ready", () => { + const { manager, internals } = createManager(); + const fake = createFakeChild(); + let writes = 0; + fake.stdin.writeImpl = () => { + writes += 1; + return true; + }; + internals.child = fake.child; + internals.activeSessionId = "session"; + internals.capabilities = { + protocolVersion: 4, + backend: "native", + supportsOfferAnswer: true, + supportsRemoteIce: true, + supportsLocalIce: true, + supportsInput: true, + supportsVideoDecode: true, + supportsVideoPresent: true, + }; + internals.activeTransportCapabilities = activeInputCapabilities(); + + manager.sendInput({ payloadBase64: "AQ==" }); + assert.equal(writes, 0); + + internals.handleEvent({ type: "input-ready", protocolVersion: 3 }); + manager.sendInput({ payloadBase64: "AQ==" }); + assert.equal(writes, 1); +}); + +test("input readiness reports the native window owner to the renderer", () => { + const emitted: MainToRendererSignalingEvent[] = []; + const { internals } = createManager(emitted); + internals.activeSessionId = "wayland-session"; + internals.activeTransportCapabilities = activeInputCapabilities(); + internals.nativeInputOwner = "native"; + + internals.handleEvent({ type: "input-ready", protocolVersion: 3 }); + + assert.deepEqual(emitted, [{ + type: "native-input-ready", + protocolVersion: 3, + inputOwner: "native", + }]); +}); + +test("input unavailable clears readiness and forwards the native reason", () => { + const emitted: MainToRendererSignalingEvent[] = []; + const { internals } = createManager(emitted); + internals.activeTransportCapabilities = activeInputCapabilities(); + internals.inputReady = true; + + internals.handleEvent({ type: "input-unavailable", reason: "reliable channel failed" }); + + assert.equal(internals.inputReady, false); + assert.deepEqual(emitted, [{ + type: "native-input-unavailable", + reason: "reliable channel failed", + }]); +}); + +test("native input responses preserve success and report SCTP write failures", () => { + const emitted: MainToRendererSignalingEvent[] = []; + const { manager, internals } = createManager(emitted); + const fake = createFakeChild(); + const commandIds: string[] = []; + fake.stdin.writeImpl = (chunk) => { + commandIds.push((JSON.parse(chunk) as { id: string }).id); + return true; + }; + internals.child = fake.child; + internals.activeSessionId = "session"; + internals.capabilities = { + protocolVersion: 4, + backend: "native", + supportsOfferAnswer: true, + supportsRemoteIce: true, + supportsLocalIce: true, + supportsInput: true, + supportsVideoDecode: true, + supportsVideoPresent: true, + }; + internals.activeTransportCapabilities = activeInputCapabilities(); + internals.inputReady = true; + + manager.sendInput({ payloadBase64: "AQ==" }); + assert.equal(internals.pending.size, 1); + internals.handleStdout(fake.child, `${JSON.stringify({ + id: commandIds[0], + type: "ok", + })}\n`); + assert.equal(internals.pending.size, 0); + assert.equal(internals.inputReady, true); + assert.deepEqual(emitted, []); + + manager.sendInput({ payloadBase64: "Ag==" }); + assert.equal(internals.pending.size, 1); + internals.handleStdout(fake.child, `${JSON.stringify({ + id: commandIds[1], + type: "error", + code: "input-write-failed", + message: "reliable SCTP write failed", + })}\n`); + + assert.equal(internals.pending.size, 0); + assert.equal(internals.inputReady, false); + assert.deepEqual(emitted, [{ + type: "native-input-unavailable", + reason: "Native input write failed: input-write-failed: reliable SCTP write failed", + }]); +}); + +test("terminal stopped clears ownership so same-session prepare starts again", async () => { + const { manager, internals } = createManager(); + internals.activeSessionId = "same-session"; + internals.activeTransport = "nvst"; + internals.activeTransportCapabilities = activeInputCapabilities(); + internals.inputReady = true; + internals.ensureProcess = async () => undefined; + let starts = 0; + internals.request = async (input) => { + assert.equal(input.type, "start"); + starts += 1; + return { + id: "start", + type: "ok", + transport: "nvst", + capabilities: activeInputCapabilities(), + }; + }; + + internals.handleEvent({ type: "status", status: "stopped", message: "remote ended" }); + assert.equal(internals.activeSessionId, null); + assert.equal(internals.activeTransport, null); + assert.equal(internals.activeTransportCapabilities, null); + assert.equal(internals.inputReady, false); + + await manager.prepareForSession({ + session: { sessionId: "same-session" }, + settings: { + resolution: "1920x1080", + fps: 60, + codec: "H264", + transportMode: "nvst", + enableCloudGsync: false, + }, + } as NativeStreamerSessionContext); + + assert.equal(starts, 1); + assert.equal(internals.activeSessionId, "same-session"); +}); + +test("native NVST reservation release sends an idempotent unbind command", async () => { + const { manager, internals } = createManager(); + internals.ensureProcess = async () => undefined; + let unbinds = 0; + internals.request = async (input) => { + if (input.type === "nvst-bind") { + return { id: "bind", type: "nvst-bound", port: 45_000 }; + } + assert.equal(input.type, "nvst-unbind"); + unbinds += 1; + return { id: "unbind", type: "ok" }; + }; + + const reservation = await manager.reserveNvstUdp(); + await reservation.release(); + await reservation.release(); + assert.equal(unbinds, 1); +}); + +test("native NVST start takes ownership without unbinding its reserved socket", async () => { + const { manager, internals } = createManager(); + internals.ensureProcess = async () => undefined; + const commands: string[] = []; + internals.request = async (input) => { + commands.push(input.type); + if (input.type === "nvst-bind") { + return { id: "bind", type: "nvst-bound", port: 45_000 }; + } + if (input.type === "start") { + return { + id: "start", + type: "ok", + transport: "nvst", + capabilities: activeInputCapabilities(), + }; + } + assert.fail(`Unexpected command after native NVST ownership transfer: ${input.type}`); + }; + + const reservation = await manager.reserveNvstUdp(); + await manager.prepareForSession({ + session: { sessionId: "native-owner" }, + settings: { + resolution: "1920x1080", + fps: 60, + codec: "H264", + transportMode: "nvst", + enableCloudGsync: false, + }, + nvstVideo: { clientUdpPort: 45_000 }, + } as NativeStreamerSessionContext); + await reservation.release(); + + assert.deepEqual(commands, ["nvst-bind", "start"]); +}); + +test("NVST readiness waits for the native SCTP transport event", async () => { + const { manager, internals } = createManager(); + internals.activeSessionId = "ready-session"; + internals.activeTransport = "nvst"; + internals.activeTransportCapabilities = activeInputCapabilities(); + + const ready = manager.waitForNvstTransportReady("ready-session", 1_000); + internals.handleEvent({ type: "nvst-transport-ready", phase: "dtls" }); + assert.equal(internals.nvstTransportReady, false); + internals.handleEvent({ type: "nvst-transport-ready", phase: "sctp" }); + await ready; + assert.equal(internals.nvstTransportReady, true); +}); + +test("NVST readiness is bounded when native DTLS/SCTP never becomes ready", async () => { + const { manager, internals } = createManager(); + internals.activeSessionId = "timeout-session"; + internals.activeTransport = "nvst"; + internals.activeTransportCapabilities = activeInputCapabilities(); + + await assert.rejects( + manager.waitForNvstTransportReady("timeout-session", 5), + /DTLS\/SCTP readiness timed out after 5ms/, + ); +}); + +test("NVST readiness survives an input-ready event racing the start response", async () => { + const { manager, internals } = createManager(); + internals.ensureProcess = async () => undefined; + internals.request = async (input) => { + assert.equal(input.type, "start"); + internals.handleEvent({ type: "input-ready", protocolVersion: 3 }); + return { + id: "start", + type: "ok", + transport: "nvst", + capabilities: activeInputCapabilities(), + }; + }; + + await manager.prepareForSession({ + session: { sessionId: "racing-session" }, + settings: { + resolution: "1920x1080", + fps: 60, + codec: "H264", + transportMode: "nvst", + enableCloudGsync: false, + }, + } as NativeStreamerSessionContext); + + await manager.waitForNvstTransportReady("racing-session", 5); + assert.equal(internals.inputReady, true); +}); + +test("NVST readiness preserves input failure racing the start response", async () => { + const { manager, internals } = createManager(); + internals.ensureProcess = async () => undefined; + internals.request = async (input) => { + assert.equal(input.type, "start"); + internals.handleEvent({ type: "input-unavailable", reason: "handshake failed" }); + return { + id: "start", + type: "ok", + transport: "nvst", + capabilities: activeInputCapabilities(), + }; + }; + + await manager.prepareForSession({ + session: { sessionId: "failing-race-session" }, + settings: { + resolution: "1920x1080", + fps: 60, + codec: "H264", + transportMode: "nvst", + enableCloudGsync: false, + }, + } as NativeStreamerSessionContext); + + await assert.rejects( + manager.waitForNvstTransportReady("failing-race-session", 1_000), + /handshake failed/, + ); + assert.equal(internals.nvstReadinessError?.message.includes("handshake failed"), true); +}); + test("unrelated synchronous command write failures reject only their request", async () => { const { internals } = createManager(); const fake = createFakeChild(); diff --git a/opennow-stable/src/main/nativeStreamer/manager.ts b/opennow-stable/src/main/nativeStreamer/manager.ts index 887bae3c8..84ec16b16 100644 --- a/opennow-stable/src/main/nativeStreamer/manager.ts +++ b/opennow-stable/src/main/nativeStreamer/manager.ts @@ -1,6 +1,5 @@ import electron from "electron"; import { randomUUID } from "node:crypto"; -import { tmpdir } from "node:os"; import { spawn, type ChildProcessWithoutNullStreams } from "node:child_process"; import { basename } from "node:path"; @@ -12,11 +11,10 @@ import { type IceCandidatePayload, type KeyframeRequest, type MainToRendererSignalingEvent, - type NativeStreamerBackendPreference, type NativeStreamerFeatureMode, type NativeVideoBackendPreference, type NativeStreamerStatus, - type NativeGstreamerRuntimeStatus, + type NativeStreamerRuntimeStatus, type NativeRenderSurface, type NativeStreamerSessionContext, type SendAnswerRequest, @@ -25,6 +23,7 @@ import { import { NATIVE_STREAMER_PROTOCOL_VERSION, type NativeStreamerCapabilities, + type NativeStreamerActiveTransportCapabilities, type NativeStreamerCommand, type NativeStreamerEvent, type NativeStreamerInputPacket, @@ -32,7 +31,6 @@ import { type NativeStreamerResponse, } from "@shared/nativeStreamer"; import { isTerminalBrokenWriteError, setLogContext } from "@shared/logger"; -import type { NativeStreamerShortcutBindings } from "@shared/gfn"; import { createNativeStreamerDetectionFailureStatus, createNativeStreamerStatus, @@ -59,7 +57,6 @@ interface NativeStreamerCallbacks { interface NativeStreamerManagerOptions extends NativeStreamerCallbacks { mainDir: string; - getBackendPreference(): NativeStreamerBackendPreference; getVideoBackendPreference(): NativeVideoBackendPreference; getExecutablePathOverride(): string; getCloudGsyncMode(): NativeStreamerFeatureMode; @@ -73,41 +70,51 @@ interface PendingRequest { timeout: NodeJS.Timeout; } +interface NvstReservationLease { + ownership: "negotiator" | "native"; + released: boolean; +} + +interface PendingNvstReadiness { + sessionId: string; + resolve(): void; + reject(error: Error): void; + timeout: NodeJS.Timeout; +} + const HELLO_TIMEOUT_MS = 10000; -const BUNDLED_GSTREAMER_HELLO_TIMEOUT_MS = process.platform === "win32" ? 120000 : 30000; +const BUNDLED_NATIVE_HELLO_TIMEOUT_MS = process.platform === "win32" ? 120000 : 30000; const CONTROL_TIMEOUT_MS = 8000; const SESSION_START_TIMEOUT_MS = process.platform === "win32" ? 90000 : 45000; const SURFACE_UPDATE_TIMEOUT_MS = 15000; const OFFER_TIMEOUT_MS = 20000; const STOP_TIMEOUT_MS = 1200; +const NVST_TRANSPORT_READY_TIMEOUT_MS = 7000; +const INPUT_RESPONSE_TIMEOUT_MS = 2000; const MAX_INPUT_STDIN_BUFFER_BYTES = 64 * 1024; -const MIN_NATIVE_BITRATE_KBPS = 5_000; -const MAX_NATIVE_BITRATE_KBPS = 150_000; function toError(error: unknown): Error { return error instanceof Error ? error : new Error(String(error)); } -function normalizeBitrateKbps(value: number): number { - if (!Number.isFinite(value)) { - return MIN_NATIVE_BITRATE_KBPS; - } - - return Math.min( - MAX_NATIVE_BITRATE_KBPS, - Math.max(MIN_NATIVE_BITRATE_KBPS, Math.round(value)), - ); -} - export class NativeStreamerManager { private child: ChildProcessWithoutNullStreams | null = null; private startupPromise: Promise | null = null; private stdoutBuffer = ""; private stderrTail: string[] = []; - private gstreamerRuntime: NativeGstreamerRuntimeStatus | null = null; + private runtimeStatus: NativeStreamerRuntimeStatus | null = null; private pending = new Map(); private capabilities: NativeStreamerCapabilities | null = null; private activeSessionId: string | null = null; + private activeTransport: "webrtc" | "nvst" | null = null; + private activeTransportCapabilities: NativeStreamerActiveTransportCapabilities | null = null; + private nvstReservation: NvstReservationLease | null = null; + private pendingNvstSessionId: string | null = null; + private nvstReadinessWaiters = new Set(); + private nvstTransportReady = false; + private nvstReadinessError: Error | null = null; + private inputReady = false; + private nativeInputOwner: "electron" | "native" = "electron"; private inputBackpressureWarned = false; private answerInFlight = false; private queuedLocalIce: IceCandidatePayload[] = []; @@ -136,6 +143,10 @@ export class NativeStreamerManager { return this.activeSessionId !== null; } + isNvstSessionActive(sessionId: string): boolean { + return this.activeSessionId === sessionId && this.activeTransport === "nvst"; + } + private retainDiagnosticState(values: Record): void { this.diagnosticState = { ...this.diagnosticState, @@ -148,6 +159,74 @@ export class NativeStreamerManager { this.videoBackendOverride = value; } + async reserveNvstUdp(): Promise<{ + port: number; + mjolnirPort?: number; + localAddress?: string; + iceUsernameFragment?: string; + icePassword?: string; + dtlsFingerprint?: string; + send(payload: Buffer, host: string, port: number): Promise; + release(): Promise; + }> { + await this.ensureProcess(); + const response = await this.request({ type: "nvst-bind" }, CONTROL_TIMEOUT_MS); + if (response.type !== "nvst-bound" || !Number.isInteger(response.port) || response.port <= 0) { + throw new Error("Native streamer did not reserve an NVST UDP socket."); + } + const port = response.port; + const mjolnirPort = Number.isInteger(response.mjolnirPort) && (response.mjolnirPort ?? 0) > 0 + ? response.mjolnirPort + : undefined; + const localAddress = typeof response.localAddress === "string" && response.localAddress.length > 0 + ? response.localAddress + : undefined; + const lease: NvstReservationLease = { + ownership: "negotiator", + released: false, + }; + this.nvstReservation = lease; + console.log( + `[NativeStreamer] Reserved NVST video UDP on port ${port} before RTSP ANNOUNCE` + + `${mjolnirPort ? ` mjolnirPort=${mjolnirPort}` : ""}` + + `${localAddress ? ` localAddress=${localAddress}` : ""}` + + `${response.dtlsFingerprint ? ` (dtlsFingerprintBytes=${response.dtlsFingerprint.length})` : ""}`, + ); + return { + port, + mjolnirPort, + localAddress, + iceUsernameFragment: response.iceUsernameFragment, + icePassword: response.icePassword, + dtlsFingerprint: response.dtlsFingerprint, + send: async (payload, host, peerPort) => { + const sent = await this.request({ + type: "nvst-send", + host, + port: peerPort, + payloadBase64: payload.toString("base64"), + }, CONTROL_TIMEOUT_MS); + if (sent.type !== "ok") { + throw new Error(`Native streamer returned ${sent.type} instead of ok for nvst-send.`); + } + }, + release: async () => { + if (lease.released) { + return; + } + lease.released = true; + if (lease.ownership === "native" || this.nvstReservation !== lease) { + return; + } + this.nvstReservation = null; + const released = await this.request({ type: "nvst-unbind" }, CONTROL_TIMEOUT_MS); + if (released.type !== "ok") { + throw new Error(`Native streamer returned ${released.type} instead of ok for nvst-unbind.`); + } + }, + }; + } + async prepareForSession(context: NativeStreamerSessionContext): Promise { if (this.activeSessionId && this.activeSessionId !== context.session.sessionId) { await this.stop("new native streamer session"); @@ -174,15 +253,91 @@ export class NativeStreamerManager { ); } - await this.request({ - type: "start", - context, - }, SESSION_START_TIMEOUT_MS); + const expectsNvst = context.settings.transportMode === "nvst" || context.nvstVideo !== undefined; + this.inputReady = false; + this.nvstTransportReady = false; + this.nvstReadinessError = null; + this.pendingNvstSessionId = expectsNvst ? context.session.sessionId : null; + let response: NativeStreamerResponse; + try { + response = await this.request({ + type: "start", + context, + }, SESSION_START_TIMEOUT_MS); + } catch (error) { + this.pendingNvstSessionId = null; + throw error; + } + if (response.type !== "ok") { + this.pendingNvstSessionId = null; + throw new Error(`Native streamer returned ${response.type} instead of ok.`); + } this.activeSessionId = context.session.sessionId; + this.activeTransport = response.transport === "nvst" ? "nvst" : "webrtc"; + this.activeTransportCapabilities = response.capabilities ?? { + supportsOfferAnswer: this.activeTransport === "webrtc" + && this.capabilities?.supportsOfferAnswer === true, + supportsRemoteIce: this.activeTransport === "webrtc" + && this.capabilities?.supportsRemoteIce === true, + supportsLocalIce: this.activeTransport === "webrtc" + && this.capabilities?.supportsLocalIce === true, + supportsInput: this.capabilities?.supportsInput === true, + supportsAudioDecode: this.capabilities?.supportsAudioDecode === true, + supportsAudioOutput: this.capabilities?.supportsAudioOutput === true, + }; + if (this.activeTransport === "nvst" && this.nvstReservation?.ownership === "negotiator") { + this.nvstReservation.ownership = "native"; + } + if (this.activeTransport !== "nvst") { + this.inputReady = false; + this.nvstTransportReady = false; + this.nvstReadinessError = null; + } + this.pendingNvstSessionId = null; this.retainDiagnosticState({ sessionState: "ready" }); await this.flushQueuedRemoteIce(context.session.sessionId); } + waitForNvstTransportReady( + sessionId: string, + timeoutMs = NVST_TRANSPORT_READY_TIMEOUT_MS, + ): Promise { + if (this.activeSessionId !== sessionId || this.activeTransport !== "nvst") { + return Promise.reject(new Error(`Native NVST session ${sessionId} is not active.`)); + } + if (!this.activeTransportCapabilities?.supportsInput) { + return Promise.reject(new Error("Native NVST transport does not support the DTLS/SCTP readiness handshake.")); + } + if (this.nvstReadinessError) { + return Promise.reject(this.nvstReadinessError); + } + if (this.nvstTransportReady) { + return Promise.resolve(); + } + + return new Promise((resolve, reject) => { + const waiter: PendingNvstReadiness = { + sessionId, + resolve: () => { + clearTimeout(waiter.timeout); + this.nvstReadinessWaiters.delete(waiter); + resolve(); + }, + reject: (error) => { + clearTimeout(waiter.timeout); + this.nvstReadinessWaiters.delete(waiter); + reject(error); + }, + timeout: setTimeout(() => { + waiter.reject(new Error( + `Native NVST DTLS/SCTP readiness timed out after ${timeoutMs}ms.`, + )); + }, timeoutMs), + }; + this.nvstReadinessWaiters.add(waiter); + }); + } + async handleOffer(sdp: string, context: NativeStreamerSessionContext): Promise { const negotiatedProfile = context.session.negotiatedStreamProfile; console.log( @@ -208,9 +363,9 @@ export class NativeStreamerManager { negotiatedCodec: negotiatedProfile?.codec ?? context.settings.codec, }); - if (!this.capabilities?.supportsOfferAnswer) { - console.warn( - `[NativeStreamer] Backend "${this.capabilities?.backend ?? "unknown"}" reports offer/answer is not ready; forwarding offer for validation/fallback.`, + if (!(this.activeTransportCapabilities?.supportsOfferAnswer ?? this.capabilities?.supportsOfferAnswer)) { + throw new Error( + `Native streamer backend "${this.capabilities?.backend ?? "unknown"}" does not support offer/answer.`, ); } @@ -261,14 +416,14 @@ export class NativeStreamerManager { await this.ensureProcess(); return createNativeStreamerStatus( this.capabilities, - this.gstreamerRuntime, + this.runtimeStatus, this.options.getVideoBackendPreference(), process.platform, ); } catch (error) { return createNativeStreamerDetectionFailureStatus( error, - this.gstreamerRuntime, + this.runtimeStatus, process.platform, ); } @@ -276,6 +431,13 @@ export class NativeStreamerManager { async addRemoteIce(candidate: IceCandidatePayload, context: NativeStreamerSessionContext): Promise { const sessionId = context.session.sessionId; + if ( + this.activeTransportCapabilities + ? !this.activeTransportCapabilities.supportsRemoteIce + : this.capabilities && !this.capabilities.supportsRemoteIce + ) { + return; + } if (!this.child || this.activeSessionId !== sessionId) { this.queueRemoteIce(sessionId, candidate); return; @@ -305,6 +467,8 @@ export class NativeStreamerManager { || child.stdin.writableEnded || !this.activeSessionId || !this.capabilities?.supportsInput + || !this.activeTransportCapabilities?.supportsInput + || !this.inputReady ) { return; } @@ -323,6 +487,33 @@ export class NativeStreamerManager { input, } satisfies NativeStreamerCommand; + const reportInputFailure = (error: Error): void => { + if (!this.inputReady) { + return; + } + const reason = `Native input write failed: ${formatError(error)}`; + this.inputReady = false; + this.retainDiagnosticState({ inputReady: false, inputUnavailableReason: reason }); + this.options.emit({ type: "native-input-unavailable", reason }); + }; + const timeout = setTimeout(() => { + if (!this.pending.delete(payload.id)) { + return; + } + reportInputFailure(new Error(`Native input acknowledgement timed out after ${INPUT_RESPONSE_TIMEOUT_MS}ms.`)); + }, INPUT_RESPONSE_TIMEOUT_MS); + timeout.unref?.(); + this.pending.set(payload.id, { + resolve: () => { + clearTimeout(timeout); + }, + reject: (error) => { + clearTimeout(timeout); + reportInputFailure(error); + }, + timeout, + }); + let writeFailed = false; let flushed: boolean; try { @@ -336,6 +527,7 @@ export class NativeStreamerManager { } catch (error) { const writeError = toError(error); if (!isTerminalBrokenWriteError(writeError, child.stdin)) { + this.rejectPendingRequest(payload.id, writeError); throw error; } this.handleStdinFailure(child, writeError); @@ -361,19 +553,6 @@ export class NativeStreamerManager { this.surfaceUpdates.update(surface); } - updateBitrateLimit(maxBitrateKbps: number): void { - if (!this.child || !this.activeSessionId) { - return; - } - - void this.request({ - type: "bitrate", - maxBitrateKbps: normalizeBitrateKbps(maxBitrateKbps), - }, CONTROL_TIMEOUT_MS).catch((error) => { - console.warn("[NativeStreamer] Failed to update native bitrate limit:", error); - }); - } - setInputPaused(paused: boolean): void { if (!this.child || !this.activeSessionId) { return; @@ -387,19 +566,6 @@ export class NativeStreamerManager { }); } - updateShortcuts(shortcuts: NativeStreamerShortcutBindings): void { - if (!this.child || !this.activeSessionId) { - return; - } - - void this.request({ - type: "update-shortcuts", - shortcuts, - }, CONTROL_TIMEOUT_MS).catch((error) => { - console.warn("[NativeStreamer] Failed to update native shortcut bindings:", error); - }); - } - async stop(reason = "stopped"): Promise { if (reason === "retrying native video with software decoding") { this.suppressNextStoppedEvent = true; @@ -412,6 +578,14 @@ export class NativeStreamerManager { stopReason: reason, }); this.activeSessionId = null; + this.activeTransport = null; + this.activeTransportCapabilities = null; + this.pendingNvstSessionId = null; + this.nvstReservation = null; + this.inputReady = false; + this.nvstTransportReady = false; + this.nvstReadinessError = null; + this.rejectNvstReadiness(new Error(`Native streamer stopped before NVST transport readiness (${reason}).`)); this.capabilities = null; this.surfaceUpdates.markNotReady(); this.clearQueuedRemoteIce(); @@ -448,6 +622,14 @@ export class NativeStreamerManager { stopReason: reason, }); this.activeSessionId = null; + this.activeTransport = null; + this.activeTransportCapabilities = null; + this.pendingNvstSessionId = null; + this.nvstReservation = null; + this.inputReady = false; + this.nvstTransportReady = false; + this.nvstReadinessError = null; + this.rejectNvstReadiness(new Error(`Native streamer ${reason} before NVST transport readiness.`)); this.capabilities = null; this.surfaceUpdates.markNotReady(); this.clearQueuedRemoteIce(); @@ -478,7 +660,6 @@ export class NativeStreamerManager { } const startupPromise = (async () => { - const backendPreference = this.options.getBackendPreference(); let lastError: Error | null = null; for (const executablePath of resolveNativeStreamerExecutableCandidates({ @@ -487,20 +668,11 @@ export class NativeStreamerManager { resourcesPath: process.resourcesPath, appPath: app.getAppPath(), mainDir: this.options.mainDir, - isPackaged: app.isPackaged, envExecutablePath: process.env.OPENNOW_NATIVE_STREAMER, getConfiguredPath: () => this.options.getExecutablePathOverride(), - cacheContext: { - appVersion: app.getVersion(), - isPackaged: app.isPackaged, - platform: process.platform, - resourcesPath: process.resourcesPath, - tempDirectory: tmpdir(), - userDataPath: app.getPath("userData"), - }, })) { try { - await this.startProcess(executablePath, backendPreference); + await this.startProcess(executablePath); return; } catch (error) { lastError = error instanceof Error ? error : new Error(String(error)); @@ -533,17 +705,12 @@ export class NativeStreamerManager { } } - private async startProcess( - executablePath: string, - backendPreference: NativeStreamerBackendPreference, - ): Promise { + private async startProcess(executablePath: string): Promise { this.retainDiagnosticState({ processState: "starting", executable: basename(executablePath), - backendPreference, }); console.log("[NativeStreamer] Starting:", executablePath); - console.log("[NativeStreamer] Backend preference:", backendPreference); const videoBackendPreference = this.videoBackendOverride ?? this.options.getVideoBackendPreference(); this.retainDiagnosticState({ videoBackendPreference }); @@ -556,7 +723,6 @@ export class NativeStreamerManager { arch: process.arch, userDataPath: app.getPath("userData"), protocolVersion: NATIVE_STREAMER_PROTOCOL_VERSION, - backendPreference, videoBackendPreference, externalRendererEnabled: process.platform === "win32" ? this.options.getExternalRendererEnabled() @@ -566,35 +732,33 @@ export class NativeStreamerManager { cloudGsyncMode: this.options.getCloudGsyncMode(), d3dFullscreenMode: this.options.getD3dFullscreenMode(), }); - this.gstreamerRuntime = runtimeStatus; + this.runtimeStatus = runtimeStatus; this.retainDiagnosticState({ - runtimeBundled: runtimeStatus.bundled, + runtimeSelfContained: runtimeStatus.selfContained, runtimeState: runtimeStatus.message, }); - if (runtimeStatus.bundled) { - console.log("[NativeStreamer] Using bundled GStreamer runtime:", runtimeStatus.path); - } else { - console.log("[NativeStreamer]", runtimeStatus.message); - } + console.log("[NativeStreamer]", runtimeStatus.message, runtimeStatus.path); const child = spawn(executablePath, [], { stdio: "pipe", - // The default native path lets the GStreamer video sink create its own - // render window. Hiding the child process also hides that sink window on - // Windows, which leaves the Electron input placeholder black. + // The native presenter may own a top-level window on Windows. windowsHide: false, env: childEnv, }); this.child = child; + this.nativeInputOwner = childEnv.OPENNOW_NATIVE_INPUT_OWNER === "native" + ? "native" + : "electron"; this.stdoutBuffer = ""; this.stderrTail = []; this.inputBackpressureWarned = false; child.stdout.setEncoding("utf8"); - child.stdout.on("data", (chunk: string) => this.handleStdout(chunk)); + child.stdout.on("data", (chunk: string) => this.handleStdout(child, chunk)); child.stderr.setEncoding("utf8"); child.stderr.on("data", (chunk: string) => { + if (this.child !== child) return; for (const line of chunk.split(/\r?\n/)) { if (line.trim()) { this.appendStderr(line); @@ -614,7 +778,7 @@ export class NativeStreamerManager { this.handleProcessExit(child, reason); }); - const helloTimeoutMs = runtimeStatus.bundled ? BUNDLED_GSTREAMER_HELLO_TIMEOUT_MS : HELLO_TIMEOUT_MS; + const helloTimeoutMs = runtimeStatus.selfContained ? BUNDLED_NATIVE_HELLO_TIMEOUT_MS : HELLO_TIMEOUT_MS; const response = await this.request({ type: "hello", protocolVersion: NATIVE_STREAMER_PROTOCOL_VERSION, @@ -638,24 +802,9 @@ export class NativeStreamerManager { `Native streamer reported protocolVersion=${response.capabilities.protocolVersion}, expected ${NATIVE_STREAMER_PROTOCOL_VERSION}.`, ); } - this.assertBackendPreference(response.capabilities, backendPreference); await this.surfaceUpdates.markReady(); } - private assertBackendPreference( - capabilities: NativeStreamerCapabilities, - backendPreference: NativeStreamerBackendPreference, - ): void { - if (backendPreference === "auto" || capabilities.backend === backendPreference) { - return; - } - - const reason = capabilities.fallbackReason ? ` ${capabilities.fallbackReason}` : ""; - throw new Error( - `Native streamer backend "${backendPreference}" is unavailable; process selected "${capabilities.backend}".${reason}`, - ); - } - private request(input: NativeStreamerCommandInput, timeoutMs: number): Promise { const child = this.child; if ( @@ -707,7 +856,8 @@ export class NativeStreamerManager { }); } - private handleStdout(chunk: string): void { + private handleStdout(child: ChildProcessWithoutNullStreams, chunk: string): void { + if (this.child !== child) return; this.stdoutBuffer += chunk; const lines = this.stdoutBuffer.split(/\r?\n/); this.stdoutBuffer = lines.pop() ?? ""; @@ -771,6 +921,10 @@ export class NativeStreamerManager { } if (message.type === "local-ice") { + if (!this.capabilities?.supportsLocalIce) { + console.warn("[NativeStreamer] Ignoring local ICE from a backend that did not advertise it."); + return; + } if (this.answerInFlight) { this.queuedLocalIce.push(message.candidate); return; @@ -781,105 +935,56 @@ export class NativeStreamerManager { } if (message.type === "input-ready") { + const readySessionId = this.activeSessionId ?? this.pendingNvstSessionId; + if ( + !readySessionId + || (this.activeTransportCapabilities && !this.activeTransportCapabilities.supportsInput) + ) { + console.warn("[NativeStreamer] Ignoring input readiness from an active transport that does not advertise input."); + return; + } + this.inputReady = true; console.log(`[NativeStreamer] Input protocol ready: v${message.protocolVersion}`); - this.options.emit({ type: "native-input-ready", protocolVersion: message.protocolVersion }); - return; - } - - if (message.type === "shortcut") { - this.options.emit({ type: "native-shortcut", action: message.action }); - return; - } - - if (message.type === "clipboard-paste") { - this.options.emit({ type: "native-clipboard-paste" }); - return; - } - - if (message.type === "input-capture-changed") { - this.options.emit({ type: "native-input-capture-changed", captured: message.captured }); - return; - } - - if (message.type === "video-stall") { - const formatAge = (value: number | undefined): string => value === undefined ? "n/a" : `${value}ms`; - const stats = [ - `stall=${message.stallMs}ms`, - `stage=${message.likelyStage ?? "unknown"}`, - `encoded=${(message.encodedKbps ?? 0).toFixed(0)}kbps`, - `decoded=${message.decodedFps.toFixed(1)}fps`, - `sink=${message.sinkFps.toFixed(1)}fps`, - `requestedFps=${message.requestedFps ?? "n/a"}`, - `capsFramerate=${message.capsFramerate ?? "n/a"}`, - `queueMode=${message.queueMode ?? "unknown"}`, - `partialFlushes=${message.partialFlushCount ?? 0}`, - `completeFlushes=${message.completeFlushCount ?? 0}`, - `lastTransition=${message.lastTransitionType ?? "none"}`, - `ages=encoded:${formatAge(message.encodedAgeMs)} decoded:${formatAge(message.decodedAgeMs)} sink:${formatAge(message.sinkAgeMs)}`, - `rendered=${message.sinkRendered ?? "n/a"}`, - `dropped=${message.sinkDropped ?? "n/a"}`, - `memory=${message.memoryMode ?? "unknown"}`, - `zeroCopy=${message.zeroCopy ?? "unknown"}`, - `zeroCopyD3D11=${message.zeroCopyD3D11}`, - `zeroCopyD3D12=${message.zeroCopyD3D12}`, - ].join(" "); - console.warn(`[NativeStreamer] Video stall recovery attempt ${message.recoveryAttempt}: ${stats}`); + if (this.activeTransport === "nvst" || this.pendingNvstSessionId === readySessionId) { + this.nvstTransportReady = true; + this.nvstReadinessError = null; + this.resolveNvstReadiness(readySessionId); + } this.options.emit({ - type: "log", - message: `[NativeStreamer] Video stall recovery attempt ${message.recoveryAttempt}: ${stats}`, - }); - void this.options.requestKeyframe({ - reason: "native-video-stall", - backlogFrames: 0, - attempt: message.recoveryAttempt, - }).catch((error) => { - console.warn("[NativeStreamer] Failed to request video keyframe after stall:", error); + type: "native-input-ready", + protocolVersion: message.protocolVersion, + inputOwner: this.nativeInputOwner, }); return; } - if (message.type === "video-transition") { - const transition = message.transition; - const summary = transition.summary ?? `${transition.transitionType} @ ${transition.atMs}ms`; - console.warn(`[NativeStreamer] Video transition: ${summary}`); - this.options.emit({ - type: "native-stream-transition", - transition, - }); - this.options.emit({ - type: "log", - message: `[NativeStreamer] Video transition: ${summary}`, - }); + if (message.type === "nvst-transport-ready") { + const readySessionId = this.activeSessionId ?? this.pendingNvstSessionId; + if ( + !readySessionId + || (this.activeTransport !== null && this.activeTransport !== "nvst") + ) { + console.warn("[NativeStreamer] Ignoring NVST readiness without an active NVST session."); + return; + } + console.log(`[NativeStreamer] NVST transport readiness: ${message.phase}`); + if (message.phase === "sctp") { + this.nvstTransportReady = true; + this.resolveNvstReadiness(readySessionId); + } return; } - if (message.type === "stats") { - this.retainDiagnosticState({ - sessionState: "streaming", - statsCapturedAt: new Date().toISOString(), - codec: message.stats.codec, - resolution: message.stats.resolution, - hardwareAcceleration: message.stats.hardwareAcceleration, - memoryMode: message.stats.memoryMode ?? "unknown", - zeroCopy: message.stats.zeroCopy ?? false, - bitrateKbps: message.stats.bitrateKbps, - targetBitrateKbps: message.stats.targetBitrateKbps, - decodedFps: message.stats.decodedFps, - renderFps: message.stats.renderFps, - framesDecoded: message.stats.framesDecoded, - framesRendered: message.stats.framesRendered, - sinkDropped: message.stats.sinkDropped ?? 0, - queueMode: message.stats.queueMode ?? "unknown", - partialFlushCount: message.stats.partialFlushCount ?? 0, - completeFlushCount: message.stats.completeFlushCount ?? 0, - lastTransition: message.stats.lastTransitionSummary ?? "none", - serverGpuType: message.stats.serverGpuType ?? "unknown", - serverLocation: message.stats.serverLocation ?? "unknown", - }); - this.options.emit({ - type: "native-stream-stats", - stats: message.stats, - }); + if (message.type === "input-unavailable") { + this.inputReady = false; + if (this.activeTransport === "nvst" || this.pendingNvstSessionId !== null) { + this.nvstReadinessError = new Error( + `Native NVST DTLS/SCTP readiness failed: ${message.reason}`, + ); + this.rejectNvstReadiness(this.nvstReadinessError); + } + console.warn(`[NativeStreamer] Input unavailable: ${message.reason}`); + this.options.emit({ type: "native-input-unavailable", reason: message.reason }); return; } @@ -892,6 +997,7 @@ export class NativeStreamerManager { if (message.status === "streaming") { this.options.emit({ type: "native-stream-started", message: message.message }); } else if (message.status === "stopped") { + this.clearActiveSessionOwnership(); if (this.suppressNextStoppedEvent) { this.suppressNextStoppedEvent = false; return; @@ -920,6 +1026,21 @@ export class NativeStreamerManager { } } + private clearActiveSessionOwnership(): void { + this.rejectNvstReadiness(new Error("Native NVST session stopped before transport readiness.")); + this.activeSessionId = null; + this.activeTransport = null; + this.activeTransportCapabilities = null; + this.pendingNvstSessionId = null; + this.nvstReservation = null; + this.inputReady = false; + this.nativeInputOwner = "electron"; + this.nvstTransportReady = false; + this.nvstReadinessError = null; + this.surfaceUpdates.markNotReady(); + this.clearQueuedRemoteIce(); + } + private handleStdinFailure( child: ChildProcessWithoutNullStreams, error: Error, @@ -972,6 +1093,14 @@ export class NativeStreamerManager { this.stdoutBuffer = ""; this.stderrTail = []; this.activeSessionId = null; + this.activeTransport = null; + this.activeTransportCapabilities = null; + this.pendingNvstSessionId = null; + this.nvstReservation = null; + this.inputReady = false; + this.nvstTransportReady = false; + this.nvstReadinessError = null; + this.rejectNvstReadiness(new Error(`Native streamer process ended before NVST transport readiness (${reason}).`)); this.capabilities = null; this.inputBackpressureWarned = false; this.surfaceUpdates.markNotReady(); @@ -1011,6 +1140,20 @@ export class NativeStreamerManager { pending.reject(error); } + private resolveNvstReadiness(sessionId: string): void { + for (const waiter of this.nvstReadinessWaiters) { + if (waiter.sessionId === sessionId) { + waiter.resolve(); + } + } + } + + private rejectNvstReadiness(error: Error): void { + for (const waiter of this.nvstReadinessWaiters) { + waiter.reject(error); + } + } + private async flushQueuedLocalIce(): Promise { const queued = this.queuedLocalIce; this.queuedLocalIce = []; @@ -1039,6 +1182,9 @@ export class NativeStreamerManager { private async flushQueuedRemoteIce(sessionId: string): Promise { const queued = this.drainQueuedRemoteIce(sessionId); + if (!this.capabilities?.supportsRemoteIce) { + return; + } for (const candidate of queued) { await this.sendRemoteIce(candidate); } diff --git a/opennow-stable/src/main/nativeStreamer/protocol.test.ts b/opennow-stable/src/main/nativeStreamer/protocol.test.ts index 02e18496b..d3e62500a 100644 --- a/opennow-stable/src/main/nativeStreamer/protocol.test.ts +++ b/opennow-stable/src/main/nativeStreamer/protocol.test.ts @@ -16,3 +16,13 @@ test("protocol guards distinguish request responses from events by id", () => { assert.equal(isNativeStreamerResponse(event), false); assert.equal(isNativeStreamerEvent(event), true); }); + +test("NVST transport readiness is an id-less native event", () => { + const event = { + type: "nvst-transport-ready", + phase: "sctp", + } satisfies NativeStreamerMessage; + + assert.equal(isNativeStreamerEvent(event), true); + assert.equal(isNativeStreamerResponse(event), false); +}); diff --git a/opennow-stable/src/main/nativeStreamer/runtime.test.ts b/opennow-stable/src/main/nativeStreamer/runtime.test.ts index bad8d2652..633c7842f 100644 --- a/opennow-stable/src/main/nativeStreamer/runtime.test.ts +++ b/opennow-stable/src/main/nativeStreamer/runtime.test.ts @@ -1,106 +1,114 @@ import assert from "node:assert/strict"; -import { mkdtempSync, mkdirSync, rmSync, symlinkSync } from "node:fs"; -import { tmpdir } from "node:os"; -import { join } from "node:path"; import test from "node:test"; import { createNativeStreamerRuntimeEnvironment, - isNativeWaylandSession, - isPathInside, nativeStreamerExecutableName, nativeStreamerPlatformKey, - normalizePathForComparison, - shouldDefaultLinuxShellToX11, } from "./runtime"; -function createLinuxRuntimeEnvironment( - baseEnv: NodeJS.ProcessEnv, - linuxOzonePlatform?: string, -): NodeJS.ProcessEnv { - return createNativeStreamerRuntimeEnvironment({ +test("v2 runtime is self-contained and removes inherited GStreamer variables", () => { + const result = createNativeStreamerRuntimeEnvironment({ executablePath: "/tmp/opennow-streamer", - baseEnv, + baseEnv: { + GST_PLUGIN_PATH: "/old/plugins", + DISPLAY: ":1", + OPENNOW_NATIVE_VIDEO_BACKEND: "software", + }, platform: "linux", arch: "arm64", userDataPath: "/tmp/opennow-test", protocolVersion: 4, - backendPreference: "auto", videoBackendPreference: "auto", externalRendererEnabled: false, - linuxOzonePlatform, - cloudGsyncMode: "auto", + cloudGsyncMode: "disabled", d3dFullscreenMode: "auto", - }).env; -} + }); -test("detects native Wayland sessions", () => { - assert.equal(isNativeWaylandSession({ WAYLAND_DISPLAY: "wayland-0" }), true); - assert.equal(isNativeWaylandSession({ XDG_SESSION_TYPE: "wayland" }), true); - assert.equal(isNativeWaylandSession({}, "wayland"), true); + assert.equal(result.env.GST_PLUGIN_PATH, undefined); + assert.equal(result.env.OPENNOW_NATIVE_STREAMER_PROTOCOL, "4"); + assert.equal(result.env.OPENNOW_NATIVE_INPUT_OWNER, "electron"); + assert.equal(result.env.OPENNOW_NATIVE_VIDEO_BACKEND, "auto"); + assert.equal(result.env.SDL_VIDEODRIVER, "x11"); + assert.equal(result.env.OPENNOW_NATIVE_WINDOW_SYSTEM, "x11"); + assert.equal(result.runtimeStatus.selfContained, true); + assert.match(result.runtimeStatus.message, /self-contained/); }); -test("explicit X11 keeps Linux child-surface embedding enabled", () => { - const waylandEnvironment = { - ELECTRON_OZONE_PLATFORM_HINT: "wayland", - WAYLAND_DISPLAY: "wayland-0", - XDG_SESSION_TYPE: "wayland", - }; +test("external renderer makes the native SDL window the input owner", () => { + const result = createNativeStreamerRuntimeEnvironment({ + executablePath: "C:\\OpenNOW\\opennow-streamer.exe", + baseEnv: {}, + platform: "win32", + arch: "x64", + userDataPath: "C:\\OpenNOW", + protocolVersion: 4, + videoBackendPreference: "auto", + externalRendererEnabled: true, + cloudGsyncMode: "auto", + d3dFullscreenMode: "auto", + }); - assert.equal(isNativeWaylandSession(waylandEnvironment, "x11"), false); - assert.equal(isNativeWaylandSession({ XDG_SESSION_TYPE: "x11" }), false); - assert.equal( - isNativeWaylandSession({ ELECTRON_OZONE_PLATFORM_HINT: "x11" }), - false, - ); + assert.equal(result.env.OPENNOW_NATIVE_EXTERNAL_RENDERER, "1"); + assert.equal(result.env.OPENNOW_NATIVE_INPUT_OWNER, "native"); }); -test("Linux native runtime rejects unmanaged pure Wayland presentation", () => { - assert.throws( - () => createLinuxRuntimeEnvironment({ WAYLAND_DISPLAY: "wayland-0" }), - /requires Electron to run through X11\/XWayland/, - ); - assert.equal( - createLinuxRuntimeEnvironment( - { WAYLAND_DISPLAY: "wayland-0" }, - "x11", - ).OPENNOW_NATIVE_EXTERNAL_RENDERER, - "0", - ); -}); +test("explicit Linux video backend preference is passed to the child", () => { + const result = createNativeStreamerRuntimeEnvironment({ + executablePath: "/tmp/opennow-streamer", + baseEnv: { DISPLAY: ":1" }, + platform: "linux", + arch: "x64", + userDataPath: "/tmp/opennow-test", + protocolVersion: 4, + videoBackendPreference: "v4l2", + externalRendererEnabled: false, + cloudGsyncMode: "auto", + d3dFullscreenMode: "auto", + }); -test("Linux shell defaults to X11 unless an Ozone backend was explicit", () => { - assert.equal(shouldDefaultLinuxShellToX11("linux", ""), true); - assert.equal(shouldDefaultLinuxShellToX11("linux", undefined), true); - assert.equal(shouldDefaultLinuxShellToX11("linux", "auto"), true); - assert.equal(shouldDefaultLinuxShellToX11("linux", "wayland"), false); - assert.equal(shouldDefaultLinuxShellToX11("win32", ""), false); + assert.equal(result.env.OPENNOW_NATIVE_VIDEO_BACKEND, "v4l2"); }); -test("normalizes real and symlinked paths to the same comparison path", (t) => { - const root = mkdtempSync(join(tmpdir(), "opennow-native-path-")); - t.after(() => rmSync(root, { recursive: true, force: true })); - const runtime = join(root, "runtime"); - const alias = join(root, "runtime-alias"); - mkdirSync(runtime); - mkdirSync(join(runtime, "gstreamer")); - symlinkSync(runtime, alias, "dir"); +test("Cloud G-SYNC uses a top-level native output on X11", () => { + const result = createNativeStreamerRuntimeEnvironment({ + executablePath: "/tmp/opennow-streamer", + baseEnv: { DISPLAY: ":1", XDG_SESSION_TYPE: "x11" }, + platform: "linux", + arch: "x64", + userDataPath: "/tmp/opennow-test", + protocolVersion: 4, + videoBackendPreference: "auto", + externalRendererEnabled: false, + cloudGsyncMode: "auto", + d3dFullscreenMode: "auto", + }); - assert.equal( - normalizePathForComparison(alias), - normalizePathForComparison(runtime), - ); - assert.equal(isPathInside(alias, join(runtime, "gstreamer")), true); + assert.equal(result.env.OPENNOW_NATIVE_EXTERNAL_RENDERER, "1"); + assert.equal(result.env.OPENNOW_NATIVE_INPUT_OWNER, "native"); + assert.match(result.runtimeStatus.message, /Cloud G-SYNC\/VRR/); }); -test("path containment rejects sibling names that only share a prefix", (t) => { - const root = mkdtempSync(join(tmpdir(), "opennow-native-path-")); - t.after(() => rmSync(root, { recursive: true, force: true })); - const runtime = join(root, "runtime"); +test("Wayland uses a native top-level renderer and owns its input", () => { + const result = createNativeStreamerRuntimeEnvironment({ + executablePath: "/tmp/opennow-streamer", + baseEnv: { WAYLAND_DISPLAY: "wayland-0", XDG_SESSION_TYPE: "wayland" }, + platform: "linux", + arch: "arm64", + userDataPath: "/tmp/opennow-test", + protocolVersion: 4, + videoBackendPreference: "auto", + externalRendererEnabled: false, + linuxOzonePlatform: "wayland", + cloudGsyncMode: "auto", + d3dFullscreenMode: "auto", + }); - assert.equal(isPathInside(runtime, runtime), true); - assert.equal(isPathInside(runtime, join(runtime, "cached", "streamer")), true); - assert.equal(isPathInside(runtime, `${runtime}-old/streamer`), false); + assert.equal(result.env.SDL_VIDEODRIVER, "wayland"); + assert.equal(result.env.OPENNOW_NATIVE_WINDOW_SYSTEM, "wayland"); + assert.equal(result.env.OPENNOW_NATIVE_EXTERNAL_RENDERER, "1"); + assert.equal(result.env.OPENNOW_NATIVE_INPUT_OWNER, "native"); + assert.match(result.runtimeStatus.message, /Wayland output window/); }); test("runtime executable names and platform keys accept explicit platforms", () => { diff --git a/opennow-stable/src/main/nativeStreamer/runtime.ts b/opennow-stable/src/main/nativeStreamer/runtime.ts index 056a79917..d69e09acd 100644 --- a/opennow-stable/src/main/nativeStreamer/runtime.ts +++ b/opennow-stable/src/main/nativeStreamer/runtime.ts @@ -1,19 +1,13 @@ -import { - existsSync, - mkdirSync, - realpathSync, - statSync, -} from "node:fs"; -import { delimiter, dirname, join, resolve, sep } from "node:path"; +import { existsSync, realpathSync, statSync } from "node:fs"; +import { resolve, sep } from "node:path"; import { nativeStreamerFeatureModeToEnvValue, - type NativeGstreamerInstallInstruction, - type NativeGstreamerRuntimeStatus, - type NativeStreamerBackendPreference, type NativeStreamerFeatureMode, + type NativeStreamerRuntimeStatus, type NativeVideoBackendPreference, } from "@shared/gfn"; +import { resolveLinuxWindowSystem } from "../linuxWindowSystem"; export interface NativeStreamerRuntimeEnvironmentOptions { executablePath: string; @@ -22,7 +16,6 @@ export interface NativeStreamerRuntimeEnvironmentOptions { arch: string; userDataPath: string; protocolVersion: number; - backendPreference: NativeStreamerBackendPreference; videoBackendPreference: NativeVideoBackendPreference; externalRendererEnabled: boolean; linuxOzonePlatform?: string; @@ -32,31 +25,12 @@ export interface NativeStreamerRuntimeEnvironmentOptions { export interface NativeStreamerRuntimeEnvironment { env: NodeJS.ProcessEnv; - runtimeStatus: NativeGstreamerRuntimeStatus; + runtimeStatus: NativeStreamerRuntimeStatus; } -const LINUX_GSTREAMER_INSTALL_INSTRUCTIONS: NativeGstreamerInstallInstruction[] = [ - { - distro: "Debian / Ubuntu / Mint / Pop!_OS / KDE neon", - command: "sudo apt update && sudo apt install libgstreamer1.0-0 libgstreamer-plugins-base1.0-0 gstreamer1.0-tools gstreamer1.0-libav gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-nice gstreamer1.0-gl gstreamer1.0-vaapi gstreamer1.0-x gstreamer1.0-alsa libva2 libva-drm2 libvulkan1 mesa-vulkan-drivers", - }, - { - distro: "Fedora / RHEL / Nobara / Bazzite", - command: "sudo dnf install gstreamer1 gstreamer1-plugins-base gstreamer1-plugins-good gstreamer1-plugins-bad-free gstreamer1-plugins-bad-freeworld gstreamer1-plugins-ugly gstreamer1-libav gstreamer1-vaapi gstreamer1-plugin-openh264 libnice-gstreamer1 mesa-vulkan-drivers libva", - note: "RPM Fusion may be required for libav, ugly, or bad-freeworld packages.", - }, - { - distro: "Arch / Manjaro / EndeavourOS / SteamOS", - command: "sudo pacman -S --needed gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav gst-plugin-va libnice libva mesa vulkan-radeon", - note: "NVIDIA users should use their distro NVIDIA/Vulkan driver packages instead of vulkan-radeon.", - }, - { - distro: "openSUSE Tumbleweed / Leap", - command: "sudo zypper install gstreamer gstreamer-plugins-base gstreamer-plugins-good gstreamer-plugins-bad gstreamer-plugins-ugly gstreamer-plugins-libav gstreamer-plugins-vaapi gstreamer-libnice libva2 Mesa-vulkan-device-select", - }, -]; - -export function nativeStreamerExecutableName(platform = process.platform): string { +export function nativeStreamerExecutableName( + platform = process.platform, +): string { return platform === "win32" ? "opennow-streamer.exe" : "opennow-streamer"; } @@ -75,14 +49,6 @@ export function isExistingFile(path: string): boolean { } } -export function isExistingDirectory(path: string): boolean { - try { - return existsSync(path) && statSync(path).isDirectory(); - } catch { - return false; - } -} - export function normalizePathForComparison( path: string, platform = process.platform, @@ -91,7 +57,7 @@ export function normalizePathForComparison( try { resolvedPath = realpathSync.native(resolvedPath); } catch { - // Cache destinations and configured overrides may not exist yet. + // Paths selected in settings may not exist yet. } return platform === "win32" ? resolvedPath.toLowerCase() : resolvedPath; } @@ -103,170 +69,70 @@ export function isPathInside( ): boolean { const normalizedParent = normalizePathForComparison(parent, platform); const normalizedChild = normalizePathForComparison(child, platform); - return normalizedChild === normalizedParent || normalizedChild.startsWith(`${normalizedParent}${sep}`); -} - -export function hasBundledRuntimeNextToExecutable(executablePath: string): boolean { - return isExistingDirectory(join(dirname(executablePath), "gstreamer")); -} - -export function linuxInstallInstructions( - platform = process.platform, -): NativeGstreamerInstallInstruction[] | undefined { - return platform === "linux" ? LINUX_GSTREAMER_INSTALL_INSTRUCTIONS : undefined; -} - -export function isNativeWaylandSession( - env: NodeJS.ProcessEnv, - ozonePlatform?: string, -): boolean { - const explicitPlatform = ozonePlatform?.trim().toLowerCase(); - if (explicitPlatform === "x11") return false; - if (explicitPlatform === "wayland") return true; - - const environmentHint = env.ELECTRON_OZONE_PLATFORM_HINT?.trim().toLowerCase(); - if (!explicitPlatform && environmentHint === "x11") return false; - if (!explicitPlatform && environmentHint === "wayland") return true; - - return env.XDG_SESSION_TYPE?.trim().toLowerCase() === "wayland" - || Boolean(env.WAYLAND_DISPLAY?.trim()); -} - -export function shouldDefaultLinuxShellToX11( - platform: NodeJS.Platform, - ozonePlatform?: string, -): boolean { - const normalized = ozonePlatform?.trim().toLowerCase(); - return platform === "linux" && (!normalized || normalized === "auto"); -} - -function prependEnvPath(env: NodeJS.ProcessEnv, key: string, directory: string): void { - env[key] = env[key] ? `${directory}${delimiter}${env[key]}` : directory; -} - -function prependProcessPath(env: NodeJS.ProcessEnv, directory: string): void { - const pathKey = Object.keys(env).find((key) => key.toLowerCase() === "path") || "PATH"; - prependEnvPath(env, pathKey, directory); -} - -function configureBundledGstreamerRuntime( - env: NodeJS.ProcessEnv, - executablePath: string, - platform: NodeJS.Platform, - arch: string, - userDataPath: string, -): NativeGstreamerRuntimeStatus { - const runtimeRoot = join(dirname(executablePath), "gstreamer"); - if (!isExistingDirectory(runtimeRoot)) { - return { - source: "system", - bundled: false, - message: platform === "linux" - ? "No bundled GStreamer runtime was found. Linux uses distro GStreamer packages so VAAPI/V4L2/Vulkan plugins match the host driver stack." - : "No bundled GStreamer runtime was found; using the system runtime if available.", - installInstructions: linuxInstallInstructions(platform), - }; - } - - const binDir = join(runtimeRoot, "bin"); - const libDir = join(runtimeRoot, "lib"); - const pluginDir = join(runtimeRoot, "lib", "gstreamer-1.0"); - const scanner = join( - runtimeRoot, - "libexec", - "gstreamer-1.0", - platform === "win32" ? "gst-plugin-scanner.exe" : "gst-plugin-scanner", + return ( + normalizedChild === normalizedParent || + normalizedChild.startsWith(`${normalizedParent}${sep}`) ); - const gioModulesDir = join(runtimeRoot, "lib", "gio", "modules"); - - if (platform === "win32") prependProcessPath(env, dirname(executablePath)); - if (isExistingDirectory(binDir)) prependProcessPath(env, binDir); - if (isExistingDirectory(pluginDir)) { - env.GST_PLUGIN_PATH = pluginDir; - env.GST_PLUGIN_PATH_1_0 = pluginDir; - env.GST_PLUGIN_SYSTEM_PATH = pluginDir; - env.GST_PLUGIN_SYSTEM_PATH_1_0 = pluginDir; - } - if (isExistingFile(scanner)) { - env.GST_PLUGIN_SCANNER = scanner; - env.GST_PLUGIN_SCANNER_1_0 = scanner; - } - env.GST_REGISTRY_REUSE_PLUGIN_SCANNER = "no"; - if (isExistingDirectory(gioModulesDir)) { - env.GIO_MODULE_DIR = gioModulesDir; - env.GIO_EXTRA_MODULES = gioModulesDir; - } - const registryDir = join(userDataPath, "native-streamer", "gstreamer"); - const registryPath = join(registryDir, `${nativeStreamerPlatformKey(platform, arch)}-registry.bin`); - mkdirSync(registryDir, { recursive: true }); - env.GST_REGISTRY = registryPath; - if (platform === "linux") { - if (isExistingDirectory(libDir)) prependEnvPath(env, "LD_LIBRARY_PATH", libDir); - if (isExistingDirectory(binDir)) prependEnvPath(env, "LD_LIBRARY_PATH", binDir); - } - if (platform === "darwin") { - if (isExistingDirectory(libDir)) { - prependEnvPath(env, "DYLD_LIBRARY_PATH", libDir); - prependEnvPath(env, "DYLD_FALLBACK_LIBRARY_PATH", libDir); - } - if (isExistingDirectory(binDir)) { - prependEnvPath(env, "DYLD_LIBRARY_PATH", binDir); - prependEnvPath(env, "DYLD_FALLBACK_LIBRARY_PATH", binDir); - } - } - - return { - source: "bundled", - bundled: true, - path: runtimeRoot, - message: "Using bundled GStreamer runtime next to the native streamer executable.", - }; } export function createNativeStreamerRuntimeEnvironment( options: NativeStreamerRuntimeEnvironmentOptions, ): NativeStreamerRuntimeEnvironment { - if ( - options.platform === "linux" - && isNativeWaylandSession(options.baseEnv, options.linuxOzonePlatform) - ) { - throw new Error( - "Native Linux video requires Electron to run through X11/XWayland so GStreamer can embed frames in the OpenNOW window. Relaunch with --ozone-platform=x11; pure Wayland native embedding is not supported yet.", - ); - } - + const linuxWindowSystem = options.platform === "linux" + ? resolveLinuxWindowSystem(options.linuxOzonePlatform, options.baseEnv) + : null; + const linuxCloudGsyncOutput = options.platform === "linux" + && options.cloudGsyncMode !== "disabled"; + // Wayland deliberately gives the streamer its own compositor-managed window: + // the protocol has no portable equivalent of X11 child-window reparenting. + // Cloud G-SYNC also needs a top-level window on X11 so SDL/Vulkan can enter + // compositor-managed fullscreen and drive the VRR scanout directly. + const externalRendererEnabled = options.externalRendererEnabled + || linuxWindowSystem === "wayland" + || linuxCloudGsyncOutput; const env: NodeJS.ProcessEnv = { ...options.baseEnv, OPENNOW_NATIVE_STREAMER_PROTOCOL: String(options.protocolVersion), + OPENNOW_NATIVE_CLOUD_GSYNC: nativeStreamerFeatureModeToEnvValue( + options.cloudGsyncMode, + ), + OPENNOW_NATIVE_D3D_FULLSCREEN: nativeStreamerFeatureModeToEnvValue( + options.d3dFullscreenMode, + ), + OPENNOW_NATIVE_EXTERNAL_RENDERER: externalRendererEnabled + ? "1" + : "0", + // A separate renderer window owns its SDL event loop and forwards input + // directly over NVST. Embedded mode keeps Electron as the sole owner. + OPENNOW_NATIVE_INPUT_OWNER: externalRendererEnabled + ? "native" + : "electron", + OPENNOW_NATIVE_VIDEO_BACKEND: options.videoBackendPreference, }; - delete env.OPENNOW_NATIVE_VIDEO_API; - delete env.OPENNOW_NATIVE_VIDEO_BACKEND; - if (options.videoBackendPreference !== "auto") { - env.OPENNOW_NATIVE_VIDEO_BACKEND = options.videoBackendPreference; - } - if (options.platform === "linux") { - env.OPENNOW_NATIVE_EXTERNAL_RENDERER = "0"; - if ((options.arch === "arm64" || options.arch === "arm") && !env.GST_V4L2_ENABLE_PROBE) { - env.GST_V4L2_ENABLE_PROBE = "1"; - } - } else if (options.platform === "win32") { - env.OPENNOW_NATIVE_EXTERNAL_RENDERER = options.externalRendererEnabled ? "1" : "0"; - env.OPENNOW_NATIVE_D3D_ALLOW_TEARING = "1"; - } - env.OPENNOW_NATIVE_CLOUD_GSYNC = nativeStreamerFeatureModeToEnvValue(options.cloudGsyncMode); - env.OPENNOW_NATIVE_D3D_FULLSCREEN = nativeStreamerFeatureModeToEnvValue(options.d3dFullscreenMode); - if (options.backendPreference !== "auto") { - env.OPENNOW_NATIVE_STREAMER_BACKEND = options.backendPreference; + if (linuxWindowSystem) { + env.OPENNOW_NATIVE_WINDOW_SYSTEM = linuxWindowSystem; + env.SDL_VIDEODRIVER = linuxWindowSystem; } + delete env.GST_PLUGIN_PATH; + delete env.GST_PLUGIN_PATH_1_0; + delete env.GST_PLUGIN_SYSTEM_PATH; + delete env.GST_PLUGIN_SYSTEM_PATH_1_0; + delete env.GST_PLUGIN_SCANNER; + delete env.GST_PLUGIN_SCANNER_1_0; + delete env.GST_REGISTRY; return { env, - runtimeStatus: configureBundledGstreamerRuntime( - env, - options.executablePath, - options.platform, - options.arch, - options.userDataPath, - ), + runtimeStatus: { + source: "self-contained", + selfContained: true, + path: options.executablePath, + message: + linuxWindowSystem === "wayland" + ? "Native streamer v2 is using a compositor-managed Wayland output window; no external media runtime is required." + : linuxCloudGsyncOutput + ? "Native streamer v2 is using a top-level Linux output window for Cloud G-SYNC/VRR; no external media runtime is required." + : "Native streamer v2 is self-contained; no external media runtime is required.", + }, }; } diff --git a/opennow-stable/src/main/nativeStreamer/runtimeCache.test.ts b/opennow-stable/src/main/nativeStreamer/runtimeCache.test.ts deleted file mode 100644 index 899c32595..000000000 --- a/opennow-stable/src/main/nativeStreamer/runtimeCache.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import assert from "node:assert/strict"; -import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; -import { tmpdir } from "node:os"; -import { join } from "node:path"; -import test from "node:test"; - -import { - buildPackagedNativeStreamerCacheMarker, - isSamePackagedNativeStreamerCacheMarker, - shouldUseStablePackagedNativeStreamerCache, -} from "./runtimeCache"; - -test("cache markers compare every executable and runtime identity field", (t) => { - const source = mkdtempSync(join(tmpdir(), "opennow-native-marker-")); - t.after(() => rmSync(source, { recursive: true, force: true })); - const runtime = join(source, "gstreamer"); - mkdirSync(runtime); - writeFileSync(join(source, "opennow-streamer.exe"), "streamer-v1"); - writeFileSync(join(runtime, "OPENNOW-GSTREAMER-RUNTIME.txt"), "runtime-v1"); - - const marker = buildPackagedNativeStreamerCacheMarker( - source, - "opennow-streamer.exe", - "win32-x64", - "1.2.3", - ); - const sameMarker = buildPackagedNativeStreamerCacheMarker( - source, - "opennow-streamer.exe", - "win32-x64", - "1.2.3", - ); - assert.equal(isSamePackagedNativeStreamerCacheMarker(marker, sameMarker), true); - - writeFileSync(join(runtime, "OPENNOW-GSTREAMER-RUNTIME.txt"), "runtime-v2"); - const changedRuntimeMarker = buildPackagedNativeStreamerCacheMarker( - source, - "opennow-streamer.exe", - "win32-x64", - "1.2.3", - ); - assert.equal(isSamePackagedNativeStreamerCacheMarker(marker, changedRuntimeMarker), false); - assert.equal(isSamePackagedNativeStreamerCacheMarker(null, marker), false); -}); - -test("stable packaged cache selection is constrained to Windows temporary resources", (t) => { - const temporaryRoot = mkdtempSync(join(tmpdir(), "opennow-native-cache-")); - t.after(() => rmSync(temporaryRoot, { recursive: true, force: true })); - const resourcesPath = join(temporaryRoot, "resources"); - mkdirSync(resourcesPath); - - assert.equal(shouldUseStablePackagedNativeStreamerCache({ - isPackaged: true, - platform: "win32", - resourcesPath, - tempDirectory: tmpdir(), - }), true); - assert.equal(shouldUseStablePackagedNativeStreamerCache({ - isPackaged: true, - platform: "linux", - resourcesPath, - tempDirectory: tmpdir(), - }), false); - assert.equal(shouldUseStablePackagedNativeStreamerCache({ - isPackaged: false, - platform: "win32", - resourcesPath, - tempDirectory: tmpdir(), - }), false); -}); diff --git a/opennow-stable/src/main/nativeStreamer/runtimeCache.ts b/opennow-stable/src/main/nativeStreamer/runtimeCache.ts deleted file mode 100644 index 572e998d2..000000000 --- a/opennow-stable/src/main/nativeStreamer/runtimeCache.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { createHash } from "node:crypto"; -import { - cpSync, - mkdirSync, - readFileSync, - renameSync, - rmSync, - writeFileSync, -} from "node:fs"; -import { dirname, join } from "node:path"; - -import { - hasBundledRuntimeNextToExecutable, - isExistingDirectory, - isExistingFile, - isPathInside, -} from "./runtime"; - -export interface PackagedNativeStreamerCacheMarker { - appVersion: string; - platformKey: string; - exeName: string; - exeSha256: string; - bundledRuntime: boolean; - runtimeManifestSha256?: string; -} - -export interface PackagedNativeStreamerCacheContext { - appVersion: string; - isPackaged: boolean; - platform: NodeJS.Platform; - resourcesPath: string; - tempDirectory: string; - userDataPath: string; -} - -function safePathSegment(value: string): string { - return value.replace(/[^a-zA-Z0-9._-]/g, "_") || "unknown"; -} - -function fileSha256(path: string): string { - return createHash("sha256").update(readFileSync(path)).digest("hex"); -} - -export function shouldUseStablePackagedNativeStreamerCache( - context: Pick< - PackagedNativeStreamerCacheContext, - "isPackaged" | "platform" | "resourcesPath" | "tempDirectory" - >, -): boolean { - return context.isPackaged - && context.platform === "win32" - && isPathInside(context.tempDirectory, context.resourcesPath, context.platform); -} - -export function buildPackagedNativeStreamerCacheMarker( - sourceDirectory: string, - exeName: string, - platformKey: string, - appVersion: string, -): PackagedNativeStreamerCacheMarker { - const runtimeManifest = join(sourceDirectory, "gstreamer", "OPENNOW-GSTREAMER-RUNTIME.txt"); - return { - appVersion, - platformKey, - exeName, - exeSha256: fileSha256(join(sourceDirectory, exeName)), - bundledRuntime: isExistingDirectory(join(sourceDirectory, "gstreamer")), - runtimeManifestSha256: isExistingFile(runtimeManifest) ? fileSha256(runtimeManifest) : undefined, - }; -} - -export function readPackagedNativeStreamerCacheMarker( - markerPath: string, -): PackagedNativeStreamerCacheMarker | null { - try { - return JSON.parse(readFileSync(markerPath, "utf8")) as PackagedNativeStreamerCacheMarker; - } catch { - return null; - } -} - -export function isSamePackagedNativeStreamerCacheMarker( - left: PackagedNativeStreamerCacheMarker | null, - right: PackagedNativeStreamerCacheMarker, -): boolean { - if (!left) { - return false; - } - - return left.appVersion === right.appVersion - && left.platformKey === right.platformKey - && left.exeName === right.exeName - && left.exeSha256 === right.exeSha256 - && left.bundledRuntime === right.bundledRuntime - && left.runtimeManifestSha256 === right.runtimeManifestSha256; -} - -export function materializePackagedNativeStreamerCache( - sourceExecutablePath: string, - platformKey: string, - exeName: string, - context: PackagedNativeStreamerCacheContext, -): string | null { - if (!shouldUseStablePackagedNativeStreamerCache(context)) { - return null; - } - - const sourceDirectory = dirname(sourceExecutablePath); - const cacheDirectory = join( - context.userDataPath, - "native-streamer", - "runtime", - safePathSegment(context.appVersion), - safePathSegment(platformKey), - ); - const cachedExecutablePath = join(cacheDirectory, exeName); - const markerPath = join(cacheDirectory, ".opennow-native-runtime.json"); - let stagingDirectory: string | null = null; - - try { - const expectedMarker = buildPackagedNativeStreamerCacheMarker( - sourceDirectory, - exeName, - platformKey, - context.appVersion, - ); - const cachedMarker = readPackagedNativeStreamerCacheMarker(markerPath); - if ( - isExistingFile(cachedExecutablePath) - && isSamePackagedNativeStreamerCacheMarker(cachedMarker, expectedMarker) - && (!expectedMarker.bundledRuntime || hasBundledRuntimeNextToExecutable(cachedExecutablePath)) - ) { - return cachedExecutablePath; - } - - stagingDirectory = `${cacheDirectory}.tmp-${process.pid}-${Date.now()}`; - rmSync(stagingDirectory, { recursive: true, force: true }); - mkdirSync(dirname(stagingDirectory), { recursive: true }); - cpSync(sourceDirectory, stagingDirectory, { - recursive: true, - force: true, - dereference: true, - filter: (entry) => { - const lower = entry.toLowerCase(); - return !lower.endsWith(".pdb") && !lower.endsWith(".lib") && !lower.endsWith(".a"); - }, - }); - writeFileSync( - join(stagingDirectory, ".opennow-native-runtime.json"), - `${JSON.stringify(expectedMarker, null, 2)}\n`, - "utf8", - ); - - if (!isExistingFile(join(stagingDirectory, exeName))) { - throw new Error(`Cached native streamer executable was not created: ${join(stagingDirectory, exeName)}`); - } - if (expectedMarker.bundledRuntime && !hasBundledRuntimeNextToExecutable(join(stagingDirectory, exeName))) { - throw new Error("Cached native streamer runtime is missing its bundled GStreamer directory."); - } - - rmSync(cacheDirectory, { recursive: true, force: true }); - renameSync(stagingDirectory, cacheDirectory); - stagingDirectory = null; - console.log("[NativeStreamer] Cached packaged native streamer in stable runtime path:", cachedExecutablePath); - return cachedExecutablePath; - } catch (error) { - console.warn("[NativeStreamer] Failed to prepare stable packaged runtime cache; using packaged resource path:", error); - return null; - } finally { - if (stagingDirectory) { - rmSync(stagingDirectory, { recursive: true, force: true }); - } - } -} diff --git a/opennow-stable/src/main/nativeStreamer/surface.test.ts b/opennow-stable/src/main/nativeStreamer/surface.test.ts new file mode 100644 index 000000000..0acb562c4 --- /dev/null +++ b/opennow-stable/src/main/nativeStreamer/surface.test.ts @@ -0,0 +1,78 @@ +/// + +import assert from "node:assert/strict"; +import test from "node:test"; + +import type { BrowserWindow } from "electron"; +import { normalizeNativeRenderSurface } from "./surface"; + +test("normalizes renderer bounds into absolute screen coordinates", () => { + const handle = Buffer.alloc(8); + handle.writeBigUInt64LE(0x1234n); + const window = { + getNativeWindowHandle: () => handle, + getContentBounds: () => ({ x: 100, y: 200, width: 1280, height: 720 }), + } as unknown as BrowserWindow; + + const surface = normalizeNativeRenderSurface(window, { + rect: { x: 12.4, y: 24.6, width: 640.2, height: 360.4 }, + visible: true, + deviceScaleFactor: 2, + }); + + assert.deepEqual(surface, { + windowHandle: "0x1234", + deviceScaleFactor: 2, + visible: true, + showStats: false, + rect: { x: 12, y: 25, width: 640, height: 360 }, + screenRect: { x: 106, y: 212, width: 320, height: 180 }, + }); +}); + +test("uses Windows display-aware DIP conversion without scaling the global monitor origin", () => { + const handle = Buffer.alloc(8); + handle.writeBigUInt64LE(0x1234n); + const window = { + getNativeWindowHandle: () => handle, + getContentBounds: () => ({ x: 1920, y: 0, width: 1280, height: 720 }), + } as unknown as BrowserWindow; + + const surface = normalizeNativeRenderSurface( + window, + { + rect: { x: 150, y: 30, width: 640, height: 360 }, + visible: true, + deviceScaleFactor: 1.5, + }, + (point) => ({ + x: 1920 + Math.round((point.x - 1920) * 1.5), + y: Math.round(point.y * 1.5), + }), + ); + + assert.deepEqual(surface?.screenRect, { + x: 2070, + y: 30, + width: 640, + height: 360, + }); +}); + +test("keeps publishing bounds when Wayland has no embeddable native handle", () => { + const window = { + getNativeWindowHandle: () => { + throw new Error("not supported on Wayland"); + }, + getContentBounds: () => ({ x: 0, y: 0, width: 1280, height: 720 }), + } as unknown as BrowserWindow; + + const surface = normalizeNativeRenderSurface(window, { + rect: { x: 0, y: 0, width: 1280, height: 720 }, + visible: true, + deviceScaleFactor: 2, + }); + + assert.equal(surface?.windowHandle, undefined); + assert.deepEqual(surface?.screenRect, { x: 0, y: 0, width: 640, height: 360 }); +}); diff --git a/opennow-stable/src/main/nativeStreamer/surface.ts b/opennow-stable/src/main/nativeStreamer/surface.ts index 0344956c2..3b0097c58 100644 --- a/opennow-stable/src/main/nativeStreamer/surface.ts +++ b/opennow-stable/src/main/nativeStreamer/surface.ts @@ -5,12 +5,17 @@ import type { } from "@shared/gfn"; export function nativeWindowHandleToHex(window: BrowserWindow): string | null { - const handle = window.getNativeWindowHandle(); - if (handle.byteLength >= 8) { - return `0x${handle.readBigUInt64LE(0).toString(16)}`; - } - if (handle.byteLength >= 4) { - return `0x${handle.readUInt32LE(0).toString(16)}`; + try { + const handle = window.getNativeWindowHandle(); + if (handle.byteLength >= 8) { + return `0x${handle.readBigUInt64LE(0).toString(16)}`; + } + if (handle.byteLength >= 4) { + return `0x${handle.readUInt32LE(0).toString(16)}`; + } + } catch { + // Native Wayland output is a separate top-level surface and does not need + // an Electron platform handle. } return null; } @@ -18,20 +23,19 @@ export function nativeWindowHandleToHex(window: BrowserWindow): string | null { export function normalizeNativeRenderSurface( window: BrowserWindow, input: NativeRenderSurfaceUpdate, + dipToScreenPoint?: (point: { x: number; y: number }) => { x: number; y: number }, ): NativeRenderSurface | null { if (!input || typeof input !== "object") { return null; } const windowHandle = nativeWindowHandleToHex(window); - if (!windowHandle) { - return null; - } const deviceScaleFactor = Number.isFinite(input.deviceScaleFactor) ? Math.min(8, Math.max(0.25, input.deviceScaleFactor)) : 1; const rect = input.rect; + const contentBounds = window.getContentBounds(); const visible = input.visible === true && rect !== null && @@ -42,8 +46,14 @@ export function normalizeNativeRenderSurface( rect.width >= 2 && rect.height >= 2; + const screenOriginDip = { + x: contentBounds.x + Math.round((rect?.x ?? 0) / deviceScaleFactor), + y: contentBounds.y + Math.round((rect?.y ?? 0) / deviceScaleFactor), + }; + const screenOrigin = dipToScreenPoint?.(screenOriginDip) ?? screenOriginDip; + return { - windowHandle, + ...(windowHandle ? { windowHandle } : {}), deviceScaleFactor, visible, showStats: input.showStats === true, @@ -55,5 +65,17 @@ export function normalizeNativeRenderSurface( height: Math.max(2, Math.round(rect.height)), } : null, + screenRect: visible + ? { + x: screenOrigin.x, + y: screenOrigin.y, + width: dipToScreenPoint + ? Math.max(2, Math.round(rect.width)) + : Math.max(2, Math.round(rect.width / deviceScaleFactor)), + height: dipToScreenPoint + ? Math.max(2, Math.round(rect.height)) + : Math.max(2, Math.round(rect.height / deviceScaleFactor)), + } + : undefined, }; } diff --git a/opennow-stable/src/main/platforms/gfn/clientHeaders.ts b/opennow-stable/src/main/platforms/gfn/clientHeaders.ts index 4314e588e..cbdc4625e 100644 --- a/opennow-stable/src/main/platforms/gfn/clientHeaders.ts +++ b/opennow-stable/src/main/platforms/gfn/clientHeaders.ts @@ -1,4 +1,6 @@ -import crypto from "node:crypto"; +import os from "node:os"; + +import { getCloudMatchDeviceHashId } from "./deviceId"; import { GFN_PLAY_ORIGIN as SHARED_GFN_PLAY_ORIGIN, GFN_PLAY_REFERER as SHARED_GFN_PLAY_REFERER } from "@shared/gfn/endpoints"; @@ -8,14 +10,48 @@ import { type GfnDeviceOs, } from "./deviceIdentity"; +/** Official mall `shared/assets/config/config.json` build.version / hash (2.0.87.131). */ +export const GFN_CLIENT_VERSION = "2.0.87.131"; +/** Official CEF host token: `HEAD/` + first 10 hex chars of mall `build.hash`. */ +const GFN_CEF_PRODUCT = "NVIDIACEFClient/HEAD/7b92719716"; + const GFN_WINDOWS_USER_AGENT = - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 NVIDIACEFClient/HEAD/debb5919f6 GFN-PC/2.0.80.173"; + `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ${GFN_CEF_PRODUCT} GFN-PC/${GFN_CLIENT_VERSION}`; const GFN_MACOS_USER_AGENT = - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 GFN-PC/2.0.80.173"; + `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ${GFN_CEF_PRODUCT} GFN-PC/${GFN_CLIENT_VERSION}`; +const GFN_LINUX_USER_AGENT = + `Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ${GFN_CEF_PRODUCT} GFN-PC/${GFN_CLIENT_VERSION}`; + +export function gfnUserAgentForPlatform(platform: NodeJS.Platform = process.platform): string { + if (platform === "darwin") { + return GFN_MACOS_USER_AGENT; + } + if (platform === "linux") { + return GFN_LINUX_USER_AGENT; + } + return GFN_WINDOWS_USER_AGENT; +} + +export const GFN_USER_AGENT = gfnUserAgentForPlatform(); +/** Official mall JSON `clientVersion` token used in native Grid User-Agent. */ +export const GFN_BIFROST_CLIENT_VERSION = "30.0"; +/** Official Mac BifrostClientSDK token from Grid POST 2026-08-19. */ +const GFN_BIFROST_SDK = "4.9"; +const GFN_BIFROST_SDK_BUILD = "38495286"; + +export function gfnBifrostUserAgentForPlatform(platform: NodeJS.Platform = process.platform): string { + if (platform === "darwin") { + return `GFN-PC/${GFN_BIFROST_CLIENT_VERSION} (MacOSX ${os.release()}) BifrostClientSDK/${GFN_BIFROST_SDK} (${GFN_BIFROST_SDK_BUILD})`; + } + if (platform === "linux") { + return `GFN-PC/${GFN_BIFROST_CLIENT_VERSION} (Linux ${os.release()}) BifrostClientSDK/${GFN_BIFROST_SDK} (${GFN_BIFROST_SDK_BUILD})`; + } + return `GFN-PC/${GFN_BIFROST_CLIENT_VERSION} (Windows NT 10.0) BifrostClientSDK/${GFN_BIFROST_SDK} (${GFN_BIFROST_SDK_BUILD})`; +} -export const GFN_USER_AGENT = process.platform === "darwin" ? GFN_MACOS_USER_AGENT : GFN_WINDOWS_USER_AGENT; -export const GFN_CLIENT_VERSION = "2.0.80.173"; export const LCARS_CLIENT_ID = "ec7e38d4-03af-4b58-b131-cfb0495903ab"; +/** Official CloudMatch / Bifrost `clientIdentification` for the native PC client. */ +export const GFN_CLIENT_IDENTIFICATION = "GFN-PC"; export const GFN_PLAY_ORIGIN = SHARED_GFN_PLAY_ORIGIN; export const GFN_PLAY_REFERER = SHARED_GFN_PLAY_REFERER; @@ -45,6 +81,7 @@ function applyDeviceIdentityHeaders( ): void { headers["nv-device-os"] = identity.deviceOs; headers["nv-device-type"] = identity.deviceType; + headers["x-nv-client-identity"] = GFN_CLIENT_IDENTIFICATION; if (options?.includeMakeModel !== false) { headers["nv-device-make"] = identity.deviceMake; headers["nv-device-model"] = identity.deviceModel; @@ -148,50 +185,64 @@ export interface GfnCloudMatchHeadersOptions { function resolveCloudMatchIdentity(options: GfnCloudMatchHeadersOptions): { clientId: string; deviceId: string } { return { - clientId: options.clientId ?? crypto.randomUUID(), - deviceId: options.deviceId ?? crypto.randomUUID(), + clientId: options.clientId ?? LCARS_CLIENT_ID, + deviceId: options.deviceId ?? getCloudMatchDeviceHashId(), }; } export function buildGfnCloudMatchHeaders(options: GfnCloudMatchHeadersOptions): Record { const { clientId, deviceId } = resolveCloudMatchIdentity(options); const identity = resolveGfnDeviceIdentity({ identifyAsSteamDeck: options.identifyAsSteamDeck }); - const headers: Record = { - "User-Agent": GFN_USER_AGENT, + const userAgent = gfnBifrostUserAgentForPlatform(); + void options.includeOrigin; + return { + "User-Agent": userAgent, Authorization: gfnJwtAuthorization(options.token), - "Content-Type": "application/json", - "nv-browser-type": "CHROME", - "nv-client-id": clientId, - "nv-client-streamer": "NVIDIA-CLASSIC", - "nv-client-type": "NATIVE", - "nv-client-version": GFN_CLIENT_VERSION, - "x-device-id": deviceId, + "Content-Type": "text/plain", + "NV-Client-ID": clientId, + "NV-Client-Streamer": "NVIDIA-CLASSIC", + "NV-Client-Type": "NATIVE", + "NV-Client-Version": GFN_CLIENT_VERSION, + "NV-Device-OS": identity.deviceOs, + "NV-Device-Type": identity.deviceType, + "NV-Device-Make": identity.deviceMake, + "NV-Device-Model": identity.deviceModel, + "X-Device-Id": deviceId, + "x-nv-client-identity": userAgent, }; - applyDeviceIdentityHeaders(headers, identity); - - if (options.includeOrigin !== false) { - headers.Origin = GFN_PLAY_ORIGIN; - headers.Referer = GFN_PLAY_REFERER; - } +} - return headers; +export interface GfnNvstClientHeadersOptions { + deviceId?: string; + identifyAsSteamDeck?: boolean; } -export function buildGfnCloudMatchClaimHeaders(options: GfnCloudMatchHeadersOptions): Record { - const { clientId, deviceId } = resolveCloudMatchIdentity(options); +/** + * Official Bifrost GridServer / CloudMatch HTTP identity. Not used on RTSP-over-WSS: + * that upgrade is `GET /rtsp` + `x-nv-sessionid` only. + */ +export function buildGfnNvstClientHeaders( + options: GfnNvstClientHeadersOptions = {}, +): Record { const identity = resolveGfnDeviceIdentity({ identifyAsSteamDeck: options.identifyAsSteamDeck }); + const userAgent = gfnBifrostUserAgentForPlatform(); const headers: Record = { - "User-Agent": GFN_USER_AGENT, - Authorization: gfnJwtAuthorization(options.token), - "Content-Type": "application/json", - Origin: GFN_PLAY_ORIGIN, - Referer: GFN_PLAY_REFERER, - "nv-client-id": clientId, - "nv-client-streamer": "NVIDIA-CLASSIC", - "nv-client-type": "NATIVE", - "nv-client-version": GFN_CLIENT_VERSION, - "x-device-id": deviceId, + "User-Agent": userAgent, + "x-nv-client-identity": userAgent, + "NV-Device-OS": identity.deviceOs, + "NV-Client-Streamer": "NVIDIA-CLASSIC", + "NV-Device-Type": identity.deviceType, + "NV-Client-Type": "NATIVE", + "NV-Device-Make": identity.deviceMake, + "NV-Device-Model": identity.deviceModel, + "NV-Client-Version": GFN_CLIENT_VERSION, }; - applyDeviceIdentityHeaders(headers, identity); + if (options.deviceId) { + headers["X-Device-Id"] = options.deviceId; + } return headers; } + +export function buildGfnCloudMatchClaimHeaders(options: GfnCloudMatchHeadersOptions): Record { + return buildGfnCloudMatchHeaders({ ...options, includeOrigin: false }); +} diff --git a/opennow-stable/src/main/platforms/gfn/cloudmatch.test.ts b/opennow-stable/src/main/platforms/gfn/cloudmatch.test.ts index a0cec4957..cb4d9dac0 100644 --- a/opennow-stable/src/main/platforms/gfn/cloudmatch.test.ts +++ b/opennow-stable/src/main/platforms/gfn/cloudmatch.test.ts @@ -20,6 +20,8 @@ import { resolveRequestedCodecWireValue, } from "./cloudmatch"; import { buildSessionRequestBody } from "./cloudmatchSessionRequest"; +import { resolveNvstCreateStreamSku } from "./cloudmatchFeatures"; +import { resolveGfnDeviceIdentity } from "./deviceIdentity"; function makeSettings(overrides: Partial = {}): StreamSettings { return { @@ -191,6 +193,97 @@ test("CloudMatch session request body carries supported codecs into the wire cod assert.equal(body.sessionRequestData.requestedStreamingFeatures.codec, 2); }); +test("CloudMatch requests secure RTSPS for explicit classic native sessions", () => { + const nativeBody = buildSessionRequestBody( + { + appId: "1001", + internalTitle: "Test Game", + zone: "prod", + settings: makeSettings({ transportMode: "nvst" }), + }, + "device-id", + ); + const webRtcBody = buildSessionRequestBody( + { + appId: "1001", + internalTitle: "Test Game", + zone: "prod", + settings: makeSettings({ transportMode: "webrtc" }), + }, + "device-id", + ); + + assert.equal(nativeBody.sessionRequestData.secureRTSPSupported, true); + assert.equal(nativeBody.sessionRequestData.sdkVersion, "2.0"); + assert.equal(nativeBody.sessionRequestData.streamerVersion, "14"); + assert.equal(nativeBody.sessionRequestData.enhancedStreamMode, 0); + assert.deepEqual(nativeBody.sessionRequestData.availableSupportedControllers, [2]); + assert.equal(nativeBody.sessionRequestData.preferredController, 2); + assert.equal(nativeBody.sessionRequestData.requestedAudioFormat, 0); + assert.equal(nativeBody.sessionRequestData.partnerCustomData, null); + assert.equal(nativeBody.sessionRequestData.transport, null); + assert.equal(nativeBody.sessionRequestData.externalAppId, null); + assert.equal(nativeBody.sessionRequestData.appId, 1001); + assert.equal(nativeBody.sessionRequestData.internalTitle, null); + assert.equal(nativeBody.sessionRequestData.accountLinked, false); + assert.equal(nativeBody.sessionRequestData.deviceHashId, "device-id"); + assert.equal(nativeBody.sessionRequestData.userAge, 25); + assert.ok((nativeBody.sessionRequestData.clientRequestMonitorSettings[0]?.dpi ?? 0) > 0); + assert.equal( + nativeBody.sessionRequestData.clientPlatformName, + resolveGfnDeviceIdentity().clientPlatformName, + ); + if (process.platform === "darwin") { + assert.equal(nativeBody.sessionRequestData.clientPlatformName, "MacOSX"); + assert.equal(nativeBody.sessionRequestData.sdrHdrMode, 1); + assert.equal(nativeBody.sessionRequestData.clientDisplayHdrCapabilities?.version, 2); + assert.equal( + nativeBody.sessionRequestData.metaData.find((entry) => entry.key === "networkType")?.value, + "WiFi5.0", + ); + } + assert.equal(nativeBody.sessionRequestData.requestedStreamingFeatures.codec, 2); + assert.equal(nativeBody.sessionRequestData.requestedStreamingFeatures.maxBitrateKbps, undefined); + assert.equal(nativeBody.sessionRequestData.requestedStreamingFeatures.dynamicStreamingMode, undefined); + assert.equal(nativeBody.sessionRequestData.requestedStreamingFeatures.audioChannelCount, undefined); + assert.equal(nativeBody.sessionRequestData.requestedStreamingFeatures.trueHdr, false); + assert.equal(nativeBody.sessionRequestData.requestedStreamingFeatures.bitDepth, 0); + assert.equal(nativeBody.sessionRequestData.requestedStreamingFeatures.chromaFormat, 0); + assert.equal(nativeBody.sessionRequestData.requestedStreamingFeatures.reflex, true); + assert.equal(nativeBody.sessionRequestData.requestedStreamingFeatures.qosPolicy, 0); + assert.deepEqual(resolveNvstCreateStreamSku(makeSettings({ transportMode: "nvst" })), { + bitDepth: 0, + chromaFormat: 0, + reflex: true, + }); + assert.equal( + nativeBody.sessionRequestData.metaData.some((entry) => entry.key === "GSStreamerType"), + false, + ); + assert.equal(webRtcBody.sessionRequestData.secureRTSPSupported, false); + assert.deepEqual( + webRtcBody.sessionRequestData.metaData.find((entry) => entry.key === "GSStreamerType"), + { key: "GSStreamerType", value: "WebRTC" }, + ); +}); + +test("CloudMatch caps native sessions at 240 FPS", () => { + const body = buildSessionRequestBody( + { + appId: "1001", + internalTitle: "Test Game", + zone: "prod", + settings: makeSettings({ fps: 360, transportMode: "nvst" }), + }, + "device-id", + ); + + assert.equal( + body.sessionRequestData.clientRequestMonitorSettings[0]?.framesPerSecond, + 240, + ); +}); + test("CloudMatch extracts local serverInfo region before fallback regions", () => { const bases = extractServerInfoRegionBases({ metaData: [ @@ -209,12 +302,16 @@ test("CloudMatch extracts local serverInfo region before fallback regions", () = ]); }); -test("CloudMatch pins the resolved region with a network-test session before creating a session", async () => { +test("CloudMatch creates a session without a network-test pin", async () => { const originalFetch = globalThis.fetch; const originalWarn = console.warn; const calls: string[] = []; type CapturedSessionRequestBody = { sessionRequestData: { + appId?: string | number; + internalTitle?: string | null; + accountLinked?: boolean; + deviceHashId?: string; networkTestSessionId?: string | null; appLaunchMode?: number; enablePersistingInGameSettings?: boolean; @@ -232,15 +329,7 @@ test("CloudMatch pins the resolved region with a network-test session before cre }; }; }; - type CapturedNetworkTestRequestBody = { - netTestRequestData: { - netTestProfile: { - framesPerSecond: number; - }; - }; - }; let requestBody: CapturedSessionRequestBody | null = null; - let networkTestRequestBody: CapturedNetworkTestRequestBody | null = null; const expectedSessionUrl = `https://np-lax-01.cloudmatchbeta.nvidiagrid.net/v2/session?${new URLSearchParams({ keyboardLayout: resolveGfnKeyboardLayout(DEFAULT_KEYBOARD_LAYOUT, process.platform), languageCode: "en_US", @@ -263,16 +352,6 @@ test("CloudMatch pins the resolved region with a network-test session before cre }), { status: 200 }); } - if (url === "https://np-lax-01.cloudmatchbeta.nvidiagrid.net/v2/nettestsession") { - networkTestRequestBody = JSON.parse(String(init?.body)); - return new Response(JSON.stringify({ - requestStatus: { statusCode: 1, statusDescription: "SUCCESS_STATUS", serverId: "NP-LAX-01" }, - netTestSession: { - sessionId: "nettest-lax-1", - }, - }), { status: 200 }); - } - if (url === expectedSessionUrl) { requestBody = JSON.parse(String(init?.body)); const createdRequestBody = requestBody; @@ -317,12 +396,8 @@ test("CloudMatch pins the resolved region with a network-test session before cre assert.equal(session.enablePersistingInGameSettings, false); assert.deepEqual(calls, [ "https://prod.cloudmatchbeta.nvidiagrid.net/v2/serverInfo", - "https://np-lax-01.cloudmatchbeta.nvidiagrid.net/v2/nettestsession", expectedSessionUrl, ]); - const capturedNetworkTestRequestBody = networkTestRequestBody as CapturedNetworkTestRequestBody | null; - assert.ok(capturedNetworkTestRequestBody); - assert.equal(capturedNetworkTestRequestBody.netTestRequestData.netTestProfile.framesPerSecond, 90); const capturedRequestBody = requestBody as CapturedSessionRequestBody | null; assert.ok(capturedRequestBody); assert.equal(capturedRequestBody.sessionRequestData.clientRequestMonitorSettings[0]?.framesPerSecond, 90); @@ -335,43 +410,133 @@ test("CloudMatch pins the resolved region with a network-test session before cre assert.equal(capturedRequestBody.sessionRequestData.requestedStreamingFeatures.audioChannelCount, 2); assert.equal(capturedRequestBody.sessionRequestData.appLaunchMode, 2); assert.equal(capturedRequestBody.sessionRequestData.enablePersistingInGameSettings, false); - assert.equal(capturedRequestBody.sessionRequestData.networkTestSessionId, "nettest-lax-1"); + assert.equal(capturedRequestBody.sessionRequestData.networkTestSessionId, null); + assert.equal(capturedRequestBody.sessionRequestData.appId, 1001); + assert.equal(capturedRequestBody.sessionRequestData.internalTitle, null); + assert.equal(capturedRequestBody.sessionRequestData.accountLinked, false); + assert.match(capturedRequestBody.sessionRequestData.deviceHashId ?? "", /^[0-9a-f]{64}$/); } finally { globalThis.fetch = originalFetch; console.warn = originalWarn; } }); -test("CloudMatch pins a manually selected zone before creating a session", async (t) => { +test("CloudMatch NVST create posts to regional host then sends official RESUME", async (t) => { const originalFetch = globalThis.fetch; const originalLog = console.log; + const originalWarn = console.warn; const calls: string[] = []; - let networkTestSessionId: string | null | undefined; - const base = "https://np-mia-04.cloudmatchbeta.nvidiagrid.net"; - const expectedSessionUrl = `${base}/v2/session?${new URLSearchParams({ + let resumeBodyJson: unknown = null; + + const regionalBase = "https://eu-netherlands-north.cloudmatchbeta.nvidiagrid.net"; + const query = new URLSearchParams({ keyboardLayout: resolveGfnKeyboardLayout(DEFAULT_KEYBOARD_LAYOUT, process.platform), languageCode: "en_US", - }).toString()}`; + }).toString(); + const expectedPostUrl = `${regionalBase}/v2/session?${query}`; + const expectedResumeUrl = `${regionalBase}/v2/session/session-nvst-1?${query}`; console.log = () => {}; + console.warn = () => {}; t.after(() => { globalThis.fetch = originalFetch; console.log = originalLog; + console.warn = originalWarn; }); globalThis.fetch = (async (input, init) => { const url = String(input); calls.push(url); - if (url === `${base}/v2/nettestsession`) { + if (url === "https://prod.cloudmatchbeta.nvidiagrid.net/v2/serverInfo") { return new Response(JSON.stringify({ - requestStatus: { statusCode: 1, statusDescription: "SUCCESS_STATUS", serverId: "NP-MIA-04" }, - netTestSession: { - sessionId: "nettest-mia-1", + requestStatus: { statusCode: 1, statusDescription: "SUCCESS_STATUS", serverId: "NP-AMS-06" }, + metaData: [ + { key: "local-region", value: "EU Northwest" }, + { key: "gfn-regions", value: "EU Northwest, Netherlands North" }, + { key: "EU Northwest", value: "https://np-ams-06.cloudmatchbeta.nvidiagrid.net/" }, + { key: "Netherlands North", value: "https://eu-netherlands-north.cloudmatchbeta.nvidiagrid.net/" }, + ], + }), { status: 200 }); + } + + if (url === expectedPostUrl && (init?.method ?? "GET") === "POST") { + return new Response(JSON.stringify({ + requestStatus: { statusCode: 1, statusDescription: "SUCCESS_STATUS" }, + session: { + sessionId: "session-nvst-1", + status: 1, + seatSetupInfo: { seatSetupStep: 0 }, + sessionControlInfo: { ip: "np-ams-06.cloudmatchbeta.nvidiagrid.net" }, + connectionInfo: [], + iceServerConfiguration: { + iceServers: [{ urls: "stun:127.0.0.1:19302" }], + }, }, }), { status: 200 }); } + if (url === expectedResumeUrl && init?.method === "PUT") { + resumeBodyJson = JSON.parse(String(init.body)); + return new Response(JSON.stringify({ + requestStatus: { statusCode: 1, statusDescription: "SUCCESS_STATUS" }, + session: { sessionId: "session-nvst-1", status: 1 }, + }), { status: 200 }); + } + + throw new Error(`Unexpected fetch: ${url} ${init?.method ?? "GET"}`); + }) as typeof fetch; + + const session = await createSession({ + token: "token", + streamingBaseUrl: "https://prod.cloudmatchbeta.nvidiagrid.net/", + appId: "1001", + internalTitle: "Test Game", + zone: "prod", + settings: makeSettings({ transportMode: "nvst", resolution: "2560x1600", fps: 120 }), + }); + + assert.deepEqual(calls, [ + "https://prod.cloudmatchbeta.nvidiagrid.net/v2/serverInfo", + expectedPostUrl, + expectedResumeUrl, + ]); + const resumeBody = resumeBodyJson as { + action?: number; + data?: string; + sessionRequestData?: { + requestedStreamingFeatures?: { bitDepth?: number; reflex?: boolean; chromaFormat?: number }; + }; + } | null; + assert.equal(resumeBody?.action, 2); + assert.equal(resumeBody?.data, "RESUME"); + assert.equal(resumeBody?.sessionRequestData?.requestedStreamingFeatures?.bitDepth, 0); + assert.equal(resumeBody?.sessionRequestData?.requestedStreamingFeatures?.reflex, true); + assert.equal(resumeBody?.sessionRequestData?.requestedStreamingFeatures?.chromaFormat, 0); + assert.equal(session.sessionId, "session-nvst-1"); +}); + +test("CloudMatch pins a manually selected zone before creating a session", async (t) => { + const originalFetch = globalThis.fetch; + const originalLog = console.log; + const calls: string[] = []; + let networkTestSessionId: string | null | undefined; + const base = "https://np-mia-04.cloudmatchbeta.nvidiagrid.net"; + const expectedSessionUrl = `${base}/v2/session?${new URLSearchParams({ + keyboardLayout: resolveGfnKeyboardLayout(DEFAULT_KEYBOARD_LAYOUT, process.platform), + languageCode: "en_US", + }).toString()}`; + + console.log = () => {}; + t.after(() => { + globalThis.fetch = originalFetch; + console.log = originalLog; + }); + + globalThis.fetch = (async (input, init) => { + const url = String(input); + calls.push(url); + if (url === expectedSessionUrl) { const body = JSON.parse(String(init?.body)) as { sessionRequestData: { @@ -412,10 +577,9 @@ test("CloudMatch pins a manually selected zone before creating a session", async }); assert.deepEqual(calls, [ - `${base}/v2/nettestsession`, expectedSessionUrl, ]); - assert.equal(networkTestSessionId, "nettest-mia-1"); + assert.equal(networkTestSessionId, null); }); test("CloudMatch retries transient serverInfo failures before creating a session", async () => { @@ -449,15 +613,6 @@ test("CloudMatch retries transient serverInfo failures before creating a session }), { status: 200 }); } - if (url === "https://np-lax-01.cloudmatchbeta.nvidiagrid.net/v2/nettestsession") { - return new Response(JSON.stringify({ - requestStatus: { statusCode: 1, statusDescription: "SUCCESS_STATUS", serverId: "NP-LAX-01" }, - netTestSession: { - sessionId: "nettest-lax-retry", - }, - }), { status: 200 }); - } - if (url === expectedSessionUrl) { const body = JSON.parse(String(init?.body)) as { sessionRequestData: { @@ -500,7 +655,6 @@ test("CloudMatch retries transient serverInfo failures before creating a session assert.deepEqual(calls, [ "https://prod.cloudmatchbeta.nvidiagrid.net/v2/serverInfo", "https://prod.cloudmatchbeta.nvidiagrid.net/v2/serverInfo", - "https://np-lax-01.cloudmatchbeta.nvidiagrid.net/v2/nettestsession", expectedSessionUrl, ]); } finally { @@ -684,11 +838,21 @@ test("CloudMatch claim keeps the session-stable appLaunchMode over live settings requestStatus: { statusCode: 1, statusDescription: "SUCCESS_STATUS" }, session: { sessionId: "sess-1", + subSessionId: "subsess-1", status: 3, sessionControlInfo: { ip: "203.0.113.10" }, connectionInfo: [ { ip: "203.0.113.10", port: 443, usage: 14, resourcePath: "/nvst/" }, - { ip: "203.0.113.10", port: 49006, usage: 2 }, + { ip: "203.0.113.11", port: 49006, usage: 15, protocol: 2 }, + { ip: "203.0.113.13", port: 49007, usage: 17, protocol: 2 }, + { + ip: "203.0.113.12", + port: 48322, + usage: 16, + protocol: 1, + appLevelProtocol: 6, + resourcePath: "rtsps://203.0.113.12:48322/session", + }, ], iceServerConfiguration: { iceServers: [{ urls: "stun:127.0.0.1:19302" }], @@ -711,7 +875,7 @@ test("CloudMatch claim keeps the session-stable appLaunchMode over live settings try { // Session created as gamepad-friendly (wire 2) must stay gamepad-friendly on // resume even if the live settings toggles now say "default". - await claimSession({ + const claimed = await claimSession({ token: "token", sessionId: "sess-1", serverIp: "203.0.113.10", @@ -719,6 +883,26 @@ test("CloudMatch claim keeps the session-stable appLaunchMode over live settings appLaunchMode: 2, settings: makeSettings(), }); + assert.deepEqual(claimed.connectionInfo, [ + { ip: "203.0.113.10", port: 443, usage: 14, resourcePath: "/nvst/" }, + { ip: "203.0.113.11", port: 49006, usage: 15, protocol: 2 }, + { ip: "203.0.113.13", port: 49007, usage: 17, protocol: 2 }, + { + ip: "203.0.113.12", + port: 48322, + usage: 16, + protocol: 1, + appLevelProtocol: 6, + resourcePath: "rtsps://203.0.113.12:48322/session", + }, + ]); + assert.equal(claimed.subSessionId, "subsess-1"); + assert.deepEqual(claimed.mediaConnectionInfo, { + ip: "203.0.113.13", + port: 49007, + usage: 17, + }); + assert.deepEqual(claimed.rtspsEndpoints, ["rtsps://203.0.113.12:48322/session"]); // Without a session-stable value the claim falls back to the settings-derived mode. await claimSession({ diff --git a/opennow-stable/src/main/platforms/gfn/cloudmatch.ts b/opennow-stable/src/main/platforms/gfn/cloudmatch.ts index 8b6d0e152..e41452279 100644 --- a/opennow-stable/src/main/platforms/gfn/cloudmatch.ts +++ b/opennow-stable/src/main/platforms/gfn/cloudmatch.ts @@ -1,5 +1,3 @@ -import crypto from "node:crypto"; - import type { ActiveSessionInfo, SessionAdAction, @@ -21,8 +19,9 @@ import { SessionError } from "./errorCodes"; import { buildGfnCloudMatchClaimHeaders, buildGfnCloudMatchHeaders, + LCARS_CLIENT_ID, } from "./clientHeaders"; -import { getStableDeviceId } from "./deviceId"; +import { getCloudMatchDeviceHashId } from "./deviceId"; import { readCloudMatchJson, throwIfCloudMatchResponseError, @@ -49,7 +48,6 @@ import { buildClaimRequestBody, buildSessionRequestBody, } from "./cloudmatchSessionRequest"; -import { createNetworkTestSession } from "./networkTestSession"; import { echoedSessionAppLaunchMode, extractAdState, @@ -71,6 +69,7 @@ export { export { extractServerInfoRegionBases } from "./cloudmatchTransport"; const SESSION_MODIFY_ACTION_AD_UPDATE = 6; +const SESSION_MODIFY_ACTION_RESUME = 2; const AD_ACTION_CODES: Record = { start: 1, @@ -90,8 +89,8 @@ export async function createSession(input: SessionCreateRequest): Promise(response); + + // Official Bifrost follows every fresh create with an immediate + // PUT action=2 RESUME carrying the same full sessionRequestData (fresh + // SubSessionId). That explicit RESUME starts seat setup on the modern hex + // ping-hash streamer pool; sessions left to auto-start from POST alone land + // on the legacy literal-"PING" pool that never completes NVST hole-punch. + if (input.settings.transportMode === "nvst" && payload.session?.sessionId) { + await resumeFreshNvstSession({ + base, + sessionId: payload.session.sessionId, + input, + clientId, + deviceId, + keyboardLayout, + languageCode, + }); + } + return await toSessionInfo({ zone: input.zone, streamingBaseUrl: base, @@ -138,14 +161,63 @@ export async function createSession(input: SessionCreateRequest): Promise { - if (!input.token) { +/** + * Official fresh-create parity for the classic (NVST) streamer: immediately + * RESUME the just-created session with the full sessionRequestData. Failures + * are logged and ignored — the caller still polls to readiness as before. + */ +async function resumeFreshNvstSession(args: { + base: string; + sessionId: string; + input: SessionCreateRequest; + clientId: string; + deviceId: string; + keyboardLayout: string; + languageCode: string; +}): Promise { + const { base, sessionId, input, clientId, deviceId, keyboardLayout, languageCode } = args; + // Rebuild the body so SubSessionId is fresh, mirroring the official client. + const resumeBody = buildSessionRequestBody(input, deviceId, null); + const payload = { + action: SESSION_MODIFY_ACTION_RESUME, + data: "RESUME", + sessionRequestData: resumeBody.sessionRequestData, + metaData: null, + adUpdates: null, + }; + const url = `${base}/v2/session/${sessionId}?${new URLSearchParams({ keyboardLayout, languageCode }).toString()}`; + console.log(`[CloudMatch] createSession RESUME PUT ${url} (official fresh-create parity)`); + try { + const response = await fetchCloudMatch(url, { + method: "PUT", + headers: buildGfnCloudMatchHeaders({ token: input.token as string, clientId, deviceId, includeOrigin: false }), + body: JSON.stringify(payload), + }, { proxyUrl: input.proxyUrl }); + const text = await response.text(); + let statusCode = -1; + try { + statusCode = (JSON.parse(text) as CloudMatchResponse).requestStatus?.statusCode ?? -1; + } catch { + // Keep -1 for unparsable bodies; the warning below carries the HTTP status. + } + console.log(`[CloudMatch] createSession RESUME response: HTTP ${response.status}, requestStatus=${statusCode}`); + if (!response.ok || statusCode !== 1) { + console.warn( + `[CloudMatch] createSession RESUME not accepted (HTTP ${response.status}, status=${statusCode}); continuing with poll-based setup`, + ); + } + } catch (error) { + console.warn(`[CloudMatch] createSession RESUME failed: ${formatErrorForLog(error)}; continuing with poll-based setup`); + } +} + +export async function pollSession(input: SessionPollRequest): Promise { if (!input.token) { throw new Error("Missing token for session polling"); } // Use provided client/device IDs if available (should match session creation) - const clientId = input.clientId ?? crypto.randomUUID(); - const deviceId = input.deviceId ?? crypto.randomUUID(); + const clientId = input.clientId ?? LCARS_CLIENT_ID; + const deviceId = input.deviceId ?? getCloudMatchDeviceHashId(); const base = resolvePollStopBase(input.zone, input.streamingBaseUrl, input.serverIp); const baseHost = new URL(base).hostname; @@ -208,8 +280,8 @@ export async function reportSessionAd(input: SessionAdReportRequest): Promise { } // Use provided client/device IDs if available (should match session creation) - const clientId = input.clientId ?? crypto.randomUUID(); - const deviceId = input.deviceId ?? crypto.randomUUID(); + const clientId = input.clientId ?? LCARS_CLIENT_ID; + const deviceId = input.deviceId ?? getCloudMatchDeviceHashId(); const base = resolvePollStopBase(input.zone, input.streamingBaseUrl, input.serverIp); const url = `${base}/v2/session/${input.sessionId}`; @@ -303,7 +375,7 @@ export async function getActiveSessions( const base = normalizeTrustedCloudMatchBaseUrl(streamingBaseUrl); const headers = buildGfnCloudMatchHeaders({ token, - deviceId: getStableDeviceId(), + deviceId: getCloudMatchDeviceHashId(), includeOrigin: false, }); const primary = await fetchActiveSessionsFromBase(base, headers); @@ -435,6 +507,7 @@ async function fetchActiveSessionsFromBase( return { sessionId: s.sessionId, + subSessionId: s.subSessionId, appId, appLaunchMode, enablePersistingInGameSettings, @@ -462,8 +535,8 @@ export async function claimSession(input: SessionClaimRequest): Promise(response, { - onText: (text) => { - console.log(`[CloudMatch] claimSession response: HTTP ${response.status}`); - console.log(`[CloudMatch] claimSession response body FULL: ${text}`); - }, - }); + const { text, payload: apiResponse } = await readCloudMatchJson(response); + console.log( + `[CloudMatch] claimSession response: HTTP ${response.status}, requestStatus=${apiResponse.requestStatus.statusCode}, sessionStatus=${apiResponse.session?.status ?? "n/a"}, connectionInfo=${apiResponse.session?.connectionInfo?.length ?? 0}`, + ); if (apiResponse.requestStatus.statusCode !== 1) { throw SessionError.fromResponse(200, text); @@ -642,6 +712,7 @@ export async function claimSession(input: SessionClaimRequest): Promise ({ ...connection })), rtspsEndpoints: signaling.rtspsEndpoints.length > 0 ? signaling.rtspsEndpoints : undefined, iceServers: await normalizeIceServers(pollApiResponse), mediaConnectionInfo: signaling.mediaConnectionInfo, diff --git a/opennow-stable/src/main/platforms/gfn/cloudmatchFeatures.ts b/opennow-stable/src/main/platforms/gfn/cloudmatchFeatures.ts index 201be03cf..6831e37e1 100644 --- a/opennow-stable/src/main/platforms/gfn/cloudmatchFeatures.ts +++ b/opennow-stable/src/main/platforms/gfn/cloudmatchFeatures.ts @@ -26,10 +26,11 @@ export function buildRequestedStreamingFeatures( chromaFormat: number, _hdrEnabled: boolean, supportedCodecs?: readonly VideoCodec[], + transportMode: StreamSettings["transportMode"] = settings.transportMode, ): CloudMatchRequest["sessionRequestData"]["requestedStreamingFeatures"] { const cloudGsync = settings.enableCloudGsync; - return { + const commonFeatures = { reflex: shouldRequestReflex(settings), bitDepth, cloudGsync, @@ -42,6 +43,29 @@ export function buildRequestedStreamingFeatures( prefilterSharpness: 0, prefilterNoiseReduction: 0, hudStreamingMode: 0, + }; + + if (transportMode === "nvst") { + const sku = resolveNvstCreateStreamSku(settings); + return { + ...commonFeatures, + reflex: sku.reflex, + bitDepth: sku.bitDepth, + chromaFormat: sku.chromaFormat, + mouseMovementFlags: 0, + trueHdr: false, + hidDevices: null, + qosPolicy: 0, + touchSupport: false, + codec: resolveRequestedCodecWireValue( + codecWireValue(settings.codec), + (supportedCodecs ?? []).map(codecWireValue), + ), + }; + } + + return { + ...commonFeatures, maxBitrateKbps: Math.round(settings.maxBitrateMbps * 1000), codec: resolveRequestedCodecWireValue( codecWireValue(settings.codec), @@ -96,6 +120,26 @@ export function shouldRequestReflex(settings: StreamSettings): boolean { return settings.enableCloudGsync || settings.fps >= reflexMinimum; } +/** + * Resolve the classic-streamer SKU. The native pipeline currently accepts the + * 8-bit 4:2:0 profiles shared by H.264, H.265, and AV1. Non-native callers retain + * the captured official Mac Bifrost profile. + */ +export function resolveNvstCreateStreamSku(settings: StreamSettings): { + bitDepth: number; + chromaFormat: number; + reflex: boolean; +} { + if (settings.clientMode === "native") { + return { + bitDepth: 0, + chromaFormat: 0, + reflex: shouldRequestReflex(settings), + }; + } + return { bitDepth: 1, chromaFormat: 0, reflex: true }; +} + export function shouldEnableInGameSettingsPersistence( input: Pick, ): boolean { diff --git a/opennow-stable/src/main/platforms/gfn/cloudmatchSessionParsing.ts b/opennow-stable/src/main/platforms/gfn/cloudmatchSessionParsing.ts index f89ff887c..056c38632 100644 --- a/opennow-stable/src/main/platforms/gfn/cloudmatchSessionParsing.ts +++ b/opennow-stable/src/main/platforms/gfn/cloudmatchSessionParsing.ts @@ -9,6 +9,7 @@ import type { import type { CloudMatchResponse, GetSessionsResponse } from "./types"; import { SessionError } from "./errorCodes"; +import { resolveSessionControlBaseUrl } from "./cloudmatchTransport"; import { normalizeIceServers, resolveSignaling, @@ -262,6 +263,19 @@ export function toColorQuality(bitDepth?: number, chromaFormat?: number): ColorQ return normalizedChromaFormat === 1 ? "8bit_444" : "8bit_420"; } +function toVideoCodec(codec?: number): NegotiatedStreamProfile["codec"] { + switch (codec) { + case 1: + return "H264"; + case 2: + return "H265"; + case 3: + return "AV1"; + default: + return undefined; + } +} + export function normalizeStreamingFeatures( features: | NonNullable["requestedStreamingFeatures"] @@ -308,6 +322,7 @@ export function extractNegotiatedStreamProfile(payload: CloudMatchResponse): Neg finalizedFeatures?.bitDepth ?? requestedFeatures?.bitDepth, finalizedFeatures?.chromaFormat ?? requestedFeatures?.chromaFormat, ); + const codec = toVideoCodec(finalizedFeatures?.codec ?? requestedFeatures?.codec); const enabledL4S = finalizedFeatures?.enabledL4S ?? requestedFeatures?.enabledL4S; const enabledCloudGsync = finalizedFeatures?.cloudGsync ?? requestedFeatures?.cloudGsync; const enabledReflex = finalizedFeatures?.reflex ?? requestedFeatures?.reflex; @@ -333,6 +348,10 @@ export function extractNegotiatedStreamProfile(payload: CloudMatchResponse): Neg profile.colorQuality = colorQuality; } + if (codec) { + profile.codec = codec; + } + if (typeof enabledL4S === "boolean") { profile.enableL4S = enabledL4S; } @@ -430,13 +449,14 @@ export async function toSessionInfo(options: ToSessionInfoOptions): Promise 0 ? connections.map((connection) => ({ ...connection })) : undefined, rtspsEndpoints: signaling.rtspsEndpoints.length > 0 ? signaling.rtspsEndpoints : undefined, iceServers: await normalizeIceServers(payload), mediaConnectionInfo: signaling.mediaConnectionInfo, diff --git a/opennow-stable/src/main/platforms/gfn/cloudmatchSessionRequest.ts b/opennow-stable/src/main/platforms/gfn/cloudmatchSessionRequest.ts index 82e97c235..09d4ccc85 100644 --- a/opennow-stable/src/main/platforms/gfn/cloudmatchSessionRequest.ts +++ b/opennow-stable/src/main/platforms/gfn/cloudmatchSessionRequest.ts @@ -2,19 +2,39 @@ import crypto from "node:crypto"; import type { SessionCreateRequest, StreamSettings } from "@shared/gfn"; import { + clampNativeStreamFps, colorQualityBitDepth, colorQualityChromaFormat, } from "@shared/gfn"; import type { CloudMatchRequest } from "./types"; +import { GFN_CLIENT_IDENTIFICATION } from "./clientHeaders"; import { resolveGfnDeviceIdentity } from "./deviceIdentity"; -import { getStableDeviceId } from "./deviceId"; +import { getCloudMatchDeviceHashId } from "./deviceId"; import { appLaunchModeWireValue, buildRequestedStreamingFeatures, + resolveNvstCreateStreamSku, shouldEnableInGameSettingsPersistence, } from "./cloudmatchFeatures"; +/** Official native Mac Bifrost `availableSupportedControllers` / `preferredController`. */ +const OFFICIAL_GAMEPAD_CONTROLLER = 2; + +const EMPTY_DISPLAY_DATA = { + displayPrimaryX0: 0, + displayPrimaryY0: 0, + displayPrimaryX1: 0, + displayPrimaryY1: 0, + displayPrimaryX2: 0, + displayPrimaryY2: 0, + displayWhitePointX: 0, + displayWhitePointY: 0, + desiredContentMaxLuminance: 0, + desiredContentMinLuminance: 0, + desiredContentMaxFrameAverageLuminance: 0, +} as const; + export function parseResolution(input: string): { width: number; height: number } { const [rawWidth, rawHeight] = input.split("x"); const width = Number.parseInt(rawWidth ?? "", 10); @@ -31,17 +51,68 @@ export function timezoneOffsetMs(): number { return -new Date().getTimezoneOffset() * 60 * 1000; } -export function webRtcSessionMetadata(width: number, height: number): Array<{ key: string; value: string }> { +function defaultMonitorDpi(): number { + return process.platform === "darwin" ? 144 : 96; +} + +function defaultNetworkType(): string { + return process.platform === "darwin" ? "WiFi5.0" : "Unknown"; +} + +function readPrimaryDisplayMetrics(): { + dpi: number; + horizontalPixels: number; + verticalPixels: number; +} | null { + try { + const electron = require("electron") as typeof import("electron"); + const display = electron.screen?.getPrimaryDisplay?.(); + if (!display) { + return null; + } + const scale = display.scaleFactor > 0 ? display.scaleFactor : 1; + const dpi = Math.round(scale * 72); + return { + dpi: dpi > 0 ? dpi : defaultMonitorDpi(), + horizontalPixels: Math.round(display.size.width * scale), + verticalPixels: Math.round(display.size.height * scale), + }; + } catch { + return null; + } +} + +function officialHdrCapabilities(): NonNullable< + CloudMatchRequest["sessionRequestData"]["clientDisplayHdrCapabilities"] +> { + return { + version: 2, + hdrEdrSupportedFlagsInUint32: 1, + static_metadata_descriptor_id: 0, + display_data: { ...EMPTY_DISPLAY_DATA }, + }; +} + +export function sessionMetadata( + width: number, + height: number, + transportMode: StreamSettings["transportMode"], +): Array<{ key: string; value: string }> { + const display = readPrimaryDisplayMetrics(); + const physical = { + horizontalPixels: display?.horizontalPixels ?? width, + verticalPixels: display?.verticalPixels ?? height, + }; return [ - { key: "SubSessionId", value: crypto.randomUUID() }, - { key: "wssignaling", value: "1" }, - { key: "GSStreamerType", value: "WebRTC" }, - { key: "networkType", value: "Unknown" }, { key: "ClientImeSupport", value: "0" }, + { key: "SubSessionId", value: crypto.randomUUID() }, { key: "clientPhysicalResolution", - value: JSON.stringify({ horizontalPixels: width, verticalPixels: height }), + value: JSON.stringify(physical), }, + { key: "networkType", value: defaultNetworkType() }, + { key: "wssignaling", value: "1" }, + ...(transportMode === "nvst" ? [] : [{ key: "GSStreamerType", value: "WebRTC" }]), { key: "surroundAudioInfo", value: "2" }, ]; } @@ -59,24 +130,41 @@ export function buildSessionRequestBody( // Conflating them caused the server to set up an HDR pipeline, which // dynamically downscaled resolution to ~540p. const hdrEnabled = false; // No HDR toggle implemented yet; hardcode off like claim body - const bitDepth = colorQualityBitDepth(cq); - const chromaFormat = colorQualityChromaFormat(cq); - const accountLinked = input.accountLinked ?? true; + const useClassicStreamer = input.settings.transportMode === "nvst"; + const streamSku = useClassicStreamer + ? resolveNvstCreateStreamSku(input.settings) + : { + bitDepth: colorQualityBitDepth(cq), + chromaFormat: colorQualityChromaFormat(cq), + }; + const bitDepth = streamSku.bitDepth; + const chromaFormat = streamSku.chromaFormat; + const accountLinked = false; + // Official Mac advertises HDR capability (sdrHdrMode 1 + caps v2) with zero luminance. + // Do not send desiredContentMaxLuminance>0 — that previously downscaled to ~540p. + const advertiseOfficialHdrCaps = useClassicStreamer && process.platform === "darwin"; + const sdrHdrMode = hdrEnabled || advertiseOfficialHdrCaps ? 1 : 0; + const display = readPrimaryDisplayMetrics(); + const requestedFps = input.settings.clientMode === "native" || useClassicStreamer + ? clampNativeStreamFps(input.settings.fps) + : input.settings.fps; return { sessionRequestData: { - appId: input.appId, - internalTitle: input.internalTitle || null, - availableSupportedControllers: [], + appId: parseInt(input.appId, 10), + externalAppId: null, + internalTitle: null, + availableSupportedControllers: [OFFICIAL_GAMEPAD_CONTROLLER], + preferredController: OFFICIAL_GAMEPAD_CONTROLLER, networkTestSessionId, parentSessionId: null, - clientIdentification: "GFN-PC", + clientIdentification: GFN_CLIENT_IDENTIFICATION, // Keep device identity stable across create -> reconnect/resume flows. // The official client preserves this identity, and resume reliability depends on it. deviceHashId, clientVersion: "30.0", - sdkVersion: "1.0", - streamerVersion: 1, + sdkVersion: "2.0", + streamerVersion: "14", clientPlatformName: resolveGfnDeviceIdentity().clientPlatformName, clientRequestMonitorSettings: [ { @@ -85,47 +173,40 @@ export function buildSessionRequestBody( positionY: 0, widthInPixels: width, heightInPixels: height, - framesPerSecond: input.settings.fps, - sdrHdrMode: hdrEnabled ? 1 : 0, - displayData: hdrEnabled - ? { - desiredContentMaxLuminance: 1000, - desiredContentMinLuminance: 0, - desiredContentMaxFrameAverageLuminance: 500, - } - : {}, + framesPerSecond: requestedFps, + sdrHdrMode, + displayData: { ...EMPTY_DISPLAY_DATA }, hdr10PlusGamingData: null, - dpi: 0, + dpi: display?.dpi ?? defaultMonitorDpi(), }, ], useOps: true, audioMode: 2, - metaData: webRtcSessionMetadata(width, height), - sdrHdrMode: hdrEnabled ? 1 : 0, - clientDisplayHdrCapabilities: hdrEnabled - ? { - version: 1, - hdrEdrSupportedFlagsInUint32: 1, - staticMetadataDescriptorId: 0, - } + metaData: sessionMetadata(width, height, input.settings.transportMode), + sdrHdrMode, + clientDisplayHdrCapabilities: advertiseOfficialHdrCaps || hdrEnabled + ? officialHdrCapabilities() : null, surroundAudioInfo: 0, remoteControllersBitmap: 0, clientTimezoneOffset: timezoneOffsetMs(), - enhancedStreamMode: 1, + enhancedStreamMode: 0, appLaunchMode: appLaunchModeWireValue(input.settings.appLaunchMode), - secureRTSPSupported: false, - partnerCustomData: "", + secureRTSPSupported: useClassicStreamer, + partnerCustomData: null, accountLinked, enablePersistingInGameSettings: shouldEnableInGameSettingsPersistence(input), - userAge: 26, + requestedAudioFormat: 0, + userAge: 25, requestedStreamingFeatures: buildRequestedStreamingFeatures( input.settings, bitDepth, chromaFormat, hdrEnabled, input.supportedCodecs, + input.settings.transportMode, ), + transport: null, }, }; } @@ -144,9 +225,10 @@ export function buildClaimRequestBody( // The session is already configured on the server side. Sending different fps, resolution, // codec, etc. causes HTTP 400 from the server because those parameters are immutable for // an already-streaming session. Only send the action and minimal required fields. - const deviceId = getStableDeviceId(); + const deviceId = getCloudMatchDeviceHashId(); const subSessionId = crypto.randomUUID(); const timezoneMs = timezoneOffsetMs(); + const useClassicStreamer = settings.transportMode === "nvst"; return { action: 2, @@ -155,39 +237,44 @@ export function buildClaimRequestBody( // Minimal fields required for resume - NO streaming parameter renegotiation audioMode: 2, remoteControllersBitmap: 0, - sdrHdrMode: 0, + sdrHdrMode: useClassicStreamer && process.platform === "darwin" ? 1 : 0, networkTestSessionId: null, - availableSupportedControllers: [], + availableSupportedControllers: [OFFICIAL_GAMEPAD_CONTROLLER], + preferredController: OFFICIAL_GAMEPAD_CONTROLLER, clientVersion: "30.0", deviceHashId: deviceId, internalTitle: null, clientPlatformName: resolveGfnDeviceIdentity().clientPlatformName, metaData: [ + { key: "ClientImeSupport", value: "0" }, { key: "SubSessionId", value: subSessionId }, + { key: "networkType", value: defaultNetworkType() }, { key: "wssignaling", value: "1" }, - { key: "GSStreamerType", value: "WebRTC" }, - { key: "networkType", value: "Unknown" }, - { key: "ClientImeSupport", value: "0" }, + ...(useClassicStreamer ? [] : [{ key: "GSStreamerType", value: "WebRTC" }]), { key: "surroundAudioInfo", value: "2" }, ], surroundAudioInfo: 0, clientTimezoneOffset: timezoneMs, - clientIdentification: "GFN-PC", + clientIdentification: GFN_CLIENT_IDENTIFICATION, parentSessionId: null, appId: parseInt(appId, 10), - streamerVersion: 1, + streamerVersion: "14", // Resume must not renegotiate session parameters: prefer the wire value the // session was created with over whatever the UI toggles currently say. appLaunchMode: sessionAppLaunchMode ?? appLaunchModeWireValue(settings.appLaunchMode), - sdkVersion: "1.0", - enhancedStreamMode: 1, + sdkVersion: "2.0", + enhancedStreamMode: 0, useOps: true, - clientDisplayHdrCapabilities: null, - accountLinked: true, - partnerCustomData: "", + clientDisplayHdrCapabilities: useClassicStreamer && process.platform === "darwin" + ? officialHdrCapabilities() + : null, + accountLinked: false, + partnerCustomData: null, enablePersistingInGameSettings, - secureRTSPSupported: false, - userAge: 26, + requestedAudioFormat: 0, + secureRTSPSupported: useClassicStreamer, + userAge: 25, + transport: null, }, metaData: [], }; diff --git a/opennow-stable/src/main/platforms/gfn/cloudmatchSignaling.test.ts b/opennow-stable/src/main/platforms/gfn/cloudmatchSignaling.test.ts new file mode 100644 index 000000000..7eaafff01 --- /dev/null +++ b/opennow-stable/src/main/platforms/gfn/cloudmatchSignaling.test.ts @@ -0,0 +1,62 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import type { CloudMatchResponse } from "./types"; +import { + buildSignalingUrl, + normalizeIceServers, + resolveMediaConnectionInfo, +} from "./cloudmatchSignaling"; + +test("normalizeIceServers preserves supplied hostnames, schemes, and credentials", async () => { + const response = { + session: { + iceServerConfiguration: { + iceServers: [{ + urls: ["turns:relay.example.test:443?transport=tcp"], + username: "synthetic-user", + credential: "synthetic-credential", + }], + }, + }, + } as CloudMatchResponse; + + assert.deepEqual(await normalizeIceServers(response), [{ + urls: ["turns:relay.example.test:443?transport=tcp"], + username: "synthetic-user", + credential: "synthetic-credential", + }]); +}); + +test("buildSignalingUrl preserves the supplied authority, path, and query", () => { + assert.deepEqual( + buildSignalingUrl( + "rtsps://signal.example.test:48322/custom/path?ticket=synthetic", + "198.51.100.1", + ), + { + signalingUrl: "wss://signal.example.test:48322/custom/path?ticket=synthetic", + signalingHost: "signal.example.test:48322", + }, + ); +}); + +test("WebRTC media projection ignores native MEDIA and prefers legacy VIDEO over BUNDLE", () => { + assert.deepEqual( + resolveMediaConnectionInfo([ + { ip: "198.51.100.15", port: 49015, usage: 15 }, + { ip: "198.51.100.17", port: 49017, usage: 17 }, + { ip: "198.51.100.2", port: 49002, usage: 2 }, + ], "198.51.100.1"), + { ip: "198.51.100.2", port: 49002, usage: 2 }, + ); + + assert.equal( + resolveMediaConnectionInfo([ + { ip: "198.51.100.14", port: 443, usage: 14 }, + { ip: "198.51.100.15", port: 49015, usage: 15 }, + { ip: "198.51.100.16", port: 48322, usage: 16 }, + ], "198.51.100.1", { logMissing: false }), + undefined, + ); +}); diff --git a/opennow-stable/src/main/platforms/gfn/cloudmatchSignaling.ts b/opennow-stable/src/main/platforms/gfn/cloudmatchSignaling.ts index aaa27593e..6eb93c42c 100644 --- a/opennow-stable/src/main/platforms/gfn/cloudmatchSignaling.ts +++ b/opennow-stable/src/main/platforms/gfn/cloudmatchSignaling.ts @@ -1,5 +1,3 @@ -import dns from "node:dns"; - import type { IceServer, MediaConnectionInfo } from "@shared/gfn"; import type { CloudMatchResponse } from "./types"; @@ -12,35 +10,6 @@ export function isReadySessionStatus(status: number): boolean { return READY_SESSION_STATUSES.has(status); } -async function resolveHostnameWithFallback(hostname: string): Promise { - // Try system resolver first, then fall back to Cloudflare (1.1.1.1) and Google (8.8.8.8) - try { - const r = await dns.promises.lookup(hostname); - if (r && (r as any).address) return (r as any).address; - } catch { - // ignore and try custom resolvers - } - - const fallbackServers = ["1.1.1.1", "8.8.8.8"]; - for (const server of fallbackServers) { - try { - const resolver = new dns.Resolver(); - resolver.setServers([server]); - const addrs: string[] = await new Promise((resolve, reject) => { - resolver.resolve4(hostname, (err, addresses) => { - if (err) reject(err); - else resolve(addresses); - }); - }); - if (addrs && addrs.length > 0) return addrs[0]; - } catch { - // try next fallback - } - } - - return null; -} - export async function normalizeIceServers(response: CloudMatchResponse): Promise { const raw = response.session.iceServerConfiguration?.iceServers ?? []; const servers = raw @@ -54,68 +23,13 @@ export async function normalizeIceServers(response: CloudMatchResponse): Promise }) .filter((entry) => entry.urls.length > 0); - if (servers.length > 0) { - // Attempt to resolve any hostnames in STUN/TURN URLs to IPs to avoid relying on the - // renderer's DNS resolution. This makes it possible to try alternate DNS servers - // when the system resolver fails. - const resolvedServers: IceServer[] = []; - for (const s of servers) { - const resolvedUrls: string[] = []; - for (const u of s.urls) { - try { - const m = u.match(/^([a-zA-Z0-9+.-]+):([^/]+)/); - if (m) { - const scheme = m[1]; - const hostPort = m[2]; - const host = hostPort.split(":")[0]; - const portPart = hostPort.includes(":") ? ":" + hostPort.split(":").slice(1).join(":") : ""; - - // Helper to bracket IPv6 literals when necessary - const bracketIfIpv6 = (h: string) => { - if (h.startsWith("[") && h.endsWith("]")) return h; - // Heuristic: contains ':' and is not an IPv4 dotted-quad - if (h.includes(":") && !/^\d{1,3}(?:\.\d{1,3}){3}$/.test(h)) { - return `[${h}]`; - } - return h; - }; - - // If host already looks like an IPv4 or bracketed IPv6, keep original URL - if (/^\d{1,3}(?:\.\d{1,3}){3}$/.test(host) || /^\[[0-9a-fA-F:]+\]$/.test(host)) { - resolvedUrls.push(u); - } else { - const ip = await resolveHostnameWithFallback(host); - const finalHost = ip ?? host; - const maybeBracketted = bracketIfIpv6(finalHost); - resolvedUrls.push(`${scheme}:${maybeBracketted}${portPart}`); - } - } else { - resolvedUrls.push(u); - } - } catch { - resolvedUrls.push(u); - } - } - resolvedServers.push({ urls: resolvedUrls, username: s.username, credential: s.credential }); - } - - return resolvedServers; - } + if (servers.length > 0) return servers; - // Default fallbacks — try to resolve known STUN hostnames to IPs as well - const defaults = ["s1.stun.gamestream.nvidia.com:19308", "stun.l.google.com:19302", "stun1.l.google.com:19302"]; - const out: IceServer[] = []; - for (const d of defaults) { - const parts = d.split(":"); - const host = parts[0]; - const port = parts.length > 1 ? `:${parts.slice(1).join(":")}` : ""; - const ip = await resolveHostnameWithFallback(host); - const bracketIfIpv6 = (h: string) => (h.includes(":") && !h.startsWith("[") ? `[${h}]` : h); - if (ip) out.push({ urls: [`stun:${bracketIfIpv6(ip)}${port}`] }); - else out.push({ urls: [`stun:${bracketIfIpv6(host)}${port}`] }); - } - - return out; + return [ + { urls: ["stun:s1.stun.gamestream.nvidia.com:19308"] }, + { urls: ["stun:stun.l.google.com:19302"] }, + { urls: ["stun:stun1.l.google.com:19302"] }, + ]; } /** @@ -208,9 +122,15 @@ export function resolveSignaling(response: CloudMatchResponse): { const rtspsHost = connections - .map((connection) => typeof connection.resourcePath === "string" - ? extractHostFromUrl(connection.resourcePath) - : null) + .filter((connection) => + connection.usage === 16 + || connection.appLevelProtocol === 6 + || (typeof connection.resourcePath === "string" && /^rtsps?:\/\//i.test(connection.resourcePath)), + ) + .map((connection) => connection.ip + ?? (typeof connection.resourcePath === "string" + ? extractHostFromUrl(connection.resourcePath) + : null)) .find((host): host is string => Boolean(host)) ?? signalingHost ?? (isZoneHostname(serverIp) ? null : serverIp); @@ -228,16 +148,18 @@ export function resolveSignaling(response: CloudMatchResponse): { /** * Resolve the media connection endpoint (IP + port) from the session's connectionInfo array. - * Matches Rust's media_connection_info() priority chain: - * 1. usage=2 (Primary media path, UDP) - * 2. usage=17 (Alternative media path) - * 3. usage=14 with highest port (Alliance fallback — distinguishes media port from signaling port) - * 4. Fallback: use serverIp with the highest port from any usage=14 entry + * This is the compatibility projection used by the WebRTC path: + * 1. usage=2 (legacy VIDEO) + * 2. usage=17 (BUNDLE) + * + * The native path receives the complete ordered connectionInfo array and must + * select current native transports such as usage=15 (MEDIA) itself. Signaling + * (14), MEDIA (15), and RTSPS (16) must not be repurposed as WebRTC ICE endpoints. * * For each entry, IP is extracted from: * a. The .ip field directly * b. The hostname in .resourcePath (e.g. rtsps://80-250-97-40.server.net:48322) - * c. Fallback to serverIp (only for usage=14 Alliance fallback) + * CloudMatch usage=14 is signaling and must never be repurposed as a media endpoint. */ export function resolveMediaConnectionInfo( connections: Array<{ ip?: string; port: number; usage: number; protocol?: number; resourcePath?: string }>, @@ -278,7 +200,7 @@ export function resolveMediaConnectionInfo( return 0; }; - // Priority 1: usage=2 (Primary media path, UDP) + // Priority 1: usage=2 (legacy VIDEO) const primary = connections.find((c) => c.usage === 2); if (primary) { const ip = extractIp(primary); @@ -287,7 +209,7 @@ export function resolveMediaConnectionInfo( if (ip && port > 0) return { ip, port, usage: primary.usage }; } - // Priority 2: usage=17 (Alternative media path) + // Priority 2: usage=17 (BUNDLE) const alt = connections.find((c) => c.usage === 17); if (alt) { const ip = extractIp(alt); @@ -296,18 +218,6 @@ export function resolveMediaConnectionInfo( if (ip && port > 0) return { ip, port, usage: alt.usage }; } - // Priority 3: usage=14 with highest port (Alliance fallback) - const alliance = connections - .filter((c) => c.usage === 14) - .sort((a, b) => b.port - a.port); - - for (const conn of alliance) { - const ip = extractIp(conn) ?? serverIp; - const port = extractPort(conn); - console.log(`[CloudMatch] resolveMediaConnectionInfo: usage=14 candidate: ip=${ip}, port=${port} (serverIp fallback=${serverIp})`); - if (ip && port > 0) return { ip, port, usage: conn.usage }; - } - if (options?.logMissing ?? true) { console.log("[CloudMatch] resolveMediaConnectionInfo: NO valid media connection info found"); } @@ -323,28 +233,29 @@ export function buildSignalingUrl( serverIp: string, ): { signalingUrl: string; signalingHost: string | null } { if (raw.startsWith("rtsps://") || raw.startsWith("rtsp://")) { - // Extract hostname from RTSP URL, convert to wss:// - const withoutScheme = raw.startsWith("rtsps://") - ? raw.slice("rtsps://".length) - : raw.slice("rtsp://".length); - const host = withoutScheme.split(":")[0]?.split("/")[0]; - if (host && host.length > 0 && !host.startsWith(".")) { + const signalingUrl = `wss://${raw.slice(raw.indexOf("://") + 3)}`; + try { + const parsed = new URL(signalingUrl); + if (!parsed.hostname || parsed.hostname.startsWith(".")) throw new Error("invalid host"); return { - signalingUrl: `wss://${host}/nvst/`, - signalingHost: host, + signalingUrl, + signalingHost: parsed.host, + }; + } catch { + return { + signalingUrl: `wss://${serverIp}:443/nvst/`, + signalingHost: null, }; } - return { - signalingUrl: `wss://${serverIp}:443/nvst/`, - signalingHost: null, - }; } if (raw.startsWith("wss://")) { // Already a full WSS URL, use as-is; extract host - const withoutScheme = raw.slice("wss://".length); - const host = withoutScheme.split("/")[0] ?? null; - return { signalingUrl: raw, signalingHost: host }; + try { + return { signalingUrl: raw, signalingHost: new URL(raw).host }; + } catch { + return { signalingUrl: raw, signalingHost: null }; + } } if (raw.startsWith("/")) { diff --git a/opennow-stable/src/main/platforms/gfn/cloudmatchTransport.test.ts b/opennow-stable/src/main/platforms/gfn/cloudmatchTransport.test.ts index f97eba098..57ae94497 100644 --- a/opennow-stable/src/main/platforms/gfn/cloudmatchTransport.test.ts +++ b/opennow-stable/src/main/platforms/gfn/cloudmatchTransport.test.ts @@ -4,6 +4,9 @@ import test from "node:test"; import { isZoneHostname, normalizeTrustedCloudMatchBaseUrl, + resolvePollStopBase, + resolveSessionControlBaseUrl, + selectCreateSessionBase, } from "./cloudmatchTransport"; test("isZoneHostname accepts NVIDIA CloudMatch domains and their subdomains", () => { @@ -18,6 +21,50 @@ test("isZoneHostname rejects hostnames that only contain a CloudMatch domain sub assert.equal(isZoneHostname("cloudmatchbeta.nvidiagrid.net.evil.test"), false); }); +test("session control base follows official zone-LB poll host", () => { + assert.equal( + resolveSessionControlBaseUrl( + "np-ams-06.cloudmatchbeta.nvidiagrid.net", + "https://eu-netherlands-north.cloudmatchbeta.nvidiagrid.net", + ), + "https://np-ams-06.cloudmatchbeta.nvidiagrid.net", + ); + assert.equal( + resolveSessionControlBaseUrl("203.0.113.10", "https://np-lax-01.cloudmatchbeta.nvidiagrid.net"), + "https://np-lax-01.cloudmatchbeta.nvidiagrid.net", + ); +}); + +test("create host prefers regional metro URL over zone LB when available", () => { + assert.equal( + selectCreateSessionBase([ + "https://np-frk-08.cloudmatchbeta.nvidiagrid.net", + "https://eu-netherlands-north.cloudmatchbeta.nvidiagrid.net", + "https://np-ams-06.cloudmatchbeta.nvidiagrid.net", + ]), + "https://eu-netherlands-north.cloudmatchbeta.nvidiagrid.net", + ); + assert.equal( + selectCreateSessionBase(["https://np-lax-01.cloudmatchbeta.nvidiagrid.net"]), + "https://np-lax-01.cloudmatchbeta.nvidiagrid.net", + ); +}); + +test("poll/stop base uses assigned CloudMatch zone host or real seat IP", () => { + assert.equal( + resolvePollStopBase( + "prod", + "https://eu-netherlands-north.cloudmatchbeta.nvidiagrid.net", + "np-ams-06.cloudmatchbeta.nvidiagrid.net", + ), + "https://np-ams-06.cloudmatchbeta.nvidiagrid.net", + ); + assert.equal( + resolvePollStopBase("prod", "https://np-lax-01.cloudmatchbeta.nvidiagrid.net", "203.0.113.10"), + "https://203.0.113.10", + ); +}); + test("trusted CloudMatch endpoints require a clean NVIDIA HTTPS origin", () => { assert.equal( normalizeTrustedCloudMatchBaseUrl("https://NP-AMS-06.CLOUDMATCHBETA.NVIDIAGRID.NET./"), diff --git a/opennow-stable/src/main/platforms/gfn/cloudmatchTransport.ts b/opennow-stable/src/main/platforms/gfn/cloudmatchTransport.ts index 048eca54b..afd967783 100644 --- a/opennow-stable/src/main/platforms/gfn/cloudmatchTransport.ts +++ b/opennow-stable/src/main/platforms/gfn/cloudmatchTransport.ts @@ -129,6 +129,26 @@ export function extractServerInfoRegionBases(payload: CloudMatchServerInfoRespon return bases; } +/** Official Bifrost POSTs to metro/regional hostnames (eu-*-*) rather than zone LBs (np-*-*). */ +export function selectCreateSessionBase(bases: readonly string[]): string | undefined { + if (bases.length === 0) { + return undefined; + } + + for (const base of bases) { + try { + const host = new URL(base).hostname.toLowerCase(); + if (!host.startsWith("np-")) { + return base; + } + } catch { + continue; + } + } + + return bases[0]; +} + export function isDefaultStreamingServiceBase(baseUrl: string): boolean { try { const hostname = new URL(baseUrl).hostname.toLowerCase(); @@ -145,6 +165,7 @@ export async function resolveCreateSessionBase( clientId: string, deviceId: string, proxyUrl?: string, + options: { preferRegionalHost?: boolean } = {}, ): Promise { if (!isDefaultStreamingServiceBase(base)) { return base; @@ -159,14 +180,19 @@ export async function resolveCreateSessionBase( return base; } - const [localRegionBase] = extractServerInfoRegionBases( + const regionBases = extractServerInfoRegionBases( (await response.json()) as CloudMatchServerInfoResponse, ); + const localRegionBase = options.preferRegionalHost + ? selectCreateSessionBase(regionBases) + : regionBases[0]; if (!localRegionBase || localRegionBase === base) { return base; } - console.log(`[CloudMatch] createSession resolved ${base} to local region ${localRegionBase}`); + console.log( + `[CloudMatch] createSession resolved ${base} to ${options.preferRegionalHost ? "regional create host" : "local region"} ${localRegionBase}`, + ); return localRegionBase; } catch (error) { console.warn(`[CloudMatch] createSession local-region discovery failed: ${formatErrorForLog(error)}`); @@ -202,14 +228,25 @@ export function isZoneHostname(ip: string): boolean { ); } +/** Official Bifrost polls GET /v2/session on sessionControlInfo.ip (zone LB), not the create host. */ +export function resolveSessionControlBaseUrl( + controlIp: string | string[] | undefined, + fallback: string, +): string { + const host = (Array.isArray(controlIp) ? controlIp[0] : controlIp)?.trim().replace(/\.$/, ""); + if (host && isZoneHostname(host)) { + return `https://${host.toLowerCase()}`; + } + return fallback; +} + export function resolvePollStopBase(zone: string, provided?: string, serverIp?: string): string { const base = resolveStreamingBaseUrl(zone, provided); - // Only use serverIp if it's a real server IP (not a zone hostname). - // The Rust version checks: if we're NOT an alliance partner AND we have a server_ip, use it. - // But if the "serverIp" is actually the zone hostname (from an early poll when connectionInfo - // was empty), using it is circular and doesn't help. - if (serverIp && shouldUseServerIp(base) && !isZoneHostname(serverIp)) { - return `https://${serverIp}`; + // Official Bifrost polls GET /v2/session on sessionControlInfo.ip, including zone LBs + // such as np-ams-06.cloudmatchbeta.nvidiagrid.net. Real seat IPs stay preferred once known. + const host = serverIp?.trim().replace(/\.$/, ""); + if (host && shouldUseServerIp(base)) { + return `https://${isZoneHostname(host) ? host.toLowerCase() : host}`; } return base; } diff --git a/opennow-stable/src/main/platforms/gfn/deviceId.test.ts b/opennow-stable/src/main/platforms/gfn/deviceId.test.ts new file mode 100644 index 000000000..a68c18542 --- /dev/null +++ b/opennow-stable/src/main/platforms/gfn/deviceId.test.ts @@ -0,0 +1,20 @@ +/// + +import test from "node:test"; +import assert from "node:assert/strict"; +import { createHash } from "node:crypto"; + +import { toCloudMatchDeviceHashId } from "./deviceId"; + +test("CloudMatch device ids are SHA-256 hex of the stable UUID", () => { + const uuid = "11111111-1111-4111-8111-111111111111"; + const expected = createHash("sha256").update(uuid, "utf8").digest("hex"); + assert.equal(toCloudMatchDeviceHashId(uuid), expected); + assert.match(toCloudMatchDeviceHashId(uuid), /^[0-9a-f]{64}$/); +}); + +test("CloudMatch device ids pass through existing 64-char hashes", () => { + const hash = "eb3d00f59d2e42dafddbb00648b14be24a0f9e262bc5ba50d853a019301b03fc"; + assert.equal(toCloudMatchDeviceHashId(hash), hash); + assert.equal(toCloudMatchDeviceHashId(hash.toUpperCase()), hash); +}); diff --git a/opennow-stable/src/main/platforms/gfn/deviceId.ts b/opennow-stable/src/main/platforms/gfn/deviceId.ts index 1839aea0d..87efb51cd 100644 --- a/opennow-stable/src/main/platforms/gfn/deviceId.ts +++ b/opennow-stable/src/main/platforms/gfn/deviceId.ts @@ -15,6 +15,19 @@ function getElectronApp(): Electron.App | null { } } +/** Official Grid `X-Device-Id` / JSON `deviceHashId` is 64-char SHA-256 hex, not a UUID. */ +export function toCloudMatchDeviceHashId(deviceId: string): string { + const trimmed = deviceId.trim(); + if (/^[0-9a-f]{64}$/i.test(trimmed)) { + return trimmed.toLowerCase(); + } + return crypto.createHash("sha256").update(trimmed, "utf8").digest("hex"); +} + +export function getCloudMatchDeviceHashId(): string { + return toCloudMatchDeviceHashId(getStableDeviceId()); +} + export function getStableDeviceId(): string { if (cachedStableDeviceId) { return cachedStableDeviceId; diff --git a/opennow-stable/src/main/platforms/gfn/deviceIdentity.test.ts b/opennow-stable/src/main/platforms/gfn/deviceIdentity.test.ts index c4d0994d5..5cc9bf83b 100644 --- a/opennow-stable/src/main/platforms/gfn/deviceIdentity.test.ts +++ b/opennow-stable/src/main/platforms/gfn/deviceIdentity.test.ts @@ -7,6 +7,12 @@ import { buildGfnCloudMatchHeaders, buildGfnGraphQlHeaders, buildGfnLcarsHeaders, + buildGfnNvstClientHeaders, + GFN_BIFROST_CLIENT_VERSION, + GFN_CLIENT_VERSION, + gfnBifrostUserAgentForPlatform, + gfnUserAgentForPlatform, + LCARS_CLIENT_ID, } from "./clientHeaders"; import { STEAM_DECK_DEVICE_IDENTITY, @@ -21,7 +27,62 @@ test("resolveGfnDeviceIdentity defaults to host desktop DESKTOP/UNKNOWN", () => assert.equal(identity.deviceType, "DESKTOP"); assert.equal(identity.deviceMake, "UNKNOWN"); assert.equal(identity.deviceModel, "UNKNOWN"); - assert.equal(identity.clientPlatformName, "windows"); + assert.equal(identity.clientPlatformName, "Windows"); +}); + +test("desktop identity uses native platform names", () => { + const darwin = resolveGfnDeviceIdentity({ platform: "darwin" }); + assert.equal(darwin.clientPlatformName, "MacOSX"); + assert.equal(darwin.deviceMake, "Apple"); + if (process.platform === "darwin") { + assert.notEqual(darwin.deviceModel, "UNKNOWN"); + } + assert.equal(resolveGfnDeviceIdentity({ platform: "linux" }).clientPlatformName, "Linux"); +}); + +test("Linux requests use the packaged native CEF product identity", () => { + const userAgent = gfnUserAgentForPlatform("linux"); + assert.match(userAgent, /\(X11; Linux x86_64\)/); + assert.match(userAgent, /NVIDIACEFClient\/HEAD\/7b92719716/); + assert.match(userAgent, new RegExp(`GFN-PC/${GFN_CLIENT_VERSION.replaceAll(".", "\\.")}`)); +}); + +test("macOS User-Agent identifies as the packaged GFN-PC CEF client", () => { + const userAgent = gfnUserAgentForPlatform("darwin"); + assert.match(userAgent, /\(Macintosh; Intel Mac OS X 10_15_7\)/); + assert.match(userAgent, /NVIDIACEFClient\/HEAD\/7b92719716/); + assert.match(userAgent, new RegExp(`GFN-PC/${GFN_CLIENT_VERSION.replaceAll(".", "\\.")}`)); +}); + +test("CloudMatch HTTP identity includes official Bifrost client identity", () => { + const headers = buildGfnCloudMatchHeaders({ token: "token", deviceId: "device" }); + const userAgent = gfnBifrostUserAgentForPlatform(); + assert.equal(headers["NV-Client-Type"], "NATIVE"); + assert.equal(headers["NV-Client-Streamer"], "NVIDIA-CLASSIC"); + assert.equal(headers["x-nv-client-identity"], userAgent); + assert.equal(headers["NV-Client-Version"], GFN_CLIENT_VERSION); + assert.equal(headers["Content-Type"], "text/plain"); + assert.equal(headers["User-Agent"], userAgent); + assert.match(headers["User-Agent"] ?? "", new RegExp(`GFN-PC/${GFN_BIFROST_CLIENT_VERSION}`)); + assert.equal(headers.Origin, undefined); + assert.equal(headers.Referer, undefined); + assert.equal(headers["nv-browser-type"], undefined); +}); + +test("Bifrost GridServer HTTP identity advertises the native PC client", () => { + const headers = buildGfnNvstClientHeaders({ deviceId: "device" }); + const userAgent = gfnBifrostUserAgentForPlatform(); + assert.equal(headers["NV-Client-Type"], "NATIVE"); + assert.equal(headers["NV-Client-Streamer"], "NVIDIA-CLASSIC"); + assert.equal(headers["x-nv-client-identity"], userAgent); + assert.equal(headers["X-Device-Id"], "device"); + assert.equal(headers["NV-Client-Version"], GFN_CLIENT_VERSION); + assert.equal(headers["User-Agent"], userAgent); +}); + +test("CloudMatch defaults to the stable LCARS client identity", () => { + const headers = buildGfnCloudMatchHeaders({ token: "token", deviceId: "device" }); + assert.equal(headers["NV-Client-ID"], LCARS_CLIENT_ID); }); test("resolveGfnDeviceIdentity Steam Deck profile matches official headers", () => { @@ -42,10 +103,10 @@ test("CloudMatch/LCARS/GraphQL headers honor Steam Deck identity", () => { clientId: "client", deviceId: "device", }); - assert.equal(cloudMatch["nv-device-os"], "STEAMOS"); - assert.equal(cloudMatch["nv-device-type"], "CONSOLE"); - assert.equal(cloudMatch["nv-device-make"], "VALVE"); - assert.equal(cloudMatch["nv-device-model"], "STEAMDECK"); + assert.equal(cloudMatch["NV-Device-OS"], "STEAMOS"); + assert.equal(cloudMatch["NV-Device-Type"], "CONSOLE"); + assert.equal(cloudMatch["NV-Device-Make"], "VALVE"); + assert.equal(cloudMatch["NV-Device-Model"], "STEAMDECK"); const lcars = buildGfnLcarsHeaders({ token: "token", @@ -74,6 +135,6 @@ test("explicit identifyAsSteamDeck option overrides settings reader", () => { deviceId: "device", identifyAsSteamDeck: true, }); - assert.equal(headers["nv-device-os"], "STEAMOS"); - assert.equal(headers["nv-device-type"], "CONSOLE"); + assert.equal(headers["NV-Device-OS"], "STEAMOS"); + assert.equal(headers["NV-Device-Type"], "CONSOLE"); }); diff --git a/opennow-stable/src/main/platforms/gfn/deviceIdentity.ts b/opennow-stable/src/main/platforms/gfn/deviceIdentity.ts index 32ad34bed..ae56e5574 100644 --- a/opennow-stable/src/main/platforms/gfn/deviceIdentity.ts +++ b/opennow-stable/src/main/platforms/gfn/deviceIdentity.ts @@ -1,3 +1,5 @@ +import { execFileSync } from "node:child_process"; + /** * GFN device identity profiles. * @@ -18,29 +20,47 @@ export interface GfnDeviceIdentity { clientPlatformName: string; } -// OpenNOW historically always sent clientPlatformName "windows" on the desktop -// CloudMatch path (even on macOS/Linux). Keep that unless Steam Deck spoof is on. +let cachedDarwinHwModel: string | null = null; + +function readDarwinHwModel(): string { + if (cachedDarwinHwModel) { + return cachedDarwinHwModel; + } + try { + const model = execFileSync("sysctl", ["-n", "hw.model"], { + encoding: "utf8", + timeout: 500, + }).trim(); + cachedDarwinHwModel = model.length > 0 ? model : "UNKNOWN"; + } catch { + cachedDarwinHwModel = "UNKNOWN"; + } + return cachedDarwinHwModel; +} + const DESKTOP_IDENTITY_BY_PLATFORM: Record<"win32" | "darwin" | "linux", GfnDeviceIdentity> = { win32: { deviceOs: "WINDOWS", deviceType: "DESKTOP", deviceMake: "UNKNOWN", deviceModel: "UNKNOWN", - clientPlatformName: "windows", + clientPlatformName: "Windows", }, darwin: { deviceOs: "MACOS", deviceType: "DESKTOP", - deviceMake: "UNKNOWN", + deviceMake: "Apple", deviceModel: "UNKNOWN", - clientPlatformName: "windows", + // Native Bifrost / QUERY_GFN_START uses MacOSX. Mall JS Session Control + // falls back to OSName "MacOS", but official Mac never POSTs that body. + clientPlatformName: "MacOSX", }, linux: { deviceOs: "LINUX", deviceType: "DESKTOP", deviceMake: "UNKNOWN", deviceModel: "UNKNOWN", - clientPlatformName: "windows", + clientPlatformName: "Linux", }, }; @@ -67,7 +87,14 @@ export function isIdentifyAsSteamDeckEnabled(): boolean { export function resolveHostDesktopIdentity( platform: NodeJS.Platform = process.platform, ): GfnDeviceIdentity { - if (platform === "win32" || platform === "darwin" || platform === "linux") { + if (platform === "darwin") { + return { + ...DESKTOP_IDENTITY_BY_PLATFORM.darwin, + deviceMake: "Apple", + deviceModel: readDarwinHwModel(), + }; + } + if (platform === "win32" || platform === "linux") { return DESKTOP_IDENTITY_BY_PLATFORM[platform]; } return DESKTOP_IDENTITY_BY_PLATFORM.linux; diff --git a/opennow-stable/src/main/platforms/gfn/index.ts b/opennow-stable/src/main/platforms/gfn/index.ts index aa0fdafa0..146eeed94 100644 --- a/opennow-stable/src/main/platforms/gfn/index.ts +++ b/opennow-stable/src/main/platforms/gfn/index.ts @@ -28,7 +28,7 @@ export { } from "./games"; export { initSessionProxyAuth } from "./proxyFetch"; export { normalizeSessionProxyUrl, sessionProxyHasCredentials } from "./proxyUrl"; -export { getStableDeviceId } from "./deviceId"; +export { getCloudMatchDeviceHashId, getStableDeviceId, toCloudMatchDeviceHashId } from "./deviceId"; export { STEAM_DECK_DEVICE_IDENTITY, configureIdentifyAsSteamDeck, @@ -47,7 +47,10 @@ export { } from "./accountConnections"; export { GfnSignalingClient } from "./signaling"; export { + GFN_BIFROST_CLIENT_VERSION, + GFN_CLIENT_IDENTIFICATION, GFN_CLIENT_VERSION, + gfnBifrostUserAgentForPlatform, GFN_PLAY_ORIGIN, GFN_PLAY_REFERER, GFN_USER_AGENT, @@ -56,6 +59,7 @@ export { buildGfnCloudMatchHeaders, buildGfnGraphQlHeaders, buildGfnLcarsHeaders, + buildGfnNvstClientHeaders, buildNvidiaAuthHeaders, gfnJwtAuthorization, } from "./clientHeaders"; diff --git a/opennow-stable/src/main/platforms/gfn/nvstRtsp/owner.test.ts b/opennow-stable/src/main/platforms/gfn/nvstRtsp/owner.test.ts new file mode 100644 index 000000000..666c5cf29 --- /dev/null +++ b/opennow-stable/src/main/platforms/gfn/nvstRtsp/owner.test.ts @@ -0,0 +1,211 @@ +/// + +import assert from "node:assert/strict"; +import test from "node:test"; + +import type { NativeStreamerSessionContext } from "@shared/gfn"; +import { + GfnNvstRtspSessionOwner, + GfnNvstUnavailableError, +} from "./owner"; +import type { NvstRtspSession } from "./probe"; + +function createContext( + sessionId: string, + transportMode: "nvst" | "webrtc" = "nvst", + withEndpoints = true, +): NativeStreamerSessionContext { + return { + session: { + sessionId, + status: 2, + zone: "test-zone", + serverIp: "192.0.2.10", + signalingServer: "signal.example", + signalingUrl: "wss://signal.example/session", + mediaConnectionInfo: { ip: "198.51.100.20", port: 5006, usage: 17 }, + rtspsEndpoints: withEndpoints ? [`rtsps://rtsp.example:322/${sessionId}`] : undefined, + iceServers: [], + }, + settings: { + resolution: "1920x1080", + fps: 60, + maxBitrateMbps: 80, + codec: "H265", + transportMode, + } as NativeStreamerSessionContext["settings"], + shortcuts: {} as NativeStreamerSessionContext["shortcuts"], + }; +} + +function createRtspSession( + sessionId: string, + onRelease: (reason: string) => void, + isHealthy: () => boolean = () => true, +): NvstRtspSession { + return { + endpoint: `rtsps://rtsp.example:322/${sessionId}`, + session: `rtsp-${sessionId}`, + hmacSeedPresent: true, + videoPeer: { ip: "192.0.2.20", port: 5004 }, + clientUdpPort: 45000, + srtp: { + aesKeyHex: "AA".repeat(32), + keyId: 42, + masterKeySaltHex: `${"AA".repeat(32)}${"00".repeat(11)}2A`, + saltHex: `${"00".repeat(11)}2A`, + clientGenerated: false, + }, + videoSession: { + clientUdpPort: 45000, + videoPeerIp: "192.0.2.20", + videoPeerPort: 5004, + srtpAesKeyHex: "AA".repeat(32), + srtpKeyId: 42, + srtpSaltHex: `${"00".repeat(11)}2A`, + codec: "H265", + }, + steps: ["wss-open", "options", "describe", "setup-video", "announce", "play"], + isHealthy, + handoffVideoUdp: async () => undefined, + release: async (reason = "released") => onRelease(reason), + }; +} + +test("owner retains one negotiated control session and reuses its video handoff", async () => { + const releases: string[] = []; + let negotiations = 0; + let codec: string | undefined; + let fps: number | undefined; + let maxBitrateKbps: number | undefined; + let bundlePeer: { ip: string; port: number } | undefined; + const owner = new GfnNvstRtspSessionOwner({ + negotiate: async (input) => { + const { sessionId } = input; + negotiations += 1; + codec = input.codec; + fps = input.fps; + maxBitrateKbps = input.maxBitrateKbps; + bundlePeer = input.bundlePeer; + return createRtspSession(sessionId, (reason) => releases.push(reason)); + }, + }); + + const first = await owner.prepare(createContext("same-session")); + const duplicate = await owner.prepare(createContext("same-session")); + + assert.equal(negotiations, 1); + assert.equal(codec, "H265"); + assert.equal(fps, 60); + assert.equal(maxBitrateKbps, 80_000); + assert.deepEqual(bundlePeer, { ip: "198.51.100.20", port: 5006, usage: 17 }); + assert.deepEqual(duplicate.nvstVideo, first.nvstVideo); + assert.deepEqual(releases, []); + + await owner.release("stream stopped"); + await owner.release("duplicate stop"); + assert.deepEqual(releases, ["stream stopped"]); +}); + +test("owner caps native NVST negotiation at 240 FPS and prefers the negotiated profile", async () => { + let fps: number | undefined; + let codec: string | undefined; + const owner = new GfnNvstRtspSessionOwner({ + negotiate: async (input) => { + fps = input.fps; + codec = input.codec; + return createRtspSession(input.sessionId, () => undefined); + }, + }); + const context = createContext("high-fps"); + context.settings.fps = 360; + context.settings.codec = "H264"; + context.session.negotiatedStreamProfile = { fps: 300, codec: "AV1" }; + + await owner.prepare(context); + + assert.equal(fps, 240); + assert.equal(codec, "AV1"); + await owner.release("test complete"); +}); + +test("owner tears down the previous session before negotiating its replacement", async () => { + const events: string[] = []; + const owner = new GfnNvstRtspSessionOwner({ + negotiate: async ({ sessionId }) => { + events.push(`negotiate:${sessionId}`); + return createRtspSession(sessionId, (reason) => { + events.push(`release:${sessionId}:${reason}`); + }); + }, + }); + + await owner.prepare(createContext("first")); + await owner.prepare(createContext("second")); + + assert.deepEqual(events, [ + "negotiate:first", + "release:first:replaced by GFN session second", + "negotiate:second", + ]); + await owner.release("test complete"); +}); + +test("owner renegotiates instead of reusing an unhealthy same-session client", async () => { + const events: string[] = []; + let negotiations = 0; + const owner = new GfnNvstRtspSessionOwner({ + negotiate: async ({ sessionId }) => { + negotiations += 1; + const negotiation = negotiations; + return createRtspSession( + sessionId, + (reason) => events.push(`release:${negotiation}:${reason}`), + () => negotiation > 1, + ); + }, + }); + + await owner.prepare(createContext("same-session")); + await owner.prepare(createContext("same-session")); + + assert.equal(negotiations, 2); + assert.deepEqual(events, ["release:1:replaced by GFN session same-session"]); + await owner.release("test complete"); +}); + +test("owner releases NVST when a WebRTC native context replaces it", async () => { + const releases: string[] = []; + const owner = new GfnNvstRtspSessionOwner({ + negotiate: async ({ sessionId }) => + createRtspSession(sessionId, (reason) => releases.push(reason)), + }); + + await owner.prepare(createContext("first")); + const webRtcContext = await owner.prepare(createContext("second", "webrtc")); + + assert.equal(webRtcContext.nvstVideo, undefined); + assert.deepEqual(releases, ["native transport is not NVST"]); +}); + +test("owner reports typed unavailability for missing endpoints and negotiation failure", async () => { + const owner = new GfnNvstRtspSessionOwner({ + negotiate: async () => { + throw new Error("synthetic RTSP failure"); + }, + }); + + await assert.rejects( + owner.prepare(createContext("missing", "nvst", false)), + (error: unknown) => + error instanceof GfnNvstUnavailableError + && error.code === "missing-rtsps-endpoints", + ); + await assert.rejects( + owner.prepare(createContext("failed")), + (error: unknown) => + error instanceof GfnNvstUnavailableError + && error.code === "negotiation-failed" + && /synthetic RTSP failure/.test(error.message), + ); +}); diff --git a/opennow-stable/src/main/platforms/gfn/nvstRtsp/owner.ts b/opennow-stable/src/main/platforms/gfn/nvstRtsp/owner.ts new file mode 100644 index 000000000..3ad29f992 --- /dev/null +++ b/opennow-stable/src/main/platforms/gfn/nvstRtsp/owner.ts @@ -0,0 +1,227 @@ +import { + clampNativeStreamFps, + type NativeStreamerSessionContext, + type NvstVideoSession, + type VideoCodec, +} from "@shared/gfn"; + +import { + bindEphemeralUdp, + createNvstNegotiationDependencies, + negotiateNvstRtspSession, + NvstRtspNegotiationError, + type NvstRtspProbeInput, + type NvstRtspSession, + type NvstUdpPortReservation, +} from "./probe"; + +export type GfnNvstUnavailableCode = + | "missing-rtsps-endpoints" + | "negotiation-failed" + | "preparation-superseded"; + +export class GfnNvstUnavailableError extends Error { + constructor( + readonly code: GfnNvstUnavailableCode, + message: string, + options?: ErrorOptions, + ) { + super(message, options); + this.name = "GfnNvstUnavailableError"; + } +} + +export interface GfnNvstRtspOwner { + prepare(context: NativeStreamerSessionContext): Promise; + /** Unix fd of the still-bound video UDP socket, if the probe kept it open. */ + videoUdpFd(): number | undefined; + /** Releases the video UDP reservation after native has rebound the same port. */ + handoffVideoUdp(): Promise; + release(reason: string): Promise; +} + +export interface GfnNvstRtspSessionOwnerDependencies { + negotiate?(input: NvstRtspProbeInput): Promise; + /** Bind the video/bundle socket in native so ANNOUNCE never races a rebind. */ + reserveVideoUdp?(): Promise; + /** Start native receive as soon as video SETUP gives us a peer. */ + onVideoReady?(videoSession: NvstVideoSession): Promise; + /** Start ICE+DTLS after ANNOUNCE, before PLAY. */ + onAnnounceReady?(videoSession: NvstVideoSession): Promise; + onLog?(message: string): void; +} + +interface OwnedSession { + sessionId: string; + rtsp: NvstRtspSession; +} + +function withoutNvstVideo( + context: NativeStreamerSessionContext, +): NativeStreamerSessionContext { + const { nvstVideo: _nvstVideo, ...rest } = context; + return rest; +} + +function resolveNvstCodec(context: NativeStreamerSessionContext): VideoCodec { + return context.session.negotiatedStreamProfile?.codec ?? context.settings.codec; +} + +export class GfnNvstRtspSessionOwner implements GfnNvstRtspOwner { + private active: OwnedSession | null = null; + private revision = 0; + private operation: Promise = Promise.resolve(); + + constructor( + private readonly dependencies: GfnNvstRtspSessionOwnerDependencies = {}, + ) {} + + prepare(context: NativeStreamerSessionContext): Promise { + const revision = ++this.revision; + return this.enqueue(async () => { + if (revision !== this.revision) { + throw new GfnNvstUnavailableError( + "preparation-superseded", + "NVST preparation was superseded before it started", + ); + } + + if (context.settings.transportMode !== "nvst") { + await this.releaseActive("native transport is not NVST"); + return withoutNvstVideo(context); + } + + const sessionId = context.session.sessionId; + if (this.active?.sessionId === sessionId && this.active.rtsp.isHealthy()) { + return { + ...withoutNvstVideo(context), + nvstVideo: this.active.rtsp.videoSession, + }; + } + + if (this.active?.sessionId === sessionId) { + this.log(`Replacing unhealthy NVST RTSPS control session for GFN session ${sessionId}`); + } + + await this.releaseActive(`replaced by GFN session ${sessionId}`); + + const rtspsEndpoints = context.session.rtspsEndpoints ?? []; + if (rtspsEndpoints.length === 0) { + const message = `GFN session ${sessionId} did not provide RTSPS endpoints for explicit NVST mode`; + this.log(message); + throw new GfnNvstUnavailableError("missing-rtsps-endpoints", message); + } + + let rtsp: NvstRtspSession; + try { + rtsp = await this.negotiateRtsp({ + sessionId, + rtspsEndpoints, + resolution: context.settings.resolution, + fps: clampNativeStreamFps( + context.session.negotiatedStreamProfile?.fps ?? context.settings.fps, + ), + maxBitrateKbps: Number.isFinite(context.settings.maxBitrateMbps) + ? Math.round(context.settings.maxBitrateMbps * 1_000) + : 100_000, + codec: resolveNvstCodec(context), + bundlePeer: context.session.mediaConnectionInfo, + onLog: this.dependencies.onLog, + onVideoReady: this.dependencies.onVideoReady, + onAnnounceReady: this.dependencies.onAnnounceReady, + }); + } catch (error) { + const detail = error instanceof NvstRtspNegotiationError + ? `${error.code}: ${error.message}` + : error instanceof Error + ? error.message + : String(error); + const message = `NVST is unavailable for GFN session ${sessionId}: ${detail}`; + this.log(message); + throw new GfnNvstUnavailableError("negotiation-failed", message, { + cause: error, + }); + } + + if (revision !== this.revision) { + await rtsp.release("superseded NVST preparation"); + throw new GfnNvstUnavailableError( + "preparation-superseded", + "NVST preparation was superseded before native startup", + ); + } + + this.active = { sessionId, rtsp }; + this.log( + `Retaining NVST RTSPS control session for GFN session ${sessionId}${rtsp.videoUdpFd !== undefined ? ` (videoUdpFd=${rtsp.videoUdpFd})` : ""}`, + ); + return { + ...withoutNvstVideo(context), + nvstVideo: rtsp.videoSession, + }; + }); + } + + videoUdpFd(): number | undefined { + return this.active?.rtsp.videoUdpFd; + } + + handoffVideoUdp(): Promise { + return this.enqueue(async () => { + const active = this.active; + if (!active) { + return; + } + await active.rtsp.handoffVideoUdp(); + }); + } + + release(reason: string): Promise { + ++this.revision; + return this.enqueue(() => this.releaseActive(reason)); + } + + private negotiateRtsp(input: NvstRtspProbeInput): Promise { + if (this.dependencies.negotiate) { + return this.dependencies.negotiate(input); + } + return negotiateNvstRtspSession( + input, + createNvstNegotiationDependencies({ + reserveUdpPort: bindEphemeralUdp, + reserveBundlePort: this.dependencies.reserveVideoUdp ?? bindEphemeralUdp, + }), + ); + } + + private enqueue(operation: () => Promise): Promise { + const result = this.operation.then(operation, operation); + this.operation = result.then( + () => undefined, + () => undefined, + ); + return result; + } + + private async releaseActive(reason: string): Promise { + const active = this.active; + this.active = null; + if (!active) { + return; + } + + this.log(`Releasing NVST RTSPS control session for GFN session ${active.sessionId} (${reason})`); + try { + await active.rtsp.release(reason); + } catch (error) { + this.log( + `Failed to release NVST RTSPS control session for GFN session ${active.sessionId}: ${error instanceof Error ? error.message : String(error)}`, + ); + } + } + + private log(message: string): void { + console.log(`[GfnNvstRtspOwner] ${message}`); + this.dependencies.onLog?.(message); + } +} diff --git a/opennow-stable/src/main/platforms/gfn/nvstRtsp/probe.test.ts b/opennow-stable/src/main/platforms/gfn/nvstRtsp/probe.test.ts index ccd6e135a..df7610532 100644 --- a/opennow-stable/src/main/platforms/gfn/nvstRtsp/probe.test.ts +++ b/opennow-stable/src/main/platforms/gfn/nvstRtsp/probe.test.ts @@ -4,17 +4,157 @@ import test from "node:test"; import assert from "node:assert/strict"; import { + buildNvstStunBindingRequest, collectRtspsEndpoints, + negotiateNvstRtspSession, + NvstRtspNegotiationError, + officialVideoSetupControl, + incrementNvstPingUfrag, + resolveNvstIceRemoteUfrag, + resolveRtspControlUri, rtspsUrlToWssUrl, selectPrimaryRtspsEndpoint, + type NvstRtspClient, + type NvstRtspNegotiationDependencies, } from "./probe"; -test("selectPrimaryRtspsEndpoint prefers :322", () => { +test("version 6 STUN request matches the official RFC 5389 packet shape", () => { + assert.equal( + buildNvstStunBindingRequest( + "loc1", + "remote01", + "remote-password-with-36-byte-value-001", + Buffer.from("000102030405060708090A0B", "hex"), + ).toString("hex").toUpperCase(), + "000100342112A442000102030405060708090A0B0006000D72656D6F746530313A6C6F633100000000080014B276DC1C7949494C7EF7EB226BE8BB5E0EE5AABD802800045A8349EF", + ); +}); +import type { ParsedRtspResponse } from "./rtspClient"; + +function response( + headers: Record = {}, + body = "", + statusCode = 200, +): ParsedRtspResponse { + return { + statusCode, + statusText: statusCode === 200 ? "OK" : "Failed", + headers, + body, + }; +} + +class FakeRtspClient implements NvstRtspClient { + closed = false; + readonly requests: Array<{ + method: string; + uri: string; + headers: Record; + body: string; + }> = []; + + constructor( + private readonly onRequest: ( + method: string, + uri: string, + headers: Record, + body: string, + ) => ParsedRtspResponse | Promise, + private readonly events: string[], + ) {} + + async connect(sessionId?: string): Promise { + this.closed = false; + this.events.push(`connect:${sessionId}`); + } + + isHealthy(): boolean { + return !this.closed; + } + + async request( + method: string, + uri: string, + headers: Record = {}, + body = "", + ): Promise { + this.requests.push({ method, uri, headers, body }); + this.events.push(`request:${method}`); + return this.onRequest(method, uri, headers, body); + } + + close(): void { + this.closed = true; + this.events.push("client-close"); + } +} + +const DESCRIBE_SDP = [ + "v=0", + "a=x-nv-runtime.encryptionKey:AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899", + "a=x-nv-runtime.encryptionKeyId:42", + "m=video 0 RTP/AVP 96", + "a=control:tracks/actual-video-track", + "m=audio 0 RTP/AVP 97", + "a=mid:audio-main", + "a=rtpmap:97 opus/48000/2", + "a=ssrc:424242 cname:audio", + "a=control:tracks/actual-audio-track", + "m=application 0 RTP/AVP 98", + "a=control:streamid=control/0", + "", +].join("\r\n"); + +function createNegotiationHarness( + events: string[], + override?: (method: string) => ParsedRtspResponse | undefined, +): { + client: FakeRtspClient; + dependencies: NvstRtspNegotiationDependencies; +} { + let nextUdpPort = 45678; + const client = new FakeRtspClient((method) => { + const overridden = override?.(method); + if (overridden) { + return overridden; + } + switch (method) { + case "DESCRIBE": + return response({ session: "rtsp-session;timeout=60" }, DESCRIBE_SDP); + case "SETUP": + return response({ + transport: "unicast;X-GS-ServerPort=5004-5005;source=192.0.2.4", + "x-nv-ping-payload": "ping-data", + "x-nv-ping": "1", + }); + default: + return response(); + } + }, events); + return { + client, + dependencies: { + createClient: () => client, + reserveUdpPort: async () => { + const port = nextUdpPort; + nextUdpPort += 2; + return { + port, + release: async () => { + events.push("udp-release"); + }, + }; + }, + }, + }; +} + +test("selectPrimaryRtspsEndpoint preserves CloudMatch endpoint order", () => { const selected = selectPrimaryRtspsEndpoint([ "rtsps://host.example:48322", "rtsps://host.example:322", ]); - assert.equal(selected, "rtsps://host.example:322"); + assert.equal(selected, "rtsps://host.example:48322"); }); test("rtspsUrlToWssUrl is host:port with no path (empty upgrade path is manual)", () => { @@ -24,23 +164,29 @@ test("rtspsUrlToWssUrl is host:port with no path (empty upgrade path is manual)" ); }); -test("collectRtspsEndpoints keeps both usage=14 paths", () => { +test("collectRtspsEndpoints keeps current and legacy RTSPS descriptors and ignores signaling paths", () => { const endpoints = collectRtspsEndpoints( [ { - usage: 14, + usage: 16, port: 322, resourcePath: "rtsps://host.example:322", }, { - usage: 14, + usage: 16, port: 48322, resourcePath: "rtsps://host.example:48322", }, { - usage: 2, - port: 49006, - resourcePath: null, + usage: 14, + appLevelProtocol: 6, + port: 48323, + resourcePath: "rtsps://legacy.example:48323", + }, + { + usage: 14, + port: 443, + resourcePath: "/nvst/", }, ], "host.example", @@ -48,14 +194,15 @@ test("collectRtspsEndpoints keeps both usage=14 paths", () => { assert.deepEqual(endpoints, [ "rtsps://host.example:322", "rtsps://host.example:48322", + "rtsps://legacy.example:48323", ]); }); test("collectRtspsEndpoints synthesizes from port when resourcePath missing", () => { const endpoints = collectRtspsEndpoints( [ - { usage: 14, port: 322, resourcePath: null }, - { usage: 14, port: 48322, resourcePath: null }, + { usage: 16, port: 322, resourcePath: null }, + { usage: 16, port: 48322, resourcePath: null }, ], "host.example", ); @@ -64,3 +211,746 @@ test("collectRtspsEndpoints synthesizes from port when resourcePath missing", () "rtsps://host.example:48322", ]); }); + +test("officialVideoSetupControl appends the official video stream index", () => { + assert.equal(officialVideoSetupControl("streamid=video/0"), "streamid=video/0/0"); + assert.equal(officialVideoSetupControl("streamid=video/0/0"), "streamid=video/0/0"); + assert.equal(officialVideoSetupControl("tracks/actual-video-track"), "tracks/actual-video-track"); +}); + +test("incrementNvstPingUfrag matches official SETUP ping plus one", () => { + assert.equal(incrementNvstPingUfrag("2baae7cf47998"), "2baae7cf47999"); + assert.equal(incrementNvstPingUfrag("PING"), null); + assert.equal(incrementNvstPingUfrag("srv1"), null); +}); + +test("resolveNvstIceRemoteUfrag keeps SETUP PING as the keepalive ufrag", () => { + assert.equal(resolveNvstIceRemoteUfrag("2baae7cf47998", "5cace022", 6), "2baae7cf47999"); + assert.equal(resolveNvstIceRemoteUfrag("PING", "5cace022", 6), "PING"); + assert.equal(resolveNvstIceRemoteUfrag("srv1", "5cace022", 6), "srv1"); + assert.equal(resolveNvstIceRemoteUfrag("ping-data", "5cace022", 1), "5cace022"); + assert.equal(resolveNvstIceRemoteUfrag(undefined, "5cace022"), "5cace022"); +}); + +test("resolveRtspControlUri preserves server-advertised absolute and relative controls", () => { + assert.equal( + resolveRtspControlUri("rtsps://host.example:322/session/base", "tracks/video-main"), + "rtsps://host.example:322/session/base/tracks/video-main", + ); + assert.equal( + resolveRtspControlUri("rtsps://host.example:322/session/base", "/tracks/video-main"), + "rtsps://host.example:322/tracks/video-main", + ); + assert.equal( + resolveRtspControlUri( + "rtsps://host.example:322/session/base", + "rtsps://media.example:322/selected/video", + ), + "rtsps://media.example:322/selected/video", + ); +}); + +test("negotiation retains RTSPS control and video UDP until native rebind", async () => { + const events: string[] = []; + const { client, dependencies } = createNegotiationHarness(events); + const negotiated = await negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322/session/base"], + codec: "H265", + }, dependencies); + events.push("native-start"); + await negotiated.handoffVideoUdp(); + + assert.deepEqual(events.slice(-3), [ + "request:ANNOUNCE", + "native-start", + "udp-release", + ]); + assert.equal(client.closed, false); + assert.equal(negotiated.videoSession.clientUdpPort, 45678); + assert.equal(negotiated.videoSession.videoPeerIp, "192.0.2.4"); + assert.equal(negotiated.videoSession.codec, "H265"); + assert.equal(negotiated.videoSession.srtpSaltHex, "00000000000000000000002A"); + assert.equal(negotiated.videoSession.srtpProfile, undefined); + assert.deepEqual(negotiated.videoSession.audioTrack, { + payloadType: 97, + codec: "opus", + clockRateHz: 48_000, + channels: 2, + mid: "audio-main", + ssrc: 424242, + }); + assert.equal(negotiated.srtp.saltHex, "00000000000000000000002A"); + assert.equal(negotiated.srtp.profile, undefined); + assert.equal( + client.requests.find(({ method }) => method === "OPTIONS")?.uri, + "rtsps://host.example:322", + ); + assert.equal( + client.requests.find(({ method }) => method === "DESCRIBE")?.headers["x-nv-abtesting"], + "2", + ); + assert.equal( + client.requests.find(({ method, uri }) => method === "SETUP" && uri.includes("video"))?.headers["x-nv-ping"], + "6", + ); + assert.equal( + client.requests.find(({ method }) => method === "DESCRIBE")?.headers["x-nv-sessionid"], + "gfn-session", + ); + assert.equal( + client.requests.find(({ method, uri }) => method === "SETUP" && uri.includes("video"))?.uri, + "tracks/actual-video-track", + ); + assert.deepEqual( + client.requests.filter(({ method }) => method === "SETUP").map(({ uri }) => uri), + ["tracks/actual-video-track", "tracks/actual-audio-track", "streamid=control/0"], + ); + assert.deepEqual( + client.requests.filter(({ method }) => method === "SETUP").map(({ headers }) => headers.Session), + ["rtsp-session", "rtsp-session", "rtsp-session"], + ); + const announce = client.requests.find(({ method }) => method === "ANNOUNCE"); + assert.equal(announce?.uri, "/"); + assert.match(announce?.body ?? "", /m=video 5004/); + assert.match(announce?.body ?? "", /a=x-nv-general\.clientPorts\.video:45678/); + assert.equal(client.requests.some(({ method }) => method === "PLAY"), false); + + await negotiated.release("test stop"); + await negotiated.release("duplicate stop"); + + assert.equal(client.closed, true); + assert.equal(client.requests.filter(({ method }) => method === "TEARDOWN").length, 1); + assert.equal( + client.requests.find(({ method }) => method === "TEARDOWN")?.headers.Session, + "rtsp-session", + ); + assert.deepEqual(events.slice(-2), ["request:TEARDOWN", "client-close"]); +}); + +test("negotiation hands off an explicitly advertised DESCRIBE SRTP profile", async () => { + const events: string[] = []; + const { dependencies } = createNegotiationHarness(events, (method) => + method === "DESCRIBE" + ? response( + { session: "rtsp-session;timeout=60" }, + DESCRIBE_SDP.replace( + "m=video", + "a=crypto:1 AEAD_AES_256_GCM inline:ignored\r\nm=video", + ), + ) + : undefined); + + const negotiated = await negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322/session/base"], + }, dependencies); + + assert.equal(negotiated.srtp.profile, "AEAD_AES_256_GCM"); + assert.equal(negotiated.videoSession.srtpProfile, "AEAD_AES_256_GCM"); + assert.equal(negotiated.videoSession.srtpSaltHex, negotiated.srtp.saltHex); + await negotiated.release("test complete"); +}); + +test("ping version 6 hands off remote and generated local ICE credentials", async () => { + const events: string[] = []; + const remoteUsername = "remote01"; + const remotePassword = "remote-password-with-36-byte-value-001"; + const { client, dependencies } = createNegotiationHarness(events, (method) => { + if (method === "DESCRIBE") { + return response( + { session: "rtsp-session;timeout=60" }, + DESCRIBE_SDP.replace( + "m=video", + `a=x-nv-general.iceUserNameFragmentV2:${remoteUsername}\r\na=x-nv-general.icePasswordV2:${remotePassword}\r\nm=video`, + ), + ); + } + if (method === "SETUP") { + return response({ + transport: "unicast;X-GS-ServerPort=5004-5005;source=192.0.2.4", + "x-nv-ping": "6", + "x-nv-ping-payload": "srv1", + }); + } + return undefined; + }); + + const negotiated = await negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322/session/base"], + }, dependencies); + + assert.equal(negotiated.videoSession.pingVersion, 6); + assert.equal(negotiated.videoSession.remoteIceUsernameFragment, "srv1"); + assert.equal(negotiated.videoSession.remoteIcePassword, remotePassword); + assert.match(negotiated.videoSession.localIceUsernameFragment ?? "", /^[A-Za-z0-9+/]{4}$/); + assert.match(negotiated.videoSession.localIcePassword ?? "", /^[A-Za-z0-9+/]{22}$/); + const announceBody = client.requests.find(({ method }) => method === "ANNOUNCE")?.body ?? ""; + assert.ok( + announceBody.includes( + `a=x-nv-general.iceUsernameFragment:${negotiated.videoSession.localIceUsernameFragment}`, + ), + ); + assert.ok( + announceBody.includes(`a=x-nv-general.iceUsernamePwd:${negotiated.videoSession.localIcePassword}`), + ); + assert.ok( + announceBody.includes( + `a=x-nv-general.iceUserNameFragmentV2:${negotiated.videoSession.localIceUsernameFragment}`, + ), + ); + assert.ok( + announceBody.includes(`a=x-nv-general.icePasswordV2:${negotiated.videoSession.localIcePassword}`), + ); + assert.match(announceBody, /m=video 5004/); + assert.match(announceBody, /a=x-nv-general\.clientPorts\.video:45678/); + assert.ok(announceBody.includes(`a=ice-ufrag:${negotiated.videoSession.localIceUsernameFragment}`)); + assert.ok(announceBody.includes(`a=ice-pwd:${negotiated.videoSession.localIcePassword}`)); + await negotiated.release("test complete"); +}); + +test("negotiation plays when DESCRIBE leaves disablePlay at 0", async () => { + const events: string[] = []; + const { client, dependencies } = createNegotiationHarness(events, (method) => { + if (method === "DESCRIBE") { + return response( + { session: "rtsp-session;timeout=60" }, + `${DESCRIBE_SDP.replace("m=video", "a=x-nv-general.disablePlay:0\r\nm=video")}`, + ); + } + if (method === "PLAY") { + return response({}, "", 455); + } + return undefined; + }); + + const negotiated = await negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322/session/base"], + }, dependencies); + + assert.equal(client.requests.some(({ method, uri }) => method === "PLAY" && uri === "/"), true); + assert.equal(negotiated.steps.includes("play-455"), true); + await negotiated.release("test complete"); +}); + +test("negotiation arms native receive after video SETUP and before ANNOUNCE", async () => { + const events: string[] = []; + const { client, dependencies } = createNegotiationHarness(events); + const negotiated = await negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322/session/base"], + onVideoReady: async (videoSession) => { + events.push(`native-armed:${videoSession.clientUdpPort}`); + }, + }, dependencies); + + const announceIndex = events.indexOf("request:ANNOUNCE"); + const armedIndex = events.indexOf("native-armed:45678"); + assert.ok(armedIndex >= 0); + assert.ok(announceIndex > armedIndex); + assert.equal(negotiated.steps.includes("native-receive-armed"), true); + assert.equal(client.requests.some(({ method }) => method === "ANNOUNCE"), true); + await negotiated.release("test complete"); +}); + +test("negotiation starts native WebRtcTransport after ANNOUNCE and before PLAY", async () => { + const events: string[] = []; + const { dependencies } = createNegotiationHarness(events, (method) => { + if (method === "DESCRIBE") { + return response( + { session: "rtsp-session;timeout=60" }, + `${DESCRIBE_SDP.replace("m=video", "a=x-nv-general.disablePlay:0\r\nm=video")}`, + ); + } + if (method === "PLAY") { + return response({}, "", 455); + } + return undefined; + }); + const negotiated = await negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322/session/base"], + onAnnounceReady: async (videoSession) => { + events.push(`native-announce-armed:${videoSession.clientUdpPort}`); + }, + }, dependencies); + + const announceIndex = events.indexOf("request:ANNOUNCE"); + const armedIndex = events.indexOf("native-announce-armed:45678"); + const playIndex = events.indexOf("request:PLAY"); + assert.ok(announceIndex >= 0); + assert.ok(armedIndex > announceIndex); + assert.ok(playIndex > armedIndex); + assert.equal(negotiated.steps.includes("native-announce-armed"), true); + await negotiated.release("test complete"); +}); + +test("negotiation reconnects retained RTSPS control when it closes before PLAY", async () => { + const events: string[] = []; + const { client, dependencies } = createNegotiationHarness(events, (method) => { + if (method === "DESCRIBE") { + return response( + { session: "rtsp-session;timeout=60" }, + `${DESCRIBE_SDP.replace("m=video", "a=x-nv-general.disablePlay:0\r\nm=video")}`, + ); + } + return undefined; + }); + + const negotiated = await negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322/session/base"], + onAnnounceReady: async () => { + client.closed = true; + events.push("control-closed-after-announce"); + }, + }, dependencies); + + assert.equal(events.filter((event) => event === "connect:gfn-session").length, 2); + assert.equal(negotiated.steps.includes("play-control-reconnected"), true); + assert.equal(negotiated.steps.includes("play"), true); + await negotiated.release("test complete"); +}); + +test("negotiation fails instead of starting a black stream when PLAY is rejected", async () => { + const events: string[] = []; + const { dependencies } = createNegotiationHarness(events, (method) => { + if (method === "DESCRIBE") { + return response( + { session: "rtsp-session;timeout=60" }, + `${DESCRIBE_SDP.replace("m=video", "a=x-nv-general.disablePlay:0\r\nm=video")}`, + ); + } + if (method === "PLAY") { + return response({}, "", 500); + } + return undefined; + }); + + await assert.rejects( + negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322/session/base"], + }, dependencies), + /PLAY failed/, + ); +}); + +test("negotiation announces reserved WebRtcTransport ICE and DTLS fingerprint", async () => { + const events: string[] = []; + const fingerprint = "00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF"; + const { client, dependencies } = createNegotiationHarness(events, (method) => { + if (method === "DESCRIBE") { + return response( + { session: "rtsp-session;timeout=60" }, + DESCRIBE_SDP + .replace("a=x-nv-runtime.encryptionKey:AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899\r\n", "") + .replace("a=x-nv-runtime.encryptionKeyId:42\r\n", "") + .replace( + "m=video", + [ + "a=x-nv-general.nativeRtcOnBundlePort:1", + "a=x-nv-general.useNewIceInfo:0", + "a=x-nv-general.dtlsFingerprintV2:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99", + "a=x-nv-general.iceUserNameFragmentV2:srvUfrag", + "a=x-nv-general.icePasswordV2:srv-password-with-22b-value", + "m=video", + ].join("\r\n"), + ), + ); + } + return undefined; + }); + // Native streamer owns the bundle socket (and the Mjolnir video socket), so the + // ICE/DTLS identity arrives on the bundle reservation. + dependencies.reserveBundlePort = async () => ({ + port: 45678, + mjolnirPort: 45680, + iceUsernameFragment: "locU", + icePassword: "local-password-22-chars!", + dtlsFingerprint: fingerprint, + localAddress: "192.0.2.8", + release: async () => { + events.push("udp-release"); + }, + }); + + const negotiated = await negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322/session/base"], + }, dependencies); + + const announceBody = client.requests.find(({ method }) => method === "ANNOUNCE")?.body ?? ""; + assert.equal(announceBody.includes("a=x-nv-general.dtlsFingerprint:"), false); + assert.ok(announceBody.includes(`a=x-nv-general.dtlsFingerprintV2:${fingerprint}`)); + assert.equal(announceBody.includes("a=x-nv-general.iceUsernameFragment:locU"), false); + assert.ok(announceBody.includes("a=x-nv-general.iceUserNameFragmentV2:locU")); + assert.ok(announceBody.includes("a=ice-ufrag:locU")); + assert.ok(announceBody.includes("a=fingerprint:sha-256 " + fingerprint)); + assert.match(announceBody, /a=candidate:1 1 udp 2122260223 192\.0\.2\.8 45678 typ host/); + assert.match(announceBody, /a=x-nv-general\.clientBundlePort:45678/); + assert.match(announceBody, /a=x-nv-general\.clientPorts\.video:0/); + assert.match(announceBody, /a=x-nv-general\.rtcVideoOnNativeBundle:0/); + assert.doesNotMatch(announceBody, /a=x-nv-general\.rtcpOnSctp:/); + assert.doesNotMatch(announceBody, /clientTransport/); + assert.equal(negotiated.videoSession.localDtlsFingerprint, fingerprint); + assert.equal(negotiated.videoSession.remoteDtlsFingerprint?.length, 95); + assert.equal(negotiated.videoSession.remoteIceUsernameFragment, "srvUfrag"); + assert.equal(negotiated.videoSession.clientUdpPort, 45678); + assert.equal(negotiated.videoSession.mjolnirUdpPort, 45680); + // Official always sends a client-generated runtime.encryptionKey in ANNOUNCE (it keys the + // video SRTP on the separate non-DTLS socket), even when a DTLS fingerprint is present. + assert.ok(announceBody.includes("a=x-nv-runtime.encryptionKey:")); + assert.ok(announceBody.includes("a=x-nv-runtime.encryptionKeyId:")); + await negotiated.release("test complete"); +}); + +function stunUsername(packet: Buffer): string { + let offset = 20; + while (offset + 4 <= packet.length) { + const type = packet.readUInt16BE(offset); + const length = packet.readUInt16BE(offset + 2); + if (type === 0x0006) { + return packet.subarray(offset + 4, offset + 4 + length).toString("utf8"); + } + offset += 4 + length; + if (length % 4 !== 0) { + offset += 4 - (length % 4); + } + } + throw new Error("STUN packet missing USERNAME"); +} + +test("negotiation hole-punch uses SETUP PING as the keepalive ICE ufrag", async () => { + const sent: Buffer[] = []; + const events: string[] = []; + const { dependencies } = createNegotiationHarness(events, (method) => { + if (method === "DESCRIBE") { + return response( + { session: "rtsp-session;timeout=60" }, + DESCRIBE_SDP.replace( + "m=video", + [ + "a=x-nv-general.iceUserNameFragmentV2:5cace022", + "a=x-nv-general.icePasswordV2:srv-password-with-22b-value", + "m=video", + ].join("\r\n"), + ), + ); + } + if (method === "SETUP") { + return response({ + transport: "unicast;X-GS-ServerPort=5004-5005;source=192.0.2.4", + "x-nv-ping": "6", + "x-nv-ping-payload": "PING", + }); + } + return undefined; + }); + const originalReserve = dependencies.reserveUdpPort; + dependencies.reserveUdpPort = async () => { + const reservation = await originalReserve(); + return { + ...reservation, + iceUsernameFragment: "18AU", + icePassword: "local-password-22-chars!", + send: async (payload) => { + sent.push(Buffer.from(payload)); + }, + }; + }; + + const negotiated = await negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322/session/base"], + }, dependencies); + + const usernames = sent.map(stunUsername); + assert.ok(usernames.length >= 3, `expected ICE burst, got ${usernames.join(",")}`); + assert.deepEqual(usernames.slice(0, 3), ["PING:18AU", "PING:18AU", "PING:18AU"]); + assert.ok(usernames.includes("PING:18AU")); + assert.equal(negotiated.videoSession.remoteIceUsernameFragment, "PING"); + await negotiated.release("test complete"); +}); + +test("negotiation follows official video-only empty-Transport SETUP on the cloud path", async () => { + const events: string[] = []; + const { client, dependencies } = createNegotiationHarness(events, (method) => { + if (method === "DESCRIBE") { + return response( + { session: "rtsp-session;timeout=60" }, + DESCRIBE_SDP.replace( + "a=control:tracks/actual-video-track", + "a=control:streamid=video/0", + ).replace("m=video", "a=x-nv-general.nativeRtcOnBundlePort:1\r\nm=video"), + ); + } + return undefined; + }); + // Native streamer owns both sockets: one nvst-bind returns the bundle port plus + // the dedicated Mjolnir video port. + dependencies.reserveBundlePort = async () => ({ + port: 45678, + mjolnirPort: 45680, + release: async () => { + events.push("udp-release"); + }, + }); + + const negotiated = await negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322/session/base"], + }, dependencies); + + const setups = client.requests.filter(({ method }) => method === "SETUP"); + assert.deepEqual(setups.map(({ uri }) => uri), ["streamid=video/0/0"]); + assert.equal(setups[0]?.headers.Transport, ""); + assert.equal(setups[0]?.headers.Host, "host.example:322"); + const announceBody = client.requests.find(({ method }) => method === "ANNOUNCE")?.body ?? ""; + assert.match(announceBody, /nativeRtcOnBundlePort:1/); + assert.match(announceBody, /clientBundlePort:45678/); + assert.match(announceBody, /clientPorts\.video:0/); + assert.match(announceBody, /rtcVideoOnNativeBundle:0/); + assert.match(announceBody, /rtcAudioOnNativeBundle:1/); + assert.equal(negotiated.videoSession.clientUdpPort, 45678); + assert.deepEqual(negotiated.videoSession.audioTrack, { + payloadType: 111, + codec: "opus", + clockRateHz: 48_000, + channels: 2, + mid: "0", + }); + // The native-owned Mjolnir port is handed off so the native raw-SRTP receiver + // reads video from it; the probe must not bind/NATT its own Mjolnir socket. + assert.equal(negotiated.videoSession.mjolnirUdpPort, 45680); + assert.equal( + client.requests.find(({ method }) => method === "ANNOUNCE")?.uri, + "rtsps://host.example:322", + ); + await negotiated.release("test complete"); +}); + +test("official cloud ICE uses SETUP ping plus one, not DESCRIBE V2", async () => { + const sent: Buffer[] = []; + const events: string[] = []; + const { dependencies } = createNegotiationHarness(events, (method) => { + if (method === "DESCRIBE") { + return response( + { session: "rtsp-session;timeout=60" }, + DESCRIBE_SDP.replace( + "m=video", + [ + "a=x-nv-general.nativeRtcOnBundlePort:1", + "a=x-nv-general.iceUserNameFragmentV2:5cace022", + "a=x-nv-general.icePasswordV2:srv-password-with-22b-value", + "m=video", + ].join("\r\n"), + ), + ); + } + if (method === "SETUP") { + return response({ + transport: "unicast;X-GS-ServerPort=5004-5005;source=192.0.2.4", + "x-nv-ping": "6", + "x-nv-ping-payload": "2baae7cf47998", + }); + } + return undefined; + }); + const originalReserve = dependencies.reserveUdpPort; + dependencies.reserveUdpPort = async () => { + const reservation = await originalReserve(); + return { + ...reservation, + iceUsernameFragment: "EF+W", + icePassword: "local-password-22-chars!", + send: async (payload) => { + sent.push(Buffer.from(payload)); + }, + }; + }; + + const negotiated = await negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322/session/base"], + }, dependencies); + + const usernames = sent.map(stunUsername); + assert.ok(usernames.includes("2baae7cf47999:EF+W")); + assert.ok(usernames.includes("2baae7cf47998:EF+W")); + assert.ok(usernames.includes("PING:EF+W")); + assert.equal(usernames.includes("5cace022:EF+W"), false); + assert.equal(negotiated.videoSession.remoteIceUsernameFragment, "2baae7cf47999"); + await negotiated.release("test complete"); +}); + +test("official cloud STUN starts after ANNOUNCE, not after SETUP", async () => { + const events: string[] = []; + const { dependencies } = createNegotiationHarness(events, (method) => { + if (method === "DESCRIBE") { + return response( + { session: "rtsp-session;timeout=60" }, + DESCRIBE_SDP.replace( + "m=video", + [ + "a=x-nv-general.nativeRtcOnBundlePort:1", + "a=x-nv-general.iceUserNameFragmentV2:5cace022", + "a=x-nv-general.icePasswordV2:srv-password-with-22b-value", + "m=video", + ].join("\r\n"), + ), + ); + } + if (method === "SETUP") { + return response({ + transport: "unicast;X-GS-ServerPort=5004-5005;source=192.0.2.4", + "x-nv-ping": "6", + "x-nv-ping-payload": "1d2fd28347998", + }); + } + return undefined; + }); + const originalReserve = dependencies.reserveUdpPort; + dependencies.reserveUdpPort = async () => { + const reservation = await originalReserve(); + return { + ...reservation, + iceUsernameFragment: "7m6V", + icePassword: "local-password-22-chars!", + send: async () => { + events.push("stun-send"); + }, + }; + }; + + const negotiated = await negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322/session/base"], + }, dependencies); + + const setupIndex = events.indexOf("request:SETUP"); + const announceIndex = events.indexOf("request:ANNOUNCE"); + const firstStun = events.indexOf("stun-send"); + assert.ok(setupIndex >= 0); + assert.ok(announceIndex > setupIndex); + assert.ok(firstStun > announceIndex, `STUN at ${firstStun} must follow ANNOUNCE at ${announceIndex}`); + await negotiated.release("test complete"); +}); + +test("ping version 6 fails closed without DESCRIBE ICE credentials", async () => { + const events: string[] = []; + const { dependencies } = createNegotiationHarness(events, (method) => + method === "SETUP" + ? response({ + transport: "unicast;X-GS-ServerPort=5004-5005;source=192.0.2.4", + "x-nv-ping": "6", + }) + : undefined); + + await assert.rejects( + negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322/session/base"], + }, dependencies), + (error: unknown) => + error instanceof NvstRtspNegotiationError + && error.code === "missing-ice-credentials", + ); +}); + +test("negotiation hands off an explicitly advertised SETUP SRTP profile", async () => { + const events: string[] = []; + const { dependencies } = createNegotiationHarness(events, (method) => + method === "SETUP" + ? response({ + transport: "unicast;X-GS-ServerPort=5004-5005;source=192.0.2.4;profile=AES_CM_128_HMAC_SHA1_80", + }) + : undefined); + + const negotiated = await negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322/session/base"], + }, dependencies); + + assert.equal(negotiated.srtp.profile, "AES_CM_128_HMAC_SHA1_80"); + assert.equal(negotiated.videoSession.srtpProfile, "AES_CM_128_HMAC_SHA1_80"); + await negotiated.release("test complete"); +}); + +test("negotiation fails closed on conflicting explicit SRTP profiles", async () => { + const events: string[] = []; + const { dependencies } = createNegotiationHarness(events, (method) => { + if (method === "DESCRIBE") { + return response( + { session: "rtsp-session;timeout=60" }, + DESCRIBE_SDP.replace( + "m=video", + "a=crypto:1 AEAD_AES_256_GCM inline:ignored\r\nm=video", + ), + ); + } + if (method === "SETUP") { + return response({ + transport: "unicast;X-GS-ServerPort=5004-5005;source=192.0.2.4;profile=AEAD_AES_128_GCM", + }); + } + return undefined; + }); + + await assert.rejects( + negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322/session/base"], + }, dependencies), + (error: unknown) => + error instanceof NvstRtspNegotiationError + && error.code === "conflicting-srtp-profile", + ); + + assert.equal(events.includes("udp-release"), true); + assert.deepEqual(events.slice(-2), ["request:TEARDOWN", "client-close"]); +}); + +test("negotiation fails closed when DESCRIBE omits video control and tears down", async () => { + const events: string[] = []; + const { client, dependencies } = createNegotiationHarness(events, (method) => + method === "DESCRIBE" + ? response({ session: "rtsp-session" }, "v=0\r\nm=video 0 RTP/AVP 96\r\n") + : undefined); + + await assert.rejects( + negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322"], + }, dependencies), + (error: unknown) => + error instanceof NvstRtspNegotiationError + && error.code === "missing-video-control", + ); + + assert.equal(client.requests.some(({ method }) => method === "SETUP"), false); + assert.deepEqual(events.slice(-2), ["request:TEARDOWN", "client-close"]); +}); + +test("failed ANNOUNCE releases the UDP reservation and closes RTSPS control", async () => { + const events: string[] = []; + const { client, dependencies } = createNegotiationHarness(events, (method) => + method === "ANNOUNCE" ? response({}, "", 500) : undefined); + + await assert.rejects( + negotiateNvstRtspSession({ + sessionId: "gfn-session", + rtspsEndpoints: ["rtsps://host.example:322"], + }, dependencies), + (error: unknown) => + error instanceof NvstRtspNegotiationError + && error.code === "negotiation-failed" + && /ANNOUNCE failed/.test(error.message), + ); + + assert.equal(events.includes("udp-release"), true); + assert.equal(client.closed, true); + assert.deepEqual(events.slice(-3), ["udp-release", "request:TEARDOWN", "client-close"]); +}); diff --git a/opennow-stable/src/main/platforms/gfn/nvstRtsp/probe.ts b/opennow-stable/src/main/platforms/gfn/nvstRtsp/probe.ts index da5da8264..dbd07998c 100644 --- a/opennow-stable/src/main/platforms/gfn/nvstRtsp/probe.ts +++ b/opennow-stable/src/main/platforms/gfn/nvstRtsp/probe.ts @@ -1,32 +1,43 @@ /** - * Classic NVST RTSPS-over-WSS handshake (GO-with-Moonlight-hypothesis). + * Classic NVST RTSPS-over-WSS handshake. * - * Runs OPTIONS → DESCRIBE → SETUP video/0/0 → ANNOUNCE → PLAY against `:322`. - * Extracts or generates runtime.encryptionKey for SRTP, then returns nvstVideo - * handoff fields for the native UDP receive scaffold. Does not keep the UDP - * socket open across the process boundary — native rebinds clientUdpPort. - * - * Evidence: docs/research/nvst-wire-format.md, nvst-srtp-key-derivation.md, - * nvst-announce-allowlist-1080p60.json. + * Runs OPTIONS → DESCRIBE → SETUP → ANNOUNCE. Official cloud (`nativeRtcOnBundlePort=1`) + * SETUPs video only with an empty Transport, binds Mjolnir before SETUP and the ICE + * bundle after SETUP, then ANNOUNCEs `clientPorts.*=0` + `clientBundlePort`. First + * bundle STUN is after ANNOUNCE; Mjolnir NATT starts just before PLAY. PLAY waits + * for WebRtcTransport. The legacy path still SETUPs every advertised stream. */ -import { createSocket, type Socket } from "node:dgram"; +import { createSocket } from "node:dgram"; +import { networkInterfaces } from "node:os"; +import { createHmac, randomBytes } from "node:crypto"; -import type { NvstVideoSession } from "@shared/gfn"; +import type { NvstSrtpProfile, NvstVideoSession } from "@shared/gfn"; import { extractVideoPeer, header, RtspOverWssClient, + type ParsedRtspResponse, } from "./rtspClient"; import { buildAnnounceSdp, extractHmacSeed, + extractNvstIceCredentials, + extractNvstOpusAudioTrack, + extractNvstSdpAttribute, + extractMediaControl, extractRuntimeEncryptionKey, generateClientEncryptionKey, + generateNvstIceCredentials, packSrtpMasterKeySalt, redactKey, } from "./sdp"; +import { + deriveSrtpSaltHex, + extractAdvertisedSrtpProfileFromHeaders, + extractAdvertisedSrtpProfileFromSdp, +} from "./srtp"; const DEFAULT_PROBE_TIMEOUT_MS = 20_000; @@ -35,9 +46,61 @@ export interface NvstRtspProbeInput { rtspsEndpoints: string[]; resolution?: string; fps?: number; + maxBitrateKbps?: number; codec?: string; + bundlePeer?: { ip: string; port: number }; timeoutMs?: number; onLog?: (message: string) => void; + /** Official Bifrost has MjolnirVideoReceiver reading before later SETUP/ANNOUNCE/PLAY. */ + onVideoReady?(videoSession: NvstVideoSession): Promise; + /** Official starts WebRtcTransport after ANNOUNCE and waits for DTLS before PLAY. */ + onAnnounceReady?(videoSession: NvstVideoSession): Promise; +} + +export interface NvstRtspClient { + connect(sessionId?: string): Promise; + isHealthy(): boolean; + request( + method: string, + uri: string, + extraHeaders?: Record, + body?: string, + ): Promise; + close(): void; +} + +export interface NvstUdpPortReservation { + port: number; + /** + * Port of the dedicated NATT-only Mjolnir video socket reserved alongside the + * bundle. Set only when the native streamer owns both sockets (nvst-bind); the + * probe must not bind or NATT a separate Mjolnir socket in that case. + */ + mjolnirPort?: number; + localAddress?: string; + fd?: number; + iceUsernameFragment?: string; + icePassword?: string; + /** SHA-256 colon hex of the local DTLS cert that owns this socket. */ + dtlsFingerprint?: string; + send?(payload: Buffer, peerHost: string, peerPort: number): Promise; + onMessage?( + handler: (payload: Buffer, peer: { address: string; port: number }) => void, + ): void; + release(): Promise; +} + +export interface NvstRtspNegotiationDependencies { + createClient( + host: string, + port: number, + timeoutMs: number, + onLog?: (message: string) => void, + ): NvstRtspClient; + /** Mjolnir / extra SETUP sockets. Official cloud uses this for video NATT. */ + reserveUdpPort(peerHost?: string, peerPort?: number): Promise; + /** ICE/DTLS bundle socket. Official binds this after video SETUP. */ + reserveBundlePort?(peerHost?: string, peerPort?: number): Promise; } export interface NvstSrtpMaterial { @@ -47,6 +110,10 @@ export interface NvstSrtpMaterial { keyId: number; /** 88-char hex libsrtp master key||salt (AES-256 || 12-byte salt). */ masterKeySaltHex: string; + /** 24-char hex salt derived from runtime.encryptionKeyId. */ + saltHex: string; + /** Present only when DESCRIBE or SETUP explicitly advertises a known profile. */ + profile?: NvstSrtpProfile; /** True when OpenNOW generated the key for ANNOUNCE (DESCRIBE lacked it). */ clientGenerated: boolean; } @@ -67,20 +134,113 @@ export interface NvstRtspProbeResult { error?: string; } +export type NvstRtspNegotiationErrorCode = + | "missing-rtsps-endpoint" + | "missing-video-control" + | "missing-audio-control" + | "missing-control-stream" + | "missing-video-peer" + | "missing-ice-credentials" + | "conflicting-srtp-profile" + | "negotiation-failed"; + +export class NvstRtspNegotiationError extends Error { + constructor( + readonly code: NvstRtspNegotiationErrorCode, + message: string, + options?: ErrorOptions, + readonly steps: string[] = [], + ) { + super(message, options); + this.name = "NvstRtspNegotiationError"; + } +} + +export interface NvstRtspSession { + endpoint: string; + session: string; + hmacSeedPresent: boolean; + videoPeer: { ip: string; port: number }; + clientUdpPort: number; + srtp: NvstSrtpMaterial; + pingPayload?: string; + pingVersion?: number; + videoSession: NvstVideoSession; + steps: string[]; + videoUdpFd?: number; + isHealthy(): boolean; + /** Releases the video UDP reservation after native has rebound clientUdpPort. */ + handoffVideoUdp(): Promise; + release(reason?: string): Promise; +} + function log(onLog: NvstRtspProbeInput["onLog"], message: string): void { console.log(`[NvstRtspProbe] ${message}`); onLog?.(message); } +const CRC32_TABLE = Array.from({ length: 256 }, (_, value) => { + let crc = value; + for (let bit = 0; bit < 8; bit += 1) { + crc = (crc >>> 1) ^ (crc & 1 ? 0xedb88320 : 0); + } + return crc >>> 0; +}); + +function appendStunAttribute(packet: Buffer[], type: number, value: Buffer): void { + const header = Buffer.alloc(4); + header.writeUInt16BE(type, 0); + header.writeUInt16BE(value.length, 2); + packet.push(header, value); + const padding = value.length % 4; + if (padding) { + packet.push(Buffer.alloc(4 - padding)); + } +} + +export function buildNvstStunBindingRequest( + localUsernameFragment: string, + remoteUsernameFragment: string, + remotePassword: string, + transactionId: Buffer = randomBytes(12), +): Buffer { + if (transactionId.length !== 12) { + throw new Error("STUN transaction ID must be 12 bytes"); + } + const header = Buffer.alloc(20); + header.writeUInt16BE(0x0001, 0); + header.writeUInt32BE(0x2112a442, 4); + transactionId.copy(header, 8); + const parts = [header]; + appendStunAttribute( + parts, + 0x0006, + Buffer.from(`${remoteUsernameFragment}:${localUsernameFragment}`, "utf8"), + ); + let packet = Buffer.concat(parts); + header.writeUInt16BE(packet.length - 20 + 24, 2); + packet = Buffer.concat(parts); + // RFC 5389 MESSAGE-INTEGRITY requires HMAC-SHA1. + // lgtm[js/weak-cryptographic-algorithm] + appendStunAttribute(parts, 0x0008, createHmac("sha1", remotePassword).update(packet).digest()); + packet = Buffer.concat(parts); + header.writeUInt16BE(packet.length - 20 + 8, 2); + packet = Buffer.concat(parts); + let crc = 0xffffffff; + for (const byte of packet) { + crc = (crc >>> 8) ^ CRC32_TABLE[(crc ^ byte) & 0xff]!; + } + const fingerprint = Buffer.alloc(4); + fingerprint.writeUInt32BE(((crc ^ 0xffffffff) ^ 0x5354554e) >>> 0); + appendStunAttribute(parts, 0x8028, fingerprint); + return Buffer.concat(parts); +} + export function selectPrimaryRtspsEndpoint(endpoints: string[]): string | null { const normalized = endpoints .map((value) => value.trim()) .filter((value) => /^rtsps?:\/\//i.test(value)); - if (normalized.length === 0) { - return null; - } - const port322 = normalized.find((url) => /:322(?:\/|$)/.test(url)); - return port322 ?? normalized[0] ?? null; + return normalized[0] ?? null; } /** @@ -95,16 +255,18 @@ export function rtspsUrlToWssUrl(rtspsUrl: string): string { } export function collectRtspsEndpoints( - connections: Array<{ usage?: number; port?: number; resourcePath?: string | null }>, + connections: Array<{ + usage?: number; + port?: number; + appLevelProtocol?: number; + resourcePath?: string | null; + }>, fallbackHost?: string | null, ): string[] { const endpoints: string[] = []; const seen = new Set(); for (const conn of connections) { - if (conn.usage !== 14) { - continue; - } const resourcePath = typeof conn.resourcePath === "string" ? conn.resourcePath.trim() : ""; if (/^rtsps?:\/\//i.test(resourcePath)) { if (!seen.has(resourcePath)) { @@ -113,6 +275,9 @@ export function collectRtspsEndpoints( } continue; } + if (conn.usage !== 16 && conn.appLevelProtocol !== 6) { + continue; + } if (!fallbackHost || !conn.port) { continue; } @@ -126,181 +291,835 @@ export function collectRtspsEndpoints( return endpoints; } -async function bindEphemeralUdp(): Promise<{ socket: Socket; port: number }> { - const socket = createSocket("udp4"); - await new Promise((resolve, reject) => { - socket.once("error", reject); - socket.bind(0, "0.0.0.0", () => { - socket.off("error", reject); - resolve(); +export function resolveRtspControlUri(baseUri: string, control: string): string { + if (/^rtsps?:\/\//i.test(control)) { + return control; + } + + const base = new URL(baseUri.replace(/^rtsps:/i, "https:").replace(/^rtsp:/i, "http:")); + const scheme = baseUri.toLowerCase().startsWith("rtsp:") ? "rtsp:" : "rtsps:"; + if (control.startsWith("/")) { + return `${scheme}//${base.host}${control}`; + } + return `${baseUri.replace(/\/+$/, "")}/${control.replace(/^\/+/, "")}`; +} + +/** Official SETUP uses `streamid=video/0/0` when DESCRIBE advertised `streamid=video/0`. */ +export function officialVideoSetupControl(control: string): string { + if (/^streamid=video\/\d+$/i.test(control)) { + return `${control}/0`; + } + return control; +} + +/** Official bundle ICE remote ufrag is SETUP ping + 1 (`…998` → `…999`). */ +export function incrementNvstPingUfrag(payload: string): string | null { + if (!/^[0-9a-fA-F]+$/.test(payload) || payload.toUpperCase() === "PING") { + return null; + } + const next = (BigInt(`0x${payload}`) + 1n).toString(16); + return next.padStart(payload.length, "0"); +} + +/** + * Official NattHolePunch STUN remote ufrag: + * hex SETUP ping → ping+1 on the ICE bundle; otherwise the ping-string itself + * (`PING` when "Old server only supports PING"). Never fall back to DESCRIBE V2 + * while a SETUP ping payload is present — that keepalive identity is what the + * server answers. + */ +export function resolveNvstIceRemoteUfrag( + pingPayload: string | undefined, + describeUfrag?: string, + pingVersion?: number, +): string | undefined { + if (pingPayload) { + const incremented = incrementNvstPingUfrag(pingPayload); + if (incremented) { + return incremented; + } + if (pingPayload.toUpperCase() === "PING" || pingVersion === 6) { + return pingPayload; + } + } + return describeUfrag; +} + +function xorMappedIPv4(host: string, port: number): Buffer | null { + const parts = host.split(".").map((part) => Number.parseInt(part, 10)); + if (parts.length !== 4 || parts.some((part) => !Number.isFinite(part) || part < 0 || part > 255)) { + return null; + } + const value = Buffer.alloc(8); + value.writeUInt8(0, 0); + value.writeUInt8(1, 1); + value.writeUInt16BE(port ^ 0x2112, 2); + value[4] = (parts[0] ?? 0) ^ 0x21; + value[5] = (parts[1] ?? 0) ^ 0x12; + value[6] = (parts[2] ?? 0) ^ 0xa4; + value[7] = (parts[3] ?? 0) ^ 0x42; + return value; +} + +/** Official ping-version 6 PONG: STUN Binding Success for an inbound request. */ +export function buildNvstStunBindingSuccess( + localPassword: string, + transactionId: Buffer, + mappedHost: string, + mappedPort: number, +): Buffer | null { + if (transactionId.length !== 12) { + return null; + } + const mapped = xorMappedIPv4(mappedHost, mappedPort); + if (!mapped) { + return null; + } + const header = Buffer.alloc(20); + header.writeUInt16BE(0x0101, 0); + header.writeUInt32BE(0x2112a442, 4); + transactionId.copy(header, 8); + const parts = [header]; + appendStunAttribute(parts, 0x0020, mapped); + let packet = Buffer.concat(parts); + header.writeUInt16BE(packet.length - 20 + 24, 2); + packet = Buffer.concat(parts); + // RFC 5389 MESSAGE-INTEGRITY requires HMAC-SHA1. + // lgtm [js/weak-cryptographic-algorithm] + appendStunAttribute(parts, 0x0008, createHmac("sha1", localPassword).update(packet).digest()); + packet = Buffer.concat(parts); + header.writeUInt16BE(packet.length - 20 + 8, 2); + packet = Buffer.concat(parts); + let crc = 0xffffffff; + for (const byte of packet) { + crc = (crc >>> 8) ^ CRC32_TABLE[(crc ^ byte) & 0xff]!; + } + const fingerprint = Buffer.alloc(4); + fingerprint.writeUInt32BE(((crc ^ 0xffffffff) ^ 0x5354554e) >>> 0); + appendStunAttribute(parts, 0x8028, fingerprint); + return Buffer.concat(parts); +} + +function pickLocalIpv4(): string | undefined { + for (const addresses of Object.values(networkInterfaces())) { + for (const address of addresses ?? []) { + if (address.family === "IPv4" && !address.internal) { + return address.address; + } + } + } + return undefined; +} + +export function createNvstNegotiationDependencies( + overrides: Partial = {}, +): NvstRtspNegotiationDependencies { + return { + ...DEFAULT_NEGOTIATION_DEPENDENCIES, + ...overrides, + }; +} + +export async function bindEphemeralUdp(peerHost?: string, peerPort?: number): Promise { + const socket = createSocket({ type: "udp4", reuseAddr: true }); + try { + await new Promise((resolve, reject) => { + socket.once("error", reject); + socket.bind(0, "0.0.0.0", () => { + socket.off("error", reject); + resolve(); + }); }); - }); + } catch (error) { + try { + socket.close(); + } catch {} + throw error; + } + if (peerHost && peerPort) { + await new Promise((resolve, reject) => { + socket.once("error", reject); + socket.connect(peerPort, peerHost, () => { + socket.off("error", reject); + resolve(); + }); + }); + } const address = socket.address(); if (typeof address === "string") { socket.close(); throw new Error("Unexpected UDP socket address shape"); } - return { socket, port: address.port }; + let released = false; + if (peerHost && peerPort) { + socket.disconnect(); + } + const handle = (socket as unknown as { _handle?: { fd?: number } })._handle; + const fd = typeof handle?.fd === "number" && handle.fd >= 0 ? handle.fd : undefined; + return { + port: address.port, + localAddress: address.address === "0.0.0.0" ? pickLocalIpv4() : address.address, + fd, + send: async (payload, host, port) => { + await new Promise((resolve, reject) => { + socket.send(payload, port, host, (error) => error ? reject(error) : resolve()); + }); + }, + onMessage: (handler) => { + socket.on("message", (message, rinfo) => { + handler(Buffer.isBuffer(message) ? message : Buffer.from(message), { + address: rinfo.address, + port: rinfo.port, + }); + }); + }, + release: async () => { + if (released) { + return; + } + released = true; + await new Promise((resolve) => socket.close(resolve)); + }, + }; } -export async function runNvstRtspHandshakeProbe(input: NvstRtspProbeInput): Promise { +const DEFAULT_NEGOTIATION_DEPENDENCIES: NvstRtspNegotiationDependencies = { + createClient: (host, port, timeoutMs, onLog) => + new RtspOverWssClient(host, port, timeoutMs, onLog), + reserveUdpPort: bindEphemeralUdp, +}; + +async function teardownAndClose( + client: NvstRtspClient, + endpoint: string, + session: string | null, + reason: string, + onLog?: (message: string) => void, +): Promise { + try { + if (session) { + const response = await client.request("TEARDOWN", endpoint, { Session: session }); + if (response.statusCode === 200) { + log(onLog, `TEARDOWN ok (${reason})`); + } else { + log(onLog, `TEARDOWN returned ${response.statusCode} ${response.statusText} (${reason})`); + } + } + } catch (error) { + log(onLog, `TEARDOWN failed (${reason}): ${error instanceof Error ? error.message : String(error)}`); + } finally { + client.close(); + } +} + +export async function negotiateNvstRtspSession( + input: NvstRtspProbeInput, + dependencies: NvstRtspNegotiationDependencies = DEFAULT_NEGOTIATION_DEPENDENCIES, +): Promise { const steps: string[] = []; const endpoint = selectPrimaryRtspsEndpoint(input.rtspsEndpoints); if (!endpoint) { - return { - ok: false, - endpoint: "", - hmacSeedPresent: false, - steps, - error: "No rtsps:// endpoints available on the session", - }; + throw new NvstRtspNegotiationError( + "missing-rtsps-endpoint", + "No rtsps:// endpoints available on the session", + ); } const timeoutMs = input.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS; const wssUrl = rtspsUrlToWssUrl(endpoint); const parsedEndpoint = new URL(endpoint.replace(/^rtsps:/i, "https:").replace(/^rtsp:/i, "http:")); - const host = parsedEndpoint.hostname; - const port = Number(parsedEndpoint.port || "322"); - const client = new RtspOverWssClient( - host, - port, + const client = dependencies.createClient( + parsedEndpoint.hostname, + Number(parsedEndpoint.port || "322"), timeoutMs, (message) => log(input.onLog, message), ); - let udp: { socket: Socket; port: number } | null = null; + let udp: NvstUdpPortReservation | null = null; + let mjolnirUdp: NvstUdpPortReservation | null = null; + // Port of the native-owned Mjolnir video socket (undefined when the probe owns + // the fallback Mjolnir socket itself). + let nativeMjolnirPort: number | undefined; + let audioUdp: NvstUdpPortReservation | null = null; + const auxiliaryUdp: NvstUdpPortReservation[] = []; + const holePunchTimers: NodeJS.Timeout[] = []; + let session: string | null = null; + + const reserveBundle = (): Promise => + (dependencies.reserveBundlePort ?? dependencies.reserveUdpPort)(); try { log( input.onLog, - `Connecting RTSPS WSS ${wssUrl} via raw-TLS Bifrost-shaped upgrade (GET / then /v2/session/) (session ${input.sessionId})`, + `Connecting RTSPS WSS ${wssUrl} via raw-TLS Bifrost-shaped upgrade (GET /rtsp) (session ${input.sessionId})`, ); await client.connect(input.sessionId); steps.push("wss-open"); - const options = await client.request("OPTIONS", endpoint); + const rtspTarget = `rtsps://${parsedEndpoint.host}`; + const commonHeaders: Record = { + "X-GS-Version": "14.2", + Host: parsedEndpoint.host, + }; + if (input.sessionId.trim()) { + commonHeaders["x-nv-sessionid"] = input.sessionId.trim(); + } + const options = await client.request("OPTIONS", rtspTarget, commonHeaders); if (options.statusCode !== 200) { throw new Error(`OPTIONS failed: ${options.statusCode} ${options.statusText}`); } steps.push("options"); log(input.onLog, `OPTIONS ok (X-GS-Version=${header(options.headers, "x-gs-version") ?? "n/a"})`); - const describe = await client.request("DESCRIBE", endpoint, { + const describe = await client.request("DESCRIBE", rtspTarget, { + ...commonHeaders, Accept: "application/sdp", + // Official Bifrost sends x-nv-abtesting on DESCRIBE; the seat keys the modern + // ping/HMAC media context off it. Omitting it is treated as a legacy client. + "x-nv-abtesting": "2", }); if (describe.statusCode !== 200) { throw new Error(`DESCRIBE failed: ${describe.statusCode} ${describe.statusText}`); } steps.push("describe"); - const session = header(describe.headers, "session")?.split(";")[0]?.trim(); + session = header(describe.headers, "session")?.split(";")[0]?.trim() ?? null; if (!session) { throw new Error("DESCRIBE response missing Session header"); } + const videoControl = extractMediaControl(describe.body, "video"); + if (!videoControl) { + throw new NvstRtspNegotiationError( + "missing-video-control", + "DESCRIBE response did not advertise a video media control URI", + ); + } + const audioControl = extractMediaControl(describe.body, "audio"); + if (!audioControl) { + throw new NvstRtspNegotiationError( + "missing-audio-control", + "DESCRIBE response did not advertise an audio media control URI", + ); + } + const audioTrack = extractNvstOpusAudioTrack(describe.body); + const describedControls = [...describe.body.matchAll(/^a=control:(.+)$/gm)] + .map((match) => match[1]?.trim()) + .filter((control): control is string => Boolean(control)); + const controlStream = describedControls.find((control) => /(?:^|[=/])control\/0(?:\/|$)/i.test(control)); + if (!controlStream) { + throw new NvstRtspNegotiationError( + "missing-control-stream", + "DESCRIBE response did not advertise the primary control/0 stream", + ); + } + log(input.onLog, `DESCRIBE media controls: ${describedControls.join(", ") || "none"}`); + const videoControlUri = videoControl; const hmacSeed = extractHmacSeed(describe.body); + const iceCredentials = extractNvstIceCredentials(describe.body); + const legacyIceUsername = extractNvstSdpAttribute(describe.body, "general.iceUsernameFragment"); + const legacyIcePassword = extractNvstSdpAttribute(describe.body, "general.iceUsernamePwd"); + const v2IceUsername = extractNvstSdpAttribute(describe.body, "general.iceUserNameFragmentV2"); + const v2IcePassword = extractNvstSdpAttribute(describe.body, "general.icePasswordV2"); + const describedSrtpProfile = extractAdvertisedSrtpProfileFromSdp(describe.body); const describedKey = extractRuntimeEncryptionKey(describe.body); - let encryptionKeyHex: string; - let encryptionKeyId: number; + const dtlsFingerprint = extractNvstSdpAttribute(describe.body, "general.dtlsFingerprintV2") + ?? extractNvstSdpAttribute(describe.body, "general.dtlsFingerprint"); + const serverTransport = extractNvstSdpAttribute(describe.body, "general.serverTransport"); + const describedClientTransport = extractNvstSdpAttribute(describe.body, "general.clientTransport"); + const useNewIceInfo = extractNvstSdpAttribute(describe.body, "general.useNewIceInfo"); + const describedPingVersion = extractNvstSdpAttribute(describe.body, "general.pingVersion"); + const disablePlay = extractNvstSdpAttribute(describe.body, "general.disablePlay"); + const nativeRtcOnBundlePort = extractNvstSdpAttribute(describe.body, "general.nativeRtcOnBundlePort"); + const describedRtcpOnSctp = extractNvstSdpAttribute(describe.body, "general.rtcpOnSctp"); + log( + input.onLog, + `DESCRIBE transport metadata: dtlsFingerprintBytes=${dtlsFingerprint?.length ?? 0}, serverTransport=${serverTransport ?? "absent"}, clientTransport=${describedClientTransport ?? "absent"}, useNewIceInfo=${useNewIceInfo ?? "absent"}, pingVersion=${describedPingVersion ?? "absent"}, disablePlay=${disablePlay ?? "absent"}, nativeRtcOnBundlePort=${nativeRtcOnBundlePort ?? "absent"}, rtcpOnSctp=${describedRtcpOnSctp ?? "absent"}, legacyIce=${legacyIceUsername?.length ?? 0}/${legacyIcePassword?.length ?? 0}, v2Ice=${v2IceUsername?.length ?? 0}/${v2IcePassword?.length ?? 0}, iceVariantsMatch=${legacyIceUsername === v2IceUsername && legacyIcePassword === v2IcePassword}`, + ); + let encryptionKeyHex: string | undefined; + let encryptionKeyId: number | undefined; let clientGenerated = false; if (describedKey) { encryptionKeyHex = describedKey.aesKeyHex; encryptionKeyId = describedKey.keyId; log( input.onLog, - `DESCRIBE ok (Session=${session}, HMAC ${hmacSeed ? "present" : "missing"}, encryptionKey ${redactKey(encryptionKeyHex)} from server)`, + `DESCRIBE ok (Session=${session}, videoControl=${videoControl}, HMAC ${hmacSeed ? "present" : "missing"}, ICE credentials ${iceCredentials ? `present (ufragBytes=${iceCredentials.usernameFragment.length}, pwdBytes=${iceCredentials.password.length})` : "missing"}, encryptionKey ${redactKey(encryptionKeyHex)} from server)`, ); } else { + // Official Bifrost ALWAYS client-generates runtime.encryptionKey and sends it in + // ANNOUNCE — even when a DTLS fingerprint is present. The video SRTP path (the + // separate non-DTLS socket) is keyed by this runtime key, not by DTLS-SRTP. If we + // skip generating it, the server never keys video for us and no video is sent. const generated = generateClientEncryptionKey(); encryptionKeyHex = generated.aesKeyHex; encryptionKeyId = generated.keyId; clientGenerated = true; log( input.onLog, - `DESCRIBE ok (Session=${session}, HMAC ${hmacSeed ? "present" : "missing"}, encryptionKey absent — client-generated ${redactKey(encryptionKeyHex)} for ANNOUNCE)`, + `DESCRIBE ok (Session=${session}, videoControl=${videoControl}, HMAC ${hmacSeed ? "present" : "missing"}, ICE credentials ${iceCredentials ? `present (ufragBytes=${iceCredentials.usernameFragment.length}, pwdBytes=${iceCredentials.password.length})` : "missing"}, encryptionKey absent — client-generated ${redactKey(encryptionKeyHex)} for ANNOUNCE)`, ); } - udp = await bindEphemeralUdp(); - const clientPort = udp.port; - // Transport uses X-GS-ClientPort (GameStream/Moonlight family). Official logs omit the - // client Transport summary string; server still returns X-GS-ServerPort + source. - const setup = await client.request("SETUP", `${endpoint}/streamid=video/0/0`, { + const officialCloudPath = nativeRtcOnBundlePort === "1"; + const negotiatedAudioTrack = officialCloudPath + ? { + payloadType: 111, + codec: "opus" as const, + clockRateHz: 48_000, + channels: 2, + mid: "0", + } + : audioTrack; + // Official Bifrost binds the ICE/bundle socket on 0.0.0.0 and never connects + // it to the RTSPS host. Connecting to :322 would create the wrong NAT mapping. + // Official: Mjolnir first (empty Transport line), then ICE bundle after SETUP. + const videoSetupUri = officialCloudPath + ? officialVideoSetupControl(videoControlUri) + : videoControlUri; + if (officialCloudPath) { + // Official two-socket model: the native streamer reserves BOTH the ICE/DTLS + // bundle and the dedicated NATT-only Mjolnir video socket in one nvst-bind. + // Reserve the bundle now so its mjolnirPort is known before video SETUP; the + // probe must not bind its own Mjolnir socket when the native streamer owns it. + udp = await reserveBundle(); + if (udp.mjolnirPort === undefined) { + // Older native streamer without a Mjolnir reservation: keep the probe-owned + // fallback socket so NATT keepalive still runs somewhere. + mjolnirUdp = await dependencies.reserveUdpPort(); + } else { + nativeMjolnirPort = udp.mjolnirPort; + } + } else { + udp = await reserveBundle(); + } + const setupHeaders: Record = { + ...commonHeaders, Session: session, - Transport: `unicast;X-GS-ClientPort=${clientPort}-${clientPort + 1}`, - }); + // Official Bifrost advertises its ping-protocol version on SETUP. The seat only + // returns a hex X-Nv-Ping-Payload (modern NATT/ICE identity) when this is present; + // without it the seat falls back to the literal "PING" keepalive and never arms + // the media relay to answer STUN. Echo the DESCRIBE-advertised version. + "x-nv-ping": describedPingVersion ?? "6", + }; + if (officialCloudPath) { + setupHeaders.Transport = ""; + } else if (udp) { + setupHeaders.Transport = `unicast;X-GS-ClientPort=${udp.port}-${udp.port + 1}`; + } + const setup = await client.request("SETUP", videoSetupUri, setupHeaders); if (setup.statusCode !== 200) { throw new Error(`SETUP video failed: ${setup.statusCode} ${setup.statusText}`); } steps.push("setup-video"); + session = header(setup.headers, "session")?.split(";")[0]?.trim() ?? session; + const setupSrtpProfile = extractAdvertisedSrtpProfileFromHeaders(setup.headers); + if ( + describedSrtpProfile + && setupSrtpProfile + && describedSrtpProfile !== setupSrtpProfile + ) { + throw new NvstRtspNegotiationError( + "conflicting-srtp-profile", + `DESCRIBE advertised ${describedSrtpProfile} but SETUP advertised ${setupSrtpProfile}`, + ); + } + const srtpProfile = setupSrtpProfile ?? describedSrtpProfile ?? undefined; const videoPeer = extractVideoPeer(header(setup.headers, "transport")); + if (!videoPeer) { + throw new NvstRtspNegotiationError( + "missing-video-peer", + "SETUP did not return video peer (X-GS-ServerPort/source)", + ); + } const pingPayload = header(setup.headers, "x-nv-ping-payload"); const pingVersionRaw = header(setup.headers, "x-nv-ping"); const pingVersion = pingVersionRaw ? Number(pingVersionRaw) : undefined; + if (pingVersion === 6 && (!iceCredentials || !pingPayload)) { + throw new NvstRtspNegotiationError( + "missing-ice-credentials", + "SETUP selected ping version 6 but its username payload or DESCRIBE password was missing", + ); + } + if (!udp) { + throw new NvstRtspNegotiationError( + "negotiation-failed", + "NVST ICE/bundle UDP socket was not reserved", + ); + } + const clientPort = udp.port; + const iceRemoteUfrag = resolveNvstIceRemoteUfrag( + pingPayload, + iceCredentials?.usernameFragment, + Number.isFinite(pingVersion) ? pingVersion : undefined, + ); + const reservedIce = udp.iceUsernameFragment && udp.icePassword + ? { usernameFragment: udp.iceUsernameFragment, password: udp.icePassword } + : null; + const localIceCredentials = iceCredentials + ? reservedIce ?? generateNvstIceCredentials() + : reservedIce; + const localDtlsFingerprint = udp.dtlsFingerprint; + const startAuthenticatedHolePunch = ( + reservation: NvstUdpPortReservation, + peer: { ip: string; port: number }, + options?: { nattUsername?: string; iceBurst?: boolean }, + ): NodeJS.Timeout | null => { + if (!localIceCredentials || !iceCredentials || !reservation.send) { + return null; + } + const iceBurst = options?.iceBurst !== false; + const nattUsername = options?.nattUsername; + let nonStunInbound = 0; + reservation.onMessage?.((payload, from) => { + if (payload.equals(Buffer.from("PING"))) { + void reservation.send?.(Buffer.from("PONG"), from.address, from.port).catch(() => undefined); + return; + } + if (payload.length >= 20 && payload.readUInt16BE(0) === 0x0001) { + const transactionId = payload.subarray(8, 20); + const pong = buildNvstStunBindingSuccess( + localIceCredentials.password, + transactionId, + from.address, + from.port, + ); + if (pong) { + void reservation.send?.(pong, from.address, from.port).catch(() => undefined); + } + return; + } + // Non-PING, non-STUN inbound is candidate video/SRTP. Log it (throttled) so we can + // confirm which socket the seat actually delivers video to (bundle vs Mjolnir). + nonStunInbound += 1; + if (nonStunInbound <= 5 || nonStunInbound % 200 === 0) { + log( + input.onLog, + `hole-punch inbound (non-STUN) port=${reservation.port} count=${nonStunInbound} bytes=${payload.length} firstByte=0x${payload.readUInt8(0).toString(16).padStart(2, "0")} from=${from.address}:${from.port}`, + ); + } + }); + const sendPing = (): void => { + // Official first burst is three ICE Binding Requests, then NATT + // ping-string PING ("Old server only supports PING") as keepalive. + if (iceBurst && iceRemoteUfrag) { + for (let burst = 0; burst < 3; burst += 1) { + const ice = buildNvstStunBindingRequest( + localIceCredentials.usernameFragment, + iceRemoteUfrag, + iceCredentials.password, + ); + void reservation.send?.(ice, peer.ip, peer.port).catch(() => undefined); + } + } + if (nattUsername) { + const natt = buildNvstStunBindingRequest( + localIceCredentials.usernameFragment, + nattUsername, + iceCredentials.password, + ); + void reservation.send?.(natt, peer.ip, peer.port).catch(() => undefined); + } + }; + sendPing(); + const timer = setInterval(sendPing, 20); + timer.unref(); + holePunchTimers.push(timer); + return timer; + }; + if (iceCredentials && localIceCredentials && !officialCloudPath) { + startAuthenticatedHolePunch( + udp, + videoPeer, + { nattUsername: "PING" }, + ); + } + const setupHeaderNames = Object.keys(setup.headers).sort(); + const setupCredentialHeaders = setupHeaderNames + .filter((name) => /(ice|stun|credential|password|user)/i.test(name)) + .map((name) => `${name}[${header(setup.headers, name)?.length ?? 0}]`); log( input.onLog, - `SETUP video/0/0 ok (clientPort=${clientPort}, peer=${videoPeer ? `${videoPeer.ip}:${videoPeer.port}` : "unknown"})`, + `SETUP ${videoSetupUri} ok (official=${officialCloudPath}, bundlePort=${clientPort}${nativeMjolnirPort !== undefined ? `, mjolnirPort=${nativeMjolnirPort} (native)` : mjolnirUdp ? `, mjolnirPort=${mjolnirUdp.port}` : ""}, transport=${officialCloudPath ? "empty" : setupHeaders.Transport}, peer=${videoPeer.ip}:${videoPeer.port}, srtpProfile=${srtpProfile ?? "legacy-default"}, pingVersion=${Number.isFinite(pingVersion) ? pingVersion : "legacy"}, pingPayload=${pingPayload === undefined ? "absent" : JSON.stringify(pingPayload)}, iceRemote=${iceRemoteUfrag ?? "absent"}, pingPayloadBytes=${pingPayload ? Buffer.byteLength(pingPayload, "utf8") : 0}, headers=${setupHeaderNames.join(",")}, credentialHeaders=${setupCredentialHeaders.join(",") || "none"})`, ); + const handoffKeyHex = encryptionKeyHex ?? "00".repeat(32); + const handoffKeyId = encryptionKeyId ?? 0; + const saltHex = deriveSrtpSaltHex(handoffKeyId); const srtp: NvstSrtpMaterial = { - aesKeyHex: encryptionKeyHex, - keyId: encryptionKeyId, - masterKeySaltHex: packSrtpMasterKeySalt(encryptionKeyHex, encryptionKeyId), + aesKeyHex: handoffKeyHex, + keyId: handoffKeyId, + masterKeySaltHex: packSrtpMasterKeySalt(handoffKeyHex, handoffKeyId), + saltHex, + profile: srtpProfile, clientGenerated, }; + const videoSession: NvstVideoSession = { + clientUdpPort: clientPort, + // Native-owned Mjolnir video socket: the native streamer reads raw-SRTP video + // here while the bundle DTLS socket carries control/audio. + mjolnirUdpPort: nativeMjolnirPort, + videoPeerIp: videoPeer.ip, + videoPeerPort: videoPeer.port, + ...(input.bundlePeer + ? { bundlePeerIp: input.bundlePeer.ip, bundlePeerPort: input.bundlePeer.port } + : {}), + srtpAesKeyHex: srtp.aesKeyHex, + srtpKeyId: srtp.keyId, + srtpSaltHex: srtp.saltHex, + srtpProfile: srtp.profile, + pingPayload, + pingVersion: Number.isFinite(pingVersion) ? pingVersion : undefined, + localIceUsernameFragment: localIceCredentials?.usernameFragment, + localIcePassword: localIceCredentials?.password, + remoteIceUsernameFragment: iceRemoteUfrag + ?? (pingVersion === 6 ? pingPayload : undefined), + remoteIcePassword: iceCredentials?.password, + localDtlsFingerprint, + remoteDtlsFingerprint: dtlsFingerprint ?? undefined, + codec: input.codec, + ...(negotiatedAudioTrack ? { audioTrack: negotiatedAudioTrack } : {}), + timeoutMs: 60_000, + }; + if (input.onVideoReady) { + // Official binds Mjolnir before SETUP but does not send STUN until after ANNOUNCE. + log( + input.onLog, + officialCloudPath + ? `Video SETUP ready; deferring STUN until after ANNOUNCE (clientUdp ${clientPort})` + : `Video SETUP ready; keeping STUN hole-punch through remaining SETUP/ANNOUNCE (clientUdp ${clientPort})`, + ); + await input.onVideoReady(videoSession); + steps.push("native-receive-armed"); + } - const announceBody = buildAnnounceSdp({ - resolution: input.resolution, - fps: input.fps, - encryptionKeyHex, - encryptionKeyId, - }); + const setupTransport = (port: number): string => + `unicast;X-GS-ClientPort=${port}-${port + 1}`; + let audioClientPort = clientPort; + let controlClientPort: number | undefined; + if (!officialCloudPath) { + audioUdp = await dependencies.reserveUdpPort(); + audioClientPort = audioUdp.port; + const audioSetup = await client.request("SETUP", audioControl, { + ...commonHeaders, + Session: session, + Transport: setupTransport(audioClientPort), + }); + if (audioSetup.statusCode !== 200) { + throw new Error(`SETUP audio failed: ${audioSetup.statusCode} ${audioSetup.statusText}`); + } + steps.push("setup-audio"); + session = header(audioSetup.headers, "session")?.split(";")[0]?.trim() ?? session; + log(input.onLog, `SETUP ${audioControl} ok (clientPort=${audioClientPort})`); + const audioPeer = extractVideoPeer(header(audioSetup.headers, "transport")); + if (audioPeer && audioUdp && audioUdp !== udp) { + startAuthenticatedHolePunch(audioUdp, audioPeer, { + nattUsername: header(audioSetup.headers, "x-nv-ping-payload") ?? pingPayload, + }); + } + + for (const control of describedControls) { + if (control === videoControl || control === audioControl) { + continue; + } + const reservation = await dependencies.reserveUdpPort(); + if (reservation !== udp) { + auxiliaryUdp.push(reservation); + } + if (control === controlStream) { + controlClientPort = reservation.port; + } + const auxiliarySetup = await client.request("SETUP", control, { + ...commonHeaders, + Session: session, + Transport: setupTransport(reservation.port), + }); + if (auxiliarySetup.statusCode !== 200) { + throw new Error(`SETUP ${control} failed: ${auxiliarySetup.statusCode} ${auxiliarySetup.statusText}`); + } + steps.push(`setup-${control}`); + session = header(auxiliarySetup.headers, "session")?.split(";")[0]?.trim() ?? session; + const auxiliaryPeer = extractVideoPeer(header(auxiliarySetup.headers, "transport")); + if (auxiliaryPeer && reservation !== udp) { + startAuthenticatedHolePunch(reservation, auxiliaryPeer, { + nattUsername: header(auxiliarySetup.headers, "x-nv-ping-payload") ?? pingPayload, + }); + } + log( + input.onLog, + `SETUP ${control} ok (clientPort=${reservation.port}, peer=${auxiliaryPeer ? `${auxiliaryPeer.ip}:${auxiliaryPeer.port}` : "absent"}, pingVersion=${header(auxiliarySetup.headers, "x-nv-ping") ?? "legacy"})`, + ); + } + } else { + log( + input.onLog, + "Official cloud path: skipping audio/mic/control SETUP (WebRtcTransport owns those streams)", + ); + } + + const localIpv4 = udp.localAddress ?? pickLocalIpv4(); + const clientTransport = officialCloudPath + ? undefined + : (localIpv4 ? `${localIpv4}:${clientPort}` : undefined); const announce = await client.request( "ANNOUNCE", - endpoint, + officialCloudPath ? rtspTarget : "/", { + ...commonHeaders, Session: session, "Content-Type": "application/sdp", }, - announceBody, + buildAnnounceSdp(officialCloudPath + ? { + resolution: input.resolution, + fps: input.fps, + codec: input.codec, + maxBitrateKbps: input.maxBitrateKbps, + // Official always advertises the runtime encryptionKey in ANNOUNCE (it keys the + // video SRTP on the separate non-DTLS socket). Now that we always generate it, + // send it unconditionally rather than dropping it when a DTLS fingerprint exists. + encryptionKeyHex, + encryptionKeyId, + iceCredentials: localIceCredentials ?? undefined, + includeNvscLegacyIce: false, + includeNvscLegacyDtls: false, + videoPort: videoPeer.port, + clientPorts: { + video: 0, + audio: 0, + mic: 0, + control: 0, + bundle: 0, + session: 0, + localAddress: localIpv4, + }, + clientBundlePort: clientPort, + nativeRtcOnBundlePort: "1", + rtcVideoOnNativeBundle: false, + rtcAudioOnNativeBundle: true, + rtcMicOnNativeBundle: true, + rtcDataChannelOnNativeBundle: true, + enableUnifiedSocket: false, + rtcpOnSctp: describedRtcpOnSctp === "1" + ? true + : describedRtcpOnSctp === "0" + ? false + : undefined, + dtlsFingerprint: localDtlsFingerprint, + } + : { + resolution: input.resolution, + fps: input.fps, + codec: input.codec, + maxBitrateKbps: input.maxBitrateKbps, + encryptionKeyHex: describedKey || !dtlsFingerprint ? encryptionKeyHex : undefined, + encryptionKeyId: describedKey || !dtlsFingerprint ? encryptionKeyId : undefined, + iceCredentials: localIceCredentials ?? undefined, + videoPort: videoPeer.port, + clientPorts: { + video: clientPort, + audio: audioClientPort, + control: controlClientPort, + localAddress: localIpv4, + }, + clientTransport, + dtlsFingerprint: localDtlsFingerprint, + }), ); if (announce.statusCode !== 200) { throw new Error(`ANNOUNCE failed: ${announce.statusCode} ${announce.statusText}`); } steps.push("announce"); - log(input.onLog, "ANNOUNCE ok (allowlist + encryptionKey; ICE/DTLS omitted)"); - - const play = await client.request("PLAY", endpoint, { - Session: session, - Range: "npt=0.000-", - }); - if (play.statusCode !== 200) { - throw new Error(`PLAY failed: ${play.statusCode} ${play.statusText}`); + log( + input.onLog, + `ANNOUNCE ok (allowlist${encryptionKeyHex && (describedKey || !dtlsFingerprint) ? " + encryptionKey" : ""}${localIceCredentials ? ` + ICE V2 credentials (local ufragBytes=${localIceCredentials.usernameFragment.length}, pwdBytes=${localIceCredentials.password.length})` : ""}${localDtlsFingerprint ? ` + dtlsFingerprintBytes=${localDtlsFingerprint.length}` : ""}${localIpv4 ? ` + localAddress=${localIpv4}` : ""}${clientTransport ? ` + clientTransport=${clientTransport}` : ""}${localIpv4 && localIceCredentials ? ` + host candidate ${localIpv4}:${clientPort}` : ""})`, + ); + if (officialCloudPath && iceCredentials && localIceCredentials) { + log( + input.onLog, + `Starting official bundle STUN after ANNOUNCE (clientUdp ${clientPort}, iceRemote=${iceRemoteUfrag ?? "absent"})`, + ); + startAuthenticatedHolePunch( + udp, + videoPeer, + { nattUsername: "PING" }, + ); } - steps.push("play"); - - // Close the probe UDP socket so the native streamer can rebind the same port. - udp.socket.close(); - udp = null; - - if (!videoPeer) { - throw new Error("SETUP did not return video peer (X-GS-ServerPort/source)"); + if (input.onAnnounceReady) { + log( + input.onLog, + `Starting native WebRtcTransport after ANNOUNCE (clientUdp ${clientPort})`, + ); + await input.onAnnounceReady(videoSession); + steps.push("native-announce-armed"); + } + if (officialCloudPath && iceCredentials && localIceCredentials && mjolnirUdp) { + // Probe-owned fallback only. When the native streamer owns the Mjolnir socket + // (nativeMjolnirPort set), its raw-SRTP receiver already runs this NATT + // keepalive — running a second one here would fight over the same socket. + // Official RtpSourceQueue on 49005 starts ~1ms before PLAY, after DTLS. + log( + input.onLog, + `Starting official Mjolnir NATT before PLAY (mjolnirPort=${mjolnirUdp.port})`, + ); + startAuthenticatedHolePunch(mjolnirUdp, videoPeer, { + iceBurst: false, + nattUsername: pingPayload && pingPayload !== "PING" ? pingPayload : "PING", + }); + } else if (officialCloudPath && nativeMjolnirPort !== undefined) { + log( + input.onLog, + `Mjolnir NATT owned by native streamer (mjolnirPort=${nativeMjolnirPort}); native raw-SRTP receiver keeps it alive`, + ); + } + if (disablePlay === "0") { + if (!client.isHealthy()) { + log(input.onLog, "RTSPS control closed before PLAY; reconnecting the retained session"); + await client.connect(input.sessionId); + steps.push("play-control-reconnected"); + } + try { + const play = await client.request("PLAY", officialCloudPath ? rtspTarget : "/", { + ...commonHeaders, + Session: session, + }); + if (play.statusCode === 200) { + steps.push("play"); + log(input.onLog, "PLAY / ok"); + } else if (play.statusCode === 455) { + steps.push("play-455"); + log( + input.onLog, + `PLAY / returned 455 ${play.statusText} — treating as Bifrost ANNOUNCE-only`, + ); + } else { + steps.push("play-failed"); + throw new Error(`PLAY failed: ${play.statusCode} ${play.statusText}`); + } + } catch (error) { + if (!steps.includes("play-failed")) { + steps.push("play-failed"); + } + throw new Error( + `PLAY failed after ANNOUNCE: ${error instanceof Error ? error.message : String(error)}`, + { cause: error }, + ); + } + } else { + steps.push("play-skipped"); + log(input.onLog, "PLAY skipped because DESCRIBE disabled it after ANNOUNCE"); } - - const videoSession: NvstVideoSession = { - clientUdpPort: clientPort, - videoPeerIp: videoPeer.ip, - videoPeerPort: videoPeer.port, - srtpAesKeyHex: srtp.aesKeyHex, - srtpKeyId: srtp.keyId, - pingPayload, - codec: input.codec, - }; - log( input.onLog, - `PLAY ok — NVST video handoff ready (peer ${videoPeer.ip}:${videoPeer.port}, clientUdp ${clientPort}); WebRTC remains for SCTP input`, + `ANNOUNCE complete — NVST video handoff ready with video UDP still bound (peer ${videoPeer.ip}:${videoPeer.port}, clientUdp ${clientPort}, clientTransport=${clientTransport ?? "absent"})`, ); + let released = false; + const releaseVideoUdp = async (): Promise => { + // Keep STUN hole-punch on the native-owned bundle socket until the RTSP + // session is fully released. Official treats punch-receive failure as + // non-fatal; stopping sends as soon as native starts drops inbound DTLS. + await udp?.release().catch(() => undefined); + udp = null; + }; return { - ok: true, endpoint, session, hmacSeedPresent: Boolean(hmacSeed), @@ -311,7 +1130,78 @@ export async function runNvstRtspHandshakeProbe(input: NvstRtspProbeInput): Prom pingVersion: Number.isFinite(pingVersion) ? pingVersion : undefined, videoSession, steps, + videoUdpFd: udp.fd, + isHealthy: () => client.isHealthy(), + handoffVideoUdp: async () => { + if (released || !udp) { + return; + } + log(input.onLog, `Releasing Electron video UDP copy after native inherited the socket (clientUdp ${clientPort})`); + await releaseVideoUdp(); + }, + release: async (reason = "NVST session released") => { + if (released) { + return; + } + released = true; + for (const timer of holePunchTimers.splice(0)) { + clearInterval(timer); + } + await udp?.release().catch(() => undefined); + udp = null; + await mjolnirUdp?.release().catch(() => undefined); + mjolnirUdp = null; + await audioUdp?.release().catch(() => undefined); + audioUdp = null; + await Promise.all( + auxiliaryUdp.splice(0).map((reservation) => reservation.release().catch(() => undefined)), + ); + await teardownAndClose(client, endpoint, session, reason, input.onLog); + }, }; + } catch (error) { + for (const timer of holePunchTimers.splice(0)) { + clearInterval(timer); + } + await udp?.release().catch(() => undefined); + await mjolnirUdp?.release().catch(() => undefined); + await audioUdp?.release().catch(() => undefined); + await Promise.all(auxiliaryUdp.map((reservation) => reservation.release().catch(() => undefined))); + await teardownAndClose(client, endpoint, session, "failed negotiation", input.onLog); + if (error instanceof NvstRtspNegotiationError) { + throw new NvstRtspNegotiationError(error.code, error.message, { + cause: error, + }, [...steps]); + } + const message = error instanceof Error ? error.message : String(error); + throw new NvstRtspNegotiationError("negotiation-failed", message, { + cause: error, + }, [...steps]); + } +} + +export async function runNvstRtspHandshakeProbe( + input: NvstRtspProbeInput, + dependencies?: NvstRtspNegotiationDependencies, +): Promise { + const endpoint = selectPrimaryRtspsEndpoint(input.rtspsEndpoints) ?? ""; + try { + const negotiated = await negotiateNvstRtspSession(input, dependencies); + const result: NvstRtspProbeResult = { + ok: true, + endpoint: negotiated.endpoint, + session: negotiated.session, + hmacSeedPresent: negotiated.hmacSeedPresent, + videoPeer: negotiated.videoPeer, + clientUdpPort: negotiated.clientUdpPort, + srtp: negotiated.srtp, + pingPayload: negotiated.pingPayload, + pingVersion: negotiated.pingVersion, + videoSession: negotiated.videoSession, + steps: negotiated.steps, + }; + await negotiated.release("handshake probe complete"); + return result; } catch (error) { const message = error instanceof Error ? error.message : String(error); log(input.onLog, `Probe failed: ${message}`); @@ -319,11 +1209,8 @@ export async function runNvstRtspHandshakeProbe(input: NvstRtspProbeInput): Prom ok: false, endpoint, hmacSeedPresent: false, - steps, + steps: error instanceof NvstRtspNegotiationError ? error.steps : [], error: message, }; - } finally { - client.close(); - udp?.socket.close(); } } diff --git a/opennow-stable/src/main/platforms/gfn/nvstRtsp/rtspClient.test.ts b/opennow-stable/src/main/platforms/gfn/nvstRtsp/rtspClient.test.ts index a021bb644..130bb5bdc 100644 --- a/opennow-stable/src/main/platforms/gfn/nvstRtsp/rtspClient.test.ts +++ b/opennow-stable/src/main/platforms/gfn/nvstRtsp/rtspClient.test.ts @@ -2,8 +2,62 @@ import test from "node:test"; import assert from "node:assert/strict"; +import { EventEmitter } from "node:events"; +import type { Duplex } from "node:stream"; -import { extractVideoPeer, parseRtspResponse } from "./rtspClient"; +import { + buildRtspRequest, + extractVideoPeer, + parseRtspResponse, + RTSPS_WS_KEEPALIVE_INTERVAL_MS, + RtspOverWssClient, +} from "./rtspClient"; + +test("RTSPS WebSocket keepalive uses the official two-second cadence", () => { + assert.equal(RTSPS_WS_KEEPALIVE_INTERVAL_MS, 2_000); +}); + +class FakeSocket extends EventEmitter { + destroyed = false; + readonly writes: Buffer[] = []; + + write(chunk: Uint8Array | string): boolean { + this.writes.push(Buffer.from(chunk)); + return true; + } + + destroy(): this { + if (!this.destroyed) { + this.destroyed = true; + this.emit("close"); + } + return this; + } +} + +function serverFrame(opcode: number, payload: Buffer): Buffer { + assert.ok(payload.length < 126); + return Buffer.concat([Buffer.from([0x80 | opcode, payload.length]), payload]); +} + +function rtspResponse(cseq: number): Buffer { + return serverFrame( + 0x1, + Buffer.from(`RTSP/1.0 200 OK\r\nCSeq: ${cseq}\r\nContent-Length: 0\r\n\r\n`), + ); +} + +function createClient(timeoutMs = 50): { client: RtspOverWssClient; socket: FakeSocket } { + const socket = new FakeSocket(); + const client = new RtspOverWssClient( + "host.example", + 322, + timeoutMs, + undefined, + async () => socket as unknown as Duplex, + ); + return { client, socket }; +} test("extractVideoPeer prefers SETUP X-GS-ServerPort", () => { assert.deepEqual( @@ -12,6 +66,36 @@ test("extractVideoPeer prefers SETUP X-GS-ServerPort", () => { ); }); +test("buildRtspRequest keeps empty Transport and only sends Content-Length with a body", () => { + const setup = buildRtspRequest("SETUP", "streamid=video/0/0", { + "X-GS-Version": "14.2", + Host: "host.example:322", + Session: "XNV2060633119", + Transport: "", + }, "", 3); + assert.equal( + setup, + [ + "SETUP streamid=video/0/0 RTSP/1.0", + "CSeq: 3", + "Request-Id: 3", + "X-GS-Version: 14.2", + "Host: host.example:322", + "Session: XNV2060633119", + "Transport: ", + "", + "", + ].join("\r\n"), + ); + assert.match(setup, /^Transport: $/m); + assert.doesNotMatch(setup, /Content-Length/); + + const announce = buildRtspRequest("ANNOUNCE", "rtsps://host.example:322", { + "Content-Type": "application/sdp", + }, "v=0\r\n", 4); + assert.match(announce, /\r\nContent-Length: 5\r\n\r\nv=0\r\n$/); +}); + test("parseRtspResponse preserves status, normalized headers, and SDP body", () => { const response = parseRtspResponse( "RTSP/1.0 200 OK\r\nCSeq: 2\r\nSession: session-id;timeout=60\r\nContent-Length: 5\r\n\r\nv=0\r\n", @@ -27,3 +111,68 @@ test("parseRtspResponse preserves status, normalized headers, and SDP body", () body: "v=0\n", }); }); + +test("RTSP client validates response CSeq and destroys mismatched connections", async () => { + const { client, socket } = createClient(); + await client.connect("session"); + const response = client.request("OPTIONS", "rtsps://host.example:322"); + + socket.emit("data", rtspResponse(9)); + + await assert.rejects(response, /CSeq mismatch: expected 1, received 9/); + assert.equal(client.isHealthy(), false); + assert.equal(socket.destroyed, true); +}); + +test("late RTSP responses cannot satisfy a request after timeout", async () => { + const { client, socket } = createClient(5); + await client.connect("session"); + + await assert.rejects( + client.request("OPTIONS", "rtsps://host.example:322"), + /timed out after 5ms/, + ); + assert.equal(client.isHealthy(), false); + assert.equal(socket.destroyed, true); + + socket.emit("data", rtspResponse(1)); + await assert.rejects( + client.request("DESCRIBE", "rtsps://host.example:322"), + /WebSocket is not open/, + ); +}); + +test("RTSP client becomes unhealthy when its WebSocket closes", async () => { + const { client, socket } = createClient(); + await client.connect("session"); + assert.equal(client.isHealthy(), true); + + socket.emit("close"); + + assert.equal(client.isHealthy(), false); + await assert.rejects( + client.request("OPTIONS", "rtsps://host.example:322"), + /WebSocket is not open/, + ); +}); + +test("RTSP WebSocket replies to ping with a masked pong carrying the same payload", async () => { + const { client, socket } = createClient(); + await client.connect("session"); + const pingPayload = Buffer.from("keepalive"); + + socket.emit("data", serverFrame(0x9, pingPayload)); + + assert.equal(socket.writes.length, 1); + const pong = socket.writes[0]!; + assert.equal(pong[0], 0x8a); + assert.equal(pong[1]! & 0x80, 0x80); + const length = pong[1]! & 0x7f; + const mask = pong.subarray(2, 6); + const decoded = Buffer.alloc(length); + for (let index = 0; index < length; index += 1) { + decoded[index] = pong[6 + index]! ^ mask[index % 4]!; + } + assert.deepEqual(decoded, pingPayload); + assert.equal(client.isHealthy(), true); +}); diff --git a/opennow-stable/src/main/platforms/gfn/nvstRtsp/rtspClient.ts b/opennow-stable/src/main/platforms/gfn/nvstRtsp/rtspClient.ts index 2136dfbc2..67035f42f 100644 --- a/opennow-stable/src/main/platforms/gfn/nvstRtsp/rtspClient.ts +++ b/opennow-stable/src/main/platforms/gfn/nvstRtsp/rtspClient.ts @@ -1,8 +1,14 @@ import type { Duplex } from "node:stream"; -import { connectNvstWss, encodeWsTextFrame, WsFrameReader } from "./websocketTransport"; +import { + connectNvstWss, + encodeWsPingFrame, + encodeWsPongFrame, + encodeWsTextFrame, + WsFrameReader, +} from "./websocketTransport"; -const GS_VERSION = "14.2"; +export const RTSPS_WS_KEEPALIVE_INTERVAL_MS = 2_000; export interface ParsedRtspResponse { statusCode: number; @@ -42,6 +48,33 @@ export function header(headers: Record, name: string): string | return headers[name.toLowerCase()]; } +/** Content-Length only when there is a body. Empty header values are kept (official SETUP sends `Transport: `). */ +export function buildRtspRequest( + method: string, + uri: string, + extraHeaders: Record = {}, + body = "", + cseq = 1, +): string { + const headers: Record = { + CSeq: String(cseq), + "Request-Id": String(cseq), + ...extraHeaders, + }; + if (body.length > 0) { + headers["Content-Length"] = String(Buffer.byteLength(body, "utf8")); + } + let message = `${method} ${uri} RTSP/1.0\r\n`; + for (const [key, value] of Object.entries(headers)) { + message += `${key}: ${value}\r\n`; + } + message += "\r\n"; + if (body.length > 0) { + message += body; + } + return message; +} + export function extractVideoPeer( transport: string | undefined, ): { ip: string; port: number } | undefined { @@ -61,7 +94,10 @@ export class RtspOverWssClient { private frameReader = new WsFrameReader(); private buffer = Buffer.alloc(0); private cseq = 0; + private healthy = false; + private keepaliveTimer: NodeJS.Timeout | null = null; private pending: { + cseq: number; resolve: (response: ParsedRtspResponse) => void; reject: (error: Error) => void; } | null = null; @@ -71,10 +107,11 @@ export class RtspOverWssClient { private readonly port: number, private readonly timeoutMs: number, private readonly onLog?: (message: string) => void, + private readonly connectSocket: typeof connectNvstWss = connectNvstWss, ) {} async connect(sessionId?: string): Promise { - const socket = await connectNvstWss( + const socket = await this.connectSocket( this.host, this.port, this.timeoutMs, @@ -82,32 +119,30 @@ export class RtspOverWssClient { this.onLog, ); this.socket = socket; + this.frameReader = new WsFrameReader(); + this.buffer = Buffer.alloc(0); + this.healthy = true; + this.keepaliveTimer = setInterval(() => { + if (this.isHealthy()) { + this.socket?.write(encodeWsPingFrame()); + } + }, RTSPS_WS_KEEPALIVE_INTERVAL_MS); + this.keepaliveTimer.unref(); socket.on("data", (chunk: Buffer) => this.onSocketData(chunk)); socket.on("error", (error) => { - if (this.pending) { - this.pending.reject(error instanceof Error ? error : new Error(String(error))); - this.pending = null; - } + this.failConnection(error instanceof Error ? error : new Error(String(error)), false); }); socket.on("close", () => { - if (this.pending) { - this.pending.reject(new Error("RTSPS WebSocket closed")); - this.pending = null; - } + this.failConnection(new Error("RTSPS WebSocket closed"), false); }); } + isHealthy(): boolean { + return this.healthy && this.socket !== null && !this.socket.destroyed; + } + close(): void { - try { - this.socket?.destroy(); - } catch { - // ignore - } - this.socket = null; - if (this.pending) { - this.pending.reject(new Error("RTSPS probe closed")); - this.pending = null; - } + this.failConnection(new Error("RTSPS probe closed"), true); } async request( @@ -116,7 +151,7 @@ export class RtspOverWssClient { extraHeaders: Record = {}, body = "", ): Promise { - if (!this.socket || this.socket.destroyed) { + if (!this.isHealthy()) { throw new Error("RTSPS WebSocket is not open"); } if (this.pending) { @@ -124,66 +159,58 @@ export class RtspOverWssClient { } this.cseq += 1; - const headers: Record = { - CSeq: String(this.cseq), - "Request-Id": String(this.cseq), - "X-GS-Version": GS_VERSION, - ...extraHeaders, - }; - if (body.length > 0) { - headers["Content-Length"] = String(Buffer.byteLength(body, "utf8")); - } - - let message = `${method} ${uri} RTSP/1.0\r\n`; - for (const [key, value] of Object.entries(headers)) { - message += `${key}: ${value}\r\n`; - } - message += "\r\n"; - if (body.length > 0) { - message += body; - } + const message = buildRtspRequest(method, uri, extraHeaders, body, this.cseq); return await new Promise((resolve, reject) => { - const timer = setTimeout(() => { - if (this.pending) { - this.pending = null; - reject(new Error(`RTSP ${method} timed out after ${this.timeoutMs}ms`)); - } - }, this.timeoutMs); - - this.pending = { - resolve: (response) => { + const pending = { + cseq: this.cseq, + resolve: (response: ParsedRtspResponse) => { clearTimeout(timer); resolve(response); }, - reject: (error) => { + reject: (error: Error) => { clearTimeout(timer); reject(error); }, }; + const timer = setTimeout(() => { + if (this.pending !== pending) { + return; + } + this.failConnection( + new Error(`RTSP ${method} timed out after ${this.timeoutMs}ms`), + true, + ); + }, this.timeoutMs); + this.pending = pending; try { this.socket?.write(encodeWsTextFrame(Buffer.from(message, "utf8"))); } catch (error) { clearTimeout(timer); this.pending = null; - reject(error instanceof Error ? error : new Error(String(error))); + const writeError = error instanceof Error ? error : new Error(String(error)); + this.failConnection(writeError, true); + reject(writeError); } }); } private onSocketData(chunk: Buffer): void { + if (!this.isHealthy()) { + return; + } try { - for (const payload of this.frameReader.push(chunk)) { + const payloads = this.frameReader.push(chunk); + for (const pingPayload of this.frameReader.drainPingPayloads()) { + this.socket?.write(encodeWsPongFrame(pingPayload)); + } + for (const payload of payloads) { this.buffer = Buffer.concat([this.buffer, payload]); this.tryCompleteResponse(); } } catch (error) { - if (this.pending) { - const pending = this.pending; - this.pending = null; - pending.reject(error instanceof Error ? error : new Error(String(error))); - } + this.failConnection(error instanceof Error ? error : new Error(String(error)), true); } } @@ -225,13 +252,38 @@ export class RtspOverWssClient { try { const parsed = parseRtspResponse(raw); + const responseCseq = header(parsed.headers, "cseq"); + if (responseCseq !== String(this.pending.cseq)) { + throw new Error( + `RTSP response CSeq mismatch: expected ${this.pending.cseq}, received ${responseCseq ?? "missing"}`, + ); + } const pending = this.pending; this.pending = null; pending?.resolve(parsed); } catch (error) { - const pending = this.pending; - this.pending = null; - pending?.reject(error instanceof Error ? error : new Error(String(error))); + this.failConnection(error instanceof Error ? error : new Error(String(error)), true); + } + } + + private failConnection(error: Error, destroySocket: boolean): void { + if (this.keepaliveTimer) { + clearInterval(this.keepaliveTimer); + this.keepaliveTimer = null; + } + this.healthy = false; + this.buffer = Buffer.alloc(0); + const socket = this.socket; + this.socket = null; + const pending = this.pending; + this.pending = null; + pending?.reject(error); + if (destroySocket) { + try { + socket?.destroy(); + } catch { + // ignore + } } } } diff --git a/opennow-stable/src/main/platforms/gfn/nvstRtsp/sdp.test.ts b/opennow-stable/src/main/platforms/gfn/nvstRtsp/sdp.test.ts index d6900a87c..a8096c96f 100644 --- a/opennow-stable/src/main/platforms/gfn/nvstRtsp/sdp.test.ts +++ b/opennow-stable/src/main/platforms/gfn/nvstRtsp/sdp.test.ts @@ -6,10 +6,35 @@ import assert from "node:assert/strict"; import { buildAnnounceSdp, extractHmacSeed, + extractNvstIceCredentials, + extractNvstSdpAttribute, + extractMediaControl, + extractNvstOpusAudioTrack, extractRuntimeEncryptionKey, + generateNvstIceCredentials, packSrtpMasterKeySalt, } from "./sdp"; +test("extractNvstIceCredentials reads native and standard SDP forms", () => { + assert.deepEqual( + extractNvstIceCredentials( + "a=x-nv-general.iceUsernameFragment:native-user\r\na=x-nv-general.iceUsernamePwd:native-password\r\n", + ), + { usernameFragment: "native-user", password: "native-password" }, + ); + assert.deepEqual( + extractNvstIceCredentials("a=ice-ufrag:standard-user\na=ice-pwd:standard-password\n"), + { usernameFragment: "standard-user", password: "standard-password" }, + ); + assert.deepEqual( + extractNvstIceCredentials( + "a=x-nv-general.iceUserNameFragmentV2:native-v2-user\r\na=x-nv-general.icePasswordV2:native-v2-password\r\n", + ), + { usernameFragment: "native-v2-user", password: "native-v2-password" }, + ); + assert.equal(extractNvstIceCredentials("a=ice-ufrag:incomplete\n"), null); +}); + test("extractHmacSeed reads DESCRIBE k= line", () => { const seed = extractHmacSeed( "v=0\r\nk=HMAC:76A28E94D8C07CB67C04C29CFAAAAF64BE4BA0899456217CB73D070E5060965F\r\na=x-nv-general.rtspWebSocketPerConnection:1\r\n", @@ -17,12 +42,207 @@ test("extractHmacSeed reads DESCRIBE k= line", () => { assert.equal(seed, "76A28E94D8C07CB67C04C29CFAAAAF64BE4BA0899456217CB73D070E5060965F"); }); -test("buildAnnounceSdp uses allowlist shape and omits ICE/DTLS", () => { - const sdp = buildAnnounceSdp({ resolution: "1920x1080", fps: 60 }); +test("extractNvstSdpAttribute reads DESCRIBE transport fields with or without x-nv-", () => { + assert.equal( + extractNvstSdpAttribute( + "a=x-nv-general.serverTransport:192.0.2.20:5004\r\na=x-nv-general.useNewIceInfo:0\r\n", + "general.serverTransport", + ), + "192.0.2.20:5004", + ); + assert.equal( + extractNvstSdpAttribute("a=general.useNewIceInfo:0\n", "general.useNewIceInfo"), + "0", + ); + assert.equal(extractNvstSdpAttribute("a=general.clientTransport:\n", "general.clientTransport"), null); +}); + +test("buildAnnounceSdp uses Bifrost session and attribute shape", () => { + const sdp = buildAnnounceSdp({ + resolution: "1920x1080", + fps: 60, + maxBitrateKbps: 100_000, + videoPort: 5004, + clientPorts: { video: 45000, audio: 45002, control: 45004 }, + }); + assert.match(sdp, /^o=unknown 0 14 IN IPv4 127\.0\.0\.1$/m); assert.match(sdp, /a=x-nv-video\[0\]\.clientViewportWd:1920/); + assert.match(sdp, /a=x-nv-video\[0\]\.videoSplitEncodeStripsPerFrame:64/); + assert.match(sdp, /a=x-nv-video\[0\]\.packetSize:1280/); + assert.match(sdp, /a=x-nv-video\[0\]\.framePacing\.mode:1/); + assert.match(sdp, /a=x-nv-video\[0\]\.framePacing\.feedbackMode:1/); + assert.match(sdp, /a=x-nv-video\[0\]\.framePacing\.pid\.minTargetFrameTimeUs:7936/); assert.match(sdp, /a=x-nv-video\[0\]\.maxFPS:60/); - assert.match(sdp, /a=x-nv-general\.controlProtocol:udp_ag/); - assert.doesNotMatch(sdp, /iceUsernameFragment|dtlsFingerprint/); + assert.match(sdp, /a=x-nv-general\.clientPorts\.video:45000/); + assert.match(sdp, /a=x-nv-general\.clientPorts\.audio:45002/); + assert.match(sdp, /a=x-nv-general\.clientPorts\.control:45004/); + assert.match(sdp, /a=x-nv-video\[0\]\.enableRtpNack:1/); + assert.match(sdp, /a=x-nv-vqos\[0\]\.fec\.enable:0/); + assert.match(sdp, /a=x-nv-vqos\[0\]\.bitStreamFormat:0/); + assert.match(sdp, /a=x-nv-vqos\[0\]\.bllFec\.enable:0/); + assert.match(sdp, /a=x-nv-vqos\[0\]\.grc\.enable:7/); + assert.match(sdp, /a=x-nv-aqos\.enableRedundancy:0/); + assert.match(sdp, /a=x-nv-video\[0\]\.initialBitrateKbps:100000/); + assert.match(sdp, /a=x-nv-video\[0\]\.initialPeakBitrateKbps:100000/); + assert.match(sdp, /a=x-nv-vqos\[0\]\.bw\.maximumBitrateKbps:100000/); + assert.match(sdp, /a=x-nv-vqos\[0\]\.bw\.minimumBitrateKbps:1000/); + assert.match(sdp, /a=x-nv-vqos\[0\]\.dynamicStreamingMode:0/); + assert.match(sdp, /a=x-nv-bwe\.useOwdCongestionControl:1/); + assert.match(sdp, /a=x-nv-runtime\.mouseCursorCapture:3/); + assert.match(sdp, /a=x-nv-runtime\.mimicRemoteCursor:0/); + assert.doesNotMatch(sdp, /a=x-nv-general\.rtcpOnSctp:/); + assert.match(sdp, /m=video 5004\r\ni=DeviceString, DeviceName/); + assert.doesNotMatch(sdp, /RTP\/AVP|msid:video_0|clientTransport|nativeRtcOnBundlePort|iceUsernameFragment|dtlsFingerprint|controlProtocol/); +}); + +test("buildAnnounceSdp advertises the negotiated high-FPS ceiling", () => { + const sdp = buildAnnounceSdp({ fps: 360 }); + assert.match(sdp, /a=x-nv-video\[0\]\.maxFPS:240/); + const normalSdp = buildAnnounceSdp({ fps: 120 }); + assert.match(normalSdp, /a=x-nv-video\[0\]\.maxFPS:120/); +}); + +test("buildAnnounceSdp selects H.265 and AV1 NVST bitstreams", () => { + const h265 = buildAnnounceSdp({ codec: "H265" }); + assert.match(h265, /a=x-nv-vqos\[0\]\.bitStreamFormat:1/); + assert.match(h265, /a=x-nv-clientSupportHevc:1/); + + const av1 = buildAnnounceSdp({ codec: "AV1" }); + assert.match(av1, /a=x-nv-vqos\[0\]\.bitStreamFormat:2/); + assert.doesNotMatch(av1, /a=x-nv-clientSupportHevc:/); +}); + +test("buildAnnounceSdp uses the selected ceiling as the native startup rate", () => { + const sdp = buildAnnounceSdp({ maxBitrateKbps: 80_000 }); + assert.match(sdp, /a=x-nv-video\[0\]\.initialBitrateKbps:80000/); + assert.match(sdp, /a=x-nv-video\[0\]\.initialPeakBitrateKbps:80000/); + assert.match(sdp, /a=x-nv-vqos\[0\]\.bw\.maximumBitrateKbps:80000/); +}); + +test("buildAnnounceSdp advertises RTCP over SCTP only when negotiated", () => { + const sdp = buildAnnounceSdp({ rtcpOnSctp: true }); + assert.match(sdp, /a=x-nv-general\.rtcpOnSctp:1/); +}); + +test("buildAnnounceSdp echoes nativeRtcOnBundlePort when the server advertised it", () => { + const sdp = buildAnnounceSdp({ + videoPort: 5004, + nativeRtcOnBundlePort: "1", + clientPorts: { video: 45000, audio: 45000, control: 45000, bundle: 45000 }, + }); + assert.match(sdp, /a=x-nv-general\.nativeRtcOnBundlePort:1/); + assert.match(sdp, /a=x-nv-general\.clientPorts\.bundle:45000/); +}); + +test("buildAnnounceSdp marks rtc streams on the native bundle when unified", () => { + const sdp = buildAnnounceSdp({ + videoPort: 5004, + nativeRtcOnBundlePort: "1", + rtcOnNativeBundle: true, + }); + assert.match(sdp, /a=x-nv-general\.rtcVideoOnNativeBundle:1/); + assert.match(sdp, /a=x-nv-general\.rtcAudioOnNativeBundle:1/); + assert.match(sdp, /a=x-nv-general\.rtcDataChannelOnNativeBundle:1/); +}); + +test("buildAnnounceSdp matches official cloud bundle flags", () => { + const fingerprint = "00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF"; + const sdp = buildAnnounceSdp({ + videoPort: 5004, + iceCredentials: { usernameFragment: "Ab1+", password: "pwd0123456789abcdefABCD" }, + includeNvscLegacyIce: false, + includeNvscLegacyDtls: false, + dtlsFingerprint: fingerprint, + clientPorts: { + video: 0, + audio: 0, + mic: 0, + control: 0, + bundle: 0, + session: 0, + localAddress: "192.0.2.8", + }, + clientBundlePort: 49006, + nativeRtcOnBundlePort: "1", + rtcVideoOnNativeBundle: false, + rtcAudioOnNativeBundle: true, + rtcMicOnNativeBundle: true, + rtcDataChannelOnNativeBundle: true, + enableUnifiedSocket: false, + }); + assert.match(sdp, /a=x-nv-general\.clientPorts\.video:0/); + assert.match(sdp, /a=x-nv-general\.clientPorts\.audio:0/); + assert.match(sdp, /a=x-nv-general\.clientPorts\.mic:0/); + assert.match(sdp, /a=x-nv-general\.clientPorts\.bundle:0/); + assert.match(sdp, /a=x-nv-general\.clientBundlePort:49006/); + assert.match(sdp, /a=x-nv-general\.rtcVideoOnNativeBundle:0/); + assert.match(sdp, /a=x-nv-general\.rtcAudioOnNativeBundle:1/); + assert.match(sdp, /a=x-nv-general\.rtcMicOnNativeBundle:1/); + assert.match(sdp, /a=x-nv-general\.enableUnifiedSocket:0/); + assert.doesNotMatch(sdp, /a=x-nv-general\.iceUsernameFragment:/); + assert.doesNotMatch(sdp, /a=x-nv-general\.iceUsernamePwd:/); + assert.doesNotMatch(sdp, /a=x-nv-general\.dtlsFingerprint:/); + assert.match(sdp, /a=x-nv-general\.iceUserNameFragmentV2:Ab1\+/); + assert.match(sdp, /a=x-nv-general\.dtlsFingerprintV2:/); + assert.match(sdp, /^a=ice-ufrag:Ab1\+$/m); + assert.match(sdp, /^a=candidate:1 1 udp 2122260223 192\.0\.2\.8 49006 typ host$/m); + assert.doesNotMatch(sdp, /clientTransport/); +}); + +test("buildAnnounceSdp includes official clientPorts.localAddress when provided", () => { + const sdp = buildAnnounceSdp({ + videoPort: 5004, + clientPorts: { video: 45000, localAddress: "192.0.2.8" }, + }); + assert.match(sdp, /a=x-nv-general\.clientPorts\.localAddress:192\.0\.2\.8/); + assert.match(sdp, /a=x-nv-general\.clientPorts\.video:45000/); +}); + +test("buildAnnounceSdp includes clientTransport only when provided", () => { + const sdp = buildAnnounceSdp({ + videoPort: 5004, + clientTransport: "192.0.2.8:45000", + }); + assert.match(sdp, /a=x-nv-general\.clientTransport:192\.0\.2\.8:45000/); +}); + +test("buildAnnounceSdp includes DTLS fingerprint V1 and V2 when provided", () => { + const fingerprint = "00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF"; + const sdp = buildAnnounceSdp({ dtlsFingerprint: fingerprint }); + assert.ok(sdp.includes(`a=x-nv-general.dtlsFingerprint:${fingerprint}`)); + assert.ok(sdp.includes(`a=x-nv-general.dtlsFingerprintV2:${fingerprint}`)); +}); + +test("buildAnnounceSdp includes generated ICE V2 credentials when negotiated", () => { + const credentials = generateNvstIceCredentials(); + assert.match(credentials.usernameFragment, /^[A-Za-z0-9+/]{4}$/); + assert.match(credentials.password, /^[A-Za-z0-9+/]{22}$/); + + const sdp = buildAnnounceSdp({ iceCredentials: credentials }); + assert.ok(sdp.includes(`a=x-nv-general.iceUsernameFragment:${credentials.usernameFragment}`)); + assert.ok(sdp.includes(`a=x-nv-general.iceUsernamePwd:${credentials.password}`)); + assert.ok(sdp.includes(`a=x-nv-general.iceUserNameFragmentV2:${credentials.usernameFragment}`)); + assert.ok(sdp.includes(`a=x-nv-general.icePasswordV2:${credentials.password}`)); + assert.ok(sdp.includes(`a=ice-ufrag:${credentials.usernameFragment}`)); + assert.ok(sdp.includes(`a=ice-pwd:${credentials.password}`)); +}); + +test("buildAnnounceSdp includes official WebRTC ICE/DTLS and host candidate", () => { + const fingerprint = "00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF"; + const sdp = buildAnnounceSdp({ + videoPort: 5004, + iceCredentials: { usernameFragment: "Ab1+", password: "pwd0123456789abcdefABCD" }, + dtlsFingerprint: fingerprint, + clientPorts: { video: 45000, bundle: 45000, localAddress: "192.0.2.8" }, + }); + assert.match(sdp, /^a=ice-options:trickle$/m); + assert.match(sdp, /^a=ice-ufrag:Ab1\+$/m); + assert.match(sdp, /^a=ice-pwd:pwd0123456789abcdefABCD$/m); + assert.ok(sdp.includes(`a=fingerprint:sha-256 ${fingerprint}`)); + assert.match(sdp, /^a=setup:actpass$/m); + assert.match(sdp, /^a=candidate:1 1 udp 2122260223 192\.0\.2\.8 45000 typ host$/m); + assert.match(sdp, /^c=IN IP4 0\.0\.0\.0$/m); + assert.match(sdp, /^m=video 5004$/m); }); test("packSrtpMasterKeySalt matches geronimo keyId packing", () => { @@ -44,3 +264,53 @@ test("extractRuntimeEncryptionKey reads DESCRIBE attrs", () => { assert.ok(parsed); assert.equal(parsed?.keyId, 2664076126); }); + +test("extractMediaControl reads the advertised video track instead of session control", () => { + const sdp = [ + "v=0", + "a=control:*", + "m=audio 0 RTP/AVP 97", + "a=control:streamid=audio/0/0", + "m=video 0 RTP/AVP 96", + "a=control:tracks/server-selected-video", + "", + ].join("\r\n"); + + assert.equal(extractMediaControl(sdp, "video"), "tracks/server-selected-video"); + assert.equal(extractMediaControl(sdp, "audio"), "streamid=audio/0/0"); + assert.equal(extractMediaControl(sdp, "control"), null); +}); + +test("extractNvstOpusAudioTrack returns only standard negotiated Opus metadata", () => { + const sdp = [ + "v=0", + "m=video 0 RTP/AVP 96", + "a=rtpmap:96 H264/90000", + "m=audio 0 RTP/AVP 97 0", + "a=mid:audio-main", + "a=rtpmap:97 opus/48000/2", + "a=rtpmap:0 PCMU/8000/1", + "a=ssrc:123456 cname:audio", + "", + ].join("\r\n"); + + assert.deepEqual(extractNvstOpusAudioTrack(sdp), { + payloadType: 97, + codec: "opus", + clockRateHz: 48_000, + channels: 2, + mid: "audio-main", + ssrc: 123456, + }); +}); + +test("extractNvstOpusAudioTrack does not guess omitted or unsupported codec metadata", () => { + assert.equal( + extractNvstOpusAudioTrack("m=audio 0 RTP/AVP 97\r\na=control:audio\r\n"), + null, + ); + assert.equal( + extractNvstOpusAudioTrack("m=audio 0 RTP/AVP 97\r\na=rtpmap:97 proprietary/48000/2\r\n"), + null, + ); +}); diff --git a/opennow-stable/src/main/platforms/gfn/nvstRtsp/sdp.ts b/opennow-stable/src/main/platforms/gfn/nvstRtsp/sdp.ts index 6f009571b..779fb2353 100644 --- a/opennow-stable/src/main/platforms/gfn/nvstRtsp/sdp.ts +++ b/opennow-stable/src/main/platforms/gfn/nvstRtsp/sdp.ts @@ -1,20 +1,23 @@ import { randomBytes } from "node:crypto"; -/** Minimal ANNOUNCE attrs from docs/research/nvst-announce-allowlist-1080p60.json */ +import { clampNativeStreamFps, type NvstAudioTrack } from "@shared/gfn"; +import { deriveSrtpSaltHex } from "./srtp"; + +/** Official macOS ANNOUNCE baseline. */ const ANNOUNCE_ALLOWLIST = { video: { clientViewportWd: "1920", clientViewportHt: "1080", - maxFPS: "60", - videoSplitEncodeStripsPerFrame: "3", + videoSplitEncodeStripsPerFrame: "64", updateSplitEncodeStateDynamically: "1", - packetSize: "1408", + packetSize: "1280", enableRtpNack: "1", rtpNackQueueLength: "2048", rtpNackQueueMaxPackets: "1024", rtpNackMaxPacketCount: "64", - "framePacing.mode": "2", - "framePacing.pid.minTargetFrameTimeUs": "16666", + "framePacing.mode": "1", + "framePacing.feedbackMode": "1", + "framePacing.pid.minTargetFrameTimeUs": "7936", "adaptiveQuantization.spatialAQSetting": "7", "adaptiveQuantization.temporalAQSetting": "0", "adaptiveQuantization.spatialAQStrength": "12", @@ -26,17 +29,19 @@ const ANNOUNCE_ALLOWLIST = { enableAv1RcPrecisionFactor: "1", }, vqos: { - "fec.enable": "1", - "fec.repairPercent": "20", - "fec.repairMinPercent": "5", - "fec.repairMaxPercent": "40", - "bllFec.enable": "1", - "grc.enable": "0", + bitStreamFormat: "0", + "fec.enable": "0", + "fec.repairPercent": "0", + "fec.repairMinPercent": "0", + "fec.repairMaxPercent": "0", + "bllFec.enable": "0", + // Official native Linux NVST config enables all H.264/H.265 GRC modes. + // Keep the user's bitrate as a ceiling while allowing the server to react + // to the RTCP loss/jitter feedback emitted by the native receiver. + "grc.enable": "7", "drc.enable": "0", "dfc.adjustResAndFps": "0", calculateAvgVideoStreamingBitrate: "1", - "bw.maximumBitrateKbps": "100000", - "bw.minimumBitrateKbps": "1000", }, packetPacing: { version: "3", @@ -58,8 +63,11 @@ const ANNOUNCE_ALLOWLIST = { enablePartiallyReliableTransferHid: "-1", }, aqos: { - enableRedundancy: "1", - redundancyLevel: "2", + enableRedundancy: "0", + redundancyLevel: "0", + }, + bwe: { + useOwdCongestionControl: "1", }, general: { rtspWebSocketPerConnection: "1", @@ -70,6 +78,10 @@ const ANNOUNCE_ALLOWLIST = { runtime: { audioSrtp: "0", micSrtp: "0", + // Match the installed native client's cursor policy. Without these the + // server accepts cursor_channel but does not publish local cursor shapes. + mouseCursorCapture: "3", + mimicRemoteCursor: "0", }, } as const; @@ -81,23 +93,84 @@ function parseResolution(resolution: string | undefined): { width: number; heigh return { width: Number(match[1]), height: Number(match[2]) }; } +export function extractNvstSdpAttribute(sdp: string, name: string): string | null { + const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const match = new RegExp(`^a=(?:x-nv-)?${escaped}:([^\\r\\n]*)$`, "mi").exec(sdp); + const value = match?.[1]?.trim(); + return value ? value : null; +} + export function buildAnnounceSdp( options: { resolution?: string; fps?: number; + codec?: string; + /** User-selected bitrate ceiling and initial native encoder target. */ + maxBitrateKbps?: number; encryptionKeyHex?: string; encryptionKeyId?: number; + iceCredentials?: { usernameFragment: string; password: string }; + /** Server video port from SETUP / DESCRIBE. Capture uses `m=video 5004`. */ + videoPort?: number; + clientPorts?: { + video: number; + audio?: number; + mic?: number; + control?: number; + bundle?: number; + session?: number; + /** Official `general.clientPorts.localAddress` — routable NIC IPv4. */ + localAddress?: string; + }; + /** Official `general.clientBundlePort` — ICE/DTLS socket, distinct from clientPorts.bundle. */ + clientBundlePort?: number; + /** Official `general.clientTransport` form is `ip:port`. */ + clientTransport?: string; + nativeRtcOnBundlePort?: string; + /** Official `general.rtc{Video,Audio,DataChannel}OnNativeBundle` when unified. */ + rtcOnNativeBundle?: boolean; + rtcVideoOnNativeBundle?: boolean; + rtcAudioOnNativeBundle?: boolean; + rtcMicOnNativeBundle?: boolean; + rtcDataChannelOnNativeBundle?: boolean; + enableUnifiedSocket?: boolean; + /** + * Official `general.rtcpOnSctp` gates RTCP feedback onto the `rtcp1` SCTP data + * channel. We do not bring that channel up, so advertise 0 to keep feedback on + * plain SRTCP over the Mjolnir socket (which the native receiver already sends). + */ + rtcpOnSctp?: boolean; + /** + * Official skips Nvsc V1 `iceUsernameFragment` / `iceUsernamePwd` / + * `dtlsFingerprint` and keeps V2 plus WebRTC `a=ice-*`. + */ + includeNvscLegacyIce?: boolean; + includeNvscLegacyDtls?: boolean; + /** SHA-256 colon hex (95 chars). Written as V1 + V2 to match Bifrost/mall. */ + dtlsFingerprint?: string; } = {}, ): string { const { width, height } = parseResolution(options.resolution); - const fps = options.fps && options.fps > 0 ? Math.round(options.fps) : 60; - const frameTimeUs = String(Math.round(1_000_000 / fps)); + const fps = options.fps && Number.isFinite(options.fps) && options.fps > 0 + ? clampNativeStreamFps(options.fps) + : 60; + const videoPort = options.videoPort && options.videoPort > 0 ? options.videoPort : 0; + const maximumBitrateKbps = Math.max( + 1_000, + Math.min(150_000, Math.round(options.maxBitrateKbps ?? 100_000)), + ); + // Start at the selected ceiling. GRC may reduce the encoder output from this + // value when the receiver reports congestion, while DRC remains disabled so + // resolution and frame rate stay predictable. + const initialBitrateKbps = maximumBitrateKbps; + const codec = options.codec?.trim().toUpperCase() ?? "H264"; + const bitStreamFormat = codec === "AV1" ? "2" : codec === "H265" || codec === "HEVC" ? "1" : "0"; const lines: string[] = [ "v=0", - "o=- 0 0 IN IP4 127.0.0.1", - "s=OpenNOW NVST Handshake", - "t=0 0", + // Official macOS handshake origin username is "unknown", not "android". + "o=unknown 0 14 IN IPv4 127.0.0.1", + "s=NVIDIA Streaming Client", ]; const pushGroup = ( @@ -111,10 +184,6 @@ export function buildAnnounceSdp( nextValue = String(width); } else if (prefix === "video" && key === "clientViewportHt") { nextValue = String(height); - } else if (prefix === "video" && key === "maxFPS") { - nextValue = String(fps); - } else if (prefix === "video" && key === "framePacing.pid.minTargetFrameTimeUs") { - nextValue = frameTimeUs; } const name = indexed ? `x-nv-${prefix}[0].${key}` : `x-nv-${prefix}.${key}`; lines.push(`a=${name}:${nextValue}`); @@ -122,23 +191,133 @@ export function buildAnnounceSdp( }; pushGroup("video", true, ANNOUNCE_ALLOWLIST.video); - pushGroup("vqos", true, ANNOUNCE_ALLOWLIST.vqos); + // CloudMatch provisions the requested profile, but NVST still requires the + // client frame-rate ceiling in ANNOUNCE. Without it, the server defaults to + // a 60 FPS video stream even when the negotiated session profile says 120. + lines.push(`a=x-nv-video[0].maxFPS:${fps}`); + lines.push(`a=x-nv-video[0].initialBitrateKbps:${initialBitrateKbps}`); + lines.push(`a=x-nv-video[0].initialPeakBitrateKbps:${initialBitrateKbps}`); + pushGroup("vqos", true, { + ...ANNOUNCE_ALLOWLIST.vqos, + bitStreamFormat, + }); + if (bitStreamFormat !== "2") { + lines.push(`a=x-nv-clientSupportHevc:${bitStreamFormat === "1" ? "1" : "0"}`); + } + // Match the installed Windows client's native NVST policy: bitrate remains + // adaptive while dynamic resolution/framerate stay disabled. Omitting these + // fields leaves the server near its low default rate even when the UI ceiling + // is much higher. + lines.push(`a=x-nv-vqos[0].bw.maximumBitrateKbps:${maximumBitrateKbps}`); + lines.push("a=x-nv-vqos[0].bw.minimumBitrateKbps:1000"); + lines.push("a=x-nv-vqos[0].drc.bitrateIirFilterFactor:128"); + lines.push("a=x-nv-vqos[0].resControl.bitrateIirFilterFactor:128"); + lines.push("a=x-nv-vqos[0].dynamicStreamingMode:0"); pushGroup("packetPacing", false, ANNOUNCE_ALLOWLIST.packetPacing); pushGroup("ri", false, ANNOUNCE_ALLOWLIST.ri); pushGroup("aqos", false, ANNOUNCE_ALLOWLIST.aqos); + pushGroup("bwe", false, ANNOUNCE_ALLOWLIST.bwe); pushGroup("general", false, ANNOUNCE_ALLOWLIST.general); pushGroup("runtime", false, ANNOUNCE_ALLOWLIST.runtime); lines.push("a=x-nv-runtime.videoSrtp:1"); if (options.encryptionKeyHex && options.encryptionKeyId !== undefined) { lines.push(`a=x-nv-runtime.encryptionKey:${options.encryptionKeyHex.toUpperCase()}`); - // Signed i32 form matches geronimo runtime.encryptionKeyId dumps. - const signedId = options.encryptionKeyId > 0x7fffffff - ? options.encryptionKeyId - 0x1_0000_0000 - : options.encryptionKeyId; - lines.push(`a=x-nv-runtime.encryptionKeyId:${signedId}`); - } - // Control protocol preference evidenced in geronimo: udp_ag (not encrypted). - lines.push("a=x-nv-general.controlProtocol:udp_ag"); + // Official sends the keyId unsigned (u32) on the wire, and our salt derivation uses the + // unsigned form too (deriveSrtpSaltHex does keyId >>> 0), so both ends derive the same salt. + lines.push(`a=x-nv-runtime.encryptionKeyId:${options.encryptionKeyId >>> 0}`); + } + if (options.iceCredentials) { + if (options.includeNvscLegacyIce !== false) { + lines.push(`a=x-nv-general.iceUsernameFragment:${options.iceCredentials.usernameFragment}`); + lines.push(`a=x-nv-general.iceUsernamePwd:${options.iceCredentials.password}`); + } + lines.push(`a=x-nv-general.iceUserNameFragmentV2:${options.iceCredentials.usernameFragment}`); + lines.push(`a=x-nv-general.icePasswordV2:${options.iceCredentials.password}`); + } + if (options.clientPorts) { + if (options.clientPorts.localAddress) { + lines.push(`a=x-nv-general.clientPorts.localAddress:${options.clientPorts.localAddress}`); + } + lines.push(`a=x-nv-general.clientPorts.video:${options.clientPorts.video}`); + if (options.clientPorts.audio !== undefined) { + lines.push(`a=x-nv-general.clientPorts.audio:${options.clientPorts.audio}`); + } + if (options.clientPorts.mic !== undefined) { + lines.push(`a=x-nv-general.clientPorts.mic:${options.clientPorts.mic}`); + } + if (options.clientPorts.control !== undefined) { + lines.push(`a=x-nv-general.clientPorts.control:${options.clientPorts.control}`); + } + if (options.clientPorts.bundle !== undefined) { + lines.push(`a=x-nv-general.clientPorts.bundle:${options.clientPorts.bundle}`); + } + if (options.clientPorts.session !== undefined) { + lines.push(`a=x-nv-general.clientPorts.session:${options.clientPorts.session}`); + } + } + if (options.clientBundlePort !== undefined) { + lines.push(`a=x-nv-general.clientBundlePort:${options.clientBundlePort}`); + } + if (options.clientTransport) { + lines.push(`a=x-nv-general.clientTransport:${options.clientTransport}`); + } + if (options.nativeRtcOnBundlePort) { + lines.push(`a=x-nv-general.nativeRtcOnBundlePort:${options.nativeRtcOnBundlePort}`); + } + const rtcVideo = options.rtcVideoOnNativeBundle ?? (options.rtcOnNativeBundle ? true : undefined); + const rtcAudio = options.rtcAudioOnNativeBundle ?? (options.rtcOnNativeBundle ? true : undefined); + const rtcMic = options.rtcMicOnNativeBundle; + const rtcData = options.rtcDataChannelOnNativeBundle ?? (options.rtcOnNativeBundle ? true : undefined); + if (rtcVideo !== undefined) { + lines.push(`a=x-nv-general.rtcVideoOnNativeBundle:${rtcVideo ? "1" : "0"}`); + } + if (rtcAudio !== undefined) { + lines.push(`a=x-nv-general.rtcAudioOnNativeBundle:${rtcAudio ? "1" : "0"}`); + } + if (rtcMic !== undefined) { + lines.push(`a=x-nv-general.rtcMicOnNativeBundle:${rtcMic ? "1" : "0"}`); + } + if (rtcData !== undefined) { + lines.push(`a=x-nv-general.rtcDataChannelOnNativeBundle:${rtcData ? "1" : "0"}`); + } + if (options.enableUnifiedSocket !== undefined) { + lines.push(`a=x-nv-general.enableUnifiedSocket:${options.enableUnifiedSocket ? "1" : "0"}`); + } + if (options.rtcpOnSctp !== undefined) { + lines.push(`a=x-nv-general.rtcpOnSctp:${options.rtcpOnSctp ? "1" : "0"}`); + } + if (options.dtlsFingerprint) { + if (options.includeNvscLegacyDtls !== false) { + lines.push(`a=x-nv-general.dtlsFingerprint:${options.dtlsFingerprint}`); + } + lines.push(`a=x-nv-general.dtlsFingerprintV2:${options.dtlsFingerprint}`); + } + // Official doAnnounce also emits CreateAnswer WebRTC ICE/DTLS (a=ice-ufrag, + // a=fingerprint, host a=candidate). NVST x-nv-general.* alone does not arm inbound UDP. + if (options.iceCredentials) { + lines.push("a=ice-options:trickle"); + lines.push(`a=ice-ufrag:${options.iceCredentials.usernameFragment}`); + lines.push(`a=ice-pwd:${options.iceCredentials.password}`); + } + if (options.dtlsFingerprint) { + lines.push(`a=fingerprint:sha-256 ${options.dtlsFingerprint}`); + lines.push("a=setup:actpass"); + } + const candidateAddress = options.clientPorts?.localAddress; + const candidatePort = options.clientBundlePort + ?? (options.clientPorts?.bundle && options.clientPorts.bundle > 0 ? options.clientPorts.bundle : undefined) + ?? (options.clientPorts?.video && options.clientPorts.video > 0 ? options.clientPorts.video : undefined); + if (candidateAddress && candidatePort) { + // Official CreateLocalCandidate format string: `a=candidate:1 1 udp 2122260223 ` + ` typ host`. + lines.push(`a=candidate:1 1 udp 2122260223 ${candidateAddress} ${candidatePort} typ host`); + } + lines.push("t=0 0"); + // Live capture ANNOUNCE uses the server video port, not SDP's "port 0 = unused". + lines.push(`m=video ${videoPort}`); + if (options.iceCredentials || options.dtlsFingerprint) { + lines.push("c=IN IP4 0.0.0.0"); + } + lines.push("i=DeviceString, DeviceName"); lines.push(""); return lines.join("\r\n"); } @@ -148,6 +327,23 @@ export function extractHmacSeed(sdp: string): string | null { return match?.[1] ?? null; } +export function extractNvstIceCredentials( + sdp: string, +): { usernameFragment: string; password: string } | null { + const usernameFragment = /^(?:a=(?:x-nv-)?general\.iceUsernameFragment:|a=ice-ufrag:)([^\r\n]+)\s*$/mi + .exec(sdp)?.[1]?.trim() + ?? /^(?:a=(?:x-nv-)?general\.iceUserNameFragmentV2:)([^\r\n]+)\s*$/mi + .exec(sdp)?.[1]?.trim(); + const password = /^(?:a=(?:x-nv-)?general\.iceUsernamePwd:|a=ice-pwd:)([^\r\n]+)\s*$/mi + .exec(sdp)?.[1]?.trim() + ?? /^(?:a=(?:x-nv-)?general\.icePasswordV2:)([^\r\n]+)\s*$/mi + .exec(sdp)?.[1]?.trim(); + if (!usernameFragment || !password) { + return null; + } + return { usernameFragment, password }; +} + /** * Pack AES-256 key + keyId into libsrtp master key||salt (88 hex). * Salt = keyId as `%024x` (12 bytes BE). See docs/research/nvst-srtp-key-derivation.md. @@ -157,9 +353,7 @@ export function packSrtpMasterKeySalt(aesKeyHex: string, keyId: number): string if (!/^[0-9A-F]{64}$/.test(key)) { throw new Error(`encryptionKey must be 64 hex chars, got length ${key.length}`); } - const id = keyId >>> 0; - const salt = id.toString(16).toUpperCase().padStart(24, "0"); - return `${key}${salt}`; + return `${key}${deriveSrtpSaltHex(keyId)}`; } export function extractRuntimeEncryptionKey( @@ -181,12 +375,122 @@ export function extractRuntimeEncryptionKey( return { aesKeyHex: keyMatch[1]!.toUpperCase(), keyId: keyId >>> 0 }; } +export function extractMediaControl(sdp: string, mediaType: string): string | null { + let currentMediaType: string | null = null; + + for (const rawLine of sdp.split(/\r?\n/)) { + const line = rawLine.trim(); + if (line.startsWith("m=")) { + currentMediaType = line.slice(2).split(/\s+/, 1)[0]?.toLowerCase() ?? null; + continue; + } + if (currentMediaType !== mediaType.toLowerCase() || !line.startsWith("a=control:")) { + continue; + } + + const control = line.slice("a=control:".length).trim(); + if (control && control !== "*") { + return control; + } + } + + return null; +} + +export function extractNvstOpusAudioTrack(sdp: string): NvstAudioTrack | null { + let inAudioSection = false; + let offeredPayloadTypes: number[] = []; + let mid: string | undefined; + let ssrc: number | undefined; + const codecs = new Map(); + + for (const rawLine of sdp.split(/\r?\n/)) { + const line = rawLine.trim(); + if (line.startsWith("m=")) { + if (inAudioSection) { + break; + } + const parts = line.slice(2).split(/\s+/); + inAudioSection = parts[0]?.toLowerCase() === "audio"; + offeredPayloadTypes = inAudioSection + ? parts.slice(3).map(Number).filter((value) => Number.isInteger(value) && value >= 0 && value <= 127) + : []; + continue; + } + if (!inAudioSection) { + continue; + } + if (line.startsWith("a=mid:")) { + mid = line.slice("a=mid:".length).trim() || undefined; + continue; + } + if (line.startsWith("a=ssrc:")) { + const value = Number(line.slice("a=ssrc:".length).split(/\s+/, 1)[0]); + if (Number.isInteger(value) && value > 0 && value <= 0xffff_ffff) { + ssrc = value; + } + continue; + } + const rtpmap = /^a=rtpmap:(\d+)\s+([^/\s]+)\/(\d+)\/(\d+)$/i.exec(line); + if (!rtpmap) { + continue; + } + const payloadType = Number(rtpmap[1]); + const clockRateHz = Number(rtpmap[3]); + const channels = Number(rtpmap[4]); + if ( + Number.isInteger(payloadType) + && payloadType >= 0 + && payloadType <= 127 + && Number.isInteger(clockRateHz) + && clockRateHz > 0 + && Number.isInteger(channels) + && channels > 0 + ) { + codecs.set(payloadType, { + codec: rtpmap[2]!.toLowerCase(), + clockRateHz, + channels, + }); + } + } + + for (const payloadType of offeredPayloadTypes) { + const track = codecs.get(payloadType); + if (track?.codec !== "opus" || track.clockRateHz !== 48_000 || track.channels > 2) { + continue; + } + return { + payloadType, + codec: "opus", + clockRateHz: track.clockRateHz, + channels: track.channels, + ...(mid ? { mid } : {}), + ...(ssrc ? { ssrc } : {}), + }; + } + return null; +} + export function generateClientEncryptionKey(): { aesKeyHex: string; keyId: number } { const aesKeyHex = randomBytes(32).toString("hex").toUpperCase(); const keyId = randomBytes(4).readUInt32BE(0); return { aesKeyHex, keyId }; } +export function generateNvstIceCredentials(): { usernameFragment: string; password: string } { + const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/"; + const random = randomBytes(26); + const encode = (start: number, length: number): string => Array.from( + random.subarray(start, start + length), + (value) => alphabet[value & 0x3f], + ).join(""); + return { + usernameFragment: encode(0, 4), + password: encode(4, 22), + }; +} + export function redactKey(aesKeyHex: string): string { if (aesKeyHex.length < 8) { return "****"; diff --git a/opennow-stable/src/main/platforms/gfn/nvstRtsp/srtp.test.ts b/opennow-stable/src/main/platforms/gfn/nvstRtsp/srtp.test.ts new file mode 100644 index 000000000..953f637bf --- /dev/null +++ b/opennow-stable/src/main/platforms/gfn/nvstRtsp/srtp.test.ts @@ -0,0 +1,77 @@ +/// + +import assert from "node:assert/strict"; +import test from "node:test"; + +import { + deriveSrtpSaltHex, + extractAdvertisedSrtpProfileFromHeaders, + extractAdvertisedSrtpProfileFromSdp, +} from "./srtp"; + +test("extractAdvertisedSrtpProfileFromSdp reads standard crypto suites", () => { + assert.equal( + extractAdvertisedSrtpProfileFromSdp([ + "v=0", + "m=video 0 RTP/SAVP 96", + "a=crypto:1 AEAD_AES_256_GCM inline:ignored", + "", + ].join("\r\n")), + "AEAD_AES_256_GCM", + ); +}); + +test("extractAdvertisedSrtpProfileFromSdp accepts an explicit SRTP-named attribute", () => { + assert.equal( + extractAdvertisedSrtpProfileFromSdp( + "v=0\r\na=x-provider-srtp-suite:AES_CM_128_HMAC_SHA1_80\r\n", + ), + "AES_CM_128_HMAC_SHA1_80", + ); +}); + +test("extractAdvertisedSrtpProfileFromHeaders reads explicit SETUP transport data", () => { + assert.equal( + extractAdvertisedSrtpProfileFromHeaders({ + transport: "RTP/SAVP;unicast;profile=AEAD_AES_128_GCM;X-GS-ServerPort=5004", + }), + "AEAD_AES_128_GCM", + ); + assert.equal( + extractAdvertisedSrtpProfileFromHeaders({ + "x-provider-srtp-suite": "AES_CM_128_HMAC_SHA1_32", + }), + "AES_CM_128_HMAC_SHA1_32", + ); +}); + +test("profile parser ignores unscoped and unknown profile text", () => { + assert.equal( + extractAdvertisedSrtpProfileFromSdp( + "v=0\r\na=x-note:prefer AEAD_AES_256_GCM\r\n", + ), + null, + ); + assert.equal( + extractAdvertisedSrtpProfileFromSdp( + "v=0\r\na=x-provider-srtp-suite:UNSUPPORTED_PROFILE\r\n", + ), + null, + ); + assert.equal( + extractAdvertisedSrtpProfileFromSdp( + "v=0\r\na=x-provider-srtp-supported-profiles:AEAD_AES_128_GCM AEAD_AES_256_GCM\r\n", + ), + null, + ); + assert.equal( + extractAdvertisedSrtpProfileFromHeaders({ + "x-note": "AEAD_AES_256_GCM", + }), + null, + ); +}); + +test("deriveSrtpSaltHex returns the direct 12-byte key-id salt", () => { + assert.equal(deriveSrtpSaltHex(2664076126), "00000000000000009ECA935E"); +}); diff --git a/opennow-stable/src/main/platforms/gfn/nvstRtsp/srtp.ts b/opennow-stable/src/main/platforms/gfn/nvstRtsp/srtp.ts new file mode 100644 index 000000000..19fd82380 --- /dev/null +++ b/opennow-stable/src/main/platforms/gfn/nvstRtsp/srtp.ts @@ -0,0 +1,77 @@ +import type { NvstSrtpProfile } from "@shared/gfn"; + +const SRTP_PROFILES: readonly NvstSrtpProfile[] = [ + "AEAD_AES_128_GCM", + "AEAD_AES_256_GCM", + "AES_CM_128_HMAC_SHA1_32", + "AES_CM_128_HMAC_SHA1_80", + "AES_CM_256_HMAC_SHA1_32", + "AES_CM_256_HMAC_SHA1_80", +]; +const SRTP_PROFILE_SET = new Set(SRTP_PROFILES); + +function findSrtpProfile(value: string): NvstSrtpProfile | null { + for (const token of value.toUpperCase().match(/[A-Z][A-Z0-9_]*/g) ?? []) { + if (SRTP_PROFILE_SET.has(token)) { + return token as NvstSrtpProfile; + } + } + return null; +} + +export function extractAdvertisedSrtpProfileFromSdp( + sdp: string, +): NvstSrtpProfile | null { + for (const rawLine of sdp.split(/\r?\n/)) { + const line = rawLine.trim(); + if (/^a=crypto:\d+\s+/i.test(line)) { + const profile = findSrtpProfile(line); + if (profile) { + return profile; + } + continue; + } + + const attribute = /^a=([^:]+):(.*)$/i.exec(line); + const attributeName = attribute?.[1] ?? ""; + if ( + !attribute + || !/(?:srtp|crypto)/i.test(attributeName) + || !/(?:profile|suite)/i.test(attributeName) + || /(?:supported|capabilit)/i.test(attributeName) + ) { + continue; + } + const profile = findSrtpProfile(attribute[2] ?? ""); + if (profile) { + return profile; + } + } + return null; +} + +export function extractAdvertisedSrtpProfileFromHeaders( + headers: Record, +): NvstSrtpProfile | null { + for (const [name, value] of Object.entries(headers)) { + if ( + name.toLowerCase() !== "transport" + && ( + !/(?:srtp|crypto)/i.test(name) + || !/(?:profile|suite)/i.test(name) + || /(?:supported|capabilit)/i.test(name) + ) + ) { + continue; + } + const profile = findSrtpProfile(value); + if (profile) { + return profile; + } + } + return null; +} + +export function deriveSrtpSaltHex(keyId: number): string { + return (keyId >>> 0).toString(16).toUpperCase().padStart(24, "0"); +} diff --git a/opennow-stable/src/main/platforms/gfn/nvstRtsp/websocketTransport.test.ts b/opennow-stable/src/main/platforms/gfn/nvstRtsp/websocketTransport.test.ts index f6cf8004e..91a83fc89 100644 --- a/opennow-stable/src/main/platforms/gfn/nvstRtsp/websocketTransport.test.ts +++ b/opennow-stable/src/main/platforms/gfn/nvstRtsp/websocketTransport.test.ts @@ -7,6 +7,7 @@ import { buildEmptyPathUpgradeRequest, buildNvstWssUpgradeRequest, buildNvstWssUpgradeRequestTarget, + encodeWsPingFrame, encodeWsTextFrame, WsFrameReader, } from "./websocketTransport"; @@ -21,6 +22,7 @@ test("buildNvstWssUpgradeRequest uses Bifrost-shaped GET / by default", () => { assert.equal(requestLine, "GET / HTTP/1.1"); assert.equal(Buffer.from(requestLine, "utf8").toString("hex"), "474554202f20485454502f312e31"); assert.equal(buildNvstWssUpgradeRequestTarget("host.example", 322, "slash"), "/"); + assert.equal(buildNvstWssUpgradeRequestTarget("host.example", 322, "rtspPath"), "/rtsp"); assert.equal( buildNvstWssUpgradeRequestTarget("host.example", 322, "sessionPath", "abc-uuid"), "/v2/session/abc-uuid", @@ -36,6 +38,15 @@ test("buildNvstWssUpgradeRequest uses Bifrost-shaped GET / by default", () => { assert.doesNotMatch(request, /x-nv-sessionid/i); }); +test("buildNvstWssUpgradeRequest supports the /rtsp endpoint with session identity", () => { + const request = buildNvstWssUpgradeRequest("host.example", 322, "key", { + form: "rtspPath", + sessionId: "sess-uuid", + }); + assert.match(request, /^GET \/rtsp HTTP\/1\.1\r\n/); + assert.match(request, /\r\nx-nv-sessionid: sess-uuid\r\n/); +}); + test("buildEmptyPathUpgradeRequest keeps empty URI for research (live → 400)", () => { const request = buildEmptyPathUpgradeRequest( "80-250-97-40.cloudmatchbeta.nvidiagrid.net", @@ -47,7 +58,7 @@ test("buildEmptyPathUpgradeRequest keeps empty URI for research (live → 400)", assert.equal(Buffer.from(requestLine, "utf8").toString("hex"), "4745542020485454502f312e31"); }); -test("buildNvstWssUpgradeRequest can attach x-nv-sessionid for 403 retry", () => { +test("buildNvstWssUpgradeRequest attaches x-nv-sessionid to upgrade requests", () => { const request = buildNvstWssUpgradeRequest("host.example", 322, "abc", { form: "slash", sessionId: "sess-uuid", @@ -65,3 +76,10 @@ test("WebSocket framing preserves masked client payload bytes", () => { assert.deepEqual(reader.push(frame.subarray(0, 3)), []); assert.deepEqual(reader.push(frame.subarray(3)), [payload]); }); + +test("WebSocket keepalive ping is a masked empty client frame", () => { + const frame = encodeWsPingFrame(); + assert.equal(frame.length, 6); + assert.equal(frame[0], 0x89); + assert.equal(frame[1], 0x80); +}); diff --git a/opennow-stable/src/main/platforms/gfn/nvstRtsp/websocketTransport.ts b/opennow-stable/src/main/platforms/gfn/nvstRtsp/websocketTransport.ts index 3d0f334f5..8cec9b614 100644 --- a/opennow-stable/src/main/platforms/gfn/nvstRtsp/websocketTransport.ts +++ b/opennow-stable/src/main/platforms/gfn/nvstRtsp/websocketTransport.ts @@ -2,19 +2,9 @@ import { createHash, randomBytes } from "node:crypto"; import type { Duplex } from "node:stream"; import { connect as tlsConnect, type TLSSocket } from "node:tls"; -/** - * Official `:322` upgrade request-target is still under research. - * - * Live matrix (raw TLS unless noted): - * - empty (`GET HTTP/1.1`) → HTTP 400 - * - absolute `rtsps://` / `wss://` / `https://` → HTTP 404 - * - `/` via Node `ws` → HTTP 404 (extra Client headers; not Bifrost-shaped) - * - `/` via raw TLS Bifrost-shaped headers → **pending** (never tried) - * - * Poco 1.14.1 WebSocket::connect does not set method/URI; it only adds Upgrade - * headers. Default HTTPRequest is GET `/`. See docs/research/_tmp-bifrost2-ws-uri-resolved.txt. - */ +/** The official client upgrades GET /rtsp with x-nv-sessionid. */ export type NvstWssUpgradeTargetForm = + | "rtspPath" | "slash" | "sessionPath" | "rtsps" @@ -29,6 +19,8 @@ export function buildNvstWssUpgradeRequestTarget( sessionId?: string, ): string { switch (form) { + case "rtspPath": + return "/rtsp"; case "slash": return "/"; case "sessionPath": @@ -49,7 +41,6 @@ export function buildNvstWssUpgradeRequestTarget( /** * Raw TLS WebSocket upgrade for NVST `:322`. * Header order matches Poco WebSocket::connect + Bifrost Content-Length: 0. - * Optional `x-nv-sessionid` is only for a 403 retry. */ export function buildNvstWssUpgradeRequest( host: string, @@ -75,7 +66,6 @@ export function buildNvstWssUpgradeRequest( `Content-Length: 0\r\n`; const sessionId = options.sessionId?.trim(); if (sessionId && form !== "sessionPath") { - // Only attach as header on 403 retry paths; sessionPath already uses UUID in URI. request += `x-nv-sessionid: ${sessionId}\r\n`; } return `${request}\r\n`; @@ -100,7 +90,6 @@ function connectNvstWssOnce( timeoutMs: number, form: NvstWssUpgradeTargetForm, sessionId?: string, - attachSessionHeader = false, ): Promise { const key = randomBytes(16).toString("base64"); const expectedAccept = createHash("sha1") @@ -108,9 +97,7 @@ function connectNvstWssOnce( .digest("base64"); const request = buildNvstWssUpgradeRequest(host, port, key, { form, - // For slash/rtsps/… first attempt: no session header. - // For 403 retry or sessionPath: pass sessionId. - sessionId: attachSessionHeader || form === "sessionPath" ? sessionId : undefined, + sessionId, }); const requestLine = request.split("\r\n")[0] ?? ""; const requestLineHex = Buffer.from(requestLine, "utf8").toString("hex"); @@ -192,7 +179,7 @@ function connectNvstWssOnce( new Error( `WSS upgrade failed: HTTP ${statusCode || "unknown"} (${statusLine || "no status"}); ` + `form=${form} request-line=${requestLine} hex=${requestLineHex}` + - (attachSessionHeader ? " with x-nv-sessionid" : ""), + (sessionId && form !== "sessionPath" ? " with x-nv-sessionid" : ""), ), ); return; @@ -206,9 +193,6 @@ function connectNvstWssOnce( }); } -/** Primary: Bifrost-shaped GET /. Fallback: CloudMatch-style /v2/session/. */ -const UPGRADE_TARGET_FORMS: NvstWssUpgradeTargetForm[] = ["slash", "sessionPath"]; - export async function connectNvstWss( host: string, port: number, @@ -216,42 +200,22 @@ export async function connectNvstWss( sessionId?: string, onLog?: (message: string) => void, ): Promise { - let lastError: Error | null = null; - for (const form of UPGRADE_TARGET_FORMS) { - try { - const target = buildNvstWssUpgradeRequestTarget(host, port, form, sessionId); - onLog?.( - `Trying WSS upgrade form=${form} (GET ${target} HTTP/1.1) raw-TLS Bifrost headers`, - ); - return await connectNvstWssOnce(host, port, timeoutMs, form, sessionId, false); - } catch (error) { - const err = error instanceof Error ? error : new Error(String(error)); - lastError = err; - const message = err.message; - if (sessionId && /\bHTTP 403\b/.test(message)) { - onLog?.(`Upgrade HTTP 403 on form=${form}; retrying with x-nv-sessionid`); - try { - return await connectNvstWssOnce(host, port, timeoutMs, form, sessionId, true); - } catch (retryError) { - lastError = retryError instanceof Error ? retryError : new Error(String(retryError)); - } - } - if (!/\bHTTP (400|404)\b/.test(message)) { - throw lastError; - } - onLog?.(message); - } - } - throw lastError ?? new Error("WSS upgrade failed for all request-target forms"); + const form = "rtspPath"; + const target = buildNvstWssUpgradeRequestTarget(host, port, form, sessionId); + onLog?.(`Trying WSS upgrade form=${form} (GET ${target} HTTP/1.1) with x-nv-sessionid`); + return connectNvstWssOnce(host, port, timeoutMs, form, sessionId); } -export function encodeWsTextFrame(payload: Buffer): Buffer { +function encodeMaskedWsFrame(opcode: number, payload: Buffer): Buffer { const len = payload.length; + if (opcode >= 0x8 && len > 125) { + throw new Error("WS control frame payload exceeds 125 bytes"); + } const mask = randomBytes(4); let header: Buffer; if (len < 126) { header = Buffer.alloc(2); - header[0] = 0x81; // FIN + text + header[0] = 0x80 | opcode; header[1] = 0x80 | len; // MASK bit set } else if (len < 65536) { header = Buffer.alloc(4); @@ -272,9 +236,22 @@ export function encodeWsTextFrame(payload: Buffer): Buffer { return Buffer.concat([header, mask, masked]); } -/** Minimal client-side WS frame reader (text + close; ignores ping/pong/control). */ +export function encodeWsTextFrame(payload: Buffer): Buffer { + return encodeMaskedWsFrame(0x1, payload); +} + +export function encodeWsPongFrame(payload: Buffer): Buffer { + return encodeMaskedWsFrame(0xa, payload); +} + +export function encodeWsPingFrame(): Buffer { + return encodeMaskedWsFrame(0x9, Buffer.alloc(0)); +} + +/** Minimal client-side WS frame reader for RTSP messages and control frames. */ export class WsFrameReader { private buffer = Buffer.alloc(0); + private pingPayloads: Buffer[] = []; push(chunk: Buffer): Buffer[] { this.buffer = Buffer.concat([this.buffer, chunk]); @@ -324,9 +301,16 @@ export class WsFrameReader { messages.push(payload); } else if (opcode === 0x8) { throw new Error("RTSPS WebSocket closed"); + } else if (opcode === 0x9) { + this.pingPayloads.push(payload); } - // 0x9/0xa ping/pong ignored for probe } return messages; } + + drainPingPayloads(): Buffer[] { + const payloads = this.pingPayloads; + this.pingPayloads = []; + return payloads; + } } diff --git a/opennow-stable/src/main/platforms/gfn/signaling.ts b/opennow-stable/src/main/platforms/gfn/signaling.ts index 9dc04b80e..d86b82162 100644 --- a/opennow-stable/src/main/platforms/gfn/signaling.ts +++ b/opennow-stable/src/main/platforms/gfn/signaling.ts @@ -58,7 +58,6 @@ export class GfnSignalingClient { signInUrl.protocol = "wss:"; signInUrl.pathname = `${signInUrl.pathname.replace(/\/?$/, "/")}sign_in`; - signInUrl.search = ""; signInUrl.searchParams.set("peer_id", this.peerName); signInUrl.searchParams.set("version", "2"); signInUrl.searchParams.set("peer_role", "1"); diff --git a/opennow-stable/src/main/platforms/gfn/types.ts b/opennow-stable/src/main/platforms/gfn/types.ts index 34fbb9dc8..de126dfa3 100644 --- a/opennow-stable/src/main/platforms/gfn/types.ts +++ b/opennow-stable/src/main/platforms/gfn/types.ts @@ -3,16 +3,20 @@ import type { SessionErrorInfo } from "@shared/sessionError"; export interface CloudMatchRequest { sessionRequestData: { - appId: string; + appId: string | number; internalTitle: string | null; availableSupportedControllers: number[]; + preferredController?: number; + requestedAudioFormat?: number; + externalAppId?: string | null; + transport?: null; networkTestSessionId: string | null; parentSessionId: string | null; clientIdentification: string; deviceHashId: string; clientVersion: string; sdkVersion: string; - streamerVersion: number; + streamerVersion: number | string; clientPlatformName: string; clientRequestMonitorSettings: Array<{ monitorId?: number; @@ -23,6 +27,14 @@ export interface CloudMatchRequest { framesPerSecond: number; sdrHdrMode: number; displayData: { + displayPrimaryX0?: number; + displayPrimaryY0?: number; + displayPrimaryX1?: number; + displayPrimaryY1?: number; + displayPrimaryX2?: number; + displayPrimaryY2?: number; + displayWhitePointX?: number; + displayWhitePointY?: number; desiredContentMaxLuminance?: number; desiredContentMinLuminance?: number; desiredContentMaxFrameAverageLuminance?: number; @@ -37,7 +49,9 @@ export interface CloudMatchRequest { clientDisplayHdrCapabilities: { version: number; hdrEdrSupportedFlagsInUint32: number; - staticMetadataDescriptorId: number; + staticMetadataDescriptorId?: number; + static_metadata_descriptor_id?: number; + display_data?: Record; } | null; surroundAudioInfo: number; remoteControllersBitmap: number; @@ -45,7 +59,7 @@ export interface CloudMatchRequest { enhancedStreamMode: number; appLaunchMode: number; secureRTSPSupported: boolean; - partnerCustomData: string; + partnerCustomData: string | null; accountLinked: boolean; enablePersistingInGameSettings: boolean; userAge: number; @@ -65,6 +79,8 @@ export interface CloudMatchRequest { prefilterSharpness?: number; prefilterNoiseReduction?: number; hudStreamingMode?: number; + qosPolicy?: number; + touchSupport?: boolean; sdrColorSpace?: number; hdrColorSpace?: number; maxBitrateKbps?: number; @@ -84,6 +100,7 @@ export interface CloudMatchResponse { }; session: { sessionId: string; + subSessionId?: string; status: number; queuePosition?: number; seatSetupInfo?: { @@ -146,7 +163,9 @@ export interface CloudMatchResponse { port: number; usage: number; protocol?: number; + appLevelProtocol?: number; resourcePath?: string; + [key: string]: unknown; }>; sessionControlInfo?: { ip?: string; @@ -174,6 +193,7 @@ export interface CloudMatchResponse { chromaFormat?: number; enabledL4S?: boolean; trueHdr?: boolean; + codec?: number; }; }; finalizedStreamingFeatures?: { @@ -183,6 +203,7 @@ export interface CloudMatchResponse { chromaFormat?: number; enabledL4S?: boolean; trueHdr?: boolean; + codec?: number; }; monitorSettings?: Array<{ widthInPixels?: number; @@ -195,6 +216,7 @@ export interface CloudMatchResponse { /** Session in the get sessions response */ export interface SessionEntry { sessionId: string; + subSessionId?: string; status: number; queuePosition?: number; seatSetupInfo?: { @@ -221,6 +243,9 @@ export interface SessionEntry { port: number; usage: number; protocol?: number; + appLevelProtocol?: number; + resourcePath?: string; + [key: string]: unknown; }>; monitorSettings?: Array<{ widthInPixels?: number; diff --git a/opennow-stable/src/main/settings.ts b/opennow-stable/src/main/settings.ts index b23b100c8..2f24f8f38 100644 --- a/opennow-stable/src/main/settings.ts +++ b/opennow-stable/src/main/settings.ts @@ -238,8 +238,8 @@ export class SettingsManager { migrated = true; } - if (settings.nativeStreamerBackend !== "gstreamer") { - settings.nativeStreamerBackend = "gstreamer"; + if ("nativeStreamerBackend" in settings) { + delete (settings as Settings & { nativeStreamerBackend?: unknown }).nativeStreamerBackend; migrated = true; } const appAccentColor = normalizeAppAccentColor(settings.appAccentColor); diff --git a/opennow-stable/src/main/signaling/signalingCoordinator.test.ts b/opennow-stable/src/main/signaling/signalingCoordinator.test.ts new file mode 100644 index 000000000..3a7b9b8d1 --- /dev/null +++ b/opennow-stable/src/main/signaling/signalingCoordinator.test.ts @@ -0,0 +1,223 @@ +/// + +import assert from "node:assert/strict"; +import test from "node:test"; + +import type { NativeStreamerSessionContext } from "@shared/gfn"; +import type { GfnNvstRtspOwner } from "../platforms/gfn/nvstRtsp/owner"; +import type { NativeStreamerManager } from "../nativeStreamer/manager"; +import type { SettingsManager } from "../settings"; +import { SignalingCoordinator } from "./signalingCoordinator"; + +function createContext(): NativeStreamerSessionContext { + return { + session: { + sessionId: "gfn-session", + status: 2, + zone: "test-zone", + serverIp: "192.0.2.10", + signalingServer: "signal.example", + signalingUrl: "wss://signal.example/session", + rtspsEndpoints: ["rtsps://rtsp.example:322/gfn-session"], + iceServers: [], + }, + settings: { + resolution: "1920x1080", + fps: 60, + codec: "H265", + transportMode: "nvst", + } as NativeStreamerSessionContext["settings"], + shortcuts: {} as NativeStreamerSessionContext["shortcuts"], + }; +} + +interface CoordinatorInternals { + nativeStreamerContext: NativeStreamerSessionContext | null; + nativeStreamerManager: NativeStreamerManager | null; + armNativeAfterNvstAnnounce(videoSession: NonNullable): Promise; + prepareNativeStreamerBeforeSignaling(): Promise; + routeSignalingEvent(event: { type: "offer"; sdp: string } | { type: "remote-ice"; candidate: string }): void; +} + +test("coordinator sends PLAY-ready acknowledgement after native sockets start without waiting for SCTP", async () => { + const events: string[] = []; + const owner: GfnNvstRtspOwner = { + prepare: async (context) => context, + videoUdpFd: () => undefined, + handoffVideoUdp: async () => undefined, + release: async () => undefined, + }; + const { internals } = createCoordinator(owner); + internals.nativeStreamerContext = createContext(); + const videoSession: NonNullable = { + clientUdpPort: 49_006, + mjolnirUdpPort: 49_005, + videoPeerIp: "192.0.2.20", + videoPeerPort: 5_004, + srtpAesKeyHex: "AA".repeat(32), + srtpKeyId: 42, + srtpSaltHex: `${"00".repeat(11)}2A`, + }; + internals.nativeStreamerManager = { + prepareForSession: async () => { + events.push("native-sockets-started"); + }, + waitForNvstTransportReady: async () => { + events.push("waited-for-sctp"); + throw new Error("must not block PLAY"); + }, + } as unknown as NativeStreamerManager; + + await internals.armNativeAfterNvstAnnounce(videoSession); + + assert.deepEqual(events, ["native-sockets-started"]); + assert.equal(internals.nativeStreamerContext?.nvstVideo, videoSession); +}); + +function createCoordinator( + owner: GfnNvstRtspOwner, +): { coordinator: SignalingCoordinator; internals: CoordinatorInternals } { + const coordinator = new SignalingCoordinator({ + ipcMain: {} as never, + mainDir: "", + settingsManager: { + get: (key: string) => key === "streamClientMode" ? "native" : undefined, + } as unknown as SettingsManager, + getMainWindow: () => null, + gfnNvstRtspOwner: owner, + }); + return { + coordinator, + internals: coordinator as unknown as CoordinatorInternals, + }; +} + +test("coordinator starts native after NVST prepare without dropping the reserved socket", async () => { + const events: string[] = []; + const owner: GfnNvstRtspOwner = { + prepare: async (context) => { + events.push("nvst-prepare"); + return { + ...context, + nvstVideo: { + clientUdpPort: 45000, + videoPeerIp: "192.0.2.20", + videoPeerPort: 5004, + srtpAesKeyHex: "AA".repeat(32), + srtpKeyId: 42, + srtpSaltHex: `${"00".repeat(11)}2A`, + }, + }; + }, + videoUdpFd: () => undefined, + handoffVideoUdp: async () => { + events.push("nvst-handoff-video-udp"); + }, + release: async (reason) => { + events.push(`nvst-release:${reason}`); + }, + }; + const { internals } = createCoordinator(owner); + internals.nativeStreamerContext = createContext(); + internals.nativeStreamerManager = { + prepareForSession: async (context: NativeStreamerSessionContext) => { + assert.equal(context.nvstVideo?.clientUdpPort, 45000); + events.push("native-prepare"); + }, + } as unknown as NativeStreamerManager; + + await internals.prepareNativeStreamerBeforeSignaling(); + + assert.deepEqual(events, ["nvst-prepare", "native-prepare", "nvst-handoff-video-udp"]); + assert.equal(internals.nativeStreamerContext?.nvstVideo?.videoPeerPort, 5004); +}); + +test("coordinator releases retained NVST control on explicit native stop", async () => { + const events: string[] = []; + const owner: GfnNvstRtspOwner = { + prepare: async (context) => context, + videoUdpFd: () => undefined, + handoffVideoUdp: async () => undefined, + release: async (reason) => { + events.push(`nvst-release:${reason}`); + }, + }; + const { coordinator, internals } = createCoordinator(owner); + internals.nativeStreamerManager = { + stop: async (reason: string) => { + events.push(`native-stop:${reason}`); + }, + } as unknown as NativeStreamerManager; + + await coordinator.stopNativeStreamer("test stop"); + + assert.deepEqual(events, ["native-stop:test stop", "nvst-release:test stop"]); +}); + +test("coordinator tears down explicit NVST without falling back to WebRTC", async () => { + const events: string[] = []; + const owner: GfnNvstRtspOwner = { + prepare: async (context) => { + events.push("nvst-prepare"); + return context; + }, + videoUdpFd: () => undefined, + handoffVideoUdp: async () => { + events.push("nvst-handoff-video-udp"); + }, + release: async (reason) => { + events.push(`nvst-release:${reason}`); + }, + }; + const { internals } = createCoordinator(owner); + internals.nativeStreamerContext = createContext(); + internals.nativeStreamerManager = { + prepareForSession: async () => { + events.push("native-prepare"); + throw new Error("synthetic native start failure"); + }, + stop: async (reason: string) => { + events.push(`native-stop:${reason}`); + }, + } as unknown as NativeStreamerManager; + + await assert.rejects( + internals.prepareNativeStreamerBeforeSignaling(), + /synthetic native start failure/, + ); + + assert.deepEqual(events, [ + "nvst-prepare", + "native-prepare", + "native-stop:explicit NVST pre-attach startup failed", + "nvst-release:explicit NVST pre-attach startup failed", + ]); +}); + +test("coordinator does not renegotiate WebRTC after native NVST starts", () => { + const owner: GfnNvstRtspOwner = { + prepare: async (context) => context, + videoUdpFd: () => undefined, + handoffVideoUdp: async () => undefined, + release: async () => undefined, + }; + const { internals } = createCoordinator(owner); + const context = createContext(); + context.nvstVideo = { + clientUdpPort: 45000, + videoPeerIp: "192.0.2.20", + videoPeerPort: 5004, + srtpAesKeyHex: "AA".repeat(32), + srtpKeyId: 42, + srtpSaltHex: `${"00".repeat(11)}2A`, + }; + internals.nativeStreamerContext = context; + internals.nativeStreamerManager = { + isNvstSessionActive: (sessionId: string) => sessionId === "gfn-session", + handleOffer: async () => assert.fail("NVST must not handle a WebRTC offer"), + addRemoteIce: async () => assert.fail("NVST must not handle WebRTC ICE"), + } as unknown as NativeStreamerManager; + + internals.routeSignalingEvent({ type: "offer", sdp: "v=0\r\n" }); + internals.routeSignalingEvent({ type: "remote-ice", candidate: "candidate:synthetic" }); +}); diff --git a/opennow-stable/src/main/signaling/signalingCoordinator.ts b/opennow-stable/src/main/signaling/signalingCoordinator.ts index 9b590c8f0..c23320170 100644 --- a/opennow-stable/src/main/signaling/signalingCoordinator.ts +++ b/opennow-stable/src/main/signaling/signalingCoordinator.ts @@ -1,4 +1,4 @@ -import { BrowserWindow, type IpcMain } from "electron"; +import electron, { type BrowserWindow, type IpcMain } from "electron"; import { IPC_CHANNELS } from "@shared/ipc"; import type { IceCandidatePayload, @@ -15,6 +15,10 @@ import type { } from "@shared/gfn"; import { streamDiagnosticId } from "@shared/gfn"; import { setLogContext } from "@shared/logger"; +import { + GfnNvstRtspSessionOwner, + type GfnNvstRtspOwner, +} from "../platforms/gfn/nvstRtsp/owner"; import { GfnSignalingClient } from "../platforms/gfn/signaling"; import { NativeStreamerManager } from "../nativeStreamer/manager"; import { normalizeNativeInputPacket } from "../nativeStreamer/input"; @@ -22,11 +26,14 @@ import { normalizeNativeRenderSurface } from "../nativeStreamer/surface"; import { getNativeCloudGsyncCapabilities } from "../nativeCloudGsync"; import type { SettingsManager } from "../settings"; +const { BrowserWindow: ElectronBrowserWindow } = electron; + export interface SignalingCoordinatorDeps { ipcMain: IpcMain; mainDir: string; settingsManager: SettingsManager; getMainWindow(): BrowserWindow | null; + gfnNvstRtspOwner?: GfnNvstRtspOwner; } export class SignalingCoordinator { @@ -37,11 +44,50 @@ export class SignalingCoordinator { private nativeStreamerFallbackSessionId: string | null = null; private nativeSoftwareRetrySessionId: string | null = null; private lastSignalingPayload: SignalingConnectRequest | null = null; + private readonly gfnNvstRtspOwner: GfnNvstRtspOwner; private sessionDiagnosticState: Record = { phase: "idle", }; - constructor(private readonly deps: SignalingCoordinatorDeps) {} + constructor(private readonly deps: SignalingCoordinatorDeps) { + this.gfnNvstRtspOwner = deps.gfnNvstRtspOwner ?? new GfnNvstRtspSessionOwner({ + reserveVideoUdp: () => this.getNativeStreamerManager().reserveNvstUdp(), + onVideoReady: async (videoSession) => { + const current = this.nativeStreamerContext; + if (!current) { + throw new Error("Native streamer context missing while arming NVST receive"); + } + this.nativeStreamerContext = { + ...current, + nvstVideo: videoSession, + }; + }, + onAnnounceReady: async (videoSession) => { + await this.armNativeAfterNvstAnnounce(videoSession); + }, + }); + } + + private async armNativeAfterNvstAnnounce(videoSession: NonNullable): Promise { + const current = this.nativeStreamerContext; + if (!current) { + throw new Error("Native streamer context missing after NVST ANNOUNCE"); + } + const armed = { + ...current, + nvstVideo: videoSession, + }; + this.nativeStreamerContext = armed; + + // `prepareForSession` returns only after both native UDP receivers have + // inherited their sockets and started. Send PLAY at that point. Waiting + // for the subsequent DTLS/SCTP readiness event here makes resume fragile: + // resumed GFN seats close their short-lived RTSPS control connection while + // that handshake is still completing, and PLAY on a replacement socket is + // acknowledged without activating the Mjolnir video route. NVIDIA likewise + // issues PLAY immediately after starting its transport workers. + await this.getNativeStreamerManager().prepareForSession(armed); + } private retainSessionState(values: Record): void { this.sessionDiagnosticState = { @@ -127,12 +173,18 @@ export class SignalingCoordinator { return; } - const window = BrowserWindow.fromWebContents(event.sender); + const window = ElectronBrowserWindow.fromWebContents(event.sender); if (!window || window.isDestroyed()) { return; } - const surface = normalizeNativeRenderSurface(window, payload); + const surface = normalizeNativeRenderSurface( + window, + payload, + process.platform === "win32" + ? (point) => electron.screen.dipToScreenPoint(point) + : undefined, + ); if (!surface) { return; } @@ -153,7 +205,6 @@ export class SignalingCoordinator { shortcuts, }; } - this.getNativeStreamerManager().updateShortcuts(shortcuts); }, ); @@ -200,6 +251,7 @@ export class SignalingCoordinator { this.signalingClientKey = null; this.nativeStreamerManager?.setVideoBackendOverride(null); this.nativeStreamerManager?.dispose(options.reason); + void this.gfnNvstRtspOwner.release(options.reason); this.nativeStreamerManager = null; this.nativeStreamerContext = null; this.nativeStreamerFallbackSessionId = null; @@ -207,11 +259,15 @@ export class SignalingCoordinator { this.lastSignalingPayload = null; } - stopNativeStreamer(reason: string): void { - void this.nativeStreamerManager?.stop(reason); + async stopNativeStreamer(reason: string): Promise { + await Promise.all([ + this.nativeStreamerManager?.stop(reason), + this.gfnNvstRtspOwner.release(reason), + ]); } resetNativeStreamerContext(): void { + void this.gfnNvstRtspOwner.release("native streamer context reset"); this.nativeStreamerContext = null; this.nativeStreamerFallbackSessionId = null; this.nativeSoftwareRetrySessionId = null; @@ -239,7 +295,6 @@ export class SignalingCoordinator { }; } - this.nativeStreamerManager?.updateBitrateLimit(maxBitrateMbps * 1000); } applySettingsChange( @@ -248,27 +303,24 @@ export class SignalingCoordinator { ): void { if ( (key === "streamClientMode" && value !== "native") || - key === "nativeStreamerBackend" || key === "nativeStreamerExecutablePath" || key === "nativeCloudGsyncMode" || key === "nativeD3dFullscreenMode" || key === "nativeExternalRenderer" || key === "transportMode" ) { - this.stopNativeStreamer( - key === "nativeStreamerBackend" - ? "native streamer backend changed" - : key === "nativeStreamerExecutablePath" - ? "native streamer executable changed" - : key === "nativeCloudGsyncMode" - ? "native Cloud G-Sync mode changed" - : key === "nativeD3dFullscreenMode" - ? "native D3D fullscreen mode changed" - : key === "nativeExternalRenderer" - ? "native external renderer setting changed" - : key === "transportMode" - ? "native transport mode changed" - : "native streamer disabled", + void this.stopNativeStreamer( + key === "nativeStreamerExecutablePath" + ? "native streamer executable changed" + : key === "nativeCloudGsyncMode" + ? "native Cloud G-Sync mode changed" + : key === "nativeD3dFullscreenMode" + ? "native D3D fullscreen mode changed" + : key === "nativeExternalRenderer" + ? "native external renderer setting changed" + : key === "transportMode" + ? "native transport mode changed" + : "native streamer disabled", ); this.resetNativeStreamerContext(); } @@ -280,7 +332,7 @@ export class SignalingCoordinator { "[NativeStreamer] Native video backend changed; active session will keep its current backend until the next native streamer restart.", ); } else { - this.stopNativeStreamer("native video backend changed"); + void this.stopNativeStreamer("native video backend changed"); } } if (key === "maxBitrateMbps") { @@ -289,6 +341,7 @@ export class SignalingCoordinator { } private async connectSignaling(payload: SignalingConnectRequest): Promise { + const previousNativeStreamerContext = this.nativeStreamerContext; if ( this.lastSignalingPayload && this.lastSignalingPayload.sessionId !== payload.sessionId @@ -342,6 +395,16 @@ export class SignalingCoordinator { } if (this.signalingClient && this.signalingClientKey === nextKey) { + if ( + previousNativeStreamerContext?.session.sessionId === payload.sessionId + && previousNativeStreamerContext.nvstVideo + && this.nativeStreamerContext?.settings.transportMode === "nvst" + ) { + this.nativeStreamerContext = { + ...this.nativeStreamerContext, + nvstVideo: previousNativeStreamerContext.nvstVideo, + }; + } console.log( "[Signaling] Reuse existing signaling connection (duplicate connect request ignored)", ); @@ -369,9 +432,12 @@ export class SignalingCoordinator { phase: "signaling-connect-failed", lastError: error instanceof Error ? error.message : String(error), }); - await this.nativeStreamerManager - ?.stop("signaling connect failed") - .catch(() => undefined); + await Promise.all([ + this.nativeStreamerManager + ?.stop("signaling connect failed") + .catch(() => undefined), + this.gfnNvstRtspOwner.release("signaling connect failed"), + ]); this.signalingClient = null; this.signalingClientKey = null; throw error; @@ -383,7 +449,10 @@ export class SignalingCoordinator { phase: "disconnecting", stopReason: "renderer signaling disconnect", }); - await this.nativeStreamerManager?.stop("signaling disconnect"); + await Promise.all([ + this.nativeStreamerManager?.stop("signaling disconnect"), + this.gfnNvstRtspOwner.release("signaling disconnect"), + ]); this.nativeStreamerManager?.setVideoBackendOverride(null); this.nativeStreamerContext = null; this.nativeStreamerFallbackSessionId = null; @@ -398,22 +467,6 @@ export class SignalingCoordinator { private emitToRenderer(event: MainToRendererSignalingEvent): void { const mainWindow = this.deps.getMainWindow(); if (mainWindow && !mainWindow.isDestroyed()) { - if (event.type === "native-stream-stats") { - const serverGpuType = event.stats.serverGpuType?.trim() - || this.nativeStreamerContext?.session.gpuType?.trim() - || undefined; - const serverLocation = event.stats.serverLocation?.trim() - || this.nativeStreamerContext?.session.serverLocation?.trim() - || undefined; - event = { - ...event, - stats: { - ...event.stats, - serverGpuType, - serverLocation, - }, - }; - } mainWindow.webContents.send(IPC_CHANNELS.SIGNALING_EVENT, event); } } @@ -421,7 +474,6 @@ export class SignalingCoordinator { private getNativeStreamerManager(): NativeStreamerManager { this.nativeStreamerManager ??= new NativeStreamerManager({ mainDir: this.deps.mainDir, - getBackendPreference: () => "gstreamer", getVideoBackendPreference: () => this.deps.settingsManager?.get("nativeVideoBackend") ?? "auto", getExecutablePathOverride: () => @@ -432,7 +484,16 @@ export class SignalingCoordinator { this.deps.settingsManager?.get("nativeD3dFullscreenMode") ?? "auto", getExternalRendererEnabled: () => this.deps.settingsManager?.get("nativeExternalRenderer") ?? false, - emit: (event) => this.emitToRenderer(event), + emit: (event) => { + if (event.type === "native-stream-stopped") { + void this.gfnNvstRtspOwner.release( + event.reason + ? `native streamer stopped: ${event.reason}` + : "native streamer stopped", + ); + } + this.emitToRenderer(event); + }, sendAnswer: async (payload) => { if (!this.signalingClient) { throw new Error("Signaling is not connected"); @@ -518,6 +579,9 @@ export class SignalingCoordinator { void this.nativeStreamerManager?.stop( `signaling disconnected: ${event.reason}`, ); + void this.gfnNvstRtspOwner.release( + `signaling disconnected: ${event.reason}`, + ); this.nativeStreamerContext = null; this.nativeStreamerFallbackSessionId = null; this.emitToRenderer(event); @@ -534,6 +598,21 @@ export class SignalingCoordinator { return; } + const nativeNvstActive = this.nativeStreamerManager + ?.isNvstSessionActive(context.session.sessionId) ?? false; + + if ( + nativeNvstActive + && (event.type === "offer" || event.type === "remote-ice") + ) { + console.log( + `[NativeStreamer] Explicit NVST is active; ignoring WebRTC ${event.type} (${ + event.type === "offer" ? `sdpBytes=${event.sdp.length}` : "candidate" + })`, + ); + return; + } + if (event.type === "offer") { void this.handleNativeStreamerOffer(event.sdp, context); return; @@ -562,6 +641,25 @@ export class SignalingCoordinator { await this.getNativeStreamerManager().handleOffer(sdp, context); } catch (error) { const message = error instanceof Error ? error.message : String(error); + if (context.settings.transportMode === "nvst") { + console.warn("[NativeStreamer] Explicit NVST startup failed:", message); + this.retainSessionState({ + streamer: "native", + phase: "native-nvst-failed", + lastError: message, + }); + await Promise.all([ + this.nativeStreamerManager + ?.stop("explicit NVST startup failed") + .catch(() => undefined), + this.gfnNvstRtspOwner.release("explicit NVST startup failed"), + ]); + this.emitToRenderer({ + type: "error", + message: `Native NVST failed: ${message}. WebRTC media fallback is disabled for explicit NVST mode.`, + }); + return; + } console.warn("[NativeStreamer] Falling back to web streamer:", message); this.retainSessionState({ streamer: "web-fallback", @@ -573,9 +671,12 @@ export class SignalingCoordinator { this.nativeStreamerManager?.drainQueuedRemoteIce( context.session.sessionId, ) ?? []; - await this.nativeStreamerManager - ?.stop("native streamer fallback") - .catch(() => undefined); + await Promise.all([ + this.nativeStreamerManager + ?.stop("native streamer fallback") + .catch(() => undefined), + this.gfnNvstRtspOwner.release("native streamer fallback"), + ]); this.emitToRenderer({ type: "error", message: `Native streamer failed: ${message}. Falling back to web streamer.`, @@ -612,9 +713,43 @@ export class SignalingCoordinator { type: "log", message: "Preparing native streamer before signaling attach.", }); - await this.getNativeStreamerManager().prepareForSession(context); + const preparedContext = await this.gfnNvstRtspOwner.prepare(context); + if ( + this.nativeStreamerContext?.session.sessionId + !== preparedContext.session.sessionId + ) { + await this.gfnNvstRtspOwner.release( + "native streamer context changed during NVST preparation", + ); + throw new Error("Native streamer context changed during NVST preparation"); + } + this.nativeStreamerContext = preparedContext; + // Official Bifrost binds the ICE/bundle socket in-process before ANNOUNCE + // and never rebinds. Native reserved that socket during prepare(); start + // must reuse it on the same process. + await this.getNativeStreamerManager().prepareForSession(preparedContext); + await this.gfnNvstRtspOwner.handoffVideoUdp(); } catch (error) { const message = error instanceof Error ? error.message : String(error); + if (context.settings.transportMode === "nvst") { + console.warn("[NativeStreamer] Explicit NVST pre-attach startup failed:", message); + this.retainSessionState({ + streamer: "native", + phase: "native-nvst-pre-attach-failed", + lastError: message, + }); + await Promise.all([ + this.nativeStreamerManager + ?.stop("explicit NVST pre-attach startup failed") + .catch(() => undefined), + this.gfnNvstRtspOwner.release("explicit NVST pre-attach startup failed"), + ]); + this.emitToRenderer({ + type: "error", + message: `Native NVST failed before signaling attach: ${message}. WebRTC media fallback is disabled for explicit NVST mode.`, + }); + throw error; + } console.warn( "[NativeStreamer] Pre-attach startup failed; falling back to web streamer:", message, @@ -625,9 +760,12 @@ export class SignalingCoordinator { lastError: message, }); this.nativeStreamerFallbackSessionId = context.session.sessionId; - await this.nativeStreamerManager - ?.stop("native streamer pre-attach fallback") - .catch(() => undefined); + await Promise.all([ + this.nativeStreamerManager + ?.stop("native streamer pre-attach fallback") + .catch(() => undefined), + this.gfnNvstRtspOwner.release("native streamer pre-attach fallback"), + ]); this.emitToRenderer({ type: "error", message: `Native streamer failed before signaling attach: ${message}. Falling back to web streamer.`, diff --git a/opennow-stable/src/renderer/src/App.tsx b/opennow-stable/src/renderer/src/App.tsx index 17b88f591..7365ebf8b 100644 --- a/opennow-stable/src/renderer/src/App.tsx +++ b/opennow-stable/src/renderer/src/App.tsx @@ -43,7 +43,8 @@ import { useGameLaunch } from "./hooks/streamSession/useGameLaunch"; import { useSignalingEvents } from "./hooks/streamSession/useSignalingEvents"; import { RECOVERABLE_STREAM_STATUSES, - SIGNALING_RECOVERY_ATTEMPT_DELAYS_MS, + SIGNALING_RECOVERY_WINDOW_MS, + nextSignalingRecoveryPollDelayMs, remoteSessionEndCode, sendStreamClipboardPaste, sleep, @@ -781,6 +782,7 @@ export function App(): JSX.Element { resetRecoveryConnectionState(); discordStreamingActivitySessionRef.current = null; signalingRecoveryRef.current.attemptCount = 0; + signalingRecoveryRef.current.deadlineAtMs = null; signalingRecoveryRef.current.inFlight = null; signalingRecoveryRef.current.appId = null; setSession(null); @@ -879,8 +881,7 @@ export function App(): JSX.Element { enableL4S: settings.enableL4S, enableCloudGsync: settings.enableCloudGsync, clientMode: settings.streamClientMode, - nativeStreamerBackend: "gstreamer", - transportMode: "webrtc", + transportMode: settings.transportMode, nativeCloudGsyncMode: settings.nativeCloudGsyncMode, nativeTransitionDiagnostics: settings.nativeTransitionDiagnostics, appLaunchMode: resolveAppLaunchMode({ @@ -906,6 +907,7 @@ export function App(): JSX.Element { settings.nativeTransitionDiagnostics, settings.resolution, settings.streamClientMode, + settings.transportMode, subscriptionInfo?.entitledResolutions, ]); @@ -1850,8 +1852,10 @@ export function App(): JSX.Element { throw new Error("Connection to the running session was lost and your login token is no longer available for resume."); } - if (recoveryState.attemptCount >= SIGNALING_RECOVERY_ATTEMPT_DELAYS_MS.length) { - console.warn("[Recovery] Recovery budget exhausted"); + const now = Date.now(); + recoveryState.deadlineAtMs ??= now + SIGNALING_RECOVERY_WINDOW_MS; + if (now >= recoveryState.deadlineAtMs) { + console.warn("[Recovery] Recovery window expired"); return false; } @@ -1862,23 +1866,29 @@ export function App(): JSX.Element { await disconnectSignalingControlled(); let lastError: Error | null = null; - while (recoveryState.attemptCount < SIGNALING_RECOVERY_ATTEMPT_DELAYS_MS.length) { - const attemptIndex = recoveryState.attemptCount; - recoveryState.attemptCount += 1; - const attemptNumber = recoveryState.attemptCount; - const attemptDelayMs = SIGNALING_RECOVERY_ATTEMPT_DELAYS_MS[attemptIndex] ?? 0; - - console.warn( - `[Recovery] Attempt ${attemptNumber}/${SIGNALING_RECOVERY_ATTEMPT_DELAYS_MS.length} after signaling disconnect: ${reason}`, - ); - - if (attemptDelayMs > 0) { - await sleep(attemptDelayMs); - } + while (Date.now() < (recoveryState.deadlineAtMs ?? 0)) { + const pollDelayMs = nextSignalingRecoveryPollDelayMs({ + attemptCount: recoveryState.attemptCount, + online: navigator.onLine !== false, + nowMs: Date.now(), + deadlineAtMs: recoveryState.deadlineAtMs ?? 0, + }); + if (pollDelayMs === null) break; + if (pollDelayMs > 0) await sleep(pollDelayMs); if (!isRecoveryGenerationCurrent(recoveryGeneration)) { console.log("[Recovery] Aborting attempt after explicit shutdown"); return false; } + if (navigator.onLine === false) { + console.log("[Recovery] Network is offline; waiting before polling the session again"); + continue; + } + + recoveryState.attemptCount += 1; + const attemptNumber = recoveryState.attemptCount; + console.warn( + `[Recovery] Attempt ${attemptNumber} after signaling disconnect: ${reason}`, + ); try { const activeSessions = await window.openNow.getActiveSessions(token, effectiveStreamingBaseUrl); @@ -3095,7 +3105,7 @@ export function App(): JSX.Element { statsPosition={settings.statsOverlayPosition} showNativeStats={settings.showNativeStreamerStats} nativeInputCaptureActive={nativeInputCaptureActive} - gstreamerEnabled={settings.streamClientMode === "native"} + nativeStreamingEnabled={settings.streamClientMode === "native"} nativeExternalRenderer={settings.nativeExternalRenderer} shortcuts={{ toggleStats: formatShortcutForDisplay(settings.shortcutToggleStats, isMac), diff --git a/opennow-stable/src/renderer/src/components/StreamStatsHud.tsx b/opennow-stable/src/renderer/src/components/StreamStatsHud.tsx index 3ce270731..dd0dd4f29 100644 --- a/opennow-stable/src/renderer/src/components/StreamStatsHud.tsx +++ b/opennow-stable/src/renderer/src/components/StreamStatsHud.tsx @@ -46,7 +46,7 @@ export interface StreamStatsHudProps { diagnosticsStore: StreamDiagnosticsStore; mode: "compact" | "full"; position: StatsOverlayPosition; - gstreamerEnabled: boolean; + nativeStreamingEnabled: boolean; serverRegion?: string; sessionTimeRemainingText: string | null; hintsVisible?: boolean; @@ -57,7 +57,7 @@ export function StreamStatsHud({ diagnosticsStore, mode, position, - gstreamerEnabled, + nativeStreamingEnabled, serverRegion, sessionTimeRemainingText, hintsVisible = false, @@ -252,13 +252,13 @@ export function StreamStatsHud({ }), ); lines.push( - gstreamerEnabled - ? t("stream.stats.advancedGstreamerEnabled", { + nativeStreamingEnabled + ? t("stream.stats.advancedNativeEnabled", { state: stats.nativeRendererActive ? t("stream.stats.inUseValue") : t("stream.stats.notActiveValue"), }) - : t("stream.stats.advancedGstreamerDisabled"), + : t("stream.stats.advancedNativeDisabled"), ); if (!stats.nativeRendererActive && stats.transportType !== "unknown") { lines.push(t("stream.stats.advancedIceCandidate", { transport: transportText })); @@ -321,7 +321,7 @@ export function StreamStatsHud({ ); } return lines; - }, [gstreamerEnabled, hasLagIssue, shaderActive, stats, t, transportText]); + }, [nativeStreamingEnabled, hasLagIssue, shaderActive, stats, t, transportText]); const kpiRow = (
diff --git a/opennow-stable/src/renderer/src/components/StreamView.tsx b/opennow-stable/src/renderer/src/components/StreamView.tsx index 4656df56a..4009206ef 100644 --- a/opennow-stable/src/renderer/src/components/StreamView.tsx +++ b/opennow-stable/src/renderer/src/components/StreamView.tsx @@ -52,7 +52,7 @@ interface StreamViewProps { statsPosition: StatsOverlayPosition; showNativeStats?: boolean; nativeInputCaptureActive?: boolean; - gstreamerEnabled: boolean; + nativeStreamingEnabled: boolean; nativeExternalRenderer?: boolean; shortcuts: { toggleStats: string; @@ -135,7 +135,7 @@ export function StreamView({ statsPosition, showNativeStats = false, nativeInputCaptureActive = false, - gstreamerEnabled, + nativeStreamingEnabled, nativeExternalRenderer = false, shortcuts, serverRegion, @@ -444,7 +444,7 @@ export function StreamView({ useEffect(() => { const video = localVideoRef.current; if (!video) return; - const effective = nativeRendererActive || (gstreamerEnabled && isConnecting) + const effective = nativeRendererActive || (nativeStreamingEnabled && isConnecting) ? { ...videoShader, enabled: false } : videoShader; if (!shaderPipelineRef.current) { @@ -453,12 +453,12 @@ export function StreamView({ } else { shaderPipelineRef.current.updateSettings(effective); } - }, [videoShader, gstreamerEnabled, isConnecting, nativeRendererActive]); + }, [videoShader, nativeStreamingEnabled, isConnecting, nativeRendererActive]); useEffect(() => { const video = localVideoRef.current; if (!video) return; - const effective = gstreamerEnabled || nativeRendererActive + const effective = nativeStreamingEnabled || nativeRendererActive ? { ...frameInterpolation, enabled: false } : frameInterpolation; if (!frameInterpolationPipelineRef.current) { @@ -467,7 +467,7 @@ export function StreamView({ } else { frameInterpolationPipelineRef.current.updateSettings(effective); } - }, [frameInterpolation, gstreamerEnabled, nativeRendererActive]); + }, [frameInterpolation, nativeStreamingEnabled, nativeRendererActive]); useEffect(() => () => { shaderPipelineRef.current?.dispose(); @@ -700,7 +700,7 @@ export function StreamView({ const nativeInternalHole = usesNativeInternalSurface({ nativeRendererActive, - nativeStreamingEnabled: gstreamerEnabled, + nativeStreamingEnabled, connecting: isConnecting, externalRenderer: nativeExternalRenderer === true, }); @@ -787,7 +787,7 @@ export function StreamView({ onMouseSensitivityChange={onMouseSensitivityChange} mouseAcceleration={mouseAcceleration} onMouseAccelerationChange={onMouseAccelerationChange} - gstreamerEnabled={gstreamerEnabled} + nativeStreamingEnabled={nativeStreamingEnabled} videoShader={videoShader} onVideoShaderChange={onVideoShaderChange} frameInterpolation={frameInterpolation} @@ -876,7 +876,7 @@ export function StreamView({ diagnosticsStore={diagnosticsStore} mode={statsMode === "full" ? "full" : "compact"} position={statsPosition} - gstreamerEnabled={gstreamerEnabled} + nativeStreamingEnabled={nativeStreamingEnabled} serverRegion={serverRegion} sessionTimeRemainingText={showSessionTimeRemainingInStats ? sessionTimeRemainingText : null} hintsVisible={showHints} diff --git a/opennow-stable/src/renderer/src/components/settings/sections/SettingsNativeStreamerSection.tsx b/opennow-stable/src/renderer/src/components/settings/sections/SettingsNativeStreamerSection.tsx index 5e0bf3484..9bceab634 100644 --- a/opennow-stable/src/renderer/src/components/settings/sections/SettingsNativeStreamerSection.tsx +++ b/opennow-stable/src/renderer/src/components/settings/sections/SettingsNativeStreamerSection.tsx @@ -9,11 +9,11 @@ import { } from "@shared/gfn"; import { useTranslation } from "../../../i18n"; import { - formatGstreamerRuntimeLabel, + formatNativeRuntimeLabel, formatNativeVideoCodec, formatNativeVideoBackendName, getAvailableNativeCodecLabels, - getGstreamerRuntimeBadgeClass, + getNativeRuntimeBadgeClass, nativeVideoBackendOptions, } from "../settingsFormatters"; import { MotionSpinner } from "../../MotionSpinner"; @@ -68,11 +68,11 @@ export function SettingsNativeStreamerSection({ ).length; const activeVideoBackendId = nativeStreamerStatus?.activeVideoBackend?.backend; const primaryStatusMessage = nativeStreamerStatus?.message.trim() ?? ""; - const runtimeStatusMessage = nativeStreamerStatus?.gstreamerRuntime.message.trim() ?? ""; + const runtimeStatusMessage = nativeStreamerStatus?.runtime.message.trim() ?? ""; const distinctRuntimeStatusMessage = runtimeStatusMessage && runtimeStatusMessage !== primaryStatusMessage ? runtimeStatusMessage : ""; - const runtimePath = nativeStreamerStatus?.gstreamerRuntime.path?.trim() ?? ""; + const runtimePath = nativeStreamerStatus?.runtime.path?.trim() ?? ""; const refreshNativeStreamerStatus = useCallback(async () => { if (!isNativeStreamerPlatform) { @@ -88,12 +88,12 @@ export function SettingsNativeStreamerSection({ console.warn("[Settings] Failed to detect native streamer:", error); setNativeStreamerStatus({ detected: false, - gstreamerAvailable: false, + available: false, supportsOfferAnswer: false, - gstreamerRuntime: { + runtime: { source: "unknown", - bundled: false, - message: "GStreamer runtime could not be checked.", + selfContained: false, + message: "Native runtime could not be checked.", }, message: "Native streamer status could not be checked.", }); @@ -222,6 +222,33 @@ export function SettingsNativeStreamerSection({
+ {settings.streamClientMode === "native" && ( +
+ +
+ + +
+ + {t("settings.nativeStreamer.transportModeHint")} + +
+ )} +
@@ -287,27 +314,13 @@ export function SettingsNativeStreamerSection({ {runtimePath ? ( - {nativeStreamerStatus?.gstreamerRuntime.bundled - ? t("settings.nativeStreamer.bundledPathDetected") - : t("settings.nativeStreamer.gstreamerRuntime")} + {nativeStreamerStatus?.runtime.selfContained + ? t("settings.nativeStreamer.nativeExecutablePath") + : t("settings.nativeStreamer.nativeRuntime")} {runtimePath} ) : null} - {!nativeStreamerStatus?.gstreamerAvailable && nativeStreamerStatus?.gstreamerRuntime.installInstructions?.length ? ( -
- - {t("settings.nativeStreamer.linuxRuntimeHint")} - - {nativeStreamerStatus.gstreamerRuntime.installInstructions.map((instruction) => ( -
- {instruction.distro} - {instruction.command} - {instruction.note ? {instruction.note} : null} -
- ))} -
- ) : null}
@@ -395,7 +408,7 @@ export function SettingsNativeStreamerSection({ )} - {(!nativeStreamerStatus?.gstreamerAvailable || hostVideoBackends.length === 0) && ( + {(!nativeStreamerStatus?.available || hostVideoBackends.length === 0) && ( {nativeStreamerStatus?.activeVideoBackend?.reason ?? t("settings.nativeStreamer.capabilityProbeHint")} diff --git a/opennow-stable/src/renderer/src/components/settings/settingsFormatters.ts b/opennow-stable/src/renderer/src/components/settings/settingsFormatters.ts index 40c209667..c942dfa27 100644 --- a/opennow-stable/src/renderer/src/components/settings/settingsFormatters.ts +++ b/opennow-stable/src/renderer/src/components/settings/settingsFormatters.ts @@ -46,7 +46,7 @@ export const colorQualityOptions: { value: ColorQuality; label: string; descript export const nativeVideoBackendOptions: { value: NativeVideoBackendPreference; label: string; description: string }[] = [ { value: "auto", label: "Auto", description: "Pick the default native path for the session" }, - { value: "d3d12", label: "DirectX 12", description: "Use the D3D12 decoder and renderer" }, + { value: "d3d12", label: "DirectX 12", description: "Use D3D11-on-12 for Media Foundation decode and D3D12-backed rendering" }, { value: "d3d11", label: "DirectX 11", description: "Use the D3D11 decoder and renderer" }, { value: "nvdec", label: "NVIDIA NVDEC", description: "Use NVIDIA's native Linux hardware decoders" }, { value: "vaapi", label: "VAAPI", description: "Use Linux VA-API hardware decoding" }, @@ -118,12 +118,10 @@ export function getAvailableNativeCodecLabels(backend: NativeVideoBackendCapabil .map((codec) => formatNativeVideoCodec(codec.codec)) ?? []; } -export function formatGstreamerRuntimeLabel(status: NativeStreamerStatus | null): string { - switch (status?.gstreamerRuntime.source) { - case "bundled": - return status.gstreamerAvailable ? "Bundled Runtime Used" : "Bundled Runtime Found"; - case "system": - return "System Runtime"; +export function formatNativeRuntimeLabel(status: NativeStreamerStatus | null): string { + switch (status?.runtime.source) { + case "self-contained": + return status.available ? "Native Runtime Ready" : "Native Runtime Found"; case "missing": return "Runtime Missing"; default: @@ -131,9 +129,8 @@ export function formatGstreamerRuntimeLabel(status: NativeStreamerStatus | null) } } -export function getGstreamerRuntimeBadgeClass(status: NativeStreamerStatus | null): string { - if (status?.gstreamerRuntime.source === "bundled" && status.gstreamerAvailable) return "settings-inline-badge--codec-gpu"; - if (status?.gstreamerRuntime.source === "system" && status.gstreamerAvailable) return "settings-inline-badge--codec-testing"; +export function getNativeRuntimeBadgeClass(status: NativeStreamerStatus | null): string { + if (status?.runtime.source === "self-contained" && status.available) return "settings-inline-badge--codec-gpu"; return "settings-inline-badge--updater-error"; } diff --git a/opennow-stable/src/renderer/src/components/settings/settingsTypes.ts b/opennow-stable/src/renderer/src/components/settings/settingsTypes.ts index 9c05dc9df..d9c2c73b2 100644 --- a/opennow-stable/src/renderer/src/components/settings/settingsTypes.ts +++ b/opennow-stable/src/renderer/src/components/settings/settingsTypes.ts @@ -154,7 +154,7 @@ export const SETTINGS_SCOPE_SEARCH_TERMS: Record void; mouseAcceleration: number; onMouseAccelerationChange: (value: number) => void; - gstreamerEnabled: boolean; + nativeStreamingEnabled: boolean; videoShader: VideoShaderSettings; onVideoShaderChange: (value: VideoShaderSettings) => void; frameInterpolation: FrameInterpolationSettings; @@ -104,7 +104,7 @@ export function StreamQuickMenu({ onMouseSensitivityChange, mouseAcceleration, onMouseAccelerationChange, - gstreamerEnabled, + nativeStreamingEnabled, videoShader, onVideoShaderChange, frameInterpolation, @@ -258,7 +258,7 @@ export function StreamQuickMenu({ onMouseSensitivityChange={onMouseSensitivityChange} mouseAcceleration={mouseAcceleration} onMouseAccelerationChange={onMouseAccelerationChange} - gstreamerEnabled={gstreamerEnabled} + nativeStreamingEnabled={nativeStreamingEnabled} videoShader={videoShader} onVideoShaderChange={onVideoShaderChange} frameInterpolation={frameInterpolation} diff --git a/opennow-stable/src/renderer/src/components/stream/quick-menu/StreamQuickMenuControlsPage.tsx b/opennow-stable/src/renderer/src/components/stream/quick-menu/StreamQuickMenuControlsPage.tsx index 925c2fea7..73d325c0c 100644 --- a/opennow-stable/src/renderer/src/components/stream/quick-menu/StreamQuickMenuControlsPage.tsx +++ b/opennow-stable/src/renderer/src/components/stream/quick-menu/StreamQuickMenuControlsPage.tsx @@ -32,7 +32,7 @@ interface StreamQuickMenuControlsPageProps { onMouseSensitivityChange: (value: number) => void; mouseAcceleration: number; onMouseAccelerationChange: (value: number) => void; - gstreamerEnabled: boolean; + nativeStreamingEnabled: boolean; videoShader: VideoShaderSettings; onVideoShaderChange: (value: VideoShaderSettings) => void; frameInterpolation: FrameInterpolationSettings; @@ -49,7 +49,7 @@ export function StreamQuickMenuControlsPage({ onMouseSensitivityChange, mouseAcceleration, onMouseAccelerationChange, - gstreamerEnabled, + nativeStreamingEnabled, videoShader, onVideoShaderChange, frameInterpolation, @@ -120,7 +120,7 @@ export function StreamQuickMenuControlsPage({ Frame Interpolation Experimental Framegen WebGPU processing. - {gstreamerEnabled ? ( + {nativeStreamingEnabled ? ( Frame interpolation is unavailable while the native streamer renders the video. @@ -196,7 +196,7 @@ export function StreamQuickMenuControlsPage({ Video Filters GPU shaders applied to the stream. - {gstreamerEnabled ? ( + {nativeStreamingEnabled ? ( Video filters are unavailable while the native streamer renders the video. ) : ( <> diff --git a/opennow-stable/src/renderer/src/hooks/streamSession/useGameLaunch.ts b/opennow-stable/src/renderer/src/hooks/streamSession/useGameLaunch.ts index c6b9bdc07..0f17484d9 100644 --- a/opennow-stable/src/renderer/src/hooks/streamSession/useGameLaunch.ts +++ b/opennow-stable/src/renderer/src/hooks/streamSession/useGameLaunch.ts @@ -247,9 +247,14 @@ export function useGameLaunch({ const otherSession = activeSessions.find((s) => s.status === 2 || s.status === 3) ?? null; if (matchingSession) { - await claimAndConnectSession(matchingSession); - setNavbarActiveSession(null); - return; + if (streamSettings.transportMode === "nvst") { + // Leftover NVST seats can carry the legacy "PING" streamer pool; always fresh-create. + existingSessionStrategy = "force-new"; + } else { + await claimAndConnectSession(matchingSession); + setNavbarActiveSession(null); + return; + } } if (otherSession) { diff --git a/opennow-stable/src/renderer/src/hooks/streamSession/useSessionRecoveryRuntime.ts b/opennow-stable/src/renderer/src/hooks/streamSession/useSessionRecoveryRuntime.ts index 76e80c594..b2fe2096c 100644 --- a/opennow-stable/src/renderer/src/hooks/streamSession/useSessionRecoveryRuntime.ts +++ b/opennow-stable/src/renderer/src/hooks/streamSession/useSessionRecoveryRuntime.ts @@ -72,6 +72,7 @@ export function useSessionRecoveryRuntime(runtime: RecoveryRuntime) { resetRecoveryConnectionState(); signalingRecoveryRef.current.generation += 1; signalingRecoveryRef.current.attemptCount = 0; + signalingRecoveryRef.current.deadlineAtMs = null; signalingRecoveryRef.current.inFlight = null; signalingRecoveryRef.current.appId = null; if (!options?.keepExplicitShutdown) { @@ -83,6 +84,7 @@ export function useSessionRecoveryRuntime(runtime: RecoveryRuntime) { resetRecoveryConnectionState(); signalingRecoveryRef.current.generation += 1; signalingRecoveryRef.current.explicitShutdown = true; + signalingRecoveryRef.current.deadlineAtMs = null; signalingRecoveryRef.current.inFlight = null; }, [resetRecoveryConnectionState, signalingRecoveryRef]); diff --git a/opennow-stable/src/renderer/src/hooks/streamSession/useSignalingEvents.ts b/opennow-stable/src/renderer/src/hooks/streamSession/useSignalingEvents.ts index 6d8cead00..846d930b5 100644 --- a/opennow-stable/src/renderer/src/hooks/streamSession/useSignalingEvents.ts +++ b/opennow-stable/src/renderer/src/hooks/streamSession/useSignalingEvents.ts @@ -8,10 +8,9 @@ import { SIGNALING_REMOTE_ICE_GRACE_MS, isRemoteSessionEndReason, readStreamClipboardText, - sendStreamClipboardPaste, } from "../../lib/streamSessionHelpers"; import { streamStatusToLoadingStage } from "../../lib/sessionState"; -import { mergeNativeStreamStats } from "../../lib/streamDiagnostics"; +import { nativeInputLifecycleAction } from "../../lib/nativeInputReadiness"; import { decideSignalingDisconnect } from "../../lib/streamRecoveryDecisions"; import { warningMessage, warningTone } from "../../lib/sessionWarnings"; import { resolveStreamProfileCodec } from "../../lib/codecDiagnostics"; @@ -56,7 +55,6 @@ export function useSignalingEvents({ awaitingRecoveryRemoteIceRef, clientRef, hasConfirmedRemoteIceRef, - handleStreamShortcutActionRef, iceDisconnectedRecoveryTimerRef, latestIceConnectionStateRef, launchInFlightRef, @@ -164,7 +162,10 @@ export function useSignalingEvents({ return clientRef.current; }; - const activateNativeInputForCurrentSession = (protocolVersion?: number): void => { + const activateNativeInputForCurrentSession = ( + protocolVersion?: number, + inputOwner?: "electron" | "native", + ): void => { const activeSession = sessionRef.current; if (!activeSession) { console.warn("[App] Received native stream event but no active session in sessionRef!"); @@ -182,10 +183,6 @@ export function useSignalingEvents({ nativeStreamingRef.current = true; pendingControlledDisconnectsRef.current = 0; - const isWindowsHost = navigator.platform.toLowerCase().includes("win"); - const electronInputBridge = - /linux/i.test(`${navigator.platform} ${navigator.userAgent}`) - || (!settings.nativeExternalRenderer && !isWindowsHost); client.activateNativeInput( protocolVersion, { @@ -196,19 +193,12 @@ export function useSignalingEvents({ maxBitrateKbps: settings.maxBitrateMbps * 1000, }, { - // Windows internal: RawInput on the child HWND (Electron click-through is flaky). - // Linux: always Electron → IPC (External floating renderer is unsupported). - // macOS internal: Electron → IPC. External floating window: always OS capture. - electronInputBridge, + electronInputBridge: inputOwner + ? inputOwner === "electron" + : !settings.nativeExternalRenderer, }, ); - // The external native window exclusively owns Escape through RawInput. - // Internal mode leaves Escape with Electron so it can prevent Chromium's - // fullscreen exit and forward one synthetic tap to the native streamer. - window.openNow.notifyNativeInputModeChange( - true, - isWindowsHost && settings.nativeExternalRenderer, - ); + window.openNow.notifyNativeInputModeChange(true, false); setLaunchError(null); setStreamStatus("streaming"); markDiscordStreamStarted(); @@ -296,49 +286,56 @@ export function useSignalingEvents({ ); } } else if (event.type === "native-stream-started") { + const inputAction = nativeInputLifecycleAction(event); console.log("[App] Native streamer started:", event.message ?? ""); + nativeStreamingRef.current = true; + setLaunchError(null); + setStreamStatus("streaming"); + if (nativeInputProtocolVersionRef.current === null) { + setNativeInputBridgeReady(false); + } diagnosticsStore.set({ ...diagnosticsStore.getSnapshot(), nativeRendererActive: true, + inputReady: nativeInputProtocolVersionRef.current !== null, + lagReasonDetail: inputAction.state === "pending" + ? "Native renderer active; input bridge pending" + : diagnosticsStore.getSnapshot().lagReasonDetail, }); - activateNativeInputForCurrentSession(nativeInputProtocolVersionRef.current ?? undefined); + const activeSession = sessionRef.current; + if (!activeSession) { + console.warn("[App] Native streamer started without an active session"); + return; + } + markDiscordStreamStarted(); + scheduleStableRecoveryReset(activeSession.sessionId); } else if (event.type === "native-input-ready") { + const inputAction = nativeInputLifecycleAction(event); console.log("[App] Native input protocol ready:", event.protocolVersion); nativeInputProtocolVersionRef.current = event.protocolVersion; setNativeInputBridgeReady(true); clientRef.current?.setNativeInputProtocolVersion(event.protocolVersion); - if (nativeStreamingRef.current || sessionRef.current) { - activateNativeInputForCurrentSession(event.protocolVersion); - } - } else if (event.type === "native-shortcut") { - handleStreamShortcutActionRef.current?.(event.action); - } else if (event.type === "native-clipboard-paste") { - if (settings.clipboardPaste && (!nativeStreamingRef.current || nativeInputBridgeReady)) { - void sendStreamClipboardPaste(clientRef.current); + if (inputAction.activate && (nativeStreamingRef.current || sessionRef.current)) { + activateNativeInputForCurrentSession( + inputAction.protocolVersion, + event.inputOwner, + ); } - } else if (event.type === "native-input-capture-changed") { - setNativeInputCaptureActive(event.captured); - // Treat OS RawInput capture like pointer lock so main-process Escape - // interception keeps Chromium from exiting fullscreen on tap. - try { - window.openNow.notifyPointerLockChange(event.captured); - } catch { - /* best-effort */ + } else if (event.type === "native-input-unavailable") { + const inputAction = nativeInputLifecycleAction(event); + if (inputAction.state !== "unavailable") { + return; } - } else if (event.type === "native-stream-stats") { - diagnosticsStore.set(mergeNativeStreamStats( - diagnosticsStore.getSnapshot(), - event.stats, - )); - } else if (event.type === "native-stream-transition") { + console.warn("[App] Native input unavailable:", inputAction.reason); + nativeInputProtocolVersionRef.current = null; + setNativeInputBridgeReady(false); + setNativeInputCaptureActive(false); + clientRef.current?.markNativeInputUnavailable(inputAction.reason); + window.openNow.notifyNativeInputModeChange(false, false); diagnosticsStore.set({ ...diagnosticsStore.getSnapshot(), - nativeRendererActive: true, - nativeTransitionSummary: event.transition.summary, - nativeRequestedFps: event.transition.requestedFps, - nativeCapsFramerate: event.transition.capsFramerate, - nativeQueueMode: event.transition.queueMode, - lagReasonDetail: event.transition.summary ?? "Native video transition detected", + inputReady: false, + lagReasonDetail: `Native input unavailable: ${inputAction.reason}`, }); } else if (event.type === "native-stream-stopped") { const reason = event.reason ?? "Native streamer stopped"; diff --git a/opennow-stable/src/renderer/src/hooks/streamSession/useStreamRuntimeState.ts b/opennow-stable/src/renderer/src/hooks/streamSession/useStreamRuntimeState.ts index 4e2874aec..92d4f14ac 100644 --- a/opennow-stable/src/renderer/src/hooks/streamSession/useStreamRuntimeState.ts +++ b/opennow-stable/src/renderer/src/hooks/streamSession/useStreamRuntimeState.ts @@ -78,6 +78,7 @@ export function useStreamRuntimeState() { const pendingControlledDisconnectsRef = useRef(0); const signalingRecoveryRef = useRef({ attemptCount: 0, + deadlineAtMs: null, inFlight: null, explicitShutdown: false, appId: null, diff --git a/opennow-stable/src/renderer/src/hooks/useStreamSession.ts b/opennow-stable/src/renderer/src/hooks/useStreamSession.ts index 4acefd423..75e5e61b4 100644 --- a/opennow-stable/src/renderer/src/hooks/useStreamSession.ts +++ b/opennow-stable/src/renderer/src/hooks/useStreamSession.ts @@ -12,10 +12,12 @@ export function useStreamSession() { export { ICE_DISCONNECTED_RECOVERY_GRACE_MS, RECOVERABLE_STREAM_STATUSES, - SIGNALING_RECOVERY_ATTEMPT_DELAYS_MS, + SIGNALING_RECOVERY_POLL_INTERVAL_MS, SIGNALING_RECOVERY_STABLE_RESET_DELAY_MS, + SIGNALING_RECOVERY_WINDOW_MS, SIGNALING_REMOTE_ICE_GRACE_MS, isRemoteSessionEndReason, + nextSignalingRecoveryPollDelayMs, remoteSessionEndCode, readStreamClipboardText, sendStreamClipboardPaste, diff --git a/opennow-stable/src/renderer/src/lib/nativeInputReadiness.test.ts b/opennow-stable/src/renderer/src/lib/nativeInputReadiness.test.ts new file mode 100644 index 000000000..3ba30c318 --- /dev/null +++ b/opennow-stable/src/renderer/src/lib/nativeInputReadiness.test.ts @@ -0,0 +1,25 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import { nativeInputLifecycleAction } from "./nativeInputReadiness"; + +test("native stream start leaves input pending without activating capture", () => { + assert.deepEqual( + nativeInputLifecycleAction({ type: "native-stream-started" }), + { state: "pending", activate: false }, + ); +}); + +test("only native input ready activates capture", () => { + assert.deepEqual( + nativeInputLifecycleAction({ type: "native-input-ready", protocolVersion: 3 }), + { state: "ready", activate: true, protocolVersion: 3 }, + ); +}); + +test("native input unavailable records a truthful reason without activating capture", () => { + assert.deepEqual( + nativeInputLifecycleAction({ type: "native-input-unavailable", reason: "data channel failed" }), + { state: "unavailable", activate: false, reason: "data channel failed" }, + ); +}); diff --git a/opennow-stable/src/renderer/src/lib/nativeInputReadiness.ts b/opennow-stable/src/renderer/src/lib/nativeInputReadiness.ts new file mode 100644 index 000000000..77a0775f6 --- /dev/null +++ b/opennow-stable/src/renderer/src/lib/nativeInputReadiness.ts @@ -0,0 +1,34 @@ +import type { MainToRendererSignalingEvent } from "@shared/gfn"; + +type NativeInputLifecycleEvent = Extract< + MainToRendererSignalingEvent, + { type: "native-stream-started" | "native-input-ready" | "native-input-unavailable" | "native-stream-stopped" } +>; + +export type NativeInputLifecycleAction = + | { state: "pending"; activate: false } + | { state: "ready"; activate: true; protocolVersion: number } + | { state: "unavailable"; activate: false; reason: string }; + +export function nativeInputLifecycleAction( + event: NativeInputLifecycleEvent, +): NativeInputLifecycleAction { + if (event.type === "native-input-ready") { + return { + state: "ready", + activate: true, + protocolVersion: event.protocolVersion, + }; + } + if (event.type === "native-input-unavailable") { + return { state: "unavailable", activate: false, reason: event.reason }; + } + if (event.type === "native-stream-stopped") { + return { + state: "unavailable", + activate: false, + reason: event.reason ?? "Native streamer stopped", + }; + } + return { state: "pending", activate: false }; +} diff --git a/opennow-stable/src/renderer/src/lib/streamDiagnostics.test.ts b/opennow-stable/src/renderer/src/lib/streamDiagnostics.test.ts index b85bc6da4..bfb3e6036 100644 --- a/opennow-stable/src/renderer/src/lib/streamDiagnostics.test.ts +++ b/opennow-stable/src/renderer/src/lib/streamDiagnostics.test.ts @@ -1,63 +1,15 @@ import assert from "node:assert/strict"; import test from "node:test"; -import type { NativeStreamStats } from "@shared/gfn"; +import { defaultDiagnostics } from "./streamDiagnostics"; -import { defaultDiagnostics, mergeNativeStreamStats } from "./streamDiagnostics"; +test("default diagnostics do not claim unavailable native measurements", () => { + const diagnostics = defaultDiagnostics(); -function nativeStats(overrides: Partial = {}): NativeStreamStats { - return { - codec: "H265", - resolution: "2560x1440", - hardwareAcceleration: "NVDEC", - bitrateKbps: 22_000, - targetBitrateKbps: 35_000, - bitratePerformancePercent: 63, - decodedFps: 118, - renderFps: 117, - framesDecoded: 10_000, - framesRendered: 9_990, - zeroCopyD3D11: false, - zeroCopyD3D12: false, - ...overrides, - }; -} - -test("native diagnostics leave receive and ICE available bitrate unknown", () => { - const current = { - ...defaultDiagnostics(), - receiveFps: 120, - availableBitrateKbps: 48_000, - }; - - const merged = mergeNativeStreamStats(current, nativeStats()); - - assert.equal(merged.decodeFps, 118); - assert.equal(merged.targetBitrateKbps, 35_000); - assert.equal(merged.receiveFps, 0); - assert.equal(merged.availableBitrateKbps, 0); -}); - -test("native diagnostics map and preserve server GPU metadata", () => { - const mapped = mergeNativeStreamStats( - defaultDiagnostics(), - nativeStats({ serverGpuType: "4080h / L40S" }), - ); - const preserved = mergeNativeStreamStats(mapped, nativeStats()); - - assert.equal(mapped.serverGpuType, "GeForce RTX 4080"); - assert.equal(preserved.serverGpuType, "GeForce RTX 4080"); -}); - -test("native diagnostics normalize and preserve server region metadata", () => { - const mapped = mergeNativeStreamStats( - defaultDiagnostics(), - nativeStats({ serverLocation: "npa-yes-kul-01.yes.geforcenow.nvidiagrid.net:443" }), - ); - const preserved = mergeNativeStreamStats(mapped, nativeStats()); - - assert.equal(mapped.serverLocation, "npa-yes-kul-01.yes.geforcenow.nvidiagrid.net:443"); - assert.equal(mapped.serverRegion, "npa-yes-kul-01.yes.geforcenow.nvidiagrid.net"); - assert.equal(preserved.serverLocation, mapped.serverLocation); - assert.equal(preserved.serverRegion, mapped.serverRegion); + assert.equal(diagnostics.nativeRendererActive, false); + assert.equal(diagnostics.inputReady, false); + assert.equal(diagnostics.bitrateKbps, 0); + assert.equal(diagnostics.targetBitrateKbps, 0); + assert.equal(diagnostics.decodeFps, 0); + assert.equal(diagnostics.renderFps, 0); }); diff --git a/opennow-stable/src/renderer/src/lib/streamDiagnostics.ts b/opennow-stable/src/renderer/src/lib/streamDiagnostics.ts index a55c8c6ba..f10cec4e8 100644 --- a/opennow-stable/src/renderer/src/lib/streamDiagnostics.ts +++ b/opennow-stable/src/renderer/src/lib/streamDiagnostics.ts @@ -1,9 +1,3 @@ -import type { NativeStreamStats } from "@shared/gfn"; - -import { - mapServerGpuType, - normalizeServerRegion, -} from "../platforms/gfn/webrtc/sessionDiagnostics"; import type { StreamDiagnostics } from "../platforms/gfn/webrtcClient"; export function defaultDiagnostics(): StreamDiagnostics { @@ -74,73 +68,3 @@ export function defaultDiagnostics(): StreamDiagnostics { micEnabled: false, }; } - -export function mergeNativeStreamStats( - current: StreamDiagnostics, - stats: NativeStreamStats, -): StreamDiagnostics { - const sinkDropped = stats.sinkDropped ?? 0; - const sinkRendered = stats.sinkRendered ?? stats.framesRendered; - const totalSinkFrames = sinkRendered + sinkDropped; - const dropPercent = totalSinkFrames > 0 ? (sinkDropped / totalSinkFrames) * 100 : 0; - const hardwareAcceleration = [ - stats.hardwareAcceleration || "GStreamer native decode", - stats.zeroCopy && stats.memoryMode ? `${stats.memoryMode} zero-copy` : "", - !stats.zeroCopy && stats.memoryMode ? stats.memoryMode : "", - !stats.memoryMode && stats.zeroCopyD3D12 ? "D3D12 zero-copy" : "", - !stats.memoryMode && stats.zeroCopyD3D11 ? "D3D11 zero-copy" : "", - ].filter(Boolean).join(" · "); - - return { - ...current, - connectionState: "connected", - inputReady: current.inputReady, - nativeRendererActive: true, - resolution: stats.resolution || current.resolution, - codec: stats.codec || current.codec, - requestedCodec: current.requestedCodec || stats.codec, - hardwareAcceleration, - bitrateKbps: stats.bitrateKbps, - targetBitrateKbps: stats.targetBitrateKbps, - availableBitrateKbps: 0, - decodeFps: Math.round(stats.decodedFps), - receiveFps: 0, - renderFps: Math.round(stats.renderFps), - transportType: "unknown", - localCandidateType: "", - framesReceived: stats.framesDecoded, - framesDecoded: stats.framesDecoded, - framesDropped: sinkDropped, - packetLossPercent: dropPercent, - inputQueueBufferedBytes: 0, - inputQueuePeakBufferedBytes: 0, - partiallyReliableInputQueueBufferedBytes: 0, - partiallyReliableInputQueuePeakBufferedBytes: 0, - inputQueueDropCount: 0, - inputQueueMaxSchedulingDelayMs: 0, - mouseAdaptiveFlushActive: false, - mousePacketsPerSecond: 0, - mouseResidualMagnitude: 0, - lagReason: dropPercent > 1 ? "render" : "stable", - lagReasonDetail: stats.lastTransitionSummary - ? `Native bitrate ${stats.bitratePerformancePercent.toFixed(0)}% of target · ${stats.lastTransitionSummary}` - : `Native bitrate ${stats.bitratePerformancePercent.toFixed(0)}% of target`, - decoderPressureActive: false, - nativeRequestedFps: stats.requestedFps, - nativeCapsFramerate: stats.capsFramerate, - nativeQueueMode: stats.queueMode, - nativeFramesPendingToPresent: stats.framesPendingToPresent, - nativePartialFlushCount: stats.partialFlushCount, - nativeCompleteFlushCount: stats.completeFlushCount, - nativeTransitionSummary: stats.lastTransitionSummary, - nativeRequestedStreamingFeaturesSummary: stats.requestedStreamingFeaturesSummary, - nativeFinalizedStreamingFeaturesSummary: stats.finalizedStreamingFeaturesSummary, - serverGpuType: stats.serverGpuType - ? mapServerGpuType(stats.serverGpuType) - : current.serverGpuType, - serverLocation: stats.serverLocation?.trim() || current.serverLocation, - serverRegion: stats.serverLocation - ? normalizeServerRegion(stats.serverLocation) - : current.serverRegion, - }; -} diff --git a/opennow-stable/src/renderer/src/lib/streamRecoveryDecisions.ts b/opennow-stable/src/renderer/src/lib/streamRecoveryDecisions.ts index 0e362bf2f..d909ce516 100644 --- a/opennow-stable/src/renderer/src/lib/streamRecoveryDecisions.ts +++ b/opennow-stable/src/renderer/src/lib/streamRecoveryDecisions.ts @@ -41,7 +41,20 @@ export function decideSignalingDisconnect({ ) { return "ignore-active-ice"; } - if (!hasConfirmedRemoteIce) return "fail-before-remote-ice"; + if (!hasConfirmedRemoteIce) { + // A 1006 WebSocket close is surfaced without its numeric code as one of + // these generic reasons. It is neither a remote session end nor a + // controlled shutdown, so let the existing bounded recovery window reclaim + // the session instead of permanently abandoning it before ICE arrives. + const normalizedReason = reason.trim().toLowerCase(); + if ( + normalizedReason === "socket closed" + || normalizedReason === "signaling disconnected: socket closed" + ) { + return "recover"; + } + return "fail-before-remote-ice"; + } if (pendingControlledDisconnects > 0) return "ignore-controlled-disconnect"; return "recover"; } diff --git a/opennow-stable/src/renderer/src/lib/streamRuntimeDecisions.test.ts b/opennow-stable/src/renderer/src/lib/streamRuntimeDecisions.test.ts index 2c59c9f80..0698f3ebf 100644 --- a/opennow-stable/src/renderer/src/lib/streamRuntimeDecisions.test.ts +++ b/opennow-stable/src/renderer/src/lib/streamRuntimeDecisions.test.ts @@ -143,6 +143,14 @@ test("disconnect recovery only treats explicit remote peer termination as a sess iceState: "failed", pendingControlledDisconnects: 0, }), "recover"); + assert.equal(decideSignalingDisconnect({ + appUnloading: false, + streamStatus: "connecting", + reason, + hasConfirmedRemoteIce: false, + iceState: "new", + pendingControlledDisconnects: 0, + }), "recover"); } }); diff --git a/opennow-stable/src/renderer/src/lib/streamSessionHelpers.test.ts b/opennow-stable/src/renderer/src/lib/streamSessionHelpers.test.ts index 11be1c812..2a07809f4 100644 --- a/opennow-stable/src/renderer/src/lib/streamSessionHelpers.test.ts +++ b/opennow-stable/src/renderer/src/lib/streamSessionHelpers.test.ts @@ -4,7 +4,10 @@ import test from "node:test"; import assert from "node:assert/strict"; import type { SessionInfo } from "@shared/gfn"; -import { disposeSessionCreatedAfterAbort } from "./streamSessionHelpers"; +import { + disposeSessionCreatedAfterAbort, + nextSignalingRecoveryPollDelayMs, +} from "./streamSessionHelpers"; const session = { sessionId: "late-session" } as SessionInfo; @@ -29,3 +32,30 @@ test("an active launch keeps its newly created session", async () => { assert.equal(disposed, false); assert.equal(stopCalls, 0); }); + +test("signaling recovery polls immediately online and waits without burning offline attempts", () => { + assert.equal(nextSignalingRecoveryPollDelayMs({ + attemptCount: 0, + online: true, + nowMs: 1_000, + deadlineAtMs: 301_000, + }), 0); + assert.equal(nextSignalingRecoveryPollDelayMs({ + attemptCount: 0, + online: false, + nowMs: 1_000, + deadlineAtMs: 301_000, + }), 5_000); + assert.equal(nextSignalingRecoveryPollDelayMs({ + attemptCount: 1, + online: true, + nowMs: 299_000, + deadlineAtMs: 301_000, + }), 2_000); + assert.equal(nextSignalingRecoveryPollDelayMs({ + attemptCount: 1, + online: true, + nowMs: 301_000, + deadlineAtMs: 301_000, + }), null); +}); diff --git a/opennow-stable/src/renderer/src/lib/streamSessionHelpers.ts b/opennow-stable/src/renderer/src/lib/streamSessionHelpers.ts index 7d1987347..431c7b65b 100644 --- a/opennow-stable/src/renderer/src/lib/streamSessionHelpers.ts +++ b/opennow-stable/src/renderer/src/lib/streamSessionHelpers.ts @@ -4,6 +4,7 @@ import type { GfnWebRtcClient } from "../platforms/gfn/webrtcClient"; export type SignalingRecoveryState = { attemptCount: number; + deadlineAtMs: number | null; inFlight: Promise | null; explicitShutdown: boolean; appId: number | null; @@ -11,11 +12,24 @@ export type SignalingRecoveryState = { }; export const RECOVERABLE_STREAM_STATUSES: readonly StreamStatus[] = ["streaming"]; -export const SIGNALING_RECOVERY_ATTEMPT_DELAYS_MS = [0, 3000] as const; +export const SIGNALING_RECOVERY_WINDOW_MS = 300_000; +export const SIGNALING_RECOVERY_POLL_INTERVAL_MS = 5_000; export const SIGNALING_RECOVERY_STABLE_RESET_DELAY_MS = 15000; export const SIGNALING_REMOTE_ICE_GRACE_MS = 5000; export const ICE_DISCONNECTED_RECOVERY_GRACE_MS = 7000; +export function nextSignalingRecoveryPollDelayMs(input: { + attemptCount: number; + online: boolean; + nowMs: number; + deadlineAtMs: number; +}): number | null { + const remainingMs = input.deadlineAtMs - input.nowMs; + if (remainingMs <= 0) return null; + if (input.attemptCount === 0 && input.online) return 0; + return Math.min(SIGNALING_RECOVERY_POLL_INTERVAL_MS, remainingMs); +} + export function isRemoteSessionEndReason(reason: string): boolean { const normalized = reason.trim().toLowerCase(); return normalized === "bye" || diff --git a/opennow-stable/src/renderer/src/platforms/gfn/webrtc/controllers.test.ts b/opennow-stable/src/renderer/src/platforms/gfn/webrtc/controllers.test.ts index 1b9b3f047..ba6065f80 100644 --- a/opennow-stable/src/renderer/src/platforms/gfn/webrtc/controllers.test.ts +++ b/opennow-stable/src/renderer/src/platforms/gfn/webrtc/controllers.test.ts @@ -9,10 +9,12 @@ import { type DecoderPressureState, } from "./decoderPressureController"; import { + GamepadController, selectGamepadPollIntervalMs, shouldSendGamepadPacket, } from "./gamepadController"; import { InputChannelPolicyController } from "./inputChannelPolicy"; +import { InputEncoder } from "../inputProtocol"; const pressureSignal: DecoderPressureSignal = { active: true, @@ -181,3 +183,84 @@ test("gamepad polling and keepalive decisions preserve adaptive timing", () => { assert.equal(shouldSendGamepadPacket(false, 100), true); assert.equal(shouldSendGamepadPacket(true, 0), true); }); + +test("standard controller haptics advertise and apply legacy and Oc rumble", () => { + const effects: Array<{ + startDelay: number; + duration: number; + weakMagnitude: number; + strongMagnitude: number; + }> = []; + const gamepad = { + connected: true, + id: "Xbox Wireless Controller", + index: 0, + vibrationActuator: { + playEffect: async (_type: string, options: { + startDelay: number; + duration: number; + weakMagnitude: number; + strongMagnitude: number; + }) => { + effects.push(options); + }, + }, + } as unknown as Gamepad; + const originalNavigator = Object.getOwnPropertyDescriptor(globalThis, "navigator"); + Object.defineProperty(globalThis, "navigator", { + configurable: true, + value: { getGamepads: () => [gamepad] }, + }); + + try { + const encoder = new InputEncoder(); + encoder.setProtocolVersion(3); + const reliable: Uint8Array[] = []; + const controller = new GamepadController({ + inputEncoder: encoder, + isInputReady: () => true, + isInputPaused: () => false, + isNativeInputActive: () => false, + isNativeElectronInputBridge: () => false, + isReliableChannelOpen: () => true, + canSendPartiallyReliableGamepad: () => true, + sendPartiallyReliable: () => {}, + sendReliable: (payload) => reliable.push(payload), + onConnectedGamepadsChanged: () => {}, + log: () => {}, + }); + + controller.refreshHapticsAdvertisement(); + assert.equal(reliable.length, 1); + assert.deepEqual(Array.from(reliable[0]?.slice(-6) ?? []), [13, 0, 0, 0, 0, 1]); + + controller.handleHapticsMessage(new Uint8Array([ + 0x0b, 0x01, + 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xff, 0xff, + ])); + assert.equal(effects.length, 1); + assert.equal(effects[0]?.duration, 500); + assert.ok(Math.abs((effects[0]?.weakMagnitude ?? 0) - (0x8000 / 0xffff)) < 0.0001); + assert.equal(effects[0]?.strongMagnitude, 1); + + controller.handleHapticsMessage(new Uint8Array([ + 0x22, + 0x11, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, + ])); + assert.equal(effects.length, 2); + assert.deepEqual(effects[1], { + startDelay: 0, + duration: 0, + weakMagnitude: 0, + strongMagnitude: 0, + }); + } finally { + if (originalNavigator) { + Object.defineProperty(globalThis, "navigator", originalNavigator); + } else { + Reflect.deleteProperty(globalThis, "navigator"); + } + } +}); diff --git a/opennow-stable/src/renderer/src/platforms/gfn/webrtc/domInputCaptureController.test.ts b/opennow-stable/src/renderer/src/platforms/gfn/webrtc/domInputCaptureController.test.ts index 6d4933281..cd9f27436 100644 --- a/opennow-stable/src/renderer/src/platforms/gfn/webrtc/domInputCaptureController.test.ts +++ b/opennow-stable/src/renderer/src/platforms/gfn/webrtc/domInputCaptureController.test.ts @@ -69,6 +69,7 @@ function installMouseHarness(options: { controller: DomInputCaptureController; dispatchMouseMove: (movementX: number, timeStamp: number) => void; dispatchMouseDown: (clientX: number, clientY: number, timeStamp: number) => void; + dispatchKey: (type: "keydown" | "keyup", code: string, keyCode: number, capsLock: boolean) => void; setPointerLocked: (locked: boolean) => void; pendingTimerCount: () => number; runNextTimer: (nowMs: number) => void; @@ -173,6 +174,22 @@ function installMouseHarness(options: { preventDefault: () => {}, }); }, + dispatchKey: (type, code, keyCode, capsLock) => { + documentTarget.dispatch(type, { + code, + key: code === "CapsLock" ? "CapsLock" : code, + keyCode, + location: 0, + repeat: false, + shiftKey: false, + ctrlKey: false, + altKey: false, + metaKey: false, + timeStamp: 1, + getModifierState: (modifier: string) => modifier === "CapsLock" && capsLock, + preventDefault: () => {}, + }); + }, setPointerLocked: (locked) => { (fakeDocument as { pointerLockElement: FakeEventTarget | null }).pointerLockElement = locked ? pointerLockTarget @@ -208,6 +225,29 @@ function installMouseHarness(options: { }; } +test("Caps Lock never emits synthetic Shift packets", () => { + const harness = installMouseHarness({ mouseSensitivity: 1, resolution: "1920x1080" }); + try { + harness.dispatchKey("keydown", "CapsLock", 0x14, false); + harness.dispatchKey("keyup", "CapsLock", 0x14, true); + + const keyPackets = harness.reliableSinglePayloads.filter((payload) => payload.byteLength === 18); + assert.equal(keyPackets.length, 2); + assert.deepEqual( + keyPackets.map((payload) => ({ + type: new DataView(payload.buffer, payload.byteOffset, payload.byteLength).getUint32(0, true), + virtualKey: new DataView(payload.buffer, payload.byteOffset, payload.byteLength).getUint16(4, false), + })), + [ + { type: 3, virtualKey: 0x14 }, + { type: 4, virtualKey: 0x14 }, + ], + ); + } finally { + harness.restoreGlobals(); + } +}); + test("negative half-pixel residual parks without synchronous recursion and resumes on input", () => { const harness = installMouseHarness({ mouseSensitivity: 0.5, resolution: "4x4" }); try { diff --git a/opennow-stable/src/renderer/src/platforms/gfn/webrtc/domInputCaptureController.ts b/opennow-stable/src/renderer/src/platforms/gfn/webrtc/domInputCaptureController.ts index 5ba54b77b..48656b42c 100644 --- a/opennow-stable/src/renderer/src/platforms/gfn/webrtc/domInputCaptureController.ts +++ b/opennow-stable/src/renderer/src/platforms/gfn/webrtc/domInputCaptureController.ts @@ -1046,9 +1046,8 @@ export class DomInputCaptureController { || event.key === "Esc" || event.code === "Escape" || event.keyCode === 27; - const isCapsLockToggle = event.code === "CapsLock"; const mapped = mapKeyboardEvent(event, this.dependencies.getKeyboardLayout()) ?? (isEscapeEvent ? codeMap.Escape : null); - if (!mapped && !isCapsLockToggle) { + if (!mapped) { return; } @@ -1056,36 +1055,7 @@ export class DomInputCaptureController { const eventTimestampUs = timestampUs(event.timeStamp); const modifiers = modifierFlags(event); - if (isCapsLockToggle) { - // Official GFN gg(): CapsLock keyup sends synthetic keydown then keyup (vk 160). - if (mapped && this.pressedKeys.has(mapped.vk)) { - this.pressedKeys.delete(mapped.vk); - this.dependencies.sendReliableSingleInput(this.dependencies.inputEncoder.encodeKeyUp({ - keycode: mapped.vk, - scancode: mapped.scancode, - modifiers, - timestampUs: eventTimestampUs, - })); - } - - const capsVk = 0xa0; - this.dependencies.sendReliableSingleInput(this.dependencies.inputEncoder.encodeKeyDown({ - keycode: capsVk, - scancode: 0, - modifiers, - timestampUs: eventTimestampUs, - })); - this.pressedKeys.delete(capsVk); - this.dependencies.sendReliableSingleInput(this.dependencies.inputEncoder.encodeKeyUp({ - keycode: capsVk, - scancode: 0, - modifiers, - timestampUs: eventTimestampUs, - })); - return; - } - - if (!mapped || !this.pressedKeys.has(mapped.vk)) { + if (!this.pressedKeys.has(mapped.vk)) { return; } diff --git a/opennow-stable/src/renderer/src/platforms/gfn/webrtc/inputHandshake.test.ts b/opennow-stable/src/renderer/src/platforms/gfn/webrtc/inputHandshake.test.ts new file mode 100644 index 000000000..e2ab3f80c --- /dev/null +++ b/opennow-stable/src/renderer/src/platforms/gfn/webrtc/inputHandshake.test.ts @@ -0,0 +1,18 @@ +/// + +import assert from "node:assert/strict"; +import test from "node:test"; + +import { parseInputProtocolVersion } from "./inputHandshake"; + +test("parses full and compact NVST input protocol announcements", () => { + assert.equal(parseInputProtocolVersion(new Uint8Array([0x0e, 0x02, 0x02, 0x00, 0x03, 0x00])), 3); + assert.equal(parseInputProtocolVersion(new Uint8Array([0x0e, 0x02, 0x03, 0x00])), 3); + assert.equal(parseInputProtocolVersion(new Uint8Array([0x0e, 0x03])), 0x030e); +}); + +test("rejects truncated and unrelated input messages", () => { + assert.equal(parseInputProtocolVersion(new Uint8Array()), null); + assert.equal(parseInputProtocolVersion(new Uint8Array([0x0e])), null); + assert.equal(parseInputProtocolVersion(new Uint8Array([0x01, 0x02, 0x03, 0x00])), null); +}); diff --git a/opennow-stable/src/renderer/src/platforms/gfn/webrtc/inputHandshake.ts b/opennow-stable/src/renderer/src/platforms/gfn/webrtc/inputHandshake.ts new file mode 100644 index 000000000..11a8b4016 --- /dev/null +++ b/opennow-stable/src/renderer/src/platforms/gfn/webrtc/inputHandshake.ts @@ -0,0 +1,16 @@ +export function parseInputProtocolVersion(bytes: Uint8Array): number | null { + if (bytes.length < 2) { + return null; + } + + const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); + const firstWord = view.getUint16(0, true); + if (firstWord === 0x020e) { + const payloadLength = bytes.length >= 4 ? view.getUint16(2, true) : 0; + if (payloadLength >= 2 && bytes.length >= 4 + payloadLength) { + return view.getUint16(4, true); + } + return bytes.length >= 4 ? view.getUint16(2, true) : 2; + } + return bytes[0] === 0x0e ? firstWord : null; +} diff --git a/opennow-stable/src/renderer/src/platforms/gfn/webrtcClient.ts b/opennow-stable/src/renderer/src/platforms/gfn/webrtcClient.ts index 9f3470abf..88c065190 100644 --- a/opennow-stable/src/renderer/src/platforms/gfn/webrtcClient.ts +++ b/opennow-stable/src/renderer/src/platforms/gfn/webrtcClient.ts @@ -75,6 +75,7 @@ import { type RiInputCapabilities, } from "./webrtc/inputChannelPolicy"; import { GamepadController } from "./webrtc/gamepadController"; +import { parseInputProtocolVersion } from "./webrtc/inputHandshake"; import { DomInputCaptureController } from "./webrtc/domInputCaptureController"; import { PeerMediaLifecycleController } from "./webrtc/peerMediaLifecycleController"; import { updateVideoSenderBitrate } from "./webrtc/senderBitrate"; @@ -154,12 +155,12 @@ function describeColorQuality(colorQuality: ColorQuality): string { function describeNativeHardwareAcceleration(): string { const platform = navigator.platform.toLowerCase(); if (platform.includes("win")) { - return "GStreamer D3D11/DXVA"; + return "Native D3D11/DXVA"; } if (platform.includes("mac")) { - return "GStreamer VideoToolbox"; + return "Native VideoToolbox"; } - return "GStreamer NVDEC/VAAPI/V4L2/Vulkan"; + return "Native VA-API/V4L2/Vulkan"; } interface ClientOptions { @@ -299,7 +300,7 @@ export class GfnWebRtcClient { /** * When true, Electron captures keyboard/mouse/gamepad and forwards packets to * the native streamer over IPC (internal child-surface renderer). - * When false, the floating external GStreamer window owns OS-level input. + * When false, the external native presenter owns OS-level input. */ private nativeElectronInputBridge = false; private remoteIceEndpoint: SessionInfo["mediaConnectionInfo"] | null = null; @@ -939,6 +940,16 @@ export class GfnWebRtcClient { this.controlChannel.onclose = null; this.controlChannel.onerror = null; } + if (this.reliableInputChannel) { + this.reliableInputChannel.onmessage = null; + this.reliableInputChannel.onclose = null; + this.reliableInputChannel.onerror = null; + } + if (this.partiallyReliableInputChannel) { + this.partiallyReliableInputChannel.onmessage = null; + this.partiallyReliableInputChannel.onclose = null; + this.partiallyReliableInputChannel.onerror = null; + } this.reliableInputChannel?.close(); this.partiallyReliableInputChannel?.close(); this.closeCursorChannel(); @@ -1347,10 +1358,7 @@ export class GfnWebRtcClient { this.nativeInputActive = true; // Internal (one-window) mode: Electron owns capture and IPC-forwards packets. // External floating window: OS-level capture stays in the native streamer. - // Linux is Internal-only: always use the Electron IPC bridge regardless of stale options. - const isLinuxHost = typeof navigator !== "undefined" - && /linux/i.test(`${navigator.platform} ${navigator.userAgent}`); - this.nativeElectronInputBridge = isLinuxHost || options?.electronInputBridge !== false; + this.nativeElectronInputBridge = options?.electronInputBridge !== false; this.inputReady = true; const nativeProtocolVersion = GfnWebRtcClient.normalizeInputProtocolVersion( protocolVersion @@ -1414,10 +1422,12 @@ export class GfnWebRtcClient { ); } else { this.detachInputCapture(); - // Overlay Meta/Home detection only; gamepad state is owned by the floating window. + // SDL owns keyboard/mouse in an external native window. Keep Chromium's + // Gamepad API polling alive because the native capture protocol currently + // carries keyboard and mouse events only. this.gamepadController.start(); this.log( - `Native external-window input active (protocol v${nativeProtocolVersion}); OS capture handled by streamer, Electron overlay shortcuts only.`, + `Native external-window input active (protocol v${nativeProtocolVersion}); SDL owns keyboard/mouse and Electron retains gamepad forwarding.`, ); } } @@ -1435,6 +1445,22 @@ export class GfnWebRtcClient { } + public markNativeInputUnavailable(reason: string): void { + this.nativeInputActive = false; + this.nativeElectronInputBridge = false; + this.inputReady = false; + this.inputProtocolVersion = 2; + this.inputEncoder.setProtocolVersion(2); + this.detachInputCapture(); + this.gamepadController.stop(); + this.diagnostics.inputReady = false; + this.diagnostics.partiallyReliableInputOpen = false; + this.diagnostics.mouseMoveTransport = "reliable"; + this.diagnostics.lagReason = "unknown"; + this.diagnostics.lagReasonDetail = `Native input unavailable: ${reason}`; + this.emitStats(); + } + private async waitForIceGathering(pc: RTCPeerConnection, timeoutMs: number): Promise { if (pc.iceGatheringState === "complete" && pc.localDescription?.sdp) { return pc.localDescription.sdp; @@ -1481,6 +1507,20 @@ export class GfnWebRtcClient { }, 2000); } + private markReliableInputChannelUnavailable(reason: string): void { + if (this.heartbeatTimer !== null) { + window.clearInterval(this.heartbeatTimer); + this.heartbeatTimer = null; + } + this.inputReady = false; + this.inputProtocolVersion = 2; + this.inputEncoder.setProtocolVersion(2); + this.gamepadController.stop(); + this.diagnostics.inputReady = false; + this.emitStats(); + this.log(reason); + } + private isPartiallyReliableChannelOpen(): boolean { return this.inputChannelPolicyController.isPartiallyReliableOpen(); } @@ -1515,10 +1555,6 @@ export class GfnWebRtcClient { return; } - const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); - const firstWord = view.getUint16(0, true); - let version = 2; - if (this.inputReady) { this.gamepadController.handleHapticsMessage(bytes); return; @@ -1529,16 +1565,14 @@ export class GfnWebRtcClient { .join(" "); this.log(`Input channel message: ${bytes.length} bytes [${hex}]`); - if (firstWord === 526) { - version = bytes.length >= 4 ? view.getUint16(2, true) : 2; - this.log(`Handshake detected: firstWord=526 (0x020e), version=${version}`); - } else if (bytes[0] === 0x0e) { - version = firstWord; - this.log(`Handshake detected: byte[0]=0x0e, version=${version}`); - } else { + const version = parseInputProtocolVersion(bytes); + if (version === null) { + const firstWord = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength) + .getUint16(0, true); this.log(`Input channel message not a handshake: firstWord=${firstWord} (0x${firstWord.toString(16)})`); return; } + this.log(`Handshake detected: protocol version=${version}`); if (!this.inputReady) { // Official GFN browser client does NOT echo the handshake back. @@ -1598,6 +1632,14 @@ export class GfnWebRtcClient { this.onInputHandshakeMessage(bytes); }; + this.reliableInputChannel.onclose = () => { + this.markReliableInputChannelUnavailable("Reliable input channel closed"); + }; + + this.reliableInputChannel.onerror = () => { + this.markReliableInputChannelUnavailable("Reliable input channel failed"); + }; + this.partiallyReliableInputChannel = pc.createDataChannel("input_channel_partially_reliable", { ordered: false, maxPacketLifeTime: this.partialReliableThresholdMs, diff --git a/opennow-stable/src/shared/cloudGsync.test.ts b/opennow-stable/src/shared/cloudGsync.test.ts index b8277319b..5ac2c2442 100644 --- a/opennow-stable/src/shared/cloudGsync.test.ts +++ b/opennow-stable/src/shared/cloudGsync.test.ts @@ -44,6 +44,23 @@ test("fps below Cloud G-Sync minimum disables it", () => { assert.equal(result.reason, "fps-too-low"); }); +test("fps above the active display refresh disables Cloud G-Sync", () => { + const result = resolveCloudGsync({ + userRequested: true, + fps: 240, + clientMode: "native", + nativeBackendAvailable: true, + capabilities: { + ...vrrCapabilities, + displayRefreshHz: 164.834, + }, + }); + + assert.equal(result.enabled, false); + assert.equal(result.reason, "fps-too-high"); + assert.equal(result.reflexEnabled, true); +}); + test("unsupported VRR display disables native Cloud G-Sync", () => { const result = resolveCloudGsync({ userRequested: true, diff --git a/opennow-stable/src/shared/cloudGsync.ts b/opennow-stable/src/shared/cloudGsync.ts index 6daf81c82..99619e69d 100644 --- a/opennow-stable/src/shared/cloudGsync.ts +++ b/opennow-stable/src/shared/cloudGsync.ts @@ -9,6 +9,7 @@ export type NativeCloudGsyncOverride = "auto" | "0" | "1"; export type CloudGsyncDisabledReason = | "user-disabled" | "fps-too-low" + | "fps-too-high" | "unsupported-backend" | "unsupported-display" | "force-disabled" @@ -20,7 +21,11 @@ export type CloudGsyncResolutionReason = CloudGsyncDisabledReason | CloudGsyncEn export interface NativeCloudGsyncCapabilities { platformSupportsCloudGsync: boolean; isVrrCapableDisplay: boolean; + isVrrActive?: boolean; isGsyncDisplay: boolean; + windowSystem?: "wayland" | "x11" | "windows" | "macos" | "unknown"; + displayName?: string; + displayRefreshHz?: number; minimumFpsForCloudGsync: number; minimumFpsForReflexWithoutVrr: number; detectionSource: NativeCloudGsyncDetectionSource; @@ -48,6 +53,7 @@ export function unsupportedNativeCloudGsyncCapabilities(reason = "unsupported"): return { platformSupportsCloudGsync: false, isVrrCapableDisplay: false, + isVrrActive: false, isGsyncDisplay: false, minimumFpsForCloudGsync: DEFAULT_MINIMUM_FPS_FOR_CLOUD_GSYNC, minimumFpsForReflexWithoutVrr: DEFAULT_MINIMUM_FPS_FOR_REFLEX_WITHOUT_VRR, @@ -75,7 +81,11 @@ export function normalizeNativeCloudGsyncCapabilities( return { platformSupportsCloudGsync: capabilities?.platformSupportsCloudGsync ?? false, isVrrCapableDisplay: capabilities?.isVrrCapableDisplay ?? false, + isVrrActive: capabilities?.isVrrActive ?? false, isGsyncDisplay: capabilities?.isGsyncDisplay ?? false, + windowSystem: capabilities?.windowSystem, + displayName: capabilities?.displayName, + displayRefreshHz: capabilities?.displayRefreshHz, minimumFpsForCloudGsync: capabilities?.minimumFpsForCloudGsync ?? DEFAULT_MINIMUM_FPS_FOR_CLOUD_GSYNC, minimumFpsForReflexWithoutVrr: @@ -158,6 +168,23 @@ export function resolveCloudGsync(input: CloudGsyncResolutionInput): CloudGsyncR }; } + // NVIDIA requires the selected streaming frame rate to be no greater than + // the VRR display's maximum refresh. Allow a small tolerance because Linux + // compositors commonly report modes such as 164.834 Hz for a marketed + // 165 Hz panel. + if ( + capabilities.displayRefreshHz !== undefined + && input.fps > capabilities.displayRefreshHz + 0.5 + ) { + return { + requested: true, + enabled: false, + reflexEnabled: reflexEnabledWithoutVrr, + reason: "fps-too-high", + capabilities, + }; + } + if (!capabilities.platformSupportsCloudGsync) { return { requested: true, diff --git a/opennow-stable/src/shared/gfn.test.ts b/opennow-stable/src/shared/gfn.test.ts index 8d349bae2..3ea153152 100644 --- a/opennow-stable/src/shared/gfn.test.ts +++ b/opennow-stable/src/shared/gfn.test.ts @@ -152,7 +152,6 @@ test("buildNativeStreamerSessionContext forwards requested/finalized streaming f enableL4S: true, enableCloudGsync: true, clientMode: "native", - nativeStreamerBackend: "gstreamer", nativeCloudGsyncMode: "auto", nativeTransitionDiagnostics: { forceQueueMode: "adaptive", @@ -184,10 +183,26 @@ test("buildNativeStreamerSessionContext forwards requested/finalized streaming f chromaFormat: 0, enabledL4S: false, }); + assert.equal(context.settings.codec, "H265"); assert.equal(context.session.negotiatedStreamProfile?.codec, "H265"); assert.equal(context.settings.enableCloudGsync, false); assert.equal(context.settings.nativeTransitionDiagnostics?.forceQueueMode, "adaptive"); assert.equal(context.shortcuts.toggleRecording, "F12"); + + const nvstContext = buildNativeStreamerSessionContext( + { + ...context.session, + negotiatedStreamProfile: { + resolution: "2560x1440", + fps: 240, + enableCloudGsync: false, + }, + }, + { ...context.settings, transportMode: "nvst", codec: "AV1" }, + context.shortcuts, + ); + assert.equal(nvstContext.settings.codec, "AV1"); + assert.equal(nvstContext.session.negotiatedStreamProfile?.codec, "AV1"); }); test("keeps native stream client mode on supported desktop platforms", () => { @@ -236,7 +251,7 @@ test("reports unsupported native streamer status on unknown platforms only", () assert.equal(isNativeStreamerSupportedPlatform("android"), false); }); -test("isNativeExternalRendererSupported is Windows-only", () => { +test("external renderer is available with the native Windows presenter", () => { assert.equal(isNativeExternalRendererSupported("win32"), true); assert.equal(isNativeExternalRendererSupported("windows"), true); assert.equal(isNativeExternalRendererSupported("linux"), false); @@ -249,14 +264,21 @@ test("isNativeExternalRendererSupported is Windows-only", () => { const status = createUnsupportedNativeStreamerStatus(); assert.equal(status.detected, false); - assert.equal(status.gstreamerAvailable, false); + assert.equal(status.available, false); assert.equal(status.supportsOfferAnswer, false); assert.equal(status.message, NATIVE_STREAMER_UNSUPPORTED_PLATFORM_MESSAGE); - assert.equal(status.gstreamerRuntime.message, NATIVE_STREAMER_UNSUPPORTED_PLATFORM_MESSAGE); + assert.equal(status.runtime.message, NATIVE_STREAMER_UNSUPPORTED_PLATFORM_MESSAGE); }); -test("NVST transport stays disabled and normalizes to WebRTC", () => { - assert.equal(isNvstTransportSupported("win32"), false); - assert.equal(normalizeTransportModeForPlatform("nvst", "win32", "native"), "webrtc"); +test("NVST transport is limited to native sessions on supported desktop platforms", () => { + assert.equal(isNvstTransportSupported("win32"), true); + assert.equal(isNvstTransportSupported("darwin"), true); + assert.equal(isNvstTransportSupported("linux"), true); + assert.equal(isNvstTransportSupported("android"), false); + assert.equal(normalizeTransportModeForPlatform("nvst", "win32", "native"), "nvst"); + assert.equal(normalizeTransportModeForPlatform("nvst", "darwin", "native"), "nvst"); + assert.equal(normalizeTransportModeForPlatform("nvst", "linux", "native"), "nvst"); + assert.equal(normalizeTransportModeForPlatform("nvst", "linux", "web"), "webrtc"); + assert.equal(normalizeTransportModeForPlatform("nvst", "android", "native"), "webrtc"); assert.equal(normalizeTransportModeForPlatform("webrtc", "win32", "native"), "webrtc"); }); diff --git a/opennow-stable/src/shared/gfn/nativeStreamer.ts b/opennow-stable/src/shared/gfn/nativeStreamer.ts index 4bdc0edb1..e4d2e2eed 100644 --- a/opennow-stable/src/shared/gfn/nativeStreamer.ts +++ b/opennow-stable/src/shared/gfn/nativeStreamer.ts @@ -1,7 +1,6 @@ import type { StreamClientMode } from "./stream"; -export type NativeStreamerBackend = "stub" | "gstreamer"; -export type NativeStreamerBackendPreference = "auto" | NativeStreamerBackend; +export type NativeStreamerBackend = "native"; export type NativeStreamerFeatureMode = "auto" | "disabled" | "forced"; export type NativeVideoBackendPreference = | "auto" @@ -16,9 +15,16 @@ export type StreamTransportMode = "webrtc" | "nvst"; export const NATIVE_STREAMER_UNSUPPORTED_PLATFORM_MESSAGE = "Native streamer requires a supported desktop OS (Windows, macOS, or Linux)."; +/** Highest frame rate the native receive, decode, and presentation pipeline accepts. */ +export const MAX_NATIVE_STREAM_FPS = 240; /** @deprecated Use NATIVE_STREAMER_UNSUPPORTED_PLATFORM_MESSAGE. */ export const NATIVE_STREAMER_WINDOWS_ONLY_MESSAGE = NATIVE_STREAMER_UNSUPPORTED_PLATFORM_MESSAGE; +export function clampNativeStreamFps(fps: number): number { + const normalized = Number.isFinite(fps) ? Math.trunc(fps) : 60; + return Math.max(1, Math.min(MAX_NATIVE_STREAM_FPS, normalized)); +} + export function isNativeStreamerSupportedPlatform(platform: string): boolean { const normalized = platform.toLowerCase(); return ( @@ -29,14 +35,15 @@ export function isNativeStreamerSupportedPlatform(platform: string): boolean { } export function isNativeExternalRendererSupported(platform: string): boolean { + return isNativeDirectXBackendSupported(platform); +} + +export function isNativeDirectXBackendSupported(platform: string): boolean { const normalized = platform.toLowerCase(); return normalized === "win32" || normalized.startsWith("win") || normalized.includes("windows"); } - -export const isNativeDirectXBackendSupported = isNativeExternalRendererSupported; -/** NVST is intentionally disabled until the transport is complete. */ -export function isNvstTransportSupported(_platform: string): boolean { - return false; +export function isNvstTransportSupported(platform: string): boolean { + return isNativeStreamerSupportedPlatform(platform); } export function normalizeStreamClientModeForPlatform(mode: StreamClientMode, platform: string): StreamClientMode { @@ -48,11 +55,15 @@ export function normalizeNativeExternalRendererForPlatform(enabled: boolean, pla } export function normalizeTransportModeForPlatform( - _mode: StreamTransportMode, - _platform: string, - _streamClientMode: StreamClientMode = "native", + mode: StreamTransportMode, + platform: string, + streamClientMode: StreamClientMode = "native", ): StreamTransportMode { - return "webrtc"; + return mode === "nvst" + && streamClientMode === "native" + && isNvstTransportSupported(platform) + ? "nvst" + : "webrtc"; } export function nativeStreamerFeatureModeToEnvValue(mode: NativeStreamerFeatureMode): "auto" | "0" | "1" { @@ -66,25 +77,18 @@ export function nativeStreamerFeatureModeToEnvValue(mode: NativeStreamerFeatureM } } -export type NativeGstreamerRuntimeSource = "bundled" | "system" | "missing" | "unknown"; - -export interface NativeGstreamerInstallInstruction { - distro: string; - command: string; - note?: string; -} +export type NativeStreamerRuntimeSource = "self-contained" | "missing" | "unknown"; -export interface NativeGstreamerRuntimeStatus { - source: NativeGstreamerRuntimeSource; - bundled: boolean; +export interface NativeStreamerRuntimeStatus { + source: NativeStreamerRuntimeSource; + selfContained: boolean; path?: string; message: string; - installInstructions?: NativeGstreamerInstallInstruction[]; } export interface NativeStreamerStatus { detected: boolean; - gstreamerAvailable: boolean; + available: boolean; supportsOfferAnswer: boolean; backend?: NativeStreamerBackend; fallbackReason?: string; @@ -92,18 +96,18 @@ export interface NativeStreamerStatus { activeVideoBackend?: NativeVideoBackendCapability; codecSummary?: string; zeroCopySummary?: string; - gstreamerRuntime: NativeGstreamerRuntimeStatus; + runtime: NativeStreamerRuntimeStatus; message: string; } export function createUnsupportedNativeStreamerStatus(): NativeStreamerStatus { return { detected: false, - gstreamerAvailable: false, + available: false, supportsOfferAnswer: false, - gstreamerRuntime: { + runtime: { source: "unknown", - bundled: false, + selfContained: false, message: NATIVE_STREAMER_UNSUPPORTED_PLATFORM_MESSAGE, }, message: NATIVE_STREAMER_UNSUPPORTED_PLATFORM_MESSAGE, diff --git a/opennow-stable/src/shared/gfn/session.ts b/opennow-stable/src/shared/gfn/session.ts index e422f1dca..714de256d 100644 --- a/opennow-stable/src/shared/gfn/session.ts +++ b/opennow-stable/src/shared/gfn/session.ts @@ -8,7 +8,6 @@ import type { VideoCodec, } from "./stream"; import type { - NativeStreamerBackendPreference, NativeStreamerFeatureMode, StreamTransportMode, } from "./nativeStreamer"; @@ -33,9 +32,7 @@ export interface StreamSettings { enableCloudGsync: boolean; /** Renderer-selected client path; main uses this to apply native-only Cloud G-Sync gating. */ clientMode?: StreamClientMode; - /** Selected native streamer backend; stub cannot support Cloud G-Sync presentation. */ - nativeStreamerBackend?: NativeStreamerBackendPreference; - /** Native media transport; legacy NVST values normalize to WebRTC. */ + /** Native media transport selected for the session. */ transportMode?: StreamTransportMode; /** Native-only override for Cloud G-Sync display detection. */ nativeCloudGsyncMode?: NativeStreamerFeatureMode; @@ -219,6 +216,7 @@ export function getSessionAdDurationMs(ad: SessionAdInfo | undefined): number | export interface SessionInfo { sessionId: string; + subSessionId?: string; appId?: string; status: number; queuePosition?: number; @@ -236,7 +234,9 @@ export interface SessionInfo { appLaunchMode?: number; /** Wire in-game settings persistence value the session was created with, kept session-stable for resumes */ enablePersistingInGameSettings?: boolean; - /** Classic NVST RTSPS endpoints from CloudMatch usage=14 connections. */ + /** Complete ordered CloudMatch transport list consumed by the native stream SDK. */ + connectionInfo?: SessionConnectionInfo[]; + /** Classic NVST RTSPS endpoints from CloudMatch usage=16 connections. */ rtspsEndpoints?: string[]; iceServers: IceServer[]; mediaConnectionInfo?: MediaConnectionInfo; @@ -247,9 +247,20 @@ export interface SessionInfo { deviceId?: string; } +export interface SessionConnectionInfo { + ip?: string; + port: number; + usage: number; + protocol?: number; + appLevelProtocol?: number; + resourcePath?: string; + [key: string]: unknown; +} + /** Information about an active session from getActiveSessions */ export interface ActiveSessionInfo { sessionId: string; + subSessionId?: string; appId: number; /** Wire appLaunchMode the session was created with, as echoed by the server */ appLaunchMode?: number; diff --git a/opennow-stable/src/shared/gfn/sessionProxy.test.ts b/opennow-stable/src/shared/gfn/sessionProxy.test.ts new file mode 100644 index 000000000..6ea84ec8e --- /dev/null +++ b/opennow-stable/src/shared/gfn/sessionProxy.test.ts @@ -0,0 +1,70 @@ +/// + +import test from "node:test"; +import assert from "node:assert/strict"; + +import { + INVALID_SESSION_PROXY_URL_MESSAGE, + isInvalidSessionProxyUrlError, + isValidSessionProxyUrl, + normalizeSessionProxyUrl, +} from "./sessionProxy"; + +test("normalizes scheme-less host:port values as http proxies", () => { + assert.equal(normalizeSessionProxyUrl("localhost:8080"), "http://localhost:8080"); + assert.equal(normalizeSessionProxyUrl("proxy.example.com:8080"), "http://proxy.example.com:8080"); + assert.equal(normalizeSessionProxyUrl("127.0.0.1:8080"), "http://127.0.0.1:8080"); +}); + +test("accepts http/https URLs with default ports stripped by WHATWG URL", () => { + assert.equal(normalizeSessionProxyUrl("http://proxy.example.com:80"), "http://proxy.example.com:80"); + assert.equal(normalizeSessionProxyUrl("https://proxy.example.com:443"), "https://proxy.example.com:443"); + assert.equal(normalizeSessionProxyUrl("http://proxy.example.com"), "http://proxy.example.com:80"); + assert.equal(normalizeSessionProxyUrl("https://proxy.example.com"), "https://proxy.example.com:443"); +}); + +test("accepts supported explicit session proxy schemes with ports", () => { + assert.equal(normalizeSessionProxyUrl("socks5://proxy.example.com:1080"), "socks5://proxy.example.com:1080"); + assert.equal(normalizeSessionProxyUrl("socks4://proxy.example.com:1080"), "socks4://proxy.example.com:1080"); +}); + +test("rejects socks proxies without an explicit port", () => { + assert.throws( + () => normalizeSessionProxyUrl("socks5://proxy.example.com"), + /Invalid session proxy URL/, + ); + assert.throws( + () => normalizeSessionProxyUrl("socks4://proxy.example.com"), + /Invalid session proxy URL/, + ); +}); + +test("rejects unsupported schemes and malformed credentials", () => { + assert.throws( + () => normalizeSessionProxyUrl("ftp://proxy.example.com:21"), + /Invalid session proxy URL/, + ); + assert.throws( + () => normalizeSessionProxyUrl("http://user%ZZ@proxy.example.com:8080"), + /Invalid session proxy URL/, + ); +}); + +test("isValidSessionProxyUrl mirrors normalize semantics", () => { + assert.equal(isValidSessionProxyUrl(""), true); + assert.equal(isValidSessionProxyUrl(" "), true); + assert.equal(isValidSessionProxyUrl("http://proxy.example.com:80"), true); + assert.equal(isValidSessionProxyUrl("socks5://proxy.example.com"), false); + assert.equal(isValidSessionProxyUrl("ftp://proxy.example.com:21"), false); +}); + +test("isInvalidSessionProxyUrlError detects wrapped IPC messages", () => { + assert.equal(isInvalidSessionProxyUrlError(new Error(INVALID_SESSION_PROXY_URL_MESSAGE)), true); + assert.equal( + isInvalidSessionProxyUrlError( + new Error(`Error invoking remote method 'games:browse-catalog': Error: ${INVALID_SESSION_PROXY_URL_MESSAGE}`), + ), + true, + ); + assert.equal(isInvalidSessionProxyUrlError(new Error("network down")), false); +}); diff --git a/opennow-stable/src/shared/gfn/sessionProxy.ts b/opennow-stable/src/shared/gfn/sessionProxy.ts new file mode 100644 index 000000000..2a6062787 --- /dev/null +++ b/opennow-stable/src/shared/gfn/sessionProxy.ts @@ -0,0 +1,89 @@ +/** + * Session-proxy URL normalization shared by main and renderer. + * Keep protocol/port rules here so settings UI and fetch paths cannot drift. + */ + +export const INVALID_SESSION_PROXY_URL_MESSAGE = + "Invalid session proxy URL. Use http://host:port, https://host:port, socks4://host:port, or socks5://host:port."; + +const SUPPORTED_PROXY_PROTOCOLS = new Set(["http:", "https:", "socks4:", "socks5:"]); + +function safeDecodeURIComponent(value: string): string { + try { + return decodeURIComponent(value); + } catch { + throw new Error(INVALID_SESSION_PROXY_URL_MESSAGE); + } +} + +function resolveExplicitProxyPort(protocol: string, parsedPort: string): string | null { + if (parsedPort) { + return parsedPort; + } + + // WHATWG URL strips default ports for http/https (`:80` / `:443` → ""), + // so accept those schemes with an implicit default port. + if (protocol === "http:") { + return "80"; + } + if (protocol === "https:") { + return "443"; + } + + // socks4/socks5 are non-special schemes and never strip ports; require an explicit one. + return null; +} + +/** + * Normalize a session proxy URL to `scheme://[user[:pass]@]host:port`. + * Returns null for empty/whitespace input. Throws for invalid values. + */ +export function normalizeSessionProxyUrl(raw?: string): string | null { + const trimmed = raw?.trim() ?? ""; + if (!trimmed) return null; + + const candidate = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) ? trimmed : `http://${trimmed}`; + let parsed: URL; + try { + parsed = new URL(candidate); + } catch { + throw new Error(INVALID_SESSION_PROXY_URL_MESSAGE); + } + + if (!SUPPORTED_PROXY_PROTOCOLS.has(parsed.protocol) || !parsed.hostname) { + throw new Error(INVALID_SESSION_PROXY_URL_MESSAGE); + } + + const port = resolveExplicitProxyPort(parsed.protocol, parsed.port); + if (!port) { + throw new Error(INVALID_SESSION_PROXY_URL_MESSAGE); + } + + const username = parsed.username ? encodeURIComponent(safeDecodeURIComponent(parsed.username)) : ""; + const password = parsed.password ? encodeURIComponent(safeDecodeURIComponent(parsed.password)) : ""; + const credentials = username ? `${username}${password ? `:${password}` : ""}@` : ""; + return `${parsed.protocol}//${credentials}${parsed.hostname}:${port}`; +} + +/** True when the value is empty or a normalizeable session proxy URL. */ +export function isValidSessionProxyUrl(raw?: string): boolean { + try { + normalizeSessionProxyUrl(raw); + return true; + } catch { + return false; + } +} + +/** True when `error` (or its message) is the invalid session-proxy validation failure. */ +export function isInvalidSessionProxyUrlError(error: unknown): boolean { + if (error instanceof Error) { + return error.message.includes(INVALID_SESSION_PROXY_URL_MESSAGE) + || error.message.includes("Invalid session proxy URL"); + } + if (typeof error === "string") { + return error.includes(INVALID_SESSION_PROXY_URL_MESSAGE) + || error.includes("Invalid session proxy URL"); + } + return false; +} diff --git a/opennow-stable/src/shared/gfn/settings.ts b/opennow-stable/src/shared/gfn/settings.ts index a44c78079..5e1139c18 100644 --- a/opennow-stable/src/shared/gfn/settings.ts +++ b/opennow-stable/src/shared/gfn/settings.ts @@ -7,7 +7,6 @@ import type { VideoAccelerationPreference, } from "./stream"; import type { - NativeStreamerBackendPreference, NativeStreamerFeatureMode, NativeVideoBackendPreference, StreamTransportMode, @@ -71,7 +70,6 @@ export interface Settings { recordingResolution: RecordingResolution; recordingFps: RecordingFps; streamClientMode: StreamClientMode; - nativeStreamerBackend: NativeStreamerBackendPreference; nativeVideoBackend: NativeVideoBackendPreference; nativeStreamerExecutablePath: string; nativeCloudGsyncMode: NativeStreamerFeatureMode; @@ -284,7 +282,6 @@ export function createDefaultSettings(platform: string): Settings { recordingResolution: DEFAULT_RECORDING_RESOLUTION, recordingFps: DEFAULT_RECORDING_FPS, streamClientMode: "web", - nativeStreamerBackend: "gstreamer", nativeVideoBackend: "auto", nativeStreamerExecutablePath: "", nativeCloudGsyncMode: "auto", diff --git a/opennow-stable/src/shared/gfn/signaling.ts b/opennow-stable/src/shared/gfn/signaling.ts index 5cf1a4b21..a6ff152b9 100644 --- a/opennow-stable/src/shared/gfn/signaling.ts +++ b/opennow-stable/src/shared/gfn/signaling.ts @@ -1,4 +1,3 @@ -import type { NativeQueueMode } from "./stream"; import type { SessionInfo, StreamSettings } from "./session"; export interface SignalingConnectRequest { @@ -53,14 +52,56 @@ export interface NativeStreamerSessionContext { nvstVideo?: NvstVideoSession; } +export type NvstSrtpProfile = + | "AEAD_AES_128_GCM" + | "AEAD_AES_256_GCM" + | "AEAD_AES_128_GCM_8" + | "AEAD_AES_256_GCM_8" + | "AES_CM_128_HMAC_SHA1_32" + | "AES_CM_128_HMAC_SHA1_80" + | "AES_CM_256_HMAC_SHA1_32" + | "AES_CM_256_HMAC_SHA1_80"; + export interface NvstVideoSession { clientUdpPort: number; + /** + * Dedicated NATT-only video (Mjolnir) socket port reserved by the native + * streamer. When present, the native streamer reads raw-SRTP video from this + * socket while the ICE/DTLS bundle socket carries control/audio. + */ + mjolnirUdpPort?: number; videoPeerIp: string; videoPeerPort: number; + /** Routable CloudMatch endpoint for the ICE/DTLS control and audio bundle. */ + bundlePeerIp?: string; + bundlePeerPort?: number; srtpAesKeyHex: string; srtpKeyId: number; + srtpSaltHex: string; + srtpProfile?: NvstSrtpProfile; pingPayload?: string; + pingVersion?: number; + localIceUsernameFragment?: string; + localIcePassword?: string; + remoteIceUsernameFragment?: string; + remoteIcePassword?: string; + /** SHA-256 colon hex from the local WebRtcTransport-equivalent cert. */ + localDtlsFingerprint?: string; + /** SHA-256 colon hex advertised by DESCRIBE (`dtlsFingerprint` / `V2`). */ + remoteDtlsFingerprint?: string; codec?: string; + audioTrack?: NvstAudioTrack; + /** Idle receive timeout. Handshake needs longer than the 5s media default. */ + timeoutMs?: number; +} + +export interface NvstAudioTrack { + payloadType: number; + codec: "opus"; + clockRateHz: number; + channels: number; + mid?: string; + ssrc?: number; } export function buildNativeStreamerSessionContext( @@ -69,12 +110,16 @@ export function buildNativeStreamerSessionContext( shortcuts: NativeStreamerShortcutBindings, nvstVideo?: NvstVideoSession, ): NativeStreamerSessionContext { + // CloudMatch does not consistently echo the chosen codec in its finalized + // profile. Prefer an explicit server value, but otherwise preserve the + // concrete codec selected by renderer capability resolution. + const codec = session.negotiatedStreamProfile?.codec ?? settings.codec; const negotiatedStreamProfile = session.negotiatedStreamProfile ? { ...session.negotiatedStreamProfile, - codec: session.negotiatedStreamProfile.codec ?? settings.codec, + codec, } - : { codec: settings.codec }; + : { codec }; return { session: { @@ -83,6 +128,7 @@ export function buildNativeStreamerSessionContext( }, settings: { ...settings, + codec, enableCloudGsync: session.negotiatedStreamProfile?.enableCloudGsync ?? settings.enableCloudGsync, }, @@ -91,24 +137,6 @@ export function buildNativeStreamerSessionContext( }; } -export interface NativeVideoTransition { - transitionType: string; - source: string; - atMs: number; - oldCaps?: string; - newCaps?: string; - oldFramerate?: string; - newFramerate?: string; - oldMemoryMode?: string; - newMemoryMode?: string; - renderGapMs?: number; - requestedFps?: number; - capsFramerate?: string; - highFpsRisk?: boolean; - queueMode?: NativeQueueMode; - summary?: string; -} - export interface NativeInputPacket { payload: ArrayBuffer | Uint8Array | number[]; partiallyReliable?: boolean; @@ -130,6 +158,7 @@ export interface NativeRenderSurfaceUpdate { export interface NativeRenderSurface extends NativeRenderSurfaceUpdate { windowHandle?: string; + screenRect?: NativeRenderSurfaceRect; } export interface KeyframeRequest { @@ -143,47 +172,13 @@ export type MainToRendererSignalingEvent = | { type: "disconnected"; reason: string } | { type: "offer"; sdp: string } | { type: "remote-ice"; candidate: IceCandidatePayload } - | { type: "native-shortcut"; action: NativeStreamerShortcutAction } - | { type: "native-clipboard-paste" } - | { type: "native-input-capture-changed"; captured: boolean } | { type: "native-stream-started"; message?: string } | { type: "native-stream-stopped"; reason?: string } - | { type: "native-stream-stats"; stats: NativeStreamStats } - | { type: "native-stream-transition"; transition: NativeVideoTransition } - | { type: "native-input-ready"; protocolVersion: number } + | { + type: "native-input-ready"; + protocolVersion: number; + inputOwner?: "electron" | "native"; + } + | { type: "native-input-unavailable"; reason: string } | { type: "error"; message: string } | { type: "log"; message: string }; - -export interface NativeStreamStats { - codec: string; - resolution: string; - hardwareAcceleration: string; - memoryMode?: string; - zeroCopy?: boolean; - requestedFps?: number; - capsFramerate?: string; - bitrateKbps: number; - targetBitrateKbps: number; - bitratePerformancePercent: number; - decodedFps: number; - renderFps: number; - framesDecoded: number; - framesRendered: number; - framesPendingToPresent?: number; - sinkRendered?: number; - sinkDropped?: number; - zeroCopyD3D11: boolean; - zeroCopyD3D12: boolean; - queueMode?: NativeQueueMode; - queueDepthChanges?: number; - presentPacingChanges?: number; - partialFlushCount?: number; - completeFlushCount?: number; - lastTransitionType?: string; - lastTransitionAtMs?: number; - lastTransitionSummary?: string; - requestedStreamingFeaturesSummary?: string; - finalizedStreamingFeaturesSummary?: string; - serverGpuType?: string; - serverLocation?: string; -} diff --git a/opennow-stable/src/shared/nativeStreamer.ts b/opennow-stable/src/shared/nativeStreamer.ts index 830e629c3..29aa36635 100644 --- a/opennow-stable/src/shared/nativeStreamer.ts +++ b/opennow-stable/src/shared/nativeStreamer.ts @@ -1,11 +1,8 @@ import type { IceCandidatePayload, NativeStreamerBackend, - NativeStreamStats, NativeRenderSurface, - NativeStreamerShortcutAction, NativeStreamerSessionContext, - NativeVideoTransition, NativeVideoBackendCapability, SendAnswerRequest, } from "./gfn"; @@ -23,6 +20,10 @@ export interface NativeStreamerCapabilities { supportsRemoteIce: boolean; supportsLocalIce: boolean; supportsInput: boolean; + supportsVideoDecode: boolean; + supportsVideoPresent: boolean; + supportsAudioDecode?: boolean; + supportsAudioOutput?: boolean; videoBackends?: NativeVideoBackendCapability[]; } @@ -31,6 +32,15 @@ export interface NativeStreamerInputPacket { partiallyReliable?: boolean; } +export interface NativeStreamerActiveTransportCapabilities { + supportsOfferAnswer: boolean; + supportsRemoteIce: boolean; + supportsLocalIce: boolean; + supportsInput: boolean; + supportsAudioDecode: boolean; + supportsAudioOutput: boolean; +} + export type NativeStreamerCommand = | { id: string; @@ -42,6 +52,21 @@ export type NativeStreamerCommand = type: "start"; context: NativeStreamerSessionContext; } + | { + id: string; + type: "nvst-bind"; + } + | { + id: string; + type: "nvst-unbind"; + } + | { + id: string; + type: "nvst-send"; + host: string; + port: number; + payloadBase64: string; + } | { id: string; type: "offer"; @@ -68,20 +93,10 @@ export type NativeStreamerCommand = type: "surface"; surface: NativeRenderSurface; } - | { - id: string; - type: "bitrate"; - maxBitrateKbps: number; - } | { id: string; type: "stop"; reason?: string; - } - | { - id: string; - type: "update-shortcuts"; - shortcuts: import("./gfn").NativeStreamerShortcutBindings; }; export type NativeStreamerResponse = @@ -93,6 +108,18 @@ export type NativeStreamerResponse = | { id: string; type: "ok"; + transport?: "webrtc" | "nvst"; + capabilities?: NativeStreamerActiveTransportCapabilities; + } + | { + id: string; + type: "nvst-bound"; + port: number; + mjolnirPort?: number; + localAddress?: string; + iceUsernameFragment?: string; + icePassword?: string; + dtlsFingerprint?: string; } | { id: string; @@ -114,7 +141,7 @@ export type NativeStreamerEvent = } | { type: "status"; - status: "starting" | "ready" | "streaming" | "stopped"; + status: "starting" | "ready" | "streaming" | "paused" | "stopped"; message?: string; } | { @@ -126,50 +153,12 @@ export type NativeStreamerEvent = protocolVersion: number; } | { - type: "shortcut"; - action: NativeStreamerShortcutAction; - } - | { - type: "clipboard-paste"; - } - | { - type: "input-capture-changed"; - captured: boolean; - } - | { - type: "video-stall"; - stallMs: number; - encodedKbps?: number; - decodedFps: number; - sinkFps: number; - encodedAgeMs?: number; - decodedAgeMs?: number; - sinkAgeMs?: number; - likelyStage?: string; - sinkRendered?: number; - sinkDropped?: number; - memoryMode?: string; - zeroCopy?: boolean; - requestedFps?: number; - capsFramerate?: string; - queueMode?: string; - partialFlushCount?: number; - completeFlushCount?: number; - lastTransitionType?: string; - lastTransitionAtMs?: number; - requestedStreamingFeaturesSummary?: string; - finalizedStreamingFeaturesSummary?: string; - zeroCopyD3D11: boolean; - zeroCopyD3D12: boolean; - recoveryAttempt: number; - } - | { - type: "video-transition"; - transition: NativeVideoTransition; + type: "nvst-transport-ready"; + phase: "dtls" | "sctp"; } | { - type: "stats"; - stats: NativeStreamStats; + type: "input-unavailable"; + reason: string; } | { type: "error";